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 }