github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 "fmt" 19 "sync/atomic" 20 21 "github.com/SagerNet/gvisor/pkg/abi/linux" 22 "github.com/SagerNet/gvisor/pkg/context" 23 "github.com/SagerNet/gvisor/pkg/refsvfs2" 24 "github.com/SagerNet/gvisor/pkg/waiter" 25 ) 26 27 // FilesystemImplSaveRestoreExtension is an optional extension to 28 // FilesystemImpl. 29 type FilesystemImplSaveRestoreExtension interface { 30 // PrepareSave prepares this filesystem for serialization. 31 PrepareSave(ctx context.Context) error 32 33 // CompleteRestore completes restoration from checkpoint for this 34 // filesystem after deserialization. 35 CompleteRestore(ctx context.Context, opts CompleteRestoreOptions) error 36 } 37 38 // PrepareSave prepares all filesystems for serialization. 39 func (vfs *VirtualFilesystem) PrepareSave(ctx context.Context) error { 40 failures := 0 41 for fs := range vfs.getFilesystems() { 42 if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok { 43 if err := ext.PrepareSave(ctx); err != nil { 44 ctx.Warningf("%T.PrepareSave failed: %v", fs.impl, err) 45 failures++ 46 } 47 } 48 fs.DecRef(ctx) 49 } 50 if failures != 0 { 51 return fmt.Errorf("%d filesystems failed to prepare for serialization", failures) 52 } 53 return nil 54 } 55 56 // CompleteRestore completes restoration from checkpoint for all filesystems 57 // after deserialization. 58 func (vfs *VirtualFilesystem) CompleteRestore(ctx context.Context, opts *CompleteRestoreOptions) error { 59 failures := 0 60 for fs := range vfs.getFilesystems() { 61 if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok { 62 if err := ext.CompleteRestore(ctx, *opts); err != nil { 63 ctx.Warningf("%T.CompleteRestore failed: %v", fs.impl, err) 64 failures++ 65 } 66 } 67 fs.DecRef(ctx) 68 } 69 if failures != 0 { 70 return fmt.Errorf("%d filesystems failed to complete restore after deserialization", failures) 71 } 72 return nil 73 } 74 75 // CompleteRestoreOptions contains options to 76 // VirtualFilesystem.CompleteRestore() and 77 // FilesystemImplSaveRestoreExtension.CompleteRestore(). 78 type CompleteRestoreOptions struct { 79 // If ValidateFileSizes is true, filesystem implementations backed by 80 // remote filesystems should verify that file sizes have not changed 81 // between checkpoint and restore. 82 ValidateFileSizes bool 83 84 // If ValidateFileModificationTimestamps is true, filesystem 85 // implementations backed by remote filesystems should validate that file 86 // mtimes have not changed between checkpoint and restore. 87 ValidateFileModificationTimestamps bool 88 } 89 90 // saveMounts is called by stateify. 91 func (vfs *VirtualFilesystem) saveMounts() []*Mount { 92 if atomic.LoadPointer(&vfs.mounts.slots) == nil { 93 // vfs.Init() was never called. 94 return nil 95 } 96 var mounts []*Mount 97 vfs.mounts.Range(func(mount *Mount) bool { 98 mounts = append(mounts, mount) 99 return true 100 }) 101 return mounts 102 } 103 104 // saveKey is called by stateify. 105 func (mnt *Mount) saveKey() VirtualDentry { return mnt.getKey() } 106 107 // loadMounts is called by stateify. 108 func (vfs *VirtualFilesystem) loadMounts(mounts []*Mount) { 109 if mounts == nil { 110 return 111 } 112 vfs.mounts.Init() 113 for _, mount := range mounts { 114 vfs.mounts.Insert(mount) 115 } 116 } 117 118 // loadKey is called by stateify. 119 func (mnt *Mount) loadKey(vd VirtualDentry) { mnt.setKey(vd) } 120 121 func (mnt *Mount) afterLoad() { 122 if atomic.LoadInt64(&mnt.refs) != 0 { 123 refsvfs2.Register(mnt) 124 } 125 } 126 127 // afterLoad is called by stateify. 128 func (epi *epollInterest) afterLoad() { 129 // Mark all epollInterests as ready after restore so that the next call to 130 // EpollInstance.ReadEvents() rechecks their readiness. 131 epi.Callback(nil, waiter.EventMaskFromLinux(epi.mask)) 132 } 133 134 // beforeSave is called by stateify. 135 func (fd *FileDescription) beforeSave() { 136 fd.saved = true 137 if fd.statusFlags&linux.O_ASYNC != 0 && fd.asyncHandler != nil { 138 fd.asyncHandler.Unregister(fd) 139 } 140 } 141 142 // afterLoad is called by stateify. 143 func (fd *FileDescription) afterLoad() { 144 if fd.statusFlags&linux.O_ASYNC != 0 && fd.asyncHandler != nil { 145 fd.asyncHandler.Register(fd) 146 } 147 }