github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/inode_overlay.go (about)

     1  // Copyright 2018 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 fs
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    21  	"github.com/SagerNet/gvisor/pkg/context"
    22  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    23  	"github.com/SagerNet/gvisor/pkg/log"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport"
    25  	"github.com/SagerNet/gvisor/pkg/syserror"
    26  )
    27  
    28  func overlayHasWhiteout(ctx context.Context, parent *Inode, name string) bool {
    29  	s, err := parent.GetXattr(ctx, XattrOverlayWhiteout(name), 1)
    30  	return err == nil && s == "y"
    31  }
    32  
    33  func overlayCreateWhiteout(ctx context.Context, parent *Inode, name string) error {
    34  	return parent.InodeOperations.SetXattr(ctx, parent, XattrOverlayWhiteout(name), "y", 0 /* flags */)
    35  }
    36  
    37  func overlayWriteOut(ctx context.Context, o *overlayEntry) error {
    38  	// Hot path. Avoid defers.
    39  	var err error
    40  	o.copyMu.RLock()
    41  	if o.upper != nil {
    42  		err = o.upper.InodeOperations.WriteOut(ctx, o.upper)
    43  	}
    44  	o.copyMu.RUnlock()
    45  	return err
    46  }
    47  
    48  // overlayLookup performs a lookup in parent.
    49  //
    50  // If name exists, it returns true if the Dirent is in the upper, false if the
    51  // Dirent is in the lower.
    52  func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name string) (*Dirent, bool, error) {
    53  	// Hot path. Avoid defers.
    54  	parent.copyMu.RLock()
    55  
    56  	// Assert that there is at least one upper or lower entry.
    57  	if parent.upper == nil && parent.lower == nil {
    58  		parent.copyMu.RUnlock()
    59  		panic("invalid overlayEntry, needs at least one Inode")
    60  	}
    61  
    62  	var upperInode *Inode
    63  	var lowerInode *Inode
    64  
    65  	// We must remember whether the upper fs returned a negative dirent,
    66  	// because it is only safe to return one if the upper did.
    67  	var negativeUpperChild bool
    68  
    69  	// Does the parent directory exist in the upper file system?
    70  	if parent.upper != nil {
    71  		// First check if a file object exists in the upper file system.
    72  		// A file could have been created over a whiteout, so we need to
    73  		// check if something exists in the upper file system first.
    74  		child, err := parent.upper.Lookup(ctx, name)
    75  		if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
    76  			// We encountered an error that an overlay cannot handle,
    77  			// we must propagate it to the caller.
    78  			parent.copyMu.RUnlock()
    79  			return nil, false, err
    80  		}
    81  		if child != nil {
    82  			if child.IsNegative() {
    83  				negativeUpperChild = true
    84  			} else {
    85  				upperInode = child.Inode
    86  				upperInode.IncRef()
    87  			}
    88  			child.DecRef(ctx)
    89  		}
    90  
    91  		// Are we done?
    92  		if overlayHasWhiteout(ctx, parent.upper, name) {
    93  			if upperInode == nil {
    94  				parent.copyMu.RUnlock()
    95  				if negativeUpperChild {
    96  					// If the upper fs returnd a negative
    97  					// Dirent, then the upper is OK with
    98  					// that negative Dirent being cached in
    99  					// the Dirent tree, so we can return
   100  					// one from the overlay.
   101  					return NewNegativeDirent(name), false, nil
   102  				}
   103  				// Upper fs is not OK with a negative Dirent
   104  				// being cached in the Dirent tree, so don't
   105  				// return one.
   106  				return nil, false, syserror.ENOENT
   107  			}
   108  			entry, err := newOverlayEntry(ctx, upperInode, nil, false)
   109  			if err != nil {
   110  				// Don't leak resources.
   111  				upperInode.DecRef(ctx)
   112  				parent.copyMu.RUnlock()
   113  				return nil, false, err
   114  			}
   115  			d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil
   116  			parent.copyMu.RUnlock()
   117  			return d, true, err
   118  		}
   119  	}
   120  
   121  	// Check the lower file system. We do this unconditionally (even for
   122  	// non-directories) because we may need to use stable attributes from
   123  	// the lower filesystem (e.g. device number, inode number) that were
   124  	// visible before a copy up.
   125  	if parent.lower != nil {
   126  		// Check the lower file system.
   127  		child, err := parent.lower.Lookup(ctx, name)
   128  		// Same song and dance as above.
   129  		if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
   130  			// Don't leak resources.
   131  			if upperInode != nil {
   132  				upperInode.DecRef(ctx)
   133  			}
   134  			parent.copyMu.RUnlock()
   135  			return nil, false, err
   136  		}
   137  		if child != nil {
   138  			if !child.IsNegative() {
   139  				if upperInode == nil {
   140  					// If nothing was in the upper, use what we found in the lower.
   141  					lowerInode = child.Inode
   142  					lowerInode.IncRef()
   143  				} else {
   144  					// If we have something from the upper, we can only use it if the types
   145  					// match.
   146  					// NOTE(b/112312863): Allow SpecialDirectories and Directories to merge.
   147  					// This is needed to allow submounts in /proc and /sys.
   148  					if upperInode.StableAttr.Type == child.Inode.StableAttr.Type ||
   149  						(IsDir(upperInode.StableAttr) && IsDir(child.Inode.StableAttr)) {
   150  						lowerInode = child.Inode
   151  						lowerInode.IncRef()
   152  					}
   153  				}
   154  			}
   155  			child.DecRef(ctx)
   156  		}
   157  	}
   158  
   159  	// Was all of this for naught?
   160  	if upperInode == nil && lowerInode == nil {
   161  		parent.copyMu.RUnlock()
   162  		// We can only return a negative dirent if the upper returned
   163  		// one as well. See comments above regarding negativeUpperChild
   164  		// for more info.
   165  		if negativeUpperChild {
   166  			return NewNegativeDirent(name), false, nil
   167  		}
   168  		return nil, false, syserror.ENOENT
   169  	}
   170  
   171  	// Did we find a lower Inode? Remember this because we may decide we don't
   172  	// actually need the lower Inode (see below).
   173  	lowerExists := lowerInode != nil
   174  
   175  	// If we found something in the upper filesystem and the lower filesystem,
   176  	// use the stable attributes from the lower filesystem. If we don't do this,
   177  	// then it may appear that the file was magically recreated across copy up.
   178  	if upperInode != nil && lowerInode != nil {
   179  		// Steal attributes.
   180  		upperInode.StableAttr = lowerInode.StableAttr
   181  
   182  		// For non-directories, the lower filesystem resource is strictly
   183  		// unnecessary because we don't need to copy-up and we will always
   184  		// operate (e.g. read/write) on the upper Inode.
   185  		if !IsDir(upperInode.StableAttr) {
   186  			lowerInode.DecRef(ctx)
   187  			lowerInode = nil
   188  		}
   189  	}
   190  
   191  	// Phew, finally done.
   192  	entry, err := newOverlayEntry(ctx, upperInode, lowerInode, lowerExists)
   193  	if err != nil {
   194  		// Well, not quite, we failed at the last moment, how depressing.
   195  		// Be sure not to leak resources.
   196  		if upperInode != nil {
   197  			upperInode.DecRef(ctx)
   198  		}
   199  		if lowerInode != nil {
   200  			lowerInode.DecRef(ctx)
   201  		}
   202  		parent.copyMu.RUnlock()
   203  		return nil, false, err
   204  	}
   205  	d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil
   206  	parent.copyMu.RUnlock()
   207  	return d, upperInode != nil, err
   208  }
   209  
   210  func overlayCreate(ctx context.Context, o *overlayEntry, parent *Dirent, name string, flags FileFlags, perm FilePermissions) (*File, error) {
   211  	// Sanity check.
   212  	if parent.Inode.overlay == nil {
   213  		panic(fmt.Sprintf("overlayCreate called with non-overlay parent inode (parent InodeOperations type is %T)", parent.Inode.InodeOperations))
   214  	}
   215  
   216  	// Dirent.Create takes renameMu if the Inode is an overlay Inode.
   217  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	upperFile, err := o.upper.InodeOperations.Create(ctx, o.upper, name, flags, perm)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	// We've added to the directory so we must drop the cache.
   227  	o.markDirectoryDirty()
   228  
   229  	// Take another reference on the upper file's inode, which will be
   230  	// owned by the overlay entry.
   231  	upperFile.Dirent.Inode.IncRef()
   232  	entry, err := newOverlayEntry(ctx, upperFile.Dirent.Inode, nil, false)
   233  	if err != nil {
   234  		werr := fmt.Errorf("newOverlayEntry failed: %v", err)
   235  		cleanupUpper(ctx, o.upper, name, werr)
   236  		return nil, err
   237  	}
   238  
   239  	// NOTE(b/71766861): Replace the Dirent with a transient Dirent, since
   240  	// we are about to create the real Dirent: an overlay Dirent.
   241  	//
   242  	// This ensures the *fs.File returned from overlayCreate is in the same
   243  	// state as the *fs.File returned by overlayGetFile, where the upper
   244  	// file has a transient Dirent.
   245  	//
   246  	// This is necessary for Save/Restore, as otherwise the upper Dirent
   247  	// (which has no path as it is unparented and never reachable by the
   248  	// user) will clobber the real path for the underlying Inode.
   249  	upperFile.Dirent.Inode.IncRef()
   250  	upperDirent := NewTransientDirent(upperFile.Dirent.Inode)
   251  	upperFile.Dirent.DecRef(ctx)
   252  	upperFile.Dirent = upperDirent
   253  
   254  	// Create the overlay inode and dirent.  We need this to construct the
   255  	// overlay file.
   256  	overlayInode := newOverlayInode(ctx, entry, parent.Inode.MountSource)
   257  	// d will own the inode reference.
   258  	overlayDirent := NewDirent(ctx, overlayInode, name)
   259  	// The overlay file created below with NewFile will take a reference on
   260  	// the overlayDirent, and it should be the only thing holding a
   261  	// reference at the time of creation, so we must drop this reference.
   262  	defer overlayDirent.DecRef(ctx)
   263  
   264  	// Create a new overlay file that wraps the upper file.
   265  	flags.Pread = upperFile.Flags().Pread
   266  	flags.Pwrite = upperFile.Flags().Pwrite
   267  	overlayFile := NewFile(ctx, overlayDirent, flags, &overlayFileOperations{upper: upperFile})
   268  
   269  	return overlayFile, nil
   270  }
   271  
   272  func overlayCreateDirectory(ctx context.Context, o *overlayEntry, parent *Dirent, name string, perm FilePermissions) error {
   273  	// Dirent.CreateDirectory takes renameMu if the Inode is an overlay
   274  	// Inode.
   275  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   276  		return err
   277  	}
   278  	if err := o.upper.InodeOperations.CreateDirectory(ctx, o.upper, name, perm); err != nil {
   279  		return err
   280  	}
   281  	// We've added to the directory so we must drop the cache.
   282  	o.markDirectoryDirty()
   283  	return nil
   284  }
   285  
   286  func overlayCreateLink(ctx context.Context, o *overlayEntry, parent *Dirent, oldname string, newname string) error {
   287  	// Dirent.CreateLink takes renameMu if the Inode is an overlay Inode.
   288  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   289  		return err
   290  	}
   291  	if err := o.upper.InodeOperations.CreateLink(ctx, o.upper, oldname, newname); err != nil {
   292  		return err
   293  	}
   294  	// We've added to the directory so we must drop the cache.
   295  	o.markDirectoryDirty()
   296  	return nil
   297  }
   298  
   299  func overlayCreateHardLink(ctx context.Context, o *overlayEntry, parent *Dirent, target *Dirent, name string) error {
   300  	// Dirent.CreateHardLink takes renameMu if the Inode is an overlay
   301  	// Inode.
   302  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   303  		return err
   304  	}
   305  	if err := copyUpLockedForRename(ctx, target); err != nil {
   306  		return err
   307  	}
   308  	if err := o.upper.InodeOperations.CreateHardLink(ctx, o.upper, target.Inode.overlay.upper, name); err != nil {
   309  		return err
   310  	}
   311  	// We've added to the directory so we must drop the cache.
   312  	o.markDirectoryDirty()
   313  	return nil
   314  }
   315  
   316  func overlayCreateFifo(ctx context.Context, o *overlayEntry, parent *Dirent, name string, perm FilePermissions) error {
   317  	// Dirent.CreateFifo takes renameMu if the Inode is an overlay Inode.
   318  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   319  		return err
   320  	}
   321  	if err := o.upper.InodeOperations.CreateFifo(ctx, o.upper, name, perm); err != nil {
   322  		return err
   323  	}
   324  	// We've added to the directory so we must drop the cache.
   325  	o.markDirectoryDirty()
   326  	return nil
   327  }
   328  
   329  func overlayRemove(ctx context.Context, o *overlayEntry, parent *Dirent, child *Dirent) error {
   330  	// Dirent.Remove and Dirent.RemoveDirectory take renameMu if the Inode
   331  	// is an overlay Inode.
   332  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   333  		return err
   334  	}
   335  	child.Inode.overlay.copyMu.RLock()
   336  	defer child.Inode.overlay.copyMu.RUnlock()
   337  	if child.Inode.StableAttr.Type == Directory {
   338  		// RemoveDirectory requires that the directory is empty.
   339  		ser := &CollectEntriesSerializer{}
   340  		dirCtx := &DirCtx{
   341  			Serializer: ser,
   342  		}
   343  		if _, err := overlayIterateDirLocked(ctx, child.Inode.overlay, child, dirCtx, 0); err != nil {
   344  			return err
   345  		}
   346  		if ser.Written() != 0 {
   347  			return linuxerr.ENOTEMPTY
   348  		}
   349  	}
   350  	if child.Inode.overlay.upper != nil {
   351  		if child.Inode.StableAttr.Type == Directory {
   352  			if err := o.upper.InodeOperations.RemoveDirectory(ctx, o.upper, child.name); err != nil {
   353  				return err
   354  			}
   355  		} else {
   356  			if err := o.upper.InodeOperations.Remove(ctx, o.upper, child.name); err != nil {
   357  				return err
   358  			}
   359  		}
   360  	}
   361  	if child.Inode.overlay.lowerExists {
   362  		if err := overlayCreateWhiteout(ctx, o.upper, child.name); err != nil {
   363  			return err
   364  		}
   365  	}
   366  	// We've removed from the directory so we must drop the cache.
   367  	o.markDirectoryDirty()
   368  	return nil
   369  }
   370  
   371  func overlayRename(ctx context.Context, o *overlayEntry, oldParent *Dirent, renamed *Dirent, newParent *Dirent, newName string, replacement bool) error {
   372  	// To be able to copy these up below, they have to be part of an
   373  	// overlay file system.
   374  	//
   375  	// Maybe some day we can allow the more complicated case of
   376  	// non-overlay X overlay renames, but that's not necessary right now.
   377  	if renamed.Inode.overlay == nil || newParent.Inode.overlay == nil || oldParent.Inode.overlay == nil {
   378  		return linuxerr.EXDEV
   379  	}
   380  
   381  	if replacement {
   382  		// Check here if the file to be replaced exists and is a
   383  		// non-empty directory. If we copy up first, we may end up
   384  		// copying the directory but none of its children, so the
   385  		// directory will appear empty in the upper fs, which will then
   386  		// allow the rename to proceed when it should return ENOTEMPTY.
   387  		//
   388  		// NOTE(b/111808347): Ideally, we'd just pass in the replaced
   389  		// Dirent from Rename, but we must drop the reference on
   390  		// replaced before we make the rename call, so Rename can't
   391  		// pass the Dirent to the Inode without significantly
   392  		// complicating the API. Thus we look it up again here.
   393  		//
   394  		// For the same reason we can't use defer here.
   395  		replaced, inUpper, err := overlayLookup(ctx, newParent.Inode.overlay, newParent.Inode, newName)
   396  		// If err == ENOENT or a negative Dirent is returned, then
   397  		// newName has been removed out from under us. That's fine;
   398  		// filesystems where that can happen must handle stale
   399  		// 'replaced'.
   400  		if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
   401  			return err
   402  		}
   403  		if err == nil {
   404  			if !inUpper {
   405  				// newName doesn't exist in
   406  				// newParent.Inode.overlay.upper, thus from
   407  				// that Inode's perspective this won't be a
   408  				// replacing rename.
   409  				replacement = false
   410  			}
   411  
   412  			if !replaced.IsNegative() && IsDir(replaced.Inode.StableAttr) {
   413  				children, err := readdirOne(ctx, replaced)
   414  				if err != nil {
   415  					replaced.DecRef(ctx)
   416  					return err
   417  				}
   418  
   419  				// readdirOne ensures that "." and ".." are not
   420  				// included among the returned children, so we don't
   421  				// need to bother checking for them.
   422  				if len(children) > 0 {
   423  					replaced.DecRef(ctx)
   424  					return linuxerr.ENOTEMPTY
   425  				}
   426  			}
   427  
   428  			replaced.DecRef(ctx)
   429  		}
   430  	}
   431  
   432  	if err := copyUpLockedForRename(ctx, renamed); err != nil {
   433  		return err
   434  	}
   435  	if err := copyUpLockedForRename(ctx, newParent); err != nil {
   436  		return err
   437  	}
   438  	oldName := renamed.name
   439  	if err := o.upper.InodeOperations.Rename(ctx, renamed.Inode.overlay.upper, oldParent.Inode.overlay.upper, oldName, newParent.Inode.overlay.upper, newName, replacement); err != nil {
   440  		return err
   441  	}
   442  	if renamed.Inode.overlay.lowerExists {
   443  		if err := overlayCreateWhiteout(ctx, oldParent.Inode.overlay.upper, oldName); err != nil {
   444  			return err
   445  		}
   446  	}
   447  	// We've changed the directory so we must drop the cache.
   448  	oldParent.Inode.overlay.markDirectoryDirty()
   449  	return nil
   450  }
   451  
   452  func overlayBind(ctx context.Context, o *overlayEntry, parent *Dirent, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) {
   453  	if err := copyUpLockedForRename(ctx, parent); err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	o.copyMu.RLock()
   458  	defer o.copyMu.RUnlock()
   459  
   460  	d, err := o.upper.InodeOperations.Bind(ctx, o.upper, name, data, perm)
   461  	if err != nil {
   462  		return nil, err
   463  	}
   464  
   465  	// We've added to the directory so we must drop the cache.
   466  	o.markDirectoryDirty()
   467  
   468  	// Grab the inode and drop the dirent, we don't need it.
   469  	inode := d.Inode
   470  	inode.IncRef()
   471  	d.DecRef(ctx)
   472  
   473  	// Create a new overlay entry and dirent for the socket.
   474  	entry, err := newOverlayEntry(ctx, inode, nil, false)
   475  	if err != nil {
   476  		inode.DecRef(ctx)
   477  		return nil, err
   478  	}
   479  	// Use the parent's MountSource, since that corresponds to the overlay,
   480  	// and not the upper filesystem.
   481  	return NewDirent(ctx, newOverlayInode(ctx, entry, parent.Inode.MountSource), name), nil
   482  }
   483  
   484  func overlayBoundEndpoint(o *overlayEntry, path string) transport.BoundEndpoint {
   485  	o.copyMu.RLock()
   486  	defer o.copyMu.RUnlock()
   487  
   488  	if o.upper != nil {
   489  		return o.upper.InodeOperations.BoundEndpoint(o.upper, path)
   490  	}
   491  
   492  	return o.lower.BoundEndpoint(path)
   493  }
   494  
   495  func overlayGetFile(ctx context.Context, o *overlayEntry, d *Dirent, flags FileFlags) (*File, error) {
   496  	// Hot path. Avoid defers.
   497  	if flags.Write {
   498  		if err := copyUp(ctx, d); err != nil {
   499  			return nil, err
   500  		}
   501  	}
   502  
   503  	o.copyMu.RLock()
   504  
   505  	if o.upper != nil {
   506  		upper, err := overlayFile(ctx, o.upper, flags)
   507  		if err != nil {
   508  			o.copyMu.RUnlock()
   509  			return nil, err
   510  		}
   511  		flags.Pread = upper.Flags().Pread
   512  		flags.Pwrite = upper.Flags().Pwrite
   513  		f, err := NewFile(ctx, d, flags, &overlayFileOperations{upper: upper}), nil
   514  		o.copyMu.RUnlock()
   515  		return f, err
   516  	}
   517  
   518  	lower, err := overlayFile(ctx, o.lower, flags)
   519  	if err != nil {
   520  		o.copyMu.RUnlock()
   521  		return nil, err
   522  	}
   523  	flags.Pread = lower.Flags().Pread
   524  	flags.Pwrite = lower.Flags().Pwrite
   525  	o.copyMu.RUnlock()
   526  	return NewFile(ctx, d, flags, &overlayFileOperations{lower: lower}), nil
   527  }
   528  
   529  func overlayUnstableAttr(ctx context.Context, o *overlayEntry) (UnstableAttr, error) {
   530  	// Hot path. Avoid defers.
   531  	var (
   532  		attr UnstableAttr
   533  		err  error
   534  	)
   535  	o.copyMu.RLock()
   536  	if o.upper != nil {
   537  		attr, err = o.upper.UnstableAttr(ctx)
   538  	} else {
   539  		attr, err = o.lower.UnstableAttr(ctx)
   540  	}
   541  	o.copyMu.RUnlock()
   542  	return attr, err
   543  }
   544  
   545  func overlayGetXattr(ctx context.Context, o *overlayEntry, name string, size uint64) (string, error) {
   546  	// Hot path. This is how the overlay checks for whiteout files.
   547  	// Avoid defers.
   548  	var (
   549  		s   string
   550  		err error
   551  	)
   552  
   553  	// Don't forward the value of the extended attribute if it would
   554  	// unexpectedly change the behavior of a wrapping overlay layer.
   555  	if isXattrOverlay(name) {
   556  		return "", linuxerr.ENODATA
   557  	}
   558  
   559  	o.copyMu.RLock()
   560  	if o.upper != nil {
   561  		s, err = o.upper.GetXattr(ctx, name, size)
   562  	} else {
   563  		s, err = o.lower.GetXattr(ctx, name, size)
   564  	}
   565  	o.copyMu.RUnlock()
   566  	return s, err
   567  }
   568  
   569  func overlaySetXattr(ctx context.Context, o *overlayEntry, d *Dirent, name, value string, flags uint32) error {
   570  	// Don't allow changes to overlay xattrs through a setxattr syscall.
   571  	if isXattrOverlay(name) {
   572  		return linuxerr.EPERM
   573  	}
   574  
   575  	if err := copyUp(ctx, d); err != nil {
   576  		return err
   577  	}
   578  	return o.upper.SetXattr(ctx, d, name, value, flags)
   579  }
   580  
   581  func overlayListXattr(ctx context.Context, o *overlayEntry, size uint64) (map[string]struct{}, error) {
   582  	o.copyMu.RLock()
   583  	defer o.copyMu.RUnlock()
   584  	var names map[string]struct{}
   585  	var err error
   586  	if o.upper != nil {
   587  		names, err = o.upper.ListXattr(ctx, size)
   588  	} else {
   589  		names, err = o.lower.ListXattr(ctx, size)
   590  	}
   591  	for name := range names {
   592  		// Same as overlayGetXattr, we shouldn't forward along
   593  		// overlay attributes.
   594  		if isXattrOverlay(name) {
   595  			delete(names, name)
   596  		}
   597  	}
   598  	return names, err
   599  }
   600  
   601  func overlayRemoveXattr(ctx context.Context, o *overlayEntry, d *Dirent, name string) error {
   602  	// Don't allow changes to overlay xattrs through a removexattr syscall.
   603  	if isXattrOverlay(name) {
   604  		return linuxerr.EPERM
   605  	}
   606  
   607  	if err := copyUp(ctx, d); err != nil {
   608  		return err
   609  	}
   610  	return o.upper.RemoveXattr(ctx, d, name)
   611  }
   612  
   613  func overlayCheck(ctx context.Context, o *overlayEntry, p PermMask) error {
   614  	o.copyMu.RLock()
   615  	// Hot path. Avoid defers.
   616  	var err error
   617  	if o.upper != nil {
   618  		err = o.upper.check(ctx, p)
   619  	} else {
   620  		err = o.lower.check(ctx, p)
   621  	}
   622  	o.copyMu.RUnlock()
   623  	return err
   624  }
   625  
   626  func overlaySetPermissions(ctx context.Context, o *overlayEntry, d *Dirent, f FilePermissions) bool {
   627  	if err := copyUp(ctx, d); err != nil {
   628  		return false
   629  	}
   630  	return o.upper.InodeOperations.SetPermissions(ctx, o.upper, f)
   631  }
   632  
   633  func overlaySetOwner(ctx context.Context, o *overlayEntry, d *Dirent, owner FileOwner) error {
   634  	if err := copyUp(ctx, d); err != nil {
   635  		return err
   636  	}
   637  	return o.upper.InodeOperations.SetOwner(ctx, o.upper, owner)
   638  }
   639  
   640  func overlaySetTimestamps(ctx context.Context, o *overlayEntry, d *Dirent, ts TimeSpec) error {
   641  	if err := copyUp(ctx, d); err != nil {
   642  		return err
   643  	}
   644  	return o.upper.InodeOperations.SetTimestamps(ctx, o.upper, ts)
   645  }
   646  
   647  func overlayTruncate(ctx context.Context, o *overlayEntry, d *Dirent, size int64) error {
   648  	if err := copyUp(ctx, d); err != nil {
   649  		return err
   650  	}
   651  	return o.upper.InodeOperations.Truncate(ctx, o.upper, size)
   652  }
   653  
   654  func overlayAllocate(ctx context.Context, o *overlayEntry, d *Dirent, offset, length int64) error {
   655  	if err := copyUp(ctx, d); err != nil {
   656  		return err
   657  	}
   658  	return o.upper.InodeOperations.Allocate(ctx, o.upper, offset, length)
   659  }
   660  
   661  func overlayReadlink(ctx context.Context, o *overlayEntry) (string, error) {
   662  	o.copyMu.RLock()
   663  	defer o.copyMu.RUnlock()
   664  	if o.upper != nil {
   665  		return o.upper.Readlink(ctx)
   666  	}
   667  	return o.lower.Readlink(ctx)
   668  }
   669  
   670  func overlayGetlink(ctx context.Context, o *overlayEntry) (*Dirent, error) {
   671  	var dirent *Dirent
   672  	var err error
   673  
   674  	o.copyMu.RLock()
   675  	defer o.copyMu.RUnlock()
   676  
   677  	if o.upper != nil {
   678  		dirent, err = o.upper.Getlink(ctx)
   679  	} else {
   680  		dirent, err = o.lower.Getlink(ctx)
   681  	}
   682  	if dirent != nil {
   683  		// This dirent is likely bogus (its Inode likely doesn't contain
   684  		// the right overlayEntry). So we're forced to drop it on the
   685  		// ground and claim that jumping around the filesystem like this
   686  		// is not supported.
   687  		name, _ := dirent.FullName(nil)
   688  		dirent.DecRef(ctx)
   689  
   690  		// Claim that the path is not accessible.
   691  		err = linuxerr.EACCES
   692  		log.Warningf("Getlink not supported in overlay for %q", name)
   693  	}
   694  	return nil, err
   695  }
   696  
   697  func overlayStatFS(ctx context.Context, o *overlayEntry) (Info, error) {
   698  	o.copyMu.RLock()
   699  	defer o.copyMu.RUnlock()
   700  
   701  	var i Info
   702  	var err error
   703  	if o.upper != nil {
   704  		i, err = o.upper.StatFS(ctx)
   705  	} else {
   706  		i, err = o.lower.StatFS(ctx)
   707  	}
   708  	if err != nil {
   709  		return Info{}, err
   710  	}
   711  
   712  	i.Type = linux.OVERLAYFS_SUPER_MAGIC
   713  
   714  	return i, nil
   715  }
   716  
   717  // NewTestOverlayDir returns an overlay Inode for tests.
   718  //
   719  // If `revalidate` is true, then the upper filesystem will require
   720  // revalidation.
   721  func NewTestOverlayDir(ctx context.Context, upper, lower *Inode, revalidate bool) *Inode {
   722  	fs := &overlayFilesystem{}
   723  	var upperMsrc *MountSource
   724  	if revalidate {
   725  		upperMsrc = NewRevalidatingMountSource(ctx, fs, MountSourceFlags{})
   726  	} else {
   727  		upperMsrc = NewNonCachingMountSource(ctx, fs, MountSourceFlags{})
   728  	}
   729  	msrc := NewMountSource(ctx, &overlayMountSourceOperations{
   730  		upper: upperMsrc,
   731  		lower: NewNonCachingMountSource(ctx, fs, MountSourceFlags{}),
   732  	}, fs, MountSourceFlags{})
   733  	overlay := &overlayEntry{
   734  		upper: upper,
   735  		lower: lower,
   736  	}
   737  	return newOverlayInode(ctx, overlay, msrc)
   738  }
   739  
   740  // TestHasUpperFS returns true if i is an overlay Inode and it has a pointer
   741  // to an Inode on an upper filesystem.
   742  func (i *Inode) TestHasUpperFS() bool {
   743  	return i.overlay != nil && i.overlay.upper != nil
   744  }
   745  
   746  // TestHasLowerFS returns true if i is an overlay Inode and it has a pointer
   747  // to an Inode on a lower filesystem.
   748  func (i *Inode) TestHasLowerFS() bool {
   749  	return i.overlay != nil && i.overlay.lower != nil
   750  }