aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c72
1 files changed, 64 insertions, 8 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 883beaf6d1da..89c1d779f04c 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -41,6 +41,7 @@
#include <sys/counter.h>
#include <sys/filedesc.h>
#include <sys/fnv_hash.h>
+#include <sys/inotify.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
@@ -331,7 +332,8 @@ SDT_PROBE_DEFINE2(vfs, namecache, evict_negative, done, "struct vnode *",
"char *");
SDT_PROBE_DEFINE1(vfs, namecache, symlink, alloc__fail, "size_t");
-SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata", "int", "bool");
+SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata *", "int",
+ "enum cache_fpl_status");
SDT_PROBE_DECLARE(vfs, namei, lookup, entry);
SDT_PROBE_DECLARE(vfs, namei, lookup, return);
@@ -2629,6 +2631,14 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
atomic_store_ptr(&dvp->v_cache_dd, ncp);
} else if (vp != NULL) {
/*
+ * Take the slow path in INOTIFY(). This flag will be lazily
+ * cleared by cache_vop_inotify() once all directories referring
+ * to vp are unwatched.
+ */
+ if (__predict_false((vn_irflag_read(dvp) & VIRF_INOTIFY) != 0))
+ vn_irflag_set_cond(vp, VIRF_INOTIFY_PARENT);
+
+ /*
* For this case, the cache entry maps both the
* directory name in it and the name ".." for the
* directory's parent.
@@ -4008,6 +4018,56 @@ out:
return (error);
}
+void
+cache_vop_inotify(struct vnode *vp, int event, uint32_t cookie)
+{
+ struct mtx *vlp;
+ struct namecache *ncp;
+ int isdir;
+ bool logged, self;
+
+ isdir = vp->v_type == VDIR ? IN_ISDIR : 0;
+ self = (vn_irflag_read(vp) & VIRF_INOTIFY) != 0 &&
+ (vp->v_type != VDIR || (event & ~_IN_DIR_EVENTS) != 0);
+
+ if (self) {
+ int selfevent;
+
+ if (event == _IN_ATTRIB_LINKCOUNT)
+ selfevent = IN_ATTRIB;
+ else
+ selfevent = event;
+ inotify_log(vp, NULL, 0, selfevent | isdir, cookie);
+ }
+ if ((event & IN_ALL_EVENTS) == 0)
+ return;
+
+ logged = false;
+ vlp = VP2VNODELOCK(vp);
+ mtx_lock(vlp);
+ TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst) {
+ if ((ncp->nc_flag & NCF_ISDOTDOT) != 0)
+ continue;
+ if ((vn_irflag_read(ncp->nc_dvp) & VIRF_INOTIFY) != 0) {
+ /*
+ * XXX-MJ if the vnode has two links in the same
+ * dir, we'll log the same event twice.
+ */
+ inotify_log(ncp->nc_dvp, ncp->nc_name, ncp->nc_nlen,
+ event | isdir, cookie);
+ logged = true;
+ }
+ }
+ if (!logged && (vn_irflag_read(vp) & VIRF_INOTIFY_PARENT) != 0) {
+ /*
+ * We didn't find a watched directory that contains this vnode,
+ * so stop calling VOP_INOTIFY for operations on the vnode.
+ */
+ vn_irflag_unset(vp, VIRF_INOTIFY_PARENT);
+ }
+ mtx_unlock(vlp);
+}
+
#ifdef DDB
static void
db_print_vpath(struct vnode *vp)
@@ -6361,15 +6421,11 @@ out:
cache_fpl_smr_assert_not_entered(&fpl);
cache_fpl_assert_status(&fpl);
*status = fpl.status;
- if (SDT_PROBES_ENABLED()) {
- SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
- if (fpl.status == CACHE_FPL_STATUS_HANDLED)
- SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
- ndp);
- }
-
+ SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
if (__predict_true(fpl.status == CACHE_FPL_STATUS_HANDLED)) {
MPASS(error != CACHE_FPL_FAILED);
+ SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
+ ndp);
if (error != 0) {
cache_fpl_cleanup_cnp(fpl.cnp);
MPASS(fpl.dvp == NULL);