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  }