gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/vfs/genericfstree/genericfstree.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package genericfstree provides tools for implementing vfs.FilesystemImpls 16 // where a single statically-determined lock or set of locks is sufficient to 17 // ensure that a Dentry's name and parent are contextually immutable. 18 // 19 // Clients using this package must use the go_template_instance rule in 20 // tools/go_generics/defs.bzl to create an instantiation of this template 21 // package, providing types to use in place of Dentry. 22 package genericfstree 23 24 import ( 25 "gvisor.dev/gvisor/pkg/fspath" 26 "gvisor.dev/gvisor/pkg/sentry/vfs" 27 ) 28 29 // We need to define an interface instead of using atomic.Pointer because 30 // the Dentry type gets removed during code generation and the compiler 31 // complains about the unused sync/atomic type. 32 type atomicptr interface { 33 Load() *Dentry 34 } 35 36 // Dentry is a required type parameter that is a struct with the given fields. 37 // 38 // +stateify savable 39 type Dentry struct { 40 // vfsd is the embedded vfs.Dentry corresponding to this vfs.DentryImpl. 41 vfsd vfs.Dentry 42 43 // parent is the parent of this Dentry in the filesystem's tree. If this 44 // Dentry is a filesystem root, parent is nil. 45 parent atomicptr 46 47 // name is the name of this Dentry in its parent. If this Dentry is a 48 // filesystem root, name is unspecified. 49 name string 50 } 51 52 // IsAncestorDentry returns true if d is an ancestor of d2; that is, d is 53 // either d2's parent or an ancestor of d2's parent. 54 func IsAncestorDentry(d, d2 *Dentry) bool { 55 for d2 != nil { // Stop at root, where d2.parent == nil. 56 parent := d2.parent.Load() 57 if parent == d { 58 return true 59 } 60 if parent == d2 { 61 return false 62 } 63 d2 = parent 64 } 65 return false 66 } 67 68 // IsDescendant returns true if vd is a descendant of vfsroot or if vd and 69 // vfsroot are the same dentry. 70 func IsDescendant(vfsroot *vfs.Dentry, d *Dentry) bool { 71 for d != nil && &d.vfsd != vfsroot { 72 d = d.parent.Load() 73 } 74 return d != nil 75 } 76 77 // ParentOrSelf returns d.parent. If d.parent is nil, ParentOrSelf returns d. 78 func ParentOrSelf(d *Dentry) *Dentry { 79 if parent := d.parent.Load(); parent != nil { 80 return parent 81 } 82 return d 83 } 84 85 // PrependPath is a generic implementation of FilesystemImpl.PrependPath(). 86 func PrependPath(vfsroot vfs.VirtualDentry, mnt *vfs.Mount, d *Dentry, b *fspath.Builder) error { 87 for { 88 if mnt == vfsroot.Mount() && &d.vfsd == vfsroot.Dentry() { 89 return vfs.PrependPathAtVFSRootError{} 90 } 91 if mnt != nil && &d.vfsd == mnt.Root() { 92 return nil 93 } 94 parent := d.parent.Load() 95 if parent == nil { 96 return vfs.PrependPathAtNonMountRootError{} 97 } 98 b.PrependComponent(d.name) 99 d = parent 100 } 101 } 102 103 // DebugPathname returns a pathname to d relative to its filesystem root. 104 // DebugPathname does not correspond to any Linux function; it's used to 105 // generate dentry pathnames for debugging. 106 func DebugPathname(d *Dentry) string { 107 var b fspath.Builder 108 _ = PrependPath(vfs.VirtualDentry{}, nil, d, &b) 109 return b.String() 110 }