gvisor/pkg/sentry/fs/save.go

78 lines
2.5 KiB
Go

// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fs
import (
"fmt"
"syscall"
"gvisor.googlesource.com/gvisor/pkg/log"
)
// SaveInodeMappings saves a mapping of path -> inode ID for every
// user-reachable Dirent.
//
// The entire kernel must be frozen to call this, and filesystem state must not
// change between SaveInodeMappings and state.Save, otherwise the saved state
// of any MountSource may be incoherent.
func SaveInodeMappings() {
mountsSeen := make(map[*MountSource]struct{})
for dirent := range allDirents.dirents {
if _, ok := mountsSeen[dirent.Inode.MountSource]; !ok {
dirent.Inode.MountSource.ResetInodeMappings()
mountsSeen[dirent.Inode.MountSource] = struct{}{}
}
}
for dirent := range allDirents.dirents {
if dirent.Inode != nil {
// We cannot trust the root provided in the mount due
// to the overlay. We can trust the overlay to delegate
// SaveInodeMappings to the right underlying
// filesystems, though.
root := dirent
for !root.mounted && root.parent != nil {
root = root.parent
}
// Add the mapping.
n, reachable := dirent.FullName(root)
if !reachable {
// Something has gone seriously wrong if we can't reach our root.
panic(fmt.Sprintf("Unreachable root on dirent file %s", n))
}
dirent.Inode.MountSource.SaveInodeMapping(dirent.Inode, n)
}
}
}
// SaveFileFsyncError converts an fs.File.Fsync error to an error that
// indicates that the fs.File was not synced sufficiently to be saved.
func SaveFileFsyncError(err error) error {
switch err {
case nil:
// We succeeded, everything is great.
return nil
case syscall.EBADF, syscall.EINVAL, syscall.EROFS, syscall.ENOSYS, syscall.EPERM:
// These errors mean that the underlying node might not be syncable,
// which we expect to be reported as such even from the gofer.
log.Infof("failed to sync during save: %v", err)
return nil
default:
// We failed in some way that indicates potential data loss.
return fmt.Errorf("failed to sync: %v, data loss may occur", err)
}
}