summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
authorCraig Chi <craigchi@google.com>2020-09-09 09:16:09 -0700
committerAndrei Vagin <avagin@gmail.com>2020-09-16 12:19:30 -0700
commit4181e8c97482a3c787c2b508e6d75a21323ba515 (patch)
tree70df02d5b3c1cb621210559b2ba82ce62330ac01 /pkg
parent1146ab6bac7c4d34a9b78a6c318db3dae8150b4d (diff)
Add fh support for revise attr and fstat(2) test
According to Linux 4.4's FUSE behavior, the flags and fh attributes in FUSE_GETATTR are only used in read, write, and lseek. fstat(2) doesn't use them either. Add tests to ensure the requests sent from FUSE module are consistent with Linux's. Updates #3655
Diffstat (limited to 'pkg')
-rw-r--r--pkg/abi/linux/fuse.go5
-rw-r--r--pkg/sentry/fsimpl/fuse/fusefs.go21
-rw-r--r--pkg/sentry/fsimpl/fuse/regular_file.go2
3 files changed, 16 insertions, 12 deletions
diff --git a/pkg/abi/linux/fuse.go b/pkg/abi/linux/fuse.go
index e49a92fb2..f0bef1e8e 100644
--- a/pkg/abi/linux/fuse.go
+++ b/pkg/abi/linux/fuse.go
@@ -227,6 +227,11 @@ type FUSEInitOut struct {
_ [8]uint32
}
+// FUSE_GETATTR_FH is currently the only flag of FUSEGetAttrIn.GetAttrFlags.
+// If it is set, the file handle (FUSEGetAttrIn.Fh) is used to indicate the
+// object instead of the node id attribute in the request header.
+const FUSE_GETATTR_FH = (1 << 0)
+
// FUSEGetAttrIn is the request sent by the kernel to the daemon,
// to get the attribute of a inode.
//
diff --git a/pkg/sentry/fsimpl/fuse/fusefs.go b/pkg/sentry/fsimpl/fuse/fusefs.go
index 8cf13dcb6..821048d87 100644
--- a/pkg/sentry/fsimpl/fuse/fusefs.go
+++ b/pkg/sentry/fsimpl/fuse/fusefs.go
@@ -609,9 +609,9 @@ func statFromFUSEAttr(attr linux.FUSEAttr, mask, devMinor uint32) linux.Statx {
}
// getAttr gets the attribute of this inode by issuing a FUSE_GETATTR request
-// or read from local cache.
-// It updates the corresponding attributes if necessary.
-func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOptions) (linux.FUSEAttr, error) {
+// or read from local cache. It updates the corresponding attributes if
+// necessary.
+func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOptions, flags uint32, fh uint64) (linux.FUSEAttr, error) {
attributeVersion := atomic.LoadUint64(&i.fs.conn.attributeVersion)
// TODO(gvisor.dev/issue/3679): send the request only if
@@ -631,11 +631,10 @@ func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOp
creds := auth.CredentialsFromContext(ctx)
- var in linux.FUSEGetAttrIn
- // We don't set any attribute in the request, because in VFS2 fstat(2) will
- // finally be translated into vfs.FilesystemImpl.StatAt() (see
- // pkg/sentry/syscalls/linux/vfs2/stat.go), resulting in the same flow
- // as stat(2). Thus GetAttrFlags and Fh variable will never be used in VFS2.
+ in := linux.FUSEGetAttrIn{
+ GetAttrFlags: flags,
+ Fh: fh,
+ }
req, err := i.fs.conn.NewRequest(creds, uint32(task.ThreadID()), i.NodeID, linux.FUSE_GETATTR, &in)
if err != nil {
return linux.FUSEAttr{}, err
@@ -676,17 +675,17 @@ func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOp
// reviseAttr attempts to update the attributes for internal purposes
// by calling getAttr with a pre-specified mask.
// Used by read, write, lseek.
-func (i *inode) reviseAttr(ctx context.Context) error {
+func (i *inode) reviseAttr(ctx context.Context, flags uint32, fh uint64) error {
// Never need atime for internal purposes.
_, err := i.getAttr(ctx, i.fs.VFSFilesystem(), vfs.StatOptions{
Mask: linux.STATX_BASIC_STATS &^ linux.STATX_ATIME,
- })
+ }, flags, fh)
return err
}
// Stat implements kernfs.Inode.Stat.
func (i *inode) Stat(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOptions) (linux.Statx, error) {
- attr, err := i.getAttr(ctx, fs, opts)
+ attr, err := i.getAttr(ctx, fs, opts, 0, 0)
if err != nil {
return linux.Statx{}, err
}
diff --git a/pkg/sentry/fsimpl/fuse/regular_file.go b/pkg/sentry/fsimpl/fuse/regular_file.go
index 193e77392..5bdd096c3 100644
--- a/pkg/sentry/fsimpl/fuse/regular_file.go
+++ b/pkg/sentry/fsimpl/fuse/regular_file.go
@@ -65,7 +65,7 @@ func (fd *regularFileFD) PRead(ctx context.Context, dst usermem.IOSequence, offs
// Reading beyond EOF, update file size if outdated.
if uint64(offset+size) > atomic.LoadUint64(&inode.size) {
- if err := inode.reviseAttr(ctx); err != nil {
+ if err := inode.reviseAttr(ctx, linux.FUSE_GETATTR_FH, fd.Fh); err != nil {
return 0, err
}
// If the offset after update is still too large, return error.