Merge release-20191114.0-16-g012102e (automated)
This commit is contained in:
commit
bd17bba359
|
@ -272,15 +272,15 @@ func (t *Tlopen) handle(cs *connState) message {
|
||||||
return newErr(syscall.EINVAL)
|
return newErr(syscall.EINVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are flags valid?
|
if ref.mode.IsDir() {
|
||||||
flags := t.Flags &^ OpenFlagsIgnoreMask
|
// Directory must be opened ReadOnly.
|
||||||
if flags&^OpenFlagsModeMask != 0 {
|
if t.Flags&OpenFlagsModeMask != ReadOnly {
|
||||||
return newErr(syscall.EINVAL)
|
return newErr(syscall.EISDIR)
|
||||||
|
}
|
||||||
|
// Directory not truncatable.
|
||||||
|
if t.Flags&OpenTruncate != 0 {
|
||||||
|
return newErr(syscall.EISDIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this an attempt to open a directory as writable? Don't accept.
|
|
||||||
if ref.mode.IsDir() && flags != ReadOnly {
|
|
||||||
return newErr(syscall.EINVAL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -47,10 +47,6 @@ const (
|
||||||
// OpenTruncate is a Tlopen flag indicating that the opened file should be
|
// OpenTruncate is a Tlopen flag indicating that the opened file should be
|
||||||
// truncated.
|
// truncated.
|
||||||
OpenTruncate OpenFlags = 01000
|
OpenTruncate OpenFlags = 01000
|
||||||
|
|
||||||
// OpenFlagsIgnoreMask is a list of OpenFlags mode bits that are ignored for Tlopen.
|
|
||||||
// Note that syscall.O_LARGEFILE is set to zero, use value from Linux fcntl.h.
|
|
||||||
OpenFlagsIgnoreMask OpenFlags = syscall.O_DIRECTORY | syscall.O_NOATIME | 0100000
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectFlags is the mode passed to Connect operations.
|
// ConnectFlags is the mode passed to Connect operations.
|
||||||
|
|
|
@ -26,7 +26,7 @@ const (
|
||||||
//
|
//
|
||||||
// Clients are expected to start requesting this version number and
|
// Clients are expected to start requesting this version number and
|
||||||
// to continuously decrement it until a Tversion request succeeds.
|
// to continuously decrement it until a Tversion request succeeds.
|
||||||
highestSupportedVersion uint32 = 8
|
highestSupportedVersion uint32 = 9
|
||||||
|
|
||||||
// lowestSupportedVersion is the lowest supported version X in a
|
// lowestSupportedVersion is the lowest supported version X in a
|
||||||
// version string of the format 9P2000.L.Google.X.
|
// version string of the format 9P2000.L.Google.X.
|
||||||
|
@ -155,3 +155,9 @@ func versionSupportsTallocate(v uint32) bool {
|
||||||
func versionSupportsFlipcall(v uint32) bool {
|
func versionSupportsFlipcall(v uint32) bool {
|
||||||
return v >= 8
|
return v >= 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VersionSupportsOpenTruncateFlag returns true if version v supports
|
||||||
|
// passing the OpenTruncate flag to Tlopen.
|
||||||
|
func VersionSupportsOpenTruncateFlag(v uint32) bool {
|
||||||
|
return v >= 9
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,10 @@ type FileFlags struct {
|
||||||
|
|
||||||
// NonSeekable indicates that file.offset isn't used.
|
// NonSeekable indicates that file.offset isn't used.
|
||||||
NonSeekable bool
|
NonSeekable bool
|
||||||
|
|
||||||
|
// Truncate indicates that the file should be truncated before opened.
|
||||||
|
// This is only applicable if the file is regular.
|
||||||
|
Truncate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SettableFileFlags is a subset of FileFlags above that can be changed
|
// SettableFileFlags is a subset of FileFlags above that can be changed
|
||||||
|
@ -118,6 +122,9 @@ func (f FileFlags) ToLinux() (mask uint) {
|
||||||
if f.LargeFile {
|
if f.LargeFile {
|
||||||
mask |= linux.O_LARGEFILE
|
mask |= linux.O_LARGEFILE
|
||||||
}
|
}
|
||||||
|
if f.Truncate {
|
||||||
|
mask |= linux.O_TRUNC
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case f.Read && f.Write:
|
case f.Read && f.Write:
|
||||||
|
|
|
@ -353,6 +353,7 @@ func (x *FileFlags) save(m state.Map) {
|
||||||
m.Save("Async", &x.Async)
|
m.Save("Async", &x.Async)
|
||||||
m.Save("LargeFile", &x.LargeFile)
|
m.Save("LargeFile", &x.LargeFile)
|
||||||
m.Save("NonSeekable", &x.NonSeekable)
|
m.Save("NonSeekable", &x.NonSeekable)
|
||||||
|
m.Save("Truncate", &x.Truncate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FileFlags) afterLoad() {}
|
func (x *FileFlags) afterLoad() {}
|
||||||
|
@ -370,6 +371,7 @@ func (x *FileFlags) load(m state.Map) {
|
||||||
m.Load("Async", &x.Async)
|
m.Load("Async", &x.Async)
|
||||||
m.Load("LargeFile", &x.LargeFile)
|
m.Load("LargeFile", &x.LargeFile)
|
||||||
m.Load("NonSeekable", &x.NonSeekable)
|
m.Load("NonSeekable", &x.NonSeekable)
|
||||||
|
m.Load("Truncate", &x.Truncate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Inode) beforeSave() {}
|
func (x *Inode) beforeSave() {}
|
||||||
|
|
|
@ -28,8 +28,14 @@ func (f *fileOperations) afterLoad() {
|
||||||
|
|
||||||
// Manually load the open handles.
|
// Manually load the open handles.
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
// The file may have been opened with Truncate, but we don't
|
||||||
|
// want to re-open it with Truncate or we will lose data.
|
||||||
|
flags := f.flags
|
||||||
|
flags.Truncate = false
|
||||||
|
|
||||||
// TODO(b/38173783): Context is not plumbed to save/restore.
|
// TODO(b/38173783): Context is not plumbed to save/restore.
|
||||||
f.handles, err = f.inodeOperations.fileState.getHandles(context.Background(), f.flags, f.inodeOperations.cachingInodeOps)
|
f.handles, err = f.inodeOperations.fileState.getHandles(context.Background(), flags, f.inodeOperations.cachingInodeOps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to re-open handle: %v", err)
|
return fmt.Errorf("failed to re-open handle: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (h *handles) DecRef() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHandles(ctx context.Context, file contextFile, flags fs.FileFlags) (*handles, error) {
|
func newHandles(ctx context.Context, client *p9.Client, file contextFile, flags fs.FileFlags) (*handles, error) {
|
||||||
_, newFile, err := file.walk(ctx, nil)
|
_, newFile, err := file.walk(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -81,6 +81,9 @@ func newHandles(ctx context.Context, file contextFile, flags fs.FileFlags) (*han
|
||||||
default:
|
default:
|
||||||
panic("impossible fs.FileFlags")
|
panic("impossible fs.FileFlags")
|
||||||
}
|
}
|
||||||
|
if flags.Truncate && p9.VersionSupportsOpenTruncateFlag(client.Version()) {
|
||||||
|
p9flags |= p9.OpenTruncate
|
||||||
|
}
|
||||||
|
|
||||||
hostFile, _, _, err := newFile.open(ctx, p9flags)
|
hostFile, _, _, err := newFile.open(ctx, p9flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -180,7 +180,7 @@ func (i *inodeFileState) setSharedHandlesLocked(flags fs.FileFlags, h *handles)
|
||||||
// given flags.
|
// given flags.
|
||||||
func (i *inodeFileState) getHandles(ctx context.Context, flags fs.FileFlags, cache *fsutil.CachingInodeOperations) (*handles, error) {
|
func (i *inodeFileState) getHandles(ctx context.Context, flags fs.FileFlags, cache *fsutil.CachingInodeOperations) (*handles, error) {
|
||||||
if !i.canShareHandles() {
|
if !i.canShareHandles() {
|
||||||
return newHandles(ctx, i.file, flags)
|
return newHandles(ctx, i.s.client, i.file, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.handlesMu.Lock()
|
i.handlesMu.Lock()
|
||||||
|
@ -201,19 +201,25 @@ func (i *inodeFileState) getHandles(ctx context.Context, flags fs.FileFlags, cac
|
||||||
// whether previously open read handle was recreated. Host mappings must be
|
// whether previously open read handle was recreated. Host mappings must be
|
||||||
// invalidated if so.
|
// invalidated if so.
|
||||||
func (i *inodeFileState) getHandlesLocked(ctx context.Context, flags fs.FileFlags) (*handles, bool, error) {
|
func (i *inodeFileState) getHandlesLocked(ctx context.Context, flags fs.FileFlags) (*handles, bool, error) {
|
||||||
// Do we already have usable shared handles?
|
// Check if we are able to use cached handles.
|
||||||
if flags.Write {
|
if flags.Truncate && p9.VersionSupportsOpenTruncateFlag(i.s.client.Version()) {
|
||||||
|
// If we are truncating (and the gofer supports it), then we
|
||||||
|
// always need a new handle. Don't return one from the cache.
|
||||||
|
} else if flags.Write {
|
||||||
if i.writeHandles != nil && (i.writeHandlesRW || !flags.Read) {
|
if i.writeHandles != nil && (i.writeHandlesRW || !flags.Read) {
|
||||||
|
// File is opened for writing, and we have cached write
|
||||||
|
// handles that we can use.
|
||||||
i.writeHandles.IncRef()
|
i.writeHandles.IncRef()
|
||||||
return i.writeHandles, false, nil
|
return i.writeHandles, false, nil
|
||||||
}
|
}
|
||||||
} else if i.readHandles != nil {
|
} else if i.readHandles != nil {
|
||||||
|
// File is opened for reading and we have cached handles.
|
||||||
i.readHandles.IncRef()
|
i.readHandles.IncRef()
|
||||||
return i.readHandles, false, nil
|
return i.readHandles, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// No; get new handles and cache them for future sharing.
|
// Get new handles and cache them for future sharing.
|
||||||
h, err := newHandles(ctx, i.file, flags)
|
h, err := newHandles(ctx, i.s.client, i.file, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
@ -239,7 +245,7 @@ func (i *inodeFileState) recreateReadHandles(ctx context.Context, writer *handle
|
||||||
if !flags.Read {
|
if !flags.Read {
|
||||||
// Writer can't be used for read, must create a new handle.
|
// Writer can't be used for read, must create a new handle.
|
||||||
var err error
|
var err error
|
||||||
h, err = newHandles(ctx, i.file, fs.FileFlags{Read: true})
|
h, err = newHandles(ctx, i.s.client, i.file, fs.FileFlags{Read: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,5 +50,6 @@ func linuxToFlags(mask uint) fs.FileFlags {
|
||||||
Directory: mask&linux.O_DIRECTORY != 0,
|
Directory: mask&linux.O_DIRECTORY != 0,
|
||||||
Async: mask&linux.O_ASYNC != 0,
|
Async: mask&linux.O_ASYNC != 0,
|
||||||
LargeFile: mask&linux.O_LARGEFILE != 0,
|
LargeFile: mask&linux.O_LARGEFILE != 0,
|
||||||
|
Truncate: mask&linux.O_TRUNC != 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue