Change FUSE so that is no longer dependent on kernel tasks.

Filesystem operations are sometimes performed outside of the context of
a kernel task.

PiperOrigin-RevId: 533271322
This commit is contained in:
Lucas Manning
2023-05-18 15:41:32 -07:00
committed by gVisor bot
parent f105ee555d
commit d6d9fe6236
15 changed files with 113 additions and 163 deletions
+2
View File
@@ -12,6 +12,8 @@ go_library(
],
visibility = ["//:sandbox"],
deps = [
"//pkg/abi/linux/errno",
"//pkg/errors",
"//pkg/log",
"//pkg/waiter",
],
+20
View File
@@ -27,6 +27,8 @@ import (
"sync"
"time"
"gvisor.dev/gvisor/pkg/abi/linux/errno"
"gvisor.dev/gvisor/pkg/errors"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -49,6 +51,11 @@ type Blocker interface {
// result of the requested event (versus an external interrupt).
BlockOn(waiter.Waitable, waiter.EventMask) bool
// Block blocks until an event is received from C, or some external
// interrupt. It returns nil if an event is received from C and an err if t
// is interrupted.
Block(C <-chan struct{}) error
// BlockWithTimeoutOn blocks until either the conditions of Block are
// satisfied, or the timeout is hit. Note that deadlines are not supported
// since the notion of "with respect to what clock" is not resolved.
@@ -88,6 +95,19 @@ func (nt *NoTask) Interrupted() bool {
return nt.cancel != nil && len(nt.cancel) > 0
}
// Block implements Blocker.Block.
func (nt *NoTask) Block(C <-chan struct{}) error {
if nt.cancel == nil {
nt.cancel = make(chan struct{}, 1)
}
select {
case <-nt.cancel:
return errors.New(errno.EINTR, "interrupted system call") // Interrupted.
case <-C:
return nil
}
}
// BlockOn implements Blocker.BlockOn.
func (nt *NoTask) BlockOn(w waiter.Waitable, mask waiter.EventMask) bool {
if nt.cancel == nil {
+12 -12
View File
@@ -22,7 +22,6 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -176,7 +175,7 @@ type connection struct {
// Negotiated and only set in INIT.
bigWrites bool
// dontMask if filestestem does not apply umask to creation modes.
// dontMask if filesystem does not apply umask to creation modes.
// Negotiated in INIT.
dontMask bool
@@ -227,9 +226,9 @@ func newFUSEConnection(_ context.Context, fuseFD *DeviceFD, opts *filesystemOpti
// CallAsync makes an async (aka background) request.
// It's a simple wrapper around Call().
func (conn *connection) CallAsync(t *kernel.Task, r *Request) error {
func (conn *connection) CallAsync(ctx context.Context, r *Request) error {
r.async = true
_, err := conn.Call(t, r)
_, err := conn.Call(ctx, r)
return err
}
@@ -251,10 +250,11 @@ func (conn *connection) CallAsync(t *kernel.Task, r *Request) error {
//
// The forget request does not have a reply,
// as documented in include/uapi/linux/fuse.h:FUSE_FORGET.
func (conn *connection) Call(t *kernel.Task, r *Request) (*Response, error) {
func (conn *connection) Call(ctx context.Context, r *Request) (*Response, error) {
b := blockerFromContext(ctx)
// Block requests sent before connection is initialized.
if !conn.Initialized() && r.hdr.Opcode != linux.FUSE_INIT {
if err := t.Block(conn.initializedChan); err != nil {
if err := b.Block(conn.initializedChan); err != nil {
return nil, err
}
}
@@ -275,19 +275,19 @@ func (conn *connection) Call(t *kernel.Task, r *Request) (*Response, error) {
return nil, linuxerr.ECONNREFUSED
}
fut, err := conn.callFuture(t, r)
fut, err := conn.callFuture(b, r)
conn.fd.mu.Unlock()
if err != nil {
return nil, err
}
return fut.resolve(t)
return fut.resolve(b)
}
// callFuture makes a request to the server and returns a future response.
// Call resolve() when the response needs to be fulfilled.
// +checklocks:conn.fd.mu
func (conn *connection) callFuture(t *kernel.Task, r *Request) (*futureResponse, error) {
func (conn *connection) callFuture(b context.Blocker, r *Request) (*futureResponse, error) {
// Is the queue full?
//
// We must busy wait here until the request can be queued. We don't
@@ -303,19 +303,19 @@ func (conn *connection) callFuture(t *kernel.Task, r *Request) (*futureResponse,
log.Infof("Blocking request %v from being queued. Too many active requests: %v",
r.id, conn.fd.numActiveRequests)
conn.fd.mu.Unlock()
err := t.Block(conn.fd.fullQueueCh)
err := b.Block(conn.fd.fullQueueCh)
conn.fd.mu.Lock()
if err != nil {
return nil, err
}
}
return conn.callFutureLocked(t, r)
return conn.callFutureLocked(r)
}
// callFutureLocked makes a request to the server and returns a future response.
// +checklocks:conn.fd.mu
func (conn *connection) callFutureLocked(t *kernel.Task, r *Request) (*futureResponse, error) {
func (conn *connection) callFutureLocked(r *Request) (*futureResponse, error) {
// Check connected again holding conn.mu.
conn.mu.Lock()
if !conn.connected {
+4 -4
View File
@@ -88,13 +88,13 @@ func (conn *connection) InitSend(creds *auth.Credentials, pid uint32) error {
req := conn.NewRequest(creds, pid, 0, linux.FUSE_INIT, &in)
// Since there is no task to block on and FUSE_INIT is the request
// to unblock other requests, use nil.
return conn.CallAsync(nil, req)
// to unblock other requests, use context.Background().
return conn.CallAsync(context.Background(), req)
}
// InitRecv receives a FUSE_INIT reply and process it.
//
// Preconditions: conn.asyncMu must not be held if minor verion is newer than 13.
// Preconditions: conn.asyncMu must not be held if minor version is newer than 13.
func (conn *connection) InitRecv(res *Response, hasSysAdminCap bool) error {
if err := res.Error(); err != nil {
return err
@@ -115,7 +115,7 @@ func (conn *connection) InitRecv(res *Response, hasSysAdminCap bool) error {
// It tries to acquire the conn.asyncMu lock if minor version is newer than 13.
func (conn *connection) initProcessReply(out *linux.FUSEInitOut, hasSysAdminCap bool) error {
conn.mu.Lock()
// No matter error or not, always set initialzied.
// No matter error or not, always set initialized.
// to unblock the blocked requests.
defer func() {
conn.SetInitialized()
+4 -9
View File
@@ -21,7 +21,6 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/marshal/primitive"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
)
@@ -33,9 +32,7 @@ func TestConnectionInitBlock(t *testing.T) {
s := setup(t)
defer s.Destroy()
k := kernel.KernelFromContext(s.Ctx)
conn, _, err := newTestConnection(s, k, maxActiveRequestsDefault)
conn, _, err := newTestConnection(s, maxActiveRequestsDefault)
if err != nil {
t.Fatalf("newTestConnection: %v", err)
}
@@ -59,13 +56,11 @@ func TestConnectionAbort(t *testing.T) {
s := setup(t)
defer s.Destroy()
k := kernel.KernelFromContext(s.Ctx)
creds := auth.CredentialsFromContext(s.Ctx)
task := kernel.TaskFromContext(s.Ctx)
const numRequests uint64 = 256
conn, _, err := newTestConnection(s, k, numRequests)
conn, _, err := newTestConnection(s, numRequests)
if err != nil {
t.Fatalf("newTestConnection: %v", err)
}
@@ -75,7 +70,7 @@ func TestConnectionAbort(t *testing.T) {
for i := 0; i < int(numRequests); i++ {
req := conn.NewRequest(creds, uint32(i), uint64(i), 0, &testObj)
conn.fd.mu.Lock()
fut, err := conn.callFutureLocked(task, req)
fut, err := conn.callFutureLocked(req)
conn.fd.mu.Unlock()
if err != nil {
t.Fatalf("callFutureLocked failed: %v", err)
@@ -104,7 +99,7 @@ func TestConnectionAbort(t *testing.T) {
// After abort, Call() should return directly with ENOTCONN.
req := conn.NewRequest(creds, 0, 0, 0, &testObj)
_, err = conn.Call(task, req)
_, err = conn.Call(s.Ctx, req)
if !linuxerr.Equals(linuxerr.ENOTCONN, err) {
t.Fatalf("Incorrect error code received for Call() after connection aborted")
}
+3 -4
View File
@@ -90,7 +90,7 @@ func TestFUSECommunication(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.Name, func(t *testing.T) {
conn, fd, err := newTestConnection(s, k, testCase.MaxActiveRequests)
conn, fd, err := newTestConnection(s, testCase.MaxActiveRequests)
if err != nil {
t.Fatalf("newTestConnection: %v", err)
}
@@ -139,8 +139,7 @@ func TestFUSECommunication(t *testing.T) {
func TestReuseFd(t *testing.T) {
s := setup(t)
defer s.Destroy()
k := kernel.KernelFromContext(s.Ctx)
_, fd, err := newTestConnection(s, k, maxActiveRequestsDefault)
_, fd, err := newTestConnection(s, maxActiveRequestsDefault)
if err != nil {
t.Fatalf("newTestConnection: %v", err)
}
@@ -174,7 +173,7 @@ func CallTest(conn *connection, t *kernel.Task, r *Request, i uint32) (*Response
conn.fd.mu.Lock()
}
fut, err := conn.callFutureLocked(t, r) // No task given.
fut, err := conn.callFutureLocked(r) // No task given.
conn.fd.mu.Unlock()
if err != nil {
+2 -4
View File
@@ -18,7 +18,6 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
@@ -56,7 +55,6 @@ func (*directoryFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.
// IterDirents implements vfs.FileDescriptionImpl.IterDirents.
func (dir *directoryFD) IterDirents(ctx context.Context, callback vfs.IterDirentsCallback) error {
fusefs := dir.inode().fs
task, creds := kernel.TaskFromContext(ctx), auth.CredentialsFromContext(ctx)
in := linux.FUSEReadIn{
Fh: dir.Fh,
@@ -66,8 +64,8 @@ func (dir *directoryFD) IterDirents(ctx context.Context, callback vfs.IterDirent
}
// TODO(gVisor.dev/issue/3404): Support FUSE_READDIRPLUS.
req := fusefs.conn.NewRequest(creds, uint32(task.ThreadID()), dir.inode().nodeID, linux.FUSE_READDIR, &in)
res, err := fusefs.conn.Call(task, req)
req := fusefs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), dir.inode().nodeID, linux.FUSE_READDIR, &in)
res, err := fusefs.conn.Call(ctx, req)
if err != nil {
return err
}
+4 -7
View File
@@ -20,7 +20,6 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
@@ -87,11 +86,10 @@ func (fd *fileDescription) Release(ctx context.Context) {
} else {
opcode = linux.FUSE_RELEASE
}
kernelTask := kernel.TaskFromContext(ctx)
// Ignoring errors and FUSE server replies is analogous to Linux's behavior.
req := conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), inode.nodeID, opcode, &in)
req := conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), inode.nodeID, opcode, &in)
// The reply will be ignored since no callback is defined in asyncCallBack().
conn.CallAsync(kernelTask, req)
conn.CallAsync(ctx, req)
}
// PRead implements vfs.FileDescriptionImpl.PRead.
@@ -149,15 +147,14 @@ func (fd *fileDescription) Sync(ctx context.Context) error {
if conn.noOpen {
return linuxerr.EINVAL
}
kernelTask := kernel.TaskFromContext(ctx)
in := linux.FUSEFsyncIn{
Fh: fd.Fh,
FsyncFlags: fd.statusFlags(),
}
// Ignoring errors and FUSE server replies is analogous to Linux's behavior.
req := conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), inode.nodeID, linux.FUSE_FSYNC, &in)
req := conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), inode.nodeID, linux.FUSE_FSYNC, &in)
// The reply will be ignored since no callback is defined in asyncCallBack().
conn.CallAsync(kernelTask, req)
conn.CallAsync(ctx, req)
return nil
}
+49 -84
View File
@@ -24,7 +24,6 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/marshal"
"gvisor.dev/gvisor/pkg/marshal/primitive"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
@@ -105,6 +104,31 @@ type inode struct {
blockSize atomicbitops.Uint32 // 0 if unknown.
}
func blockerFromContext(ctx context.Context) context.Blocker {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
return ctx
}
return kernelTask
}
func pidFromContext(ctx context.Context) uint32 {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
return 0
}
return uint32(kernelTask.ThreadID())
}
func umaskFromContext(ctx context.Context) uint32 {
kernelTask := kernel.TaskFromContext(ctx)
umask := uint32(0)
if kernelTask != nil {
umask = uint32(kernelTask.FSContext().Umask())
}
return umask
}
func (i *inode) Mode() linux.FileMode {
i.attrMu.Lock()
defer i.attrMu.Unlock()
@@ -212,14 +236,9 @@ func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, a
}
return err
} else if ats.MayRead() || ats.MayWrite() || ats.MayExec() {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.CheckPermissions: couldn't get kernel task from context")
return linuxerr.EINVAL
}
in := linux.FUSEAccessIn{Mask: uint32(ats)}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, linux.FUSE_ACCESS, &in)
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_ACCESS, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
@@ -269,7 +288,7 @@ func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentr
}
fd.LockFD.Init(&i.locks)
// FOPEN_KEEP_CACHE is the defualt flag for noOpen.
// FOPEN_KEEP_CACHE is the default flag for noOpen.
fd.OpenFlag = linux.FOPEN_KEEP_CACHE
if i.fh.new {
@@ -279,20 +298,14 @@ func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentr
// Only send an open request when the FUSE server supports open or is
// opening a directory.
} else if !i.fs.conn.noOpen || i.filemode().IsDir() {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.Open: couldn't get kernel task from context")
return nil, linuxerr.EINVAL
}
in := linux.FUSEOpenIn{Flags: opts.Flags & ^uint32(linux.O_CREAT|linux.O_EXCL|linux.O_NOCTTY)}
// Truncating with SETATTR instead of O_TRUNC, so clear the flag.
if !i.fs.conn.atomicOTrunc {
in.Flags &= ^uint32(linux.O_TRUNC)
}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, opcode, &in)
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, opcode, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return nil, err
}
@@ -370,16 +383,11 @@ func (*inode) IterDirents(ctx context.Context, mnt *vfs.Mount, callback vfs.Iter
func (i *inode) NewFile(ctx context.Context, name string, opts vfs.OpenOptions) (kernfs.Inode, error) {
opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_TRUNC |
linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NONBLOCK | linux.O_NOCTTY
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.NewFile: couldn't get kernel task from context", i.nodeID)
return nil, linuxerr.EINVAL
}
in := linux.FUSECreateIn{
CreateMeta: linux.FUSECreateMeta{
Flags: opts.Flags,
Mode: uint32(opts.Mode) | linux.S_IFREG,
Umask: uint32(kernelTask.FSContext().Umask()),
Umask: umaskFromContext(ctx),
},
Name: linux.CString(name),
}
@@ -392,7 +400,7 @@ func (i *inode) NewNode(ctx context.Context, name string, opts vfs.MknodOptions)
MknodMeta: linux.FUSEMknodMeta{
Mode: uint32(opts.Mode),
Rdev: linux.MakeDeviceID(uint16(opts.DevMajor), opts.DevMinor),
Umask: uint32(kernel.TaskFromContext(ctx).FSContext().Umask()),
Umask: umaskFromContext(ctx),
},
Name: linux.CString(name),
}
@@ -420,14 +428,9 @@ func (i *inode) NewLink(ctx context.Context, name string, target kernfs.Inode) (
// Unlink implements kernfs.Inode.Unlink.
func (i *inode) Unlink(ctx context.Context, name string, child kernfs.Inode) error {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.newEntry: couldn't get kernel task from context", i.nodeID)
return linuxerr.EINVAL
}
in := linux.FUSEUnlinkIn{Name: linux.CString(name)}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, linux.FUSE_UNLINK, &in)
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_UNLINK, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
@@ -440,7 +443,7 @@ func (i *inode) NewDir(ctx context.Context, name string, opts vfs.MkdirOptions)
in := linux.FUSEMkdirIn{
MkdirMeta: linux.FUSEMkdirMeta{
Mode: uint32(opts.Mode),
Umask: uint32(kernel.TaskFromContext(ctx).FSContext().Umask()),
Umask: umaskFromContext(ctx),
},
Name: linux.CString(name),
}
@@ -449,12 +452,9 @@ func (i *inode) NewDir(ctx context.Context, name string, opts vfs.MkdirOptions)
// RmDir implements kernfs.Inode.RmDir.
func (i *inode) RmDir(ctx context.Context, name string, child kernfs.Inode) error {
fusefs := i.fs
task, creds := kernel.TaskFromContext(ctx), auth.CredentialsFromContext(ctx)
in := linux.FUSERmDirIn{Name: linux.CString(name)}
req := fusefs.conn.NewRequest(creds, uint32(task.ThreadID()), i.nodeID, linux.FUSE_RMDIR, &in)
res, err := i.fs.conn.Call(task, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_RMDIR, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
@@ -463,20 +463,14 @@ func (i *inode) RmDir(ctx context.Context, name string, child kernfs.Inode) erro
// Rename implements kernfs.Inode.Rename.
func (i *inode) Rename(ctx context.Context, oldname, newname string, child, dstDir kernfs.Inode) error {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.newEntry: couldn't get kernel task from context", i.nodeID)
return linuxerr.EINVAL
}
dstDirInode := dstDir.(*inode)
in := linux.FUSERenameIn{
Newdir: primitive.Uint64(dstDirInode.nodeID),
Oldname: linux.CString(oldname),
Newname: linux.CString(newname),
}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, linux.FUSE_RENAME, &in)
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_RENAME, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
@@ -487,13 +481,8 @@ func (i *inode) Rename(ctx context.Context, oldname, newname string, child, dstD
// entry according to response. Shared by FUSE_MKNOD, FUSE_MKDIR, FUSE_SYMLINK,
// FUSE_LINK and FUSE_LOOKUP.
func (i *inode) newEntry(ctx context.Context, name string, fileType linux.FileMode, opcode linux.FUSEOpcode, payload marshal.Marshallable) (kernfs.Inode, error) {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.newEntry: couldn't get kernel task from context", i.nodeID)
return nil, linuxerr.EINVAL
}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, opcode, payload)
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, opcode, payload)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return nil, err
}
@@ -542,13 +531,8 @@ func (i *inode) Readlink(ctx context.Context, mnt *vfs.Mount) (string, error) {
return "", linuxerr.EINVAL
}
if len(i.link) == 0 {
kernelTask := kernel.TaskFromContext(ctx)
if kernelTask == nil {
log.Warningf("fusefs.Inode.Readlink: couldn't get kernel task from context")
return "", linuxerr.EINVAL
}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(kernelTask.ThreadID()), i.nodeID, linux.FUSE_READLINK, &linux.FUSEEmptyIn{})
res, err := i.fs.conn.Call(kernelTask, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_READLINK, &linux.FUSEEmptyIn{})
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return "", err
}
@@ -649,21 +633,14 @@ func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOp
// Currently we always send a request,
// and we always set the metadata with the new result,
// unless attributeVersion has changed.
task := kernel.TaskFromContext(ctx)
if task == nil {
log.Warningf("couldn't get kernel task from context")
return linux.FUSEAttr{}, linuxerr.EINVAL
}
creds := auth.CredentialsFromContext(ctx)
in := linux.FUSEGetAttrIn{
GetAttrFlags: flags,
Fh: fh,
}
req := i.fs.conn.NewRequest(creds, uint32(task.ThreadID()), i.nodeID, linux.FUSE_GETATTR, &in)
res, err := i.fs.conn.Call(task, req)
req := i.fs.conn.NewRequest(creds, pidFromContext(ctx), i.nodeID, linux.FUSE_GETATTR, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return linux.FUSEAttr{}, err
}
@@ -719,16 +696,10 @@ func (i *inode) DecRef(ctx context.Context) {
// StatFS implements kernfs.Inode.StatFS.
func (i *inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) {
task := kernel.TaskFromContext(ctx)
if task == nil {
log.Warningf("couldn't get kernel task from context")
return linux.Statfs{}, linuxerr.EINVAL
}
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(task.ThreadID()), i.nodeID,
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID,
linux.FUSE_STATFS, &linux.FUSEEmptyIn{},
)
res, err := i.fs.conn.Call(task, req)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return linux.Statfs{}, err
}
@@ -795,12 +766,6 @@ type fhOptions struct {
// +checklocks:i.attrMu
func (i *inode) setAttr(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions, fhOpts fhOptions) error {
task := kernel.TaskFromContext(ctx)
if task == nil {
log.Warningf("couldn't get kernel task from context")
return linuxerr.EINVAL
}
// We should retain the original file type when assigning a new mode.
fattrMask := fattrMaskFromStats(opts.Stat.Mask)
if fhOpts.useFh {
@@ -826,8 +791,8 @@ func (i *inode) setAttr(ctx context.Context, fs *vfs.Filesystem, creds *auth.Cre
UID: opts.Stat.UID,
GID: opts.Stat.GID,
}
req := i.fs.conn.NewRequest(creds, uint32(task.ThreadID()), i.nodeID, linux.FUSE_SETATTR, &in)
res, err := i.fs.conn.Call(task, req)
req := i.fs.conn.NewRequest(creds, pidFromContext(ctx), i.nodeID, linux.FUSE_SETATTR, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
+4 -20
View File
@@ -21,8 +21,6 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/usermem"
)
@@ -36,12 +34,6 @@ import (
func (fs *filesystem) ReadInPages(ctx context.Context, fd *regularFileFD, off uint64, size uint32) ([][]byte, uint32, error) {
attributeVersion := fs.conn.attributeVersion.Load()
t := kernel.TaskFromContext(ctx)
if t == nil {
log.Warningf("fusefs.Read: couldn't get kernel task from context")
return nil, 0, linuxerr.EINVAL
}
// Round up to a multiple of page size.
readSize, _ := hostarch.PageRoundUp(uint64(size))
@@ -80,9 +72,8 @@ func (fs *filesystem) ReadInPages(ctx context.Context, fd *regularFileFD, off ui
in.Size = pagesCanRead << hostarch.PageShift
// TODO(gvisor.dev/issue/3247): support async read.
req := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(t.ThreadID()), fd.inode().nodeID, linux.FUSE_READ, &in)
res, err := fs.conn.Call(t, req)
req := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), fd.inode().nodeID, linux.FUSE_READ, &in)
res, err := fs.conn.Call(ctx, req)
if err != nil {
return nil, 0, err
}
@@ -148,12 +139,6 @@ func (fs *filesystem) ReadCallback(ctx context.Context, i *inode, off uint64, si
// Write sends FUSE_WRITE requests and return the bytes written according to the
// response.
func (fs *filesystem) Write(ctx context.Context, fd *regularFileFD, offset int64, src usermem.IOSequence) (int64, int64, error) {
t := kernel.TaskFromContext(ctx)
if t == nil {
log.Warningf("fusefs.Write: couldn't get kernel task from context")
return 0, offset, linuxerr.EINVAL
}
// One request cannot exceed either maxWrite or maxPages.
maxWrite := uint32(fs.conn.maxPages) << hostarch.PageShift
if maxWrite > fs.conn.maxWrite {
@@ -204,10 +189,9 @@ func (fs *filesystem) Write(ctx context.Context, fd *regularFileFD, offset int64
in.Header.Size = uint32(cp)
in.Payload = data
req := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(t.ThreadID()), fd.inode().nodeID, linux.FUSE_WRITE, &in)
req := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), fd.inode().nodeID, linux.FUSE_WRITE, &in)
// TODO(gvisor.dev/issue/3247): support async write.
res, err := fs.conn.Call(t, req)
res, err := fs.conn.Call(ctx, req)
if err != nil {
return n, offset, err
}
+2 -9
View File
@@ -23,9 +23,7 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/fsutil"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/vfs"
@@ -62,11 +60,6 @@ type regularFileFD struct {
// Seek implements vfs.FileDescriptionImpl.Allocate.
func (fd *regularFileFD) Allocate(ctx context.Context, mode, offset, length uint64) error {
task := kernel.TaskFromContext(ctx)
if task == nil {
log.Warningf("fusefs.regularFileFD.Allocate: couldn't get kernel task from context")
return linuxerr.EINVAL
}
if mode & ^uint64(linux.FALLOC_FL_KEEP_SIZE|linux.FALLOC_FL_PUNCH_HOLE|linux.FALLOC_FL_ZERO_RANGE) != 0 {
return linuxerr.EOPNOTSUPP
}
@@ -77,8 +70,8 @@ func (fd *regularFileFD) Allocate(ctx context.Context, mode, offset, length uint
Mode: uint32(mode),
}
i := fd.inode()
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(task.ThreadID()), i.nodeID, linux.FUSE_FALLOCATE, &in)
res, err := i.fs.conn.Call(task, req)
req := i.fs.conn.NewRequest(auth.CredentialsFromContext(ctx), pidFromContext(ctx), i.nodeID, linux.FUSE_FALLOCATE, &in)
res, err := i.fs.conn.Call(ctx, req)
if err != nil {
return err
}
+3 -3
View File
@@ -17,11 +17,11 @@ package fuse
import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/marshal"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
)
@@ -156,13 +156,13 @@ func newFutureResponse(req *Request) *futureResponse {
// resolve blocks the task until the server responds to its corresponding request,
// then returns a resolved response.
func (f *futureResponse) resolve(t *kernel.Task) (*Response, error) {
func (f *futureResponse) resolve(b context.Blocker) (*Response, error) {
// Return directly for async requests.
if f.async {
return nil, nil
}
if err := t.Block(f.ch); err != nil {
if err := b.Block(f.ch); err != nil {
return nil, err
}
+1 -2
View File
@@ -20,7 +20,6 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/testutil"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
@@ -49,7 +48,7 @@ func setup(t *testing.T) *testutil.System {
// newTestConnection creates a fuse connection that the sentry can communicate with
// and the FD for the server to communicate with.
func newTestConnection(system *testutil.System, k *kernel.Kernel, maxActiveRequests uint64) (*connection, *vfs.FileDescription, error) {
func newTestConnection(system *testutil.System, maxActiveRequests uint64) (*connection, *vfs.FileDescription, error) {
fuseDev := &DeviceFD{}
vd := system.VFS.NewAnonVirtualDentry("fuse")
+1 -5
View File
@@ -114,11 +114,7 @@ func (t *Task) BlockWithTimer(C <-chan struct{}, tchan <-chan struct{}) error {
return t.block(C, tchan)
}
// Block blocks t until an event is received from C or t is interrupted. It
// returns nil if an event is received from C and linuxerr.ErrInterrupted if t
// is interrupted.
//
// Preconditions: The caller must be running on the task goroutine.
// Block implements context.Context.Block
func (t *Task) Block(C <-chan struct{}) error {
return t.block(C, nil)
}
+2
View File
@@ -70,6 +70,8 @@ deps_test(
"//pkg/sync/locking",
"//pkg/waiter",
"//pkg/xdp",
"//pkg/abi/linux/errno",
"//pkg/errors",
# Other deps.
"@com_github_google_btree//:go_default_library",