mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
f105ee555d
commit
d6d9fe6236
@@ -12,6 +12,8 @@ go_library(
|
||||
],
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
"//pkg/abi/linux/errno",
|
||||
"//pkg/errors",
|
||||
"//pkg/log",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user