github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/inotify_watch.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 "sync/atomic" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/sync" 23 ) 24 25 // Watch represent a particular inotify watch created by inotify_add_watch. 26 // 27 // While a watch is active, it ensures the target inode is pinned in memory by 28 // holding an extra ref on each dirent known (by inotify) to point to the 29 // inode. These are known as pins. For a full discussion, see 30 // fs/g3doc/inotify.md. 31 // 32 // +stateify savable 33 type Watch struct { 34 // Inotify instance which owns this watch. 35 owner *Inotify 36 37 // Descriptor for this watch. This is unique across an inotify instance. 38 wd int32 39 40 // The inode being watched. Note that we don't directly hold a reference on 41 // this inode. Instead we hold a reference on the dirent(s) containing the 42 // inode, which we record in pins. 43 target *Inode 44 45 // unpinned indicates whether we have a hard reference on target. This field 46 // may only be modified through atomic ops. 47 unpinned uint32 48 49 // mu protects the fields below. 50 mu sync.Mutex `state:"nosave"` 51 52 // Events being monitored via this watch. Must be accessed atomically, 53 // writes are protected by mu. 54 mask uint32 55 56 // pins is the set of dirents this watch is currently pinning in memory by 57 // holding a reference to them. See Pin()/Unpin(). 58 pins map[*Dirent]bool 59 } 60 61 // ID returns the id of the inotify instance that owns this watch. 62 func (w *Watch) ID() uint64 { 63 return w.owner.id 64 } 65 66 // NotifyParentAfterUnlink indicates whether the parent of the watched object 67 // should continue to be be notified of events after the target has been 68 // unlinked. 69 func (w *Watch) NotifyParentAfterUnlink() bool { 70 return atomic.LoadUint32(&w.mask)&linux.IN_EXCL_UNLINK == 0 71 } 72 73 // isRenameEvent returns true if eventMask describes a rename event. 74 func isRenameEvent(eventMask uint32) bool { 75 return eventMask&(linux.IN_MOVED_FROM|linux.IN_MOVED_TO|linux.IN_MOVE_SELF) != 0 76 } 77 78 // Notify queues a new event on this watch. 79 func (w *Watch) Notify(name string, events uint32, cookie uint32) { 80 mask := atomic.LoadUint32(&w.mask) 81 if mask&events == 0 { 82 // We weren't watching for this event. 83 return 84 } 85 86 // Event mask should include bits matched from the watch plus all control 87 // event bits. 88 unmaskableBits := ^uint32(0) &^ linux.IN_ALL_EVENTS 89 effectiveMask := unmaskableBits | mask 90 matchedEvents := effectiveMask & events 91 w.owner.queueEvent(newEvent(w.wd, name, matchedEvents, cookie)) 92 } 93 94 // Pin acquires a new ref on dirent, which pins the dirent in memory while 95 // the watch is active. Calling Pin for a second time on the same dirent for 96 // the same watch is a no-op. 97 func (w *Watch) Pin(d *Dirent) { 98 w.mu.Lock() 99 defer w.mu.Unlock() 100 if !w.pins[d] { 101 w.pins[d] = true 102 d.IncRef() 103 } 104 } 105 106 // Unpin drops any extra refs held on dirent due to a previous Pin 107 // call. Calling Unpin multiple times for the same dirent, or on a dirent 108 // without a corresponding Pin call is a no-op. 109 func (w *Watch) Unpin(ctx context.Context, d *Dirent) { 110 w.mu.Lock() 111 defer w.mu.Unlock() 112 if w.pins[d] { 113 delete(w.pins, d) 114 d.DecRef(ctx) 115 } 116 } 117 118 // TargetDestroyed notifies the owner of the watch that the watch target is 119 // gone. The owner should release its own references to the watcher upon 120 // receiving this notification. 121 func (w *Watch) TargetDestroyed() { 122 w.owner.targetDestroyed(w) 123 } 124 125 // destroy prepares the watch for destruction. It unpins all dirents pinned by 126 // this watch. Destroy does not cause any new events to be generated. The caller 127 // is responsible for ensuring there are no outstanding references to this 128 // watch. 129 func (w *Watch) destroy(ctx context.Context) { 130 w.mu.Lock() 131 defer w.mu.Unlock() 132 for d := range w.pins { 133 d.DecRef(ctx) 134 } 135 w.pins = nil 136 }