Add VFS2 plumbing for extended attributes.

PiperOrigin-RevId: 286281274
This commit is contained in:
Jamie Liu
2019-12-18 15:48:45 -08:00
committed by gVisor bot
parent 8e6e87f8e8
commit 744401297a
9 changed files with 345 additions and 2 deletions
+36
View File
@@ -443,6 +443,42 @@ func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
return syserror.EROFS
}
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
func (fs *filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
_, _, err := fs.walk(rp, false)
if err != nil {
return nil, err
}
return nil, syserror.ENOTSUP
}
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
func (fs *filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
_, _, err := fs.walk(rp, false)
if err != nil {
return "", err
}
return "", syserror.ENOTSUP
}
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
func (fs *filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
_, _, err := fs.walk(rp, false)
if err != nil {
return err
}
return syserror.ENOTSUP
}
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
func (fs *filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
_, _, err := fs.walk(rp, false)
if err != nil {
return err
}
return syserror.ENOTSUP
}
// PrependPath implements vfs.FilesystemImpl.PrependPath.
func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
fs.mu.RLock()
+52
View File
@@ -683,6 +683,58 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
return nil
}
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
func (fs *Filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
fs.mu.RLock()
_, _, err := fs.walkExistingLocked(ctx, rp)
fs.mu.RUnlock()
fs.processDeferredDecRefs()
if err != nil {
return nil, err
}
// kernfs currently does not support extended attributes.
return nil, syserror.ENOTSUP
}
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
func (fs *Filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
fs.mu.RLock()
_, _, err := fs.walkExistingLocked(ctx, rp)
fs.mu.RUnlock()
fs.processDeferredDecRefs()
if err != nil {
return "", err
}
// kernfs currently does not support extended attributes.
return "", syserror.ENOTSUP
}
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
func (fs *Filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
fs.mu.RLock()
_, _, err := fs.walkExistingLocked(ctx, rp)
fs.mu.RUnlock()
fs.processDeferredDecRefs()
if err != nil {
return err
}
// kernfs currently does not support extended attributes.
return syserror.ENOTSUP
}
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
func (fs *Filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
fs.mu.RLock()
_, _, err := fs.walkExistingLocked(ctx, rp)
fs.mu.RUnlock()
fs.processDeferredDecRefs()
if err != nil {
return err
}
// kernfs currently does not support extended attributes.
return syserror.ENOTSUP
}
// PrependPath implements vfs.FilesystemImpl.PrependPath.
func (fs *Filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
fs.mu.RLock()
+48
View File
@@ -584,6 +584,54 @@ func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
return nil
}
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
func (fs *filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
fs.mu.RLock()
defer fs.mu.RUnlock()
_, _, err := walkExistingLocked(rp)
if err != nil {
return nil, err
}
// TODO(b/127675828): support extended attributes
return nil, syserror.ENOTSUP
}
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
func (fs *filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
fs.mu.RLock()
defer fs.mu.RUnlock()
_, _, err := walkExistingLocked(rp)
if err != nil {
return "", err
}
// TODO(b/127675828): support extended attributes
return "", syserror.ENOTSUP
}
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
func (fs *filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
fs.mu.RLock()
defer fs.mu.RUnlock()
_, _, err := walkExistingLocked(rp)
if err != nil {
return err
}
// TODO(b/127675828): support extended attributes
return syserror.ENOTSUP
}
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
func (fs *filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
fs.mu.RLock()
defer fs.mu.RUnlock()
_, _, err := walkExistingLocked(rp)
if err != nil {
return err
}
// TODO(b/127675828): support extended attributes
return syserror.ENOTSUP
}
// PrependPath implements vfs.FilesystemImpl.PrependPath.
func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
fs.mu.RLock()
+48 -1
View File
@@ -22,6 +22,7 @@ import (
"gvisor.dev/gvisor/pkg/sentry/context"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -212,7 +213,21 @@ type FileDescriptionImpl interface {
// Ioctl implements the ioctl(2) syscall.
Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error)
// TODO: extended attributes; file locking
// Listxattr returns all extended attribute names for the file.
Listxattr(ctx context.Context) ([]string, error)
// Getxattr returns the value associated with the given extended attribute
// for the file.
Getxattr(ctx context.Context, name string) (string, error)
// Setxattr changes the value associated with the given extended attribute
// for the file.
Setxattr(ctx context.Context, opts SetxattrOptions) error
// Removexattr removes the given extended attribute from the file.
Removexattr(ctx context.Context, name string) error
// TODO: file locking
}
// Dirent holds the information contained in struct linux_dirent64.
@@ -329,6 +344,38 @@ func (fd *FileDescription) Ioctl(ctx context.Context, uio usermem.IO, args arch.
return fd.impl.Ioctl(ctx, uio, args)
}
// Listxattr returns all extended attribute names for the file represented by
// fd.
func (fd *FileDescription) Listxattr(ctx context.Context) ([]string, error) {
names, err := fd.impl.Listxattr(ctx)
if err == syserror.ENOTSUP {
// Linux doesn't actually return ENOTSUP in this case; instead,
// fs/xattr.c:vfs_listxattr() falls back to allowing the security
// subsystem to return security extended attributes, which by default
// don't exist.
return nil, nil
}
return names, err
}
// Getxattr returns the value associated with the given extended attribute for
// the file represented by fd.
func (fd *FileDescription) Getxattr(ctx context.Context, name string) (string, error) {
return fd.impl.Getxattr(ctx, name)
}
// Setxattr changes the value associated with the given extended attribute for
// the file represented by fd.
func (fd *FileDescription) Setxattr(ctx context.Context, opts SetxattrOptions) error {
return fd.impl.Setxattr(ctx, opts)
}
// Removexattr removes the given extended attribute from the file represented
// by fd.
func (fd *FileDescription) Removexattr(ctx context.Context, name string) error {
return fd.impl.Removexattr(ctx, name)
}
// SyncFS instructs the filesystem containing fd to execute the semantics of
// syncfs(2).
func (fd *FileDescription) SyncFS(ctx context.Context) error {
@@ -127,6 +127,31 @@ func (FileDescriptionDefaultImpl) Ioctl(ctx context.Context, uio usermem.IO, arg
return 0, syserror.ENOTTY
}
// Listxattr implements FileDescriptionImpl.Listxattr analogously to
// inode_operations::listxattr == NULL in Linux.
func (FileDescriptionDefaultImpl) Listxattr(ctx context.Context) ([]string, error) {
// This isn't exactly accurate; see FileDescription.Listxattr.
return nil, syserror.ENOTSUP
}
// Getxattr implements FileDescriptionImpl.Getxattr analogously to
// inode::i_opflags & IOP_XATTR == 0 in Linux.
func (FileDescriptionDefaultImpl) Getxattr(ctx context.Context, name string) (string, error) {
return "", syserror.ENOTSUP
}
// Setxattr implements FileDescriptionImpl.Setxattr analogously to
// inode::i_opflags & IOP_XATTR == 0 in Linux.
func (FileDescriptionDefaultImpl) Setxattr(ctx context.Context, opts SetxattrOptions) error {
return syserror.ENOTSUP
}
// Removexattr implements FileDescriptionImpl.Removexattr analogously to
// inode::i_opflags & IOP_XATTR == 0 in Linux.
func (FileDescriptionDefaultImpl) Removexattr(ctx context.Context, name string) error {
return syserror.ENOTSUP
}
// DirectoryFileDescriptionDefaultImpl may be embedded by implementations of
// FileDescriptionImpl that always represent directories to obtain
// implementations of non-directory I/O methods that return EISDIR.
+15 -1
View File
@@ -186,6 +186,20 @@ type FilesystemImpl interface {
// UnlinkAt removes the non-directory file at rp.
UnlinkAt(ctx context.Context, rp *ResolvingPath) error
// ListxattrAt returns all extended attribute names for the file at rp.
ListxattrAt(ctx context.Context, rp *ResolvingPath) ([]string, error)
// GetxattrAt returns the value associated with the given extended
// attribute for the file at rp.
GetxattrAt(ctx context.Context, rp *ResolvingPath, name string) (string, error)
// SetxattrAt changes the value associated with the given extended
// attribute for the file at rp.
SetxattrAt(ctx context.Context, rp *ResolvingPath, opts SetxattrOptions) error
// RemovexattrAt removes the given extended attribute from the file at rp.
RemovexattrAt(ctx context.Context, rp *ResolvingPath, name string) error
// PrependPath prepends a path from vd to vd.Mount().Root() to b.
//
// If vfsroot.Ok(), it is the contextual VFS root; if it is encountered
@@ -208,7 +222,7 @@ type FilesystemImpl interface {
// Preconditions: vd.Mount().Filesystem().Impl() == this FilesystemImpl.
PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error
// TODO: extended attributes; inotify_add_watch(); bind()
// TODO: inotify_add_watch(); bind()
}
// PrependPathAtVFSRootError is returned by implementations of
+14
View File
@@ -101,6 +101,20 @@ type SetStatOptions struct {
Stat linux.Statx
}
// SetxattrOptions contains options to VirtualFilesystem.SetxattrAt(),
// FilesystemImpl.SetxattrAt(), FileDescription.Setxattr(), and
// FileDescriptionImpl.Setxattr().
type SetxattrOptions struct {
// Name is the name of the extended attribute being mutated.
Name string
// Value is the extended attribute's new value.
Value string
// Flags contains flags as specified for setxattr/lsetxattr/fsetxattr(2).
Flags uint32
}
// StatOptions contains options to VirtualFilesystem.StatAt(),
// FilesystemImpl.StatAt(), FileDescription.Stat(), and
// FileDescriptionImpl.Stat().
+20
View File
@@ -117,6 +117,26 @@ func (fs *FDTestFilesystem) UnlinkAt(ctx context.Context, rp *ResolvingPath) err
return syserror.EPERM
}
// ListxattrAt implements FilesystemImpl.ListxattrAt.
func (fs *FDTestFilesystem) ListxattrAt(ctx context.Context, rp *ResolvingPath) ([]string, error) {
return nil, syserror.EPERM
}
// GetxattrAt implements FilesystemImpl.GetxattrAt.
func (fs *FDTestFilesystem) GetxattrAt(ctx context.Context, rp *ResolvingPath, name string) (string, error) {
return "", syserror.EPERM
}
// SetxattrAt implements FilesystemImpl.SetxattrAt.
func (fs *FDTestFilesystem) SetxattrAt(ctx context.Context, rp *ResolvingPath, opts SetxattrOptions) error {
return syserror.EPERM
}
// RemovexattrAt implements FilesystemImpl.RemovexattrAt.
func (fs *FDTestFilesystem) RemovexattrAt(ctx context.Context, rp *ResolvingPath, name string) error {
return syserror.EPERM
}
// PrependPath implements FilesystemImpl.PrependPath.
func (fs *FDTestFilesystem) PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error {
b.PrependComponent(fmt.Sprintf("vfs.fdTestDentry:%p", vd.dentry.impl.(*fdTestDentry)))
+87
View File
@@ -440,6 +440,93 @@ func (vfs *VirtualFilesystem) UnlinkAt(ctx context.Context, creds *auth.Credenti
}
}
// ListxattrAt returns all extended attribute names for the file at the given
// path.
func (vfs *VirtualFilesystem) ListxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation) ([]string, error) {
rp, err := vfs.getResolvingPath(creds, pop)
if err != nil {
return nil, err
}
for {
names, err := rp.mount.fs.impl.ListxattrAt(ctx, rp)
if err == nil {
vfs.putResolvingPath(rp)
return names, nil
}
if err == syserror.ENOTSUP {
// Linux doesn't actually return ENOTSUP in this case; instead,
// fs/xattr.c:vfs_listxattr() falls back to allowing the security
// subsystem to return security extended attributes, which by
// default don't exist.
vfs.putResolvingPath(rp)
return nil, nil
}
if !rp.handleError(err) {
vfs.putResolvingPath(rp)
return nil, err
}
}
}
// GetxattrAt returns the value associated with the given extended attribute
// for the file at the given path.
func (vfs *VirtualFilesystem) GetxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, name string) (string, error) {
rp, err := vfs.getResolvingPath(creds, pop)
if err != nil {
return "", err
}
for {
val, err := rp.mount.fs.impl.GetxattrAt(ctx, rp, name)
if err == nil {
vfs.putResolvingPath(rp)
return val, nil
}
if !rp.handleError(err) {
vfs.putResolvingPath(rp)
return "", err
}
}
}
// SetxattrAt changes the value associated with the given extended attribute
// for the file at the given path.
func (vfs *VirtualFilesystem) SetxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, opts *SetxattrOptions) error {
rp, err := vfs.getResolvingPath(creds, pop)
if err != nil {
return err
}
for {
err := rp.mount.fs.impl.SetxattrAt(ctx, rp, *opts)
if err == nil {
vfs.putResolvingPath(rp)
return nil
}
if !rp.handleError(err) {
vfs.putResolvingPath(rp)
return err
}
}
}
// RemovexattrAt removes the given extended attribute from the file at rp.
func (vfs *VirtualFilesystem) RemovexattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, name string) error {
rp, err := vfs.getResolvingPath(creds, pop)
if err != nil {
return err
}
for {
err := rp.mount.fs.impl.RemovexattrAt(ctx, rp, name)
if err == nil {
vfs.putResolvingPath(rp)
return nil
}
if !rp.handleError(err) {
vfs.putResolvingPath(rp)
return err
}
}
}
// SyncAllFilesystems has the semantics of Linux's sync(2).
func (vfs *VirtualFilesystem) SyncAllFilesystems(ctx context.Context) error {
fss := make(map[*Filesystem]struct{})