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  }