github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/dirent_state.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 "sync/atomic" 20 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/refs" 23 ) 24 25 // beforeSave is invoked by stateify. 26 func (d *Dirent) beforeSave() { 27 // Refuse to save if the file is on a non-virtual file system and has 28 // already been deleted (but still has open fds, which is why the Dirent 29 // is still accessible). We know the the restore re-opening of the file 30 // will always fail. This condition will last until all the open fds and 31 // this Dirent are closed and released. 32 // 33 // Such "dangling" open files on virtual file systems (e.g., tmpfs) is 34 // OK to save as their restore does not require re-opening the files. 35 // 36 // Note that this is rejection rather than failure---it would be 37 // perfectly OK to save---we are simply disallowing it here to prevent 38 // generating non-restorable state dumps. As the program continues its 39 // execution, it may become allowed to save again. 40 if !d.Inode.IsVirtual() && atomic.LoadInt32(&d.deleted) != 0 { 41 n, _ := d.FullName(nil /* root */) 42 panic(ErrSaveRejection{fmt.Errorf("deleted file %q still has open fds", n)}) 43 } 44 } 45 46 // saveChildren is invoked by stateify. 47 func (d *Dirent) saveChildren() map[string]*Dirent { 48 c := make(map[string]*Dirent) 49 for name, w := range d.children { 50 if rc := w.Get(); rc != nil { 51 // Drop the reference count obtain in w.Get() 52 rc.DecRef(context.Background()) 53 54 cd := rc.(*Dirent) 55 if cd.IsNegative() { 56 // Don't bother saving negative Dirents. 57 continue 58 } 59 c[name] = cd 60 } 61 } 62 return c 63 } 64 65 // loadChildren is invoked by stateify. 66 func (d *Dirent) loadChildren(children map[string]*Dirent) { 67 d.children = make(map[string]*refs.WeakRef) 68 for name, c := range children { 69 d.children[name] = refs.NewWeakRef(c, nil) 70 } 71 } 72 73 // afterLoad is invoked by stateify. 74 func (d *Dirent) afterLoad() { 75 if d.userVisible { 76 allDirents.add(d) 77 } 78 }