github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/vfs/save_restore.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 vfs 16 17 import ( 18 "sync/atomic" 19 20 "github.com/MerlinKodo/gvisor/pkg/context" 21 "github.com/MerlinKodo/gvisor/pkg/refs" 22 "github.com/MerlinKodo/gvisor/pkg/waiter" 23 ) 24 25 // ErrCorruption indicates a failed restore due to external file system state in 26 // corruption. 27 type ErrCorruption struct { 28 // Err is the wrapped error. 29 Err error 30 } 31 32 // Error returns a sensible description of the restore error. 33 func (e ErrCorruption) Error() string { 34 return "restore failed due to external file system state in corruption: " + e.Err.Error() 35 } 36 37 // FilesystemImplSaveRestoreExtension is an optional extension to 38 // FilesystemImpl. 39 type FilesystemImplSaveRestoreExtension interface { 40 // PrepareSave prepares this filesystem for serialization. 41 PrepareSave(ctx context.Context) error 42 43 // CompleteRestore completes restoration from checkpoint for this 44 // filesystem after deserialization. 45 CompleteRestore(ctx context.Context, opts CompleteRestoreOptions) error 46 } 47 48 // PrepareSave prepares all filesystems for serialization. 49 func (vfs *VirtualFilesystem) PrepareSave(ctx context.Context) error { 50 for fs := range vfs.getFilesystems() { 51 if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok { 52 if err := ext.PrepareSave(ctx); err != nil { 53 fs.DecRef(ctx) 54 return err 55 } 56 } 57 fs.DecRef(ctx) 58 } 59 return nil 60 } 61 62 // CompleteRestore completes restoration from checkpoint for all filesystems 63 // after deserialization. 64 func (vfs *VirtualFilesystem) CompleteRestore(ctx context.Context, opts *CompleteRestoreOptions) error { 65 for fs := range vfs.getFilesystems() { 66 if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok { 67 if err := ext.CompleteRestore(ctx, *opts); err != nil { 68 fs.DecRef(ctx) 69 return err 70 } 71 } 72 fs.DecRef(ctx) 73 } 74 return nil 75 } 76 77 // CompleteRestoreOptions contains options to 78 // VirtualFilesystem.CompleteRestore() and 79 // FilesystemImplSaveRestoreExtension.CompleteRestore(). 80 type CompleteRestoreOptions struct { 81 // If ValidateFileSizes is true, filesystem implementations backed by 82 // remote filesystems should verify that file sizes have not changed 83 // between checkpoint and restore. 84 ValidateFileSizes bool 85 86 // If ValidateFileModificationTimestamps is true, filesystem 87 // implementations backed by remote filesystems should validate that file 88 // mtimes have not changed between checkpoint and restore. 89 ValidateFileModificationTimestamps bool 90 } 91 92 // saveMounts is called by stateify. 93 func (vfs *VirtualFilesystem) saveMounts() []*Mount { 94 if atomic.LoadPointer(&vfs.mounts.slots) == nil { 95 // vfs.Init() was never called. 96 return nil 97 } 98 var mounts []*Mount 99 vfs.mounts.Range(func(mount *Mount) bool { 100 mounts = append(mounts, mount) 101 return true 102 }) 103 return mounts 104 } 105 106 // saveKey is called by stateify. 107 func (mnt *Mount) saveKey() VirtualDentry { return mnt.getKey() } 108 109 // loadMounts is called by stateify. 110 func (vfs *VirtualFilesystem) loadMounts(mounts []*Mount) { 111 if mounts == nil { 112 return 113 } 114 vfs.mounts.Init() 115 for _, mount := range mounts { 116 vfs.mounts.Insert(mount) 117 } 118 } 119 120 // loadKey is called by stateify. 121 func (mnt *Mount) loadKey(vd VirtualDentry) { mnt.setKey(vd) } 122 123 // afterLoad is called by stateify. 124 func (mnt *Mount) afterLoad() { 125 if mnt.refs.Load() != 0 { 126 refs.Register(mnt) 127 } 128 } 129 130 // afterLoad is called by stateify. 131 func (epi *epollInterest) afterLoad() { 132 // Mark all epollInterests as ready after restore so that the next call to 133 // EpollInstance.ReadEvents() rechecks their readiness. 134 epi.waiter.NotifyEvent(waiter.EventMaskFromLinux(epi.mask)) 135 }