github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/save.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  	"golang.org/x/sys/unix"
    21  	"github.com/SagerNet/gvisor/pkg/log"
    22  )
    23  
    24  // SaveInodeMappings saves a mapping of path -> inode ID for every
    25  // user-reachable Dirent.
    26  //
    27  // The entire kernel must be frozen to call this, and filesystem state must not
    28  // change between SaveInodeMappings and state.Save, otherwise the saved state
    29  // of any MountSource may be incoherent.
    30  func SaveInodeMappings() {
    31  	mountsSeen := make(map[*MountSource]struct{})
    32  	for dirent := range allDirents.dirents {
    33  		if _, ok := mountsSeen[dirent.Inode.MountSource]; !ok {
    34  			dirent.Inode.MountSource.ResetInodeMappings()
    35  			mountsSeen[dirent.Inode.MountSource] = struct{}{}
    36  		}
    37  	}
    38  
    39  	for dirent := range allDirents.dirents {
    40  		if dirent.Inode != nil {
    41  			// We cannot trust the root provided in the mount due
    42  			// to the overlay. We can trust the overlay to delegate
    43  			// SaveInodeMappings to the right underlying
    44  			// filesystems, though.
    45  			root := dirent
    46  			for !root.mounted && root.parent != nil {
    47  				root = root.parent
    48  			}
    49  
    50  			// Add the mapping.
    51  			n, reachable := dirent.FullName(root)
    52  			if !reachable {
    53  				// Something has gone seriously wrong if we can't reach our root.
    54  				panic(fmt.Sprintf("Unreachable root on dirent file %s", n))
    55  			}
    56  			dirent.Inode.MountSource.SaveInodeMapping(dirent.Inode, n)
    57  		}
    58  	}
    59  }
    60  
    61  // SaveFileFsyncError converts an fs.File.Fsync error to an error that
    62  // indicates that the fs.File was not synced sufficiently to be saved.
    63  func SaveFileFsyncError(err error) error {
    64  	switch err {
    65  	case nil:
    66  		// We succeeded, everything is great.
    67  		return nil
    68  	case unix.EBADF, unix.EINVAL, unix.EROFS, unix.ENOSYS, unix.EPERM:
    69  		// These errors mean that the underlying node might not be syncable,
    70  		// which we expect to be reported as such even from the gofer.
    71  		log.Infof("failed to sync during save: %v", err)
    72  		return nil
    73  	default:
    74  		// We failed in some way that indicates potential data loss.
    75  		return fmt.Errorf("failed to sync: %v, data loss may occur", err)
    76  	}
    77  }