[vfs] [1/2] kernfs: Internally use kernfs.Dentry instead of vfs.Dentry.
Update signatures for: - walkExistingLocked - checkDeleteLocked - Inode.Open Updates #1193 PiperOrigin-RevId: 333163381
This commit is contained in:
parent
778c367171
commit
20dc83c9ec
|
@ -187,8 +187,8 @@ 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, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (i *rootInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), d, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -50,7 +50,7 @@ type masterInode struct {
|
|||
var _ kernfs.Inode = (*masterInode)(nil)
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (mi *masterInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (mi *masterInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
t, err := mi.root.allocateTerminal(rp.Credentials())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -62,7 +62,7 @@ func (mi *masterInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vf
|
|||
t: t,
|
||||
}
|
||||
fd.LockFD.Init(&mi.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
mi.DecRef(ctx)
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -52,13 +52,13 @@ type replicaInode struct {
|
|||
var _ kernfs.Inode = (*replicaInode)(nil)
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (si *replicaInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (si *replicaInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
si.IncRef()
|
||||
fd := &replicaFileDescription{
|
||||
inode: si,
|
||||
}
|
||||
fd.LockFD.Init(&si.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
si.DecRef(ctx)
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ func (fs *filesystem) newInode(nodeID uint64, attr linux.FUSEAttr) *kernfs.Dentr
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
isDir := i.InodeAttrs.Mode().IsDir()
|
||||
// return error if specified to open directory but inode is not a directory.
|
||||
if !isDir && opts.Mode.IsDir() {
|
||||
|
@ -395,7 +395,7 @@ func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentr
|
|||
i.attributeTime = 0
|
||||
}
|
||||
|
||||
if err := fd.vfsfd.Init(fdImpl, opts.Flags, rp.Mount(), vfsd, fdOptions); err != nil {
|
||||
if err := fd.vfsfd.Init(fdImpl, opts.Flags, rp.Mount(), d.VFSDentry(), fdOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &fd.vfsfd, nil
|
||||
|
|
|
@ -126,7 +126,7 @@ func NewFD(ctx context.Context, mnt *vfs.Mount, hostFD int, opts *NewFDOptions)
|
|||
// For simplicity, fileDescription.offset is set to 0. Technically, we
|
||||
// should only set to 0 on files that are not seekable (sockets, pipes,
|
||||
// etc.), and use the offset from the host fd otherwise when importing.
|
||||
return i.open(ctx, d.VFSDentry(), mnt, flags)
|
||||
return i.open(ctx, d, mnt, flags)
|
||||
}
|
||||
|
||||
// ImportFD sets up and returns a vfs.FileDescription from a donated fd.
|
||||
|
@ -458,15 +458,15 @@ func (i *inode) DecRef(ctx context.Context) {
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
// Once created, we cannot re-open a socket fd through /proc/[pid]/fd/.
|
||||
if i.Mode().FileType() == linux.S_IFSOCK {
|
||||
return nil, syserror.ENXIO
|
||||
}
|
||||
return i.open(ctx, vfsd, rp.Mount(), opts.Flags)
|
||||
return i.open(ctx, d, rp.Mount(), opts.Flags)
|
||||
}
|
||||
|
||||
func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount, flags uint32) (*vfs.FileDescription, error) {
|
||||
func (i *inode) open(ctx context.Context, d *kernfs.Dentry, mnt *vfs.Mount, flags uint32) (*vfs.FileDescription, error) {
|
||||
var s syscall.Stat_t
|
||||
if err := syscall.Fstat(i.hostFD, &s); err != nil {
|
||||
return nil, err
|
||||
|
@ -490,7 +490,7 @@ func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount, flags u
|
|||
return nil, err
|
||||
}
|
||||
// Currently, we only allow Unix sockets to be imported.
|
||||
return unixsocket.NewFileDescription(ep, ep.Type(), flags, mnt, d, &i.locks)
|
||||
return unixsocket.NewFileDescription(ep, ep.Type(), flags, mnt, d.VFSDentry(), &i.locks)
|
||||
|
||||
case syscall.S_IFREG, syscall.S_IFIFO, syscall.S_IFCHR:
|
||||
if i.isTTY {
|
||||
|
@ -500,7 +500,7 @@ func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount, flags u
|
|||
}
|
||||
fd.LockFD.Init(&i.locks)
|
||||
vfsfd := &fd.vfsfd
|
||||
if err := vfsfd.Init(fd, flags, mnt, d, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := vfsfd.Init(fd, flags, mnt, d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vfsfd, nil
|
||||
|
@ -509,7 +509,7 @@ func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount, flags u
|
|||
fd := &fileDescription{inode: i}
|
||||
fd.LockFD.Init(&i.locks)
|
||||
vfsfd := &fd.vfsfd
|
||||
if err := vfsfd.Init(fd, flags, mnt, d, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := vfsfd.Init(fd, flags, mnt, d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vfsfd, nil
|
||||
|
|
|
@ -56,9 +56,9 @@ func (f *DynamicBytesFile) Init(creds *auth.Credentials, devMajor, devMinor uint
|
|||
}
|
||||
|
||||
// Open implements Inode.Open.
|
||||
func (f *DynamicBytesFile) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (f *DynamicBytesFile) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd := &DynamicBytesFD{}
|
||||
if err := fd.Init(rp.Mount(), vfsd, f.data, &f.locks, opts.Flags); err != nil {
|
||||
if err := fd.Init(rp.Mount(), d.VFSDentry(), f.data, &f.locks, opts.Flags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &fd.vfsfd, nil
|
||||
|
|
|
@ -76,12 +76,12 @@ type GenericDirectoryFD struct {
|
|||
|
||||
// NewGenericDirectoryFD creates a new GenericDirectoryFD and returns its
|
||||
// dentry.
|
||||
func NewGenericDirectoryFD(m *vfs.Mount, d *vfs.Dentry, children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions, fdOpts GenericDirectoryFDOptions) (*GenericDirectoryFD, error) {
|
||||
func NewGenericDirectoryFD(m *vfs.Mount, d *Dentry, children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions, fdOpts GenericDirectoryFDOptions) (*GenericDirectoryFD, error) {
|
||||
fd := &GenericDirectoryFD{}
|
||||
if err := fd.Init(children, locks, opts, fdOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, m, d, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, m, d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fd, nil
|
||||
|
|
|
@ -148,20 +148,20 @@ func (fs *Filesystem) revalidateChildLocked(ctx context.Context, vfsObj *vfs.Vir
|
|||
// Preconditions: Filesystem.mu must be locked for at least reading.
|
||||
//
|
||||
// Postconditions: Caller must call fs.processDeferredDecRefs*.
|
||||
func (fs *Filesystem) walkExistingLocked(ctx context.Context, rp *vfs.ResolvingPath) (*vfs.Dentry, Inode, error) {
|
||||
func (fs *Filesystem) walkExistingLocked(ctx context.Context, rp *vfs.ResolvingPath) (*Dentry, error) {
|
||||
vfsd := rp.Start()
|
||||
for !rp.Done() {
|
||||
var err error
|
||||
vfsd, err = fs.stepExistingLocked(ctx, rp, vfsd, true /* mayFollowSymlinks */)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
d := vfsd.Impl().(*Dentry)
|
||||
if rp.MustBeDir() && !d.isDir() {
|
||||
return nil, nil, syserror.ENOTDIR
|
||||
return nil, syserror.ENOTDIR
|
||||
}
|
||||
return vfsd, d.inode, nil
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// walkParentDirLocked resolves all but the last path component of rp to an
|
||||
|
@ -223,8 +223,8 @@ func checkCreateLocked(ctx context.Context, rp *vfs.ResolvingPath, parentVFSD *v
|
|||
// checkDeleteLocked checks that the file represented by vfsd may be deleted.
|
||||
//
|
||||
// Preconditions: Filesystem.mu must be locked for at least reading.
|
||||
func checkDeleteLocked(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry) error {
|
||||
parent := vfsd.Impl().(*Dentry).parent
|
||||
func checkDeleteLocked(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry) error {
|
||||
parent := d.parent
|
||||
if parent == nil {
|
||||
return syserror.EBUSY
|
||||
}
|
||||
|
@ -253,11 +253,11 @@ func (fs *Filesystem) AccessAt(ctx context.Context, rp *vfs.ResolvingPath, creds
|
|||
defer fs.processDeferredDecRefs(ctx)
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
_, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return inode.CheckPermissions(ctx, creds, ats)
|
||||
return d.inode.CheckPermissions(ctx, creds, ats)
|
||||
}
|
||||
|
||||
// GetDentryAt implements vfs.FilesystemImpl.GetDentryAt.
|
||||
|
@ -265,20 +265,20 @@ func (fs *Filesystem) GetDentryAt(ctx context.Context, rp *vfs.ResolvingPath, op
|
|||
fs.mu.RLock()
|
||||
defer fs.processDeferredDecRefs(ctx)
|
||||
defer fs.mu.RUnlock()
|
||||
vfsd, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.CheckSearchable {
|
||||
d := vfsd.Impl().(*Dentry)
|
||||
if !d.isDir() {
|
||||
return nil, syserror.ENOTDIR
|
||||
}
|
||||
if err := inode.CheckPermissions(ctx, rp.Credentials(), vfs.MayExec); err != nil {
|
||||
if err := d.inode.CheckPermissions(ctx, rp.Credentials(), vfs.MayExec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
vfsd := d.VFSDentry()
|
||||
vfsd.IncRef() // Ownership transferred to caller.
|
||||
return vfsd, nil
|
||||
}
|
||||
|
@ -404,28 +404,27 @@ func (fs *Filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vf
|
|||
// Do not create new file.
|
||||
if opts.Flags&linux.O_CREAT == 0 {
|
||||
fs.mu.RLock()
|
||||
vfsd, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
if err != nil {
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
return nil, err
|
||||
}
|
||||
if err := inode.CheckPermissions(ctx, rp.Credentials(), ats); err != nil {
|
||||
if err := d.inode.CheckPermissions(ctx, rp.Credentials(), ats); err != nil {
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
return nil, err
|
||||
}
|
||||
inode.IncRef()
|
||||
defer inode.DecRef(ctx)
|
||||
d.inode.IncRef()
|
||||
defer d.inode.DecRef(ctx)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
return inode.Open(ctx, rp, vfsd, opts)
|
||||
return d.inode.Open(ctx, rp, d, opts)
|
||||
}
|
||||
|
||||
// May create new file.
|
||||
mustCreate := opts.Flags&linux.O_EXCL != 0
|
||||
vfsd := rp.Start()
|
||||
inode := vfsd.Impl().(*Dentry).inode
|
||||
d := rp.Start().Impl().(*Dentry)
|
||||
fs.mu.Lock()
|
||||
unlocked := false
|
||||
unlock := func() {
|
||||
|
@ -442,13 +441,13 @@ func (fs *Filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vf
|
|||
if mustCreate {
|
||||
return nil, syserror.EEXIST
|
||||
}
|
||||
if err := inode.CheckPermissions(ctx, rp.Credentials(), ats); err != nil {
|
||||
if err := d.inode.CheckPermissions(ctx, rp.Credentials(), ats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inode.IncRef()
|
||||
defer inode.DecRef(ctx)
|
||||
d.inode.IncRef()
|
||||
defer d.inode.DecRef(ctx)
|
||||
unlock()
|
||||
return inode.Open(ctx, rp, vfsd, opts)
|
||||
return d.inode.Open(ctx, rp, d, opts)
|
||||
}
|
||||
afterTrailingSymlink:
|
||||
parentVFSD, parentInode, err := fs.walkParentDirLocked(ctx, rp)
|
||||
|
@ -492,7 +491,7 @@ afterTrailingSymlink:
|
|||
child.inode.IncRef()
|
||||
defer child.inode.DecRef(ctx)
|
||||
unlock()
|
||||
return child.inode.Open(ctx, rp, childVFSD, opts)
|
||||
return child.inode.Open(ctx, rp, child, opts)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -528,22 +527,22 @@ afterTrailingSymlink:
|
|||
child.inode.IncRef()
|
||||
defer child.inode.DecRef(ctx)
|
||||
unlock()
|
||||
return child.inode.Open(ctx, rp, &child.vfsd, opts)
|
||||
return child.inode.Open(ctx, rp, child, opts)
|
||||
}
|
||||
|
||||
// ReadlinkAt implements vfs.FilesystemImpl.ReadlinkAt.
|
||||
func (fs *Filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (string, error) {
|
||||
fs.mu.RLock()
|
||||
d, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !d.Impl().(*Dentry).isSymlink() {
|
||||
if !d.isSymlink() {
|
||||
return "", syserror.EINVAL
|
||||
}
|
||||
return inode.Readlink(ctx, rp.Mount())
|
||||
return d.inode.Readlink(ctx, rp.Mount())
|
||||
}
|
||||
|
||||
// RenameAt implements vfs.FilesystemImpl.RenameAt.
|
||||
|
@ -582,10 +581,9 @@ func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcVFSD := &src.vfsd
|
||||
|
||||
// Can we remove the src dentry?
|
||||
if err := checkDeleteLocked(ctx, rp, srcVFSD); err != nil {
|
||||
if err := checkDeleteLocked(ctx, rp, src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -625,6 +623,7 @@ func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa
|
|||
defer dstDir.dirMu.Unlock()
|
||||
}
|
||||
|
||||
srcVFSD := src.VFSDentry()
|
||||
if err := virtfs.PrepareRenameDentry(mntns, srcVFSD, dstVFSD); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -653,7 +652,7 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
|
||||
vfsd, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.processDeferredDecRefsLocked(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -662,14 +661,13 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
return err
|
||||
}
|
||||
defer rp.Mount().EndWrite()
|
||||
if err := checkDeleteLocked(ctx, rp, vfsd); err != nil {
|
||||
if err := checkDeleteLocked(ctx, rp, d); err != nil {
|
||||
return err
|
||||
}
|
||||
d := vfsd.Impl().(*Dentry)
|
||||
if !d.isDir() {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
if inode.HasChildren() {
|
||||
if d.inode.HasChildren() {
|
||||
return syserror.ENOTEMPTY
|
||||
}
|
||||
virtfs := rp.VirtualFilesystem()
|
||||
|
@ -679,11 +677,12 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
|
||||
mntns := vfs.MountNamespaceFromContext(ctx)
|
||||
defer mntns.DecRef(ctx)
|
||||
vfsd := d.VFSDentry()
|
||||
if err := virtfs.PrepareDeleteDentry(mntns, vfsd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := parentDentry.inode.RmDir(ctx, d.name, vfsd); err != nil {
|
||||
if err := parentDentry.inode.RmDir(ctx, d.name, d.VFSDentry()); err != nil {
|
||||
virtfs.AbortDeleteDentry(vfsd)
|
||||
return err
|
||||
}
|
||||
|
@ -694,7 +693,7 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
// SetStatAt implements vfs.FilesystemImpl.SetStatAt.
|
||||
func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetStatOptions) error {
|
||||
fs.mu.RLock()
|
||||
_, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
|
@ -703,31 +702,31 @@ func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
|
|||
if opts.Stat.Mask == 0 {
|
||||
return nil
|
||||
}
|
||||
return inode.SetStat(ctx, fs.VFSFilesystem(), rp.Credentials(), opts)
|
||||
return d.inode.SetStat(ctx, fs.VFSFilesystem(), rp.Credentials(), opts)
|
||||
}
|
||||
|
||||
// StatAt implements vfs.FilesystemImpl.StatAt.
|
||||
func (fs *Filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
|
||||
fs.mu.RLock()
|
||||
_, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
return linux.Statx{}, err
|
||||
}
|
||||
return inode.Stat(ctx, fs.VFSFilesystem(), opts)
|
||||
return d.inode.Stat(ctx, fs.VFSFilesystem(), opts)
|
||||
}
|
||||
|
||||
// StatFSAt implements vfs.FilesystemImpl.StatFSAt.
|
||||
func (fs *Filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linux.Statfs, error) {
|
||||
fs.mu.RLock()
|
||||
_, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
return linux.Statfs{}, err
|
||||
}
|
||||
return inode.StatFS(ctx, fs.VFSFilesystem())
|
||||
return d.inode.StatFS(ctx, fs.VFSFilesystem())
|
||||
}
|
||||
|
||||
// SymlinkAt implements vfs.FilesystemImpl.SymlinkAt.
|
||||
|
@ -763,7 +762,7 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
|
||||
vfsd, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.processDeferredDecRefsLocked(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -772,10 +771,9 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
return err
|
||||
}
|
||||
defer rp.Mount().EndWrite()
|
||||
if err := checkDeleteLocked(ctx, rp, vfsd); err != nil {
|
||||
if err := checkDeleteLocked(ctx, rp, d); err != nil {
|
||||
return err
|
||||
}
|
||||
d := vfsd.Impl().(*Dentry)
|
||||
if d.isDir() {
|
||||
return syserror.EISDIR
|
||||
}
|
||||
|
@ -785,10 +783,11 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
defer parentDentry.dirMu.Unlock()
|
||||
mntns := vfs.MountNamespaceFromContext(ctx)
|
||||
defer mntns.DecRef(ctx)
|
||||
vfsd := d.VFSDentry()
|
||||
if err := virtfs.PrepareDeleteDentry(mntns, vfsd); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parentDentry.inode.Unlink(ctx, d.name, vfsd); err != nil {
|
||||
if err := parentDentry.inode.Unlink(ctx, d.name, d.VFSDentry()); err != nil {
|
||||
virtfs.AbortDeleteDentry(vfsd)
|
||||
return err
|
||||
}
|
||||
|
@ -799,13 +798,13 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
|||
// BoundEndpointAt implements vfs.FilesystemImpl.BoundEndpointAt.
|
||||
func (fs *Filesystem) BoundEndpointAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.BoundEndpointOptions) (transport.BoundEndpoint, error) {
|
||||
fs.mu.RLock()
|
||||
_, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
d, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := inode.CheckPermissions(ctx, rp.Credentials(), vfs.MayWrite); err != nil {
|
||||
if err := d.inode.CheckPermissions(ctx, rp.Credentials(), vfs.MayWrite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, syserror.ECONNREFUSED
|
||||
|
@ -814,7 +813,7 @@ func (fs *Filesystem) BoundEndpointAt(ctx context.Context, rp *vfs.ResolvingPath
|
|||
// ListXattrAt implements vfs.FilesystemImpl.ListXattrAt.
|
||||
func (fs *Filesystem) ListXattrAt(ctx context.Context, rp *vfs.ResolvingPath, size uint64) ([]string, error) {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
_, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
|
@ -827,7 +826,7 @@ func (fs *Filesystem) ListXattrAt(ctx context.Context, rp *vfs.ResolvingPath, si
|
|||
// GetXattrAt implements vfs.FilesystemImpl.GetXattrAt.
|
||||
func (fs *Filesystem) GetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.GetXattrOptions) (string, error) {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
_, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
|
@ -840,7 +839,7 @@ func (fs *Filesystem) GetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opt
|
|||
// 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)
|
||||
_, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
|
@ -853,7 +852,7 @@ func (fs *Filesystem) SetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opt
|
|||
// 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)
|
||||
_, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -547,7 +547,7 @@ type InodeSymlink struct {
|
|||
}
|
||||
|
||||
// Open implements Inode.Open.
|
||||
func (InodeSymlink) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (InodeSymlink) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
return nil, syserror.ELOOP
|
||||
}
|
||||
|
||||
|
@ -595,8 +595,8 @@ func (s *StaticDirectory) Init(creds *auth.Credentials, devMajor, devMinor uint3
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (s *StaticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), vfsd, &s.OrderedChildren, &s.locks, &opts, s.fdOpts)
|
||||
func (s *StaticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), d, &s.OrderedChildren, &s.locks, &opts, s.fdOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -350,7 +350,7 @@ type Inode interface {
|
|||
//
|
||||
// Precondition: rp.Done(). vfsd.Impl() must be the kernfs Dentry containing
|
||||
// the inode on which Open() is being called.
|
||||
Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error)
|
||||
Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error)
|
||||
|
||||
// StatFS returns filesystem statistics for the client filesystem. This
|
||||
// corresponds to vfs.FilesystemImpl.StatFSAt. If the client filesystem
|
||||
|
|
|
@ -121,8 +121,8 @@ func (fs *filesystem) newReadonlyDir(creds *auth.Credentials, mode linux.FileMod
|
|||
return &dir.dentry
|
||||
}
|
||||
|
||||
func (d *readonlyDir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (d *readonlyDir) Open(ctx context.Context, rp *vfs.ResolvingPath, kd *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), kd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -162,8 +162,8 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
|||
return &dir.dentry
|
||||
}
|
||||
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, kd *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), kd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -60,8 +60,8 @@ func (dir *syntheticDirectory) Init(creds *auth.Credentials, devMajor, devMinor
|
|||
}
|
||||
|
||||
// Open implements Inode.Open.
|
||||
func (dir *syntheticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), vfsd, &dir.OrderedChildren, &dir.locks, &opts, GenericDirectoryFDOptions{})
|
||||
func (dir *syntheticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), d, &dir.OrderedChildren, &dir.locks, &opts, GenericDirectoryFDOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -144,8 +144,8 @@ func (i *inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
return i.pipe.Open(ctx, rp.Mount(), vfsd, opts.Flags, &i.locks)
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
return i.pipe.Open(ctx, rp.Mount(), d.VFSDentry(), opts.Flags, &i.locks)
|
||||
}
|
||||
|
||||
// StatFS implements kernfs.Inode.StatFS.
|
||||
|
|
|
@ -154,14 +154,14 @@ func (fd *subtasksFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) erro
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *subtasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *subtasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd := &subtasksFD{task: i.task}
|
||||
if err := fd.Init(&i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fd.VFSFileDescription().Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := fd.VFSFileDescription().Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fd.VFSFileDescription(), nil
|
||||
|
|
|
@ -107,8 +107,8 @@ func (i *taskInode) Valid(ctx context.Context) bool {
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *taskInode) 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, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (i *taskInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), d, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -149,8 +149,8 @@ func (i *fdDirInode) Lookup(ctx context.Context, name string) (*kernfs.Dentry, e
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *fdDirInode) 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, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (i *fdDirInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), d, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -286,8 +286,8 @@ func (i *fdInfoDirInode) Lookup(ctx context.Context, name string) (*kernfs.Dentr
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *fdInfoDirInode) 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, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (i *fdInfoDirInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), d, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -853,11 +853,11 @@ func (i *namespaceInode) Init(creds *auth.Credentials, devMajor, devMinor uint32
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *namespaceInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *namespaceInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd := &namespaceFD{inode: i}
|
||||
i.IncRef()
|
||||
fd.LockFD.Init(&i.locks)
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &fd.vfsfd, nil
|
||||
|
|
|
@ -200,8 +200,8 @@ func (i *tasksInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *tasksInode) 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, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (i *tasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), d, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -88,7 +88,7 @@ type inode struct {
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
return nil, syserror.ENXIO
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ type kcovInode struct {
|
|||
implStatFS
|
||||
}
|
||||
|
||||
func (i *kcovInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
func (i *kcovInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
k := kernel.KernelFromContext(ctx)
|
||||
if k == nil {
|
||||
panic("KernelFromContext returned nil")
|
||||
|
@ -54,7 +54,7 @@ func (i *kcovInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.D
|
|||
kcov: k.NewKcov(),
|
||||
}
|
||||
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{
|
||||
DenyPRead: true,
|
||||
DenyPWrite: true,
|
||||
}); err != nil {
|
||||
|
|
|
@ -148,8 +148,8 @@ func (*dir) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.Set
|
|||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, kd *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), kd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue