summaryrefslogtreecommitdiffhomepage
path: root/pkg/p9/file.go
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2018-10-23 00:19:11 -0700
committerShentubot <shentubot@google.com>2018-10-23 00:20:15 -0700
commit75cd70ecc9abfd5daaefea04da5070a0e0d620dd (patch)
treeff17ca619006a3bea596df09a58abbbf21c6528d /pkg/p9/file.go
parentc2c0f9cb7e8320de06ef280c6184bb6aeda71627 (diff)
Track paths and provide a rename hook.
This change also adds extensive testing to the p9 package via mocks. The sanity checks and type checks are moved from the gofer into the core package, where they can be more easily validated. PiperOrigin-RevId: 218296768 Change-Id: I4fc3c326e7bf1e0e140a454cbacbcc6fd617ab55
Diffstat (limited to 'pkg/p9/file.go')
-rw-r--r--pkg/p9/file.go151
1 files changed, 110 insertions, 41 deletions
diff --git a/pkg/p9/file.go b/pkg/p9/file.go
index d2e89e373..55ceb52e1 100644
--- a/pkg/p9/file.go
+++ b/pkg/p9/file.go
@@ -31,35 +31,63 @@ type Attacher interface {
// File is a set of operations corresponding to a single node.
//
-// Functions below MUST return syscall.Errno values.
-// TODO: Enforce that with the type.
+// Note that on the server side, the server logic places constraints on
+// concurrent operations to make things easier. This may reduce the need for
+// complex, error-prone locking and logic in the backend. These are documented
+// for each method.
//
-// These must be implemented in all circumstances.
+// There are three different types of guarantees provided:
+//
+// none: There is no concurrency guarantee. The method may be invoked
+// concurrently with any other method on any other file.
+//
+// read: The method is guaranteed to be exclusive of any write or global
+// operation that is mutating the state of the directory tree starting at this
+// node. For example, this means creating new files, symlinks, directories or
+// renaming a directory entry (or renaming in to this target), but the method
+// may be called concurrently with other read methods.
+//
+// write: The method is guaranteed to be exclusive of any read, write or global
+// operation that is mutating the state of the directory tree starting at this
+// node, as described in read above. There may however, be other write
+// operations executing concurrently on other components in the directory tree.
+//
+// global: The method is guaranteed to be exclusive of any read, write or
+// global operation.
type File interface {
// Walk walks to the path components given in names.
//
// Walk returns QIDs in the same order that the names were passed in.
//
// An empty list of arguments should return a copy of the current file.
+ //
+ // On the server, Walk has a read concurrency guarantee.
Walk(names []string) ([]QID, File, error)
+ // WalkGetAttr walks to the next file and returns its maximal set of
+ // attributes.
+ //
+ // Server-side p9.Files may return syscall.ENOSYS to indicate that Walk
+ // and GetAttr should be used separately to satisfy this request.
+ //
+ // On the server, WalkGetAttr has a read concurrency guarantee.
+ WalkGetAttr([]string) ([]QID, File, AttrMask, Attr, error)
+
// StatFS returns information about the file system associated with
// this file.
+ //
+ // On the server, StatFS has no concurrency guarantee.
StatFS() (FSStat, error)
// GetAttr returns attributes of this node.
+ //
+ // On the server, GetAttr has a read concurrency guarantee.
GetAttr(req AttrMask) (QID, AttrMask, Attr, error)
// SetAttr sets attributes on this node.
- SetAttr(valid SetAttrMask, attr SetAttr) error
-
- // Remove removes the file.
//
- // This is deprecated in favor of UnlinkAt below.
- Remove() error
-
- // Rename renames the file.
- Rename(directory File, name string) error
+ // On the server, SetAttr has a write concurrency guarantee.
+ SetAttr(valid SetAttrMask, attr SetAttr) error
// Close is called when all references are dropped on the server side,
// and Close should be called by the client to drop all references.
@@ -67,65 +95,93 @@ type File interface {
// For server-side implementations of Close, the error is ignored.
//
// Close must be called even when Open has not been called.
+ //
+ // On the server, Close has no concurrency guarantee.
Close() error
- // Open is called prior to using read/write.
+ // Open must be called prior to using Read, Write or Readdir. Once Open
+ // is called, some operations, such as Walk, will no longer work.
//
- // The *fd.FD may be nil. If an *fd.FD is provided, ownership now
- // belongs to the caller and the FD must be non-blocking.
+ // On the client, Open should be called only once. The fd return is
+ // optional, and may be nil.
//
- // If Open returns a non-nil *fd.FD, it should do so for all possible
- // OpenFlags. If Open returns a nil *fd.FD, it should similarly return
- // a nil *fd.FD for all possible OpenFlags.
+ // On the server, Open has a read concurrency guarantee. If an *fd.FD
+ // is provided, ownership now belongs to the caller. Open is guaranteed
+ // to be called only once.
//
- // This can be assumed to be one-shot only.
+ // N.B. The server must resolve any lazy paths when open is called.
+ // After this point, read and write may be called on files with no
+ // deletion check, so resolving in the data path is not viable.
Open(mode OpenFlags) (*fd.FD, QID, uint32, error)
- // Read reads from this file.
+ // Read reads from this file. Open must be called first.
//
// This may return io.EOF in addition to syscall.Errno values.
//
- // Preconditions: Open has been called and returned success.
+ // On the server, ReadAt has a read concurrency guarantee. See Open for
+ // additional requirements regarding lazy path resolution.
ReadAt(p []byte, offset uint64) (int, error)
- // Write writes to this file.
+ // Write writes to this file. Open must be called first.
//
// This may return io.EOF in addition to syscall.Errno values.
//
- // Preconditions: Open has been called and returned success.
+ // On the server, WriteAt has a read concurrency guarantee. See Open
+ // for additional requirements regarding lazy path resolution.
WriteAt(p []byte, offset uint64) (int, error)
- // FSync syncs this node.
+ // FSync syncs this node. Open must be called first.
//
- // Preconditions: Open has been called and returned success.
+ // On the server, FSync has a read concurrency guarantee.
FSync() error
// Create creates a new regular file and opens it according to the
- // flags given.
+ // flags given. This file is already Open.
+ //
+ // N.B. On the client, the returned file is a reference to the current
+ // file, which now represents the created file. This is not the case on
+ // the server. These semantics are very subtle and can easily lead to
+ // bugs, but are a consequence of the 9P create operation.
//
// See p9.File.Open for a description of *fd.FD.
+ //
+ // On the server, Create has a write concurrency guarantee.
Create(name string, flags OpenFlags, permissions FileMode, uid UID, gid GID) (*fd.FD, File, QID, uint32, error)
// Mkdir creates a subdirectory.
+ //
+ // On the server, Mkdir has a write concurrency guarantee.
Mkdir(name string, permissions FileMode, uid UID, gid GID) (QID, error)
// Symlink makes a new symbolic link.
- Symlink(oldname string, newname string, uid UID, gid GID) (QID, error)
+ //
+ // On the server, Symlink has a write concurrency guarantee.
+ Symlink(oldName string, newName string, uid UID, gid GID) (QID, error)
// Link makes a new hard link.
- Link(target File, newname string) error
+ //
+ // On the server, Link has a write concurrency guarantee.
+ Link(target File, newName string) error
// Mknod makes a new device node.
+ //
+ // On the server, Mknod has a write concurrency guarantee.
Mknod(name string, permissions FileMode, major uint32, minor uint32, uid UID, gid GID) (QID, error)
+ // Rename renames the file.
+ //
+ // Rename will never be called on the server, and RenameAt will always
+ // be used instead.
+ Rename(newDir File, newName string) error
+
// RenameAt renames a given file to a new name in a potentially new
// directory.
//
- // oldname must be a name relative to this file, which must be a
- // directory. newname is a name relative to newdir.
+ // oldName must be a name relative to this file, which must be a
+ // directory. newName is a name relative to newDir.
//
- // This is deprecated in favor of Rename.
- RenameAt(oldname string, newdir File, newname string) error
+ // On the server, RenameAt has a global concurrency guarantee.
+ RenameAt(oldName string, newDir File, newName string) error
// UnlinkAt the given named file.
//
@@ -133,16 +189,20 @@ type File interface {
//
// Flags are implementation-specific (e.g. O_DIRECTORY), but are
// generally Linux unlinkat(2) flags.
+ //
+ // On the server, UnlinkAt has a write concurrency guarantee.
UnlinkAt(name string, flags uint32) error
// Readdir reads directory entries.
//
// This may return io.EOF in addition to syscall.Errno values.
//
- // Preconditions: Open has been called and returned success.
+ // On the server, Readdir has a read concurrency guarantee.
Readdir(offset uint64, count uint32) ([]Dirent, error)
// Readlink reads the link target.
+ //
+ // On the server, Readlink has a read concurrency guarantee.
Readlink() (string, error)
// Flush is called prior to Close.
@@ -150,16 +210,11 @@ type File interface {
// Whereas Close drops all references to the file, Flush cleans up the
// file state. Behavior is implementation-specific.
//
- // Flush is not related to flush(9p). Flush is an extension to 9P2000.L,
+ // Flush is not related to flush(9p). Flush is an extension to 9P2000.L,
// see version.go.
- Flush() error
-
- // WalkGetAttr walks to the next file and returns its maximal set of
- // attributes.
//
- // Server-side p9.Files may return syscall.ENOSYS to indicate that Walk
- // and GetAttr should be used separately to satisfy this request.
- WalkGetAttr([]string) ([]QID, File, AttrMask, Attr, error)
+ // On the server, Flush has a read concurrency guarantee.
+ Flush() error
// Connect establishes a new host-socket backed connection with a
// socket. A File does not need to be opened before it can be connected
@@ -170,8 +225,22 @@ type File interface {
//
// The returned FD must be non-blocking.
//
- // flags indicates the requested type of socket.
+ // Flags indicates the requested type of socket.
+ //
+ // On the server, Connect has a read concurrency guarantee.
Connect(flags ConnectFlags) (*fd.FD, error)
+
+ // Renamed is called when this node is renamed.
+ //
+ // This may not fail. The file will hold a reference to its parent
+ // within the p9 package, and is therefore safe to use for the lifetime
+ // of this File (until Close is called).
+ //
+ // This method should not be called by clients, who should use the
+ // relevant Rename methods. (Although the method will be a no-op.)
+ //
+ // On the server, Renamed has a global concurrency guarantee.
+ Renamed(newDir File, newName string)
}
// DefaultWalkGetAttr implements File.WalkGetAttr to return ENOSYS for server-side Files.