2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-04-27 17:37:02 +00:00
|
|
|
//
|
|
|
|
// 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"
|
2018-07-03 21:07:43 +00:00
|
|
|
"sync/atomic"
|
2018-04-27 17:37:02 +00:00
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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.
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-04-27 17:37:02 +00:00
|
|
|
type Watch struct {
|
|
|
|
// Inotify instance which owns this watch.
|
|
|
|
owner *Inotify
|
|
|
|
|
|
|
|
// Descriptor for this watch. This is unique across an inotify instance.
|
|
|
|
wd int32
|
|
|
|
|
|
|
|
// 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"`
|
|
|
|
|
2018-07-03 21:07:43 +00:00
|
|
|
// Events being monitored via this watch. Must be accessed atomically,
|
|
|
|
// writes are protected by mu.
|
|
|
|
mask uint32
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// 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 {
|
2018-07-03 21:07:43 +00:00
|
|
|
return atomic.LoadUint32(&w.mask)&linux.IN_EXCL_UNLINK == 0
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2018-12-21 19:52:39 +00:00
|
|
|
mask := atomic.LoadUint32(&w.mask)
|
|
|
|
if mask&events == 0 {
|
2018-04-27 17:37:02 +00:00
|
|
|
// We weren't watching for this event.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-21 19:52:39 +00:00
|
|
|
// Event mask should include bits matched from the watch plus all control
|
|
|
|
// event bits.
|
|
|
|
unmaskableBits := ^uint32(0) &^ linux.IN_ALL_EVENTS
|
|
|
|
effectiveMask := unmaskableBits | mask
|
|
|
|
matchedEvents := effectiveMask & events
|
2018-04-27 17:37:02 +00:00
|
|
|
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
|
|
|
|
}
|