mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement flock(2) in VFS2
LockFD is the generic implementation that can be embedded in FileDescriptionImpl implementations. Unique lock ID is maintained in vfs.FileDescription and is created on demand. Updates #1480 PiperOrigin-RevId: 315604825
This commit is contained in:
committed by
gVisor bot
parent
52c922f7c0
commit
67565078bb
@@ -42,6 +42,7 @@ type fullFD struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.NoLockFD
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
|
||||
@@ -43,6 +43,7 @@ type nullFD struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.NoLockFD
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
|
||||
@@ -48,6 +48,7 @@ type randomFD struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.NoLockFD
|
||||
|
||||
// off is the "file offset". off is accessed using atomic memory
|
||||
// operations.
|
||||
|
||||
@@ -44,6 +44,7 @@ type zeroFD struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.NoLockFD
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
|
||||
@@ -146,7 +146,7 @@ func (f *File) DecRef() {
|
||||
f.DecRefWithDestructor(func() {
|
||||
// Drop BSD style locks.
|
||||
lockRng := lock.LockRange{Start: 0, End: lock.LockEOF}
|
||||
f.Dirent.Inode.LockCtx.BSD.UnlockRegion(lock.UniqueID(f.UniqueID), lockRng)
|
||||
f.Dirent.Inode.LockCtx.BSD.UnlockRegion(f, lockRng)
|
||||
|
||||
// Release resources held by the FileOperations.
|
||||
f.FileOperations.Release()
|
||||
|
||||
+15
-26
@@ -62,7 +62,7 @@ import (
|
||||
type LockType int
|
||||
|
||||
// UniqueID is a unique identifier of the holder of a regional file lock.
|
||||
type UniqueID uint64
|
||||
type UniqueID interface{}
|
||||
|
||||
const (
|
||||
// ReadLock describes a POSIX regional file lock to be taken
|
||||
@@ -98,12 +98,7 @@ type Lock struct {
|
||||
// If len(Readers) > 0 then HasWriter must be false.
|
||||
Readers map[UniqueID]bool
|
||||
|
||||
// HasWriter indicates that this is a write lock held by a single
|
||||
// UniqueID.
|
||||
HasWriter bool
|
||||
|
||||
// Writer is only valid if HasWriter is true. It identifies a
|
||||
// single write lock holder.
|
||||
// Writer holds the writer unique ID. It's nil if there are no writers.
|
||||
Writer UniqueID
|
||||
}
|
||||
|
||||
@@ -186,7 +181,6 @@ func makeLock(uid UniqueID, t LockType) Lock {
|
||||
case ReadLock:
|
||||
value.Readers[uid] = true
|
||||
case WriteLock:
|
||||
value.HasWriter = true
|
||||
value.Writer = uid
|
||||
default:
|
||||
panic(fmt.Sprintf("makeLock: invalid lock type %d", t))
|
||||
@@ -196,10 +190,7 @@ func makeLock(uid UniqueID, t LockType) Lock {
|
||||
|
||||
// isHeld returns true if uid is a holder of Lock.
|
||||
func (l Lock) isHeld(uid UniqueID) bool {
|
||||
if l.HasWriter && l.Writer == uid {
|
||||
return true
|
||||
}
|
||||
return l.Readers[uid]
|
||||
return l.Writer == uid || l.Readers[uid]
|
||||
}
|
||||
|
||||
// lock sets uid as a holder of a typed lock on Lock.
|
||||
@@ -214,20 +205,20 @@ func (l *Lock) lock(uid UniqueID, t LockType) {
|
||||
}
|
||||
// We cannot downgrade a write lock to a read lock unless the
|
||||
// uid is the same.
|
||||
if l.HasWriter {
|
||||
if l.Writer != nil {
|
||||
if l.Writer != uid {
|
||||
panic(fmt.Sprintf("lock: cannot downgrade write lock to read lock for uid %d, writer is %d", uid, l.Writer))
|
||||
}
|
||||
// Ensure that there is only one reader if upgrading.
|
||||
l.Readers = make(map[UniqueID]bool)
|
||||
// Ensure that there is no longer a writer.
|
||||
l.HasWriter = false
|
||||
l.Writer = nil
|
||||
}
|
||||
l.Readers[uid] = true
|
||||
return
|
||||
case WriteLock:
|
||||
// If we are already the writer, then this is a no-op.
|
||||
if l.HasWriter && l.Writer == uid {
|
||||
if l.Writer == uid {
|
||||
return
|
||||
}
|
||||
// We can only upgrade a read lock to a write lock if there
|
||||
@@ -243,7 +234,6 @@ func (l *Lock) lock(uid UniqueID, t LockType) {
|
||||
}
|
||||
// Ensure that there is only a writer.
|
||||
l.Readers = make(map[UniqueID]bool)
|
||||
l.HasWriter = true
|
||||
l.Writer = uid
|
||||
default:
|
||||
panic(fmt.Sprintf("lock: invalid lock type %d", t))
|
||||
@@ -277,9 +267,8 @@ func (l LockSet) canLock(uid UniqueID, t LockType, r LockRange) bool {
|
||||
switch t {
|
||||
case ReadLock:
|
||||
return l.lockable(r, func(value Lock) bool {
|
||||
// If there is no writer, there's no problem adding
|
||||
// another reader.
|
||||
if !value.HasWriter {
|
||||
// If there is no writer, there's no problem adding another reader.
|
||||
if value.Writer == nil {
|
||||
return true
|
||||
}
|
||||
// If there is a writer, then it must be the same uid
|
||||
@@ -289,10 +278,9 @@ func (l LockSet) canLock(uid UniqueID, t LockType, r LockRange) bool {
|
||||
case WriteLock:
|
||||
return l.lockable(r, func(value Lock) bool {
|
||||
// If there are only readers.
|
||||
if !value.HasWriter {
|
||||
// Then this uid can only take a write lock if
|
||||
// this is a private upgrade, meaning that the
|
||||
// only reader is uid.
|
||||
if value.Writer == nil {
|
||||
// Then this uid can only take a write lock if this is a private
|
||||
// upgrade, meaning that the only reader is uid.
|
||||
return len(value.Readers) == 1 && value.Readers[uid]
|
||||
}
|
||||
// If the uid is already a writer on this region, then
|
||||
@@ -304,7 +292,8 @@ func (l LockSet) canLock(uid UniqueID, t LockType, r LockRange) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// lock returns true if uid took a lock of type t on the entire range of LockRange.
|
||||
// lock returns true if uid took a lock of type t on the entire range of
|
||||
// LockRange.
|
||||
//
|
||||
// Preconditions: r.Start <= r.End (will panic otherwise).
|
||||
func (l *LockSet) lock(uid UniqueID, t LockType, r LockRange) bool {
|
||||
@@ -339,7 +328,7 @@ func (l *LockSet) lock(uid UniqueID, t LockType, r LockRange) bool {
|
||||
seg, _ = l.SplitUnchecked(seg, r.End)
|
||||
}
|
||||
|
||||
// Set the lock on the segment. This is guaranteed to
|
||||
// Set the lock on the segment. This is guaranteed to
|
||||
// always be safe, given canLock above.
|
||||
value := seg.ValuePtr()
|
||||
value.lock(uid, t)
|
||||
@@ -386,7 +375,7 @@ func (l *LockSet) unlock(uid UniqueID, r LockRange) {
|
||||
|
||||
value := seg.Value()
|
||||
var remove bool
|
||||
if value.HasWriter && value.Writer == uid {
|
||||
if value.Writer == uid {
|
||||
// If we are unlocking a writer, then since there can
|
||||
// only ever be one writer and no readers, then this
|
||||
// lock should always be removed from the set.
|
||||
|
||||
@@ -44,14 +44,9 @@ func (lockSetFunctions) Merge(r1 LockRange, val1 Lock, r2 LockRange, val2 Lock)
|
||||
return Lock{}, false
|
||||
}
|
||||
}
|
||||
if val1.HasWriter != val2.HasWriter {
|
||||
if val1.Writer != val2.Writer {
|
||||
return Lock{}, false
|
||||
}
|
||||
if val1.HasWriter {
|
||||
if val1.Writer != val2.Writer {
|
||||
return Lock{}, false
|
||||
}
|
||||
}
|
||||
return val1, true
|
||||
}
|
||||
|
||||
@@ -62,7 +57,6 @@ func (lockSetFunctions) Split(r LockRange, val Lock, split uint64) (Lock, Lock)
|
||||
for k, v := range val.Readers {
|
||||
val0.Readers[k] = v
|
||||
}
|
||||
val0.HasWriter = val.HasWriter
|
||||
val0.Writer = val.Writer
|
||||
|
||||
return val, val0
|
||||
|
||||
@@ -42,9 +42,6 @@ func equals(e0, e1 []entry) bool {
|
||||
if !reflect.DeepEqual(e0[i].LockRange, e1[i].LockRange) {
|
||||
return false
|
||||
}
|
||||
if e0[i].Lock.HasWriter != e1[i].Lock.HasWriter {
|
||||
return false
|
||||
}
|
||||
if e0[i].Lock.Writer != e1[i].Lock.Writer {
|
||||
return false
|
||||
}
|
||||
@@ -105,7 +102,7 @@ func TestCanLock(t *testing.T) {
|
||||
LockRange: LockRange{2048, 3072},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 1},
|
||||
Lock: Lock{Writer: 1},
|
||||
LockRange: LockRange{3072, 4096},
|
||||
},
|
||||
})
|
||||
@@ -241,7 +238,7 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -254,7 +251,7 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -273,7 +270,7 @@ func TestSetLock(t *testing.T) {
|
||||
LockRange: LockRange{0, 4096},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{4096, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -301,7 +298,7 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 4096 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 4096},
|
||||
},
|
||||
{
|
||||
@@ -318,7 +315,7 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -550,7 +547,7 @@ func TestSetLock(t *testing.T) {
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{1024, 4096},
|
||||
},
|
||||
{
|
||||
@@ -594,7 +591,7 @@ func TestSetLock(t *testing.T) {
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{1024, 3072},
|
||||
},
|
||||
{
|
||||
@@ -633,7 +630,7 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 1024 2048 4096 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
@@ -663,11 +660,11 @@ func TestSetLock(t *testing.T) {
|
||||
// 0 1024 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{1024, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -675,28 +672,30 @@ func TestSetLock(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
l := fill(test.before)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
l := fill(test.before)
|
||||
|
||||
r := LockRange{Start: test.start, End: test.end}
|
||||
success := l.lock(test.uid, test.lockType, r)
|
||||
var got []entry
|
||||
for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
|
||||
got = append(got, entry{
|
||||
Lock: seg.Value(),
|
||||
LockRange: seg.Range(),
|
||||
})
|
||||
}
|
||||
|
||||
if success != test.success {
|
||||
t.Errorf("%s: setlock(%v, %+v, %d, %d) got success %v, want %v", test.name, test.before, r, test.uid, test.lockType, success, test.success)
|
||||
continue
|
||||
}
|
||||
|
||||
if success {
|
||||
if !equals(got, test.after) {
|
||||
t.Errorf("%s: got set %+v, want %+v", test.name, got, test.after)
|
||||
r := LockRange{Start: test.start, End: test.end}
|
||||
success := l.lock(test.uid, test.lockType, r)
|
||||
var got []entry
|
||||
for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
|
||||
got = append(got, entry{
|
||||
Lock: seg.Value(),
|
||||
LockRange: seg.Range(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if success != test.success {
|
||||
t.Errorf("setlock(%v, %+v, %d, %d) got success %v, want %v", test.before, r, test.uid, test.lockType, success, test.success)
|
||||
return
|
||||
}
|
||||
|
||||
if success {
|
||||
if !equals(got, test.after) {
|
||||
t.Errorf("got set %+v, want %+v", got, test.after)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +781,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -824,7 +823,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -837,7 +836,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 4096 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{4096, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -876,7 +875,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, LockEOF},
|
||||
},
|
||||
},
|
||||
@@ -889,7 +888,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 4096
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 4096},
|
||||
},
|
||||
},
|
||||
@@ -906,7 +905,7 @@ func TestUnlock(t *testing.T) {
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{1024, 4096},
|
||||
},
|
||||
{
|
||||
@@ -974,7 +973,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 1024 4096 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
@@ -991,7 +990,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 8 4096 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 8},
|
||||
},
|
||||
{
|
||||
@@ -1008,7 +1007,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 1024 4096 max uint64
|
||||
before: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
@@ -1025,7 +1024,7 @@ func TestUnlock(t *testing.T) {
|
||||
// 0 1024 4096 8192 max uint64
|
||||
after: []entry{
|
||||
{
|
||||
Lock: Lock{HasWriter: true, Writer: 0},
|
||||
Lock: Lock{Writer: 0},
|
||||
LockRange: LockRange{0, 1024},
|
||||
},
|
||||
{
|
||||
@@ -1041,19 +1040,21 @@ func TestUnlock(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
l := fill(test.before)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
l := fill(test.before)
|
||||
|
||||
r := LockRange{Start: test.start, End: test.end}
|
||||
l.unlock(test.uid, r)
|
||||
var got []entry
|
||||
for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
|
||||
got = append(got, entry{
|
||||
Lock: seg.Value(),
|
||||
LockRange: seg.Range(),
|
||||
})
|
||||
}
|
||||
if !equals(got, test.after) {
|
||||
t.Errorf("%s: got set %+v, want %+v", test.name, got, test.after)
|
||||
}
|
||||
r := LockRange{Start: test.start, End: test.end}
|
||||
l.unlock(test.uid, r)
|
||||
var got []entry
|
||||
for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
|
||||
got = append(got, entry{
|
||||
Lock: seg.Value(),
|
||||
LockRange: seg.Range(),
|
||||
})
|
||||
}
|
||||
if !equals(got, test.after) {
|
||||
t.Errorf("got set %+v, want %+v", got, test.after)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ go_library(
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/unimpl",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sentry/vfs/lock",
|
||||
"//pkg/sync",
|
||||
"//pkg/syserror",
|
||||
"//pkg/usermem",
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs/lock"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
@@ -116,6 +117,8 @@ type rootInode struct {
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.OrderedChildren
|
||||
|
||||
locks lock.FileLocks
|
||||
|
||||
// Keep a reference to this inode's dentry.
|
||||
dentry kernfs.Dentry
|
||||
|
||||
@@ -183,7 +186,7 @@ func (i *rootInode) masterClose(t *Terminal) {
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *rootInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/unimpl"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs/lock"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
@@ -34,6 +35,8 @@ type masterInode struct {
|
||||
kernfs.InodeNotDirectory
|
||||
kernfs.InodeNotSymlink
|
||||
|
||||
locks lock.FileLocks
|
||||
|
||||
// Keep a reference to this inode's dentry.
|
||||
dentry kernfs.Dentry
|
||||
|
||||
@@ -55,6 +58,7 @@ func (mi *masterInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vf
|
||||
inode: mi,
|
||||
t: t,
|
||||
}
|
||||
fd.LockFD.Init(&mi.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
mi.DecRef()
|
||||
return nil, err
|
||||
@@ -85,6 +89,7 @@ func (mi *masterInode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds
|
||||
type masterFileDescription struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.LockFD
|
||||
|
||||
inode *masterInode
|
||||
t *Terminal
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs/lock"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
@@ -33,6 +34,8 @@ type slaveInode struct {
|
||||
kernfs.InodeNotDirectory
|
||||
kernfs.InodeNotSymlink
|
||||
|
||||
locks lock.FileLocks
|
||||
|
||||
// Keep a reference to this inode's dentry.
|
||||
dentry kernfs.Dentry
|
||||
|
||||
@@ -51,6 +54,7 @@ func (si *slaveInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs
|
||||
fd := &slaveFileDescription{
|
||||
inode: si,
|
||||
}
|
||||
fd.LockFD.Init(&si.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
si.DecRef()
|
||||
return nil, err
|
||||
@@ -91,6 +95,7 @@ func (si *slaveInode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds
|
||||
type slaveFileDescription struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.LockFD
|
||||
|
||||
inode *slaveInode
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type EventFileDescription struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.NoLockFD
|
||||
|
||||
// queue is used to notify interested parties when the event object
|
||||
// becomes readable or writable.
|
||||
|
||||
@@ -60,6 +60,7 @@ go_library(
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/sentry/syscalls/linux",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sentry/vfs/lock",
|
||||
"//pkg/sync",
|
||||
"//pkg/syserror",
|
||||
"//pkg/usermem",
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
type fileDescription struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.LockFD
|
||||
}
|
||||
|
||||
func (fd *fileDescription) filesystem() *filesystem {
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/ext/disklayout"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs/lock"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
@@ -54,6 +55,8 @@ type inode struct {
|
||||
// diskInode gives us access to the inode struct on disk. Immutable.
|
||||
diskInode disklayout.Inode
|
||||
|
||||
locks lock.FileLocks
|
||||
|
||||
// This is immutable. The first field of the implementations must have inode
|
||||
// as the first field to ensure temporality.
|
||||
impl interface{}
|
||||
@@ -157,6 +160,7 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts *vfs.OpenOpt
|
||||
switch in.impl.(type) {
|
||||
case *regularFile:
|
||||
var fd regularFileFD
|
||||
fd.LockFD.Init(&in.locks)
|
||||
if err := fd.vfsfd.Init(&fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -168,6 +172,7 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts *vfs.OpenOpt
|
||||
return nil, syserror.EISDIR
|
||||
}
|
||||
var fd directoryFD
|
||||
fd.LockFD.Init(&in.locks)
|
||||
if err := fd.vfsfd.Init(&fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -178,6 +183,7 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts *vfs.OpenOpt
|
||||
return nil, syserror.ELOOP
|
||||
}
|
||||
var fd symlinkFD
|
||||
fd.LockFD.Init(&in.locks)
|
||||
fd.vfsfd.Init(&fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
|
||||
return &fd.vfsfd, nil
|
||||
default:
|
||||
|
||||
@@ -77,6 +77,7 @@ func (in *inode) isRegular() bool {
|
||||
// vfs.FileDescriptionImpl.
|
||||
type regularFileFD struct {
|
||||
fileDescription
|
||||
vfs.LockFD
|
||||
|
||||
// off is the file offset. off is accessed using atomic memory operations.
|
||||
off int64
|
||||
|
||||
@@ -54,6 +54,7 @@ go_library(
|
||||
"//pkg/p9",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/fs/lock",
|
||||
"//pkg/sentry/fsimpl/host",
|
||||
"//pkg/sentry/hostfd",
|
||||
"//pkg/sentry/kernel",
|
||||
@@ -68,6 +69,7 @@ go_library(
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sentry/vfs/lock",
|
||||
"//pkg/syserr",
|
||||
"//pkg/syserror",
|
||||
"//pkg/unet",
|
||||
|
||||
@@ -801,6 +801,7 @@ func (d *dentry) openLocked(ctx context.Context, rp *vfs.ResolvingPath, opts *vf
|
||||
return nil, err
|
||||
}
|
||||
fd := ®ularFileFD{}
|
||||
fd.LockFD.Init(&d.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, mnt, &d.vfsd, &vfs.FileDescriptionOptions{
|
||||
AllowDirectIO: true,
|
||||
}); err != nil {
|
||||
@@ -826,6 +827,7 @@ func (d *dentry) openLocked(ctx context.Context, rp *vfs.ResolvingPath, opts *vf
|
||||
}
|
||||
}
|
||||
fd := &directoryFD{}
|
||||
fd.LockFD.Init(&d.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, mnt, &d.vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -842,7 +844,7 @@ func (d *dentry) openLocked(ctx context.Context, rp *vfs.ResolvingPath, opts *vf
|
||||
}
|
||||
case linux.S_IFIFO:
|
||||
if d.isSynthetic() {
|
||||
return d.pipe.Open(ctx, mnt, &d.vfsd, opts.Flags)
|
||||
return d.pipe.Open(ctx, mnt, &d.vfsd, opts.Flags, &d.locks)
|
||||
}
|
||||
}
|
||||
return d.openSpecialFileLocked(ctx, mnt, opts)
|
||||
@@ -902,7 +904,7 @@ retry:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
fd, err := newSpecialFileFD(h, mnt, d, opts.Flags)
|
||||
fd, err := newSpecialFileFD(h, mnt, d, &d.locks, opts.Flags)
|
||||
if err != nil {
|
||||
h.close(ctx)
|
||||
return nil, err
|
||||
@@ -989,6 +991,7 @@ func (d *dentry) createAndOpenChildLocked(ctx context.Context, rp *vfs.Resolving
|
||||
var childVFSFD *vfs.FileDescription
|
||||
if useRegularFileFD {
|
||||
fd := ®ularFileFD{}
|
||||
fd.LockFD.Init(&child.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, mnt, &child.vfsd, &vfs.FileDescriptionOptions{
|
||||
AllowDirectIO: true,
|
||||
}); err != nil {
|
||||
@@ -1003,7 +1006,7 @@ func (d *dentry) createAndOpenChildLocked(ctx context.Context, rp *vfs.Resolving
|
||||
if fdobj != nil {
|
||||
h.fd = int32(fdobj.Release())
|
||||
}
|
||||
fd, err := newSpecialFileFD(h, mnt, child, opts.Flags)
|
||||
fd, err := newSpecialFileFD(h, mnt, child, &d.locks, opts.Flags)
|
||||
if err != nil {
|
||||
h.close(ctx)
|
||||
return nil, err
|
||||
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/p9"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
fslock "gvisor.dev/gvisor/pkg/sentry/fs/lock"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/pipe"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
@@ -52,6 +53,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/pgalloc"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs/lock"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/unet"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
@@ -662,6 +664,8 @@ type dentry struct {
|
||||
// If this dentry represents a synthetic named pipe, pipe is the pipe
|
||||
// endpoint bound to this file.
|
||||
pipe *pipe.VFSPipe
|
||||
|
||||
locks lock.FileLocks
|
||||
}
|
||||
|
||||
// dentryAttrMask returns a p9.AttrMask enabling all attributes used by the
|
||||
@@ -1366,6 +1370,9 @@ func (d *dentry) decLinks() {
|
||||
type fileDescription struct {
|
||||
vfsfd vfs.FileDescription
|
||||
vfs.FileDescriptionDefaultImpl
|
||||
vfs.LockFD
|
||||
|
||||
lockLogging sync.Once
|
||||
}
|
||||
|
||||
func (fd *fileDescription) filesystem() *filesystem {
|
||||
@@ -1416,3 +1423,19 @@ func (fd *fileDescription) Setxattr(ctx context.Context, opts vfs.SetxattrOption
|
||||
func (fd *fileDescription) Removexattr(ctx context.Context, name string) error {
|
||||
return fd.dentry().removexattr(ctx, auth.CredentialsFromContext(ctx), name)
|
||||
}
|
||||
|
||||
// LockBSD implements vfs.FileDescriptionImpl.LockBSD.
|
||||
func (fd *fileDescription) LockBSD(ctx context.Context, uid fslock.UniqueID, t fslock.LockType, block fslock.Blocker) error {
|
||||
fd.lockLogging.Do(func() {
|
||||
log.Infof("File lock using gofer file handled internally.")
|
||||
})
|
||||
return fd.LockFD.LockBSD(ctx, uid, t, block)
|
||||
}
|
||||
|
||||
// LockPOSIX implements vfs.FileDescriptionImpl.LockPOSIX.
|
||||
func (fd *fileDescription) LockPOSIX(ctx context.Context, uid fslock.UniqueID, t fslock.LockType, rng fslock.LockRange, block fslock.Blocker) error {
|
||||
fd.lockLogging.Do(func() {
|
||||
log.Infof("Range lock using gofer file handled internally.")
|
||||
})
|
||||
return fd.LockFD.LockPOSIX(ctx, uid, t, rng, block)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user