1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fs
import (
"sync"
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
)
// Watch represent a particular inotify watch created by inotify_add_watch.
//
// While a watch is active, it ensures the target inode is pinned in memory by
// holding an extra ref on each dirent known (by inotify) to point to the
// inode. These are known as pins. For a full discussion, see
// fs/g3doc/inotify.md.
type Watch struct {
// Inotify instance which owns this watch.
owner *Inotify
// Descriptor for this watch. This is unique across an inotify instance.
wd int32
// Events being monitored via this watch.
mask uint32
// The inode being watched. Note that we don't directly hold a reference on
// this inode. Instead we hold a reference on the dirent(s) containing the
// inode, which we record in pins.
target *Inode
// unpinned indicates whether we have a hard reference on target. This field
// may only be modified through atomic ops.
unpinned uint32
// mu protects the fields below.
mu sync.Mutex `state:"nosave"`
// pins is the set of dirents this watch is currently pinning in memory by
// holding a reference to them. See Pin()/Unpin().
pins map[*Dirent]bool
}
// ID returns the id of the inotify instance that owns this watch.
func (w *Watch) ID() uint64 {
return w.owner.id
}
// NotifyParentAfterUnlink indicates whether the parent of the watched object
// should continue to be be notified of events after the target has been
// unlinked.
func (w *Watch) NotifyParentAfterUnlink() bool {
return w.mask&linux.IN_EXCL_UNLINK == 0
}
// isRenameEvent returns true if eventMask describes a rename event.
func isRenameEvent(eventMask uint32) bool {
return eventMask&(linux.IN_MOVED_FROM|linux.IN_MOVED_TO|linux.IN_MOVE_SELF) != 0
}
// Notify queues a new event on this watch.
func (w *Watch) Notify(name string, events uint32, cookie uint32) {
unmaskableBits := ^uint32(0) &^ linux.IN_ALL_EVENTS
effectiveMask := unmaskableBits | w.mask
matchedEvents := effectiveMask & events
if matchedEvents == 0 {
// We weren't watching for this event.
return
}
w.owner.queueEvent(newEvent(w.wd, name, matchedEvents, cookie))
}
// Pin acquires a new ref on dirent, which pins the dirent in memory while
// the watch is active. Calling Pin for a second time on the same dirent for
// the same watch is a no-op.
func (w *Watch) Pin(d *Dirent) {
w.mu.Lock()
defer w.mu.Unlock()
if !w.pins[d] {
w.pins[d] = true
d.IncRef()
}
}
// Unpin drops any extra refs held on dirent due to a previous Pin
// call. Calling Unpin multiple times for the same dirent, or on a dirent
// without a corresponding Pin call is a no-op.
func (w *Watch) Unpin(d *Dirent) {
w.mu.Lock()
defer w.mu.Unlock()
if w.pins[d] {
delete(w.pins, d)
d.DecRef()
}
}
// TargetDestroyed notifies the owner of the watch that the watch target is
// gone. The owner should release its own references to the watcher upon
// receiving this notification.
func (w *Watch) TargetDestroyed() {
w.owner.targetDestroyed(w)
}
// destroy prepares the watch for destruction. It unpins all dirents pinned by
// this watch. Destroy does not cause any new events to be generated. The caller
// is responsible for ensuring there are no outstanding references to this
// watch.
func (w *Watch) destroy() {
w.mu.Lock()
defer w.mu.Unlock()
for d := range w.pins {
d.DecRef()
}
w.pins = nil
}
|