summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorssouhlal <ssouhlal@FreeBSD.org>2005-06-09 20:20:31 +0000
committerssouhlal <ssouhlal@FreeBSD.org>2005-06-09 20:20:31 +0000
commit0835f7b4a9a7e80823912ce250d4082b5a23a401 (patch)
treef884ddce34ea556a36562577b6b807ab201ffb03 /sys/kern
parentbf3a7d1c45580ecf11f34f58fcdb57fba76c9d40 (diff)
downloadFreeBSD-src-0835f7b4a9a7e80823912ce250d4082b5a23a401.zip
FreeBSD-src-0835f7b4a9a7e80823912ce250d4082b5a23a401.tar.gz
Allow EVFILT_VNODE events to work on every filesystem type, not just
UFS by: - Making the pre and post hooks for the VOP functions work even when DEBUG_VFS_LOCKS is not defined. - Moving the KNOTE activations into the corresponding VOP hooks. - Creating a MNTK_NOKNOTE flag for the mnt_kern_flag field of struct mount that permits filesystems to disable the new behavior. - Creating a default VOP_KQFILTER function: vfs_kqfilter() My benchmarks have not revealed any performance degradation. Reviewed by: jeff, bde Approved by: rwatson, jmg (kqueue changes), grehan (mentor)
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_default.c8
-rw-r--r--sys/kern/vfs_subr.c233
-rw-r--r--sys/kern/vnode_if.src11
3 files changed, 251 insertions, 1 deletions
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index 32f3f9b..2336438 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/conf.h>
+#include <sys/event.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
@@ -82,6 +83,7 @@ struct vop_vector default_vnodeops = {
.vop_getwritemount = vop_stdgetwritemount,
.vop_inactive = VOP_NULL,
.vop_ioctl = VOP_ENOTTY,
+ .vop_kqfilter = vop_stdkqfilter,
.vop_islocked = vop_stdislocked,
.vop_lease = VOP_NULL,
.vop_lock = vop_stdlock,
@@ -464,6 +466,12 @@ vop_stdgetpages(ap)
ap->a_count, ap->a_reqpage);
}
+int
+vop_stdkqfilter(struct vop_kqfilter_args *ap)
+{
+ return vfs_kqfilter(ap);
+}
+
/* XXX Needs good comment and more info in the manpage (VOP_PUTPAGES(9)). */
int
vop_stdputpages(ap)
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9a612a4..408a4f8 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/event.h>
#include <sys/eventhandler.h>
#include <sys/extattr.h>
+#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
@@ -3304,12 +3305,14 @@ assert_vop_slocked(struct vnode *vp, const char *str)
vfs_badlock("is not locked shared but should be", str, vp);
}
#endif /* 0 */
+#endif /* DEBUG_VFS_LOCKS */
void
vop_rename_pre(void *ap)
{
struct vop_rename_args *a = ap;
+#ifdef DEBUG_VFS_LOCKS
if (a->a_tvp)
ASSERT_VI_UNLOCKED(a->a_tvp, "VOP_RENAME");
ASSERT_VI_UNLOCKED(a->a_tdvp, "VOP_RENAME");
@@ -3326,11 +3329,20 @@ vop_rename_pre(void *ap)
if (a->a_tvp)
ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked");
ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked");
+#endif
+ if (a->a_tdvp != a->a_fdvp)
+ vholdl(a->a_fdvp);
+ if (a->a_tvp != a->a_fvp)
+ vhold(a->a_fvp);
+ vhold(a->a_tdvp);
+ if (a->a_tvp)
+ vhold(a->a_tvp);
}
void
vop_strategy_pre(void *ap)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_strategy_args *a;
struct buf *bp;
@@ -3350,11 +3362,13 @@ vop_strategy_pre(void *ap)
if (vfs_badlock_ddb)
kdb_enter("lock violation");
}
+#endif
}
void
vop_lookup_pre(void *ap)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_lookup_args *a;
struct vnode *dvp;
@@ -3362,11 +3376,13 @@ vop_lookup_pre(void *ap)
dvp = a->a_dvp;
ASSERT_VI_UNLOCKED(dvp, "VOP_LOOKUP");
ASSERT_VOP_LOCKED(dvp, "VOP_LOOKUP");
+#endif
}
void
vop_lookup_post(void *ap, int rc)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_lookup_args *a;
struct vnode *dvp;
struct vnode *vp;
@@ -3380,48 +3396,155 @@ vop_lookup_post(void *ap, int rc)
if (!rc)
ASSERT_VOP_LOCKED(vp, "VOP_LOOKUP (child)");
+#endif
}
void
vop_lock_pre(void *ap)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_lock_args *a = ap;
if ((a->a_flags & LK_INTERLOCK) == 0)
ASSERT_VI_UNLOCKED(a->a_vp, "VOP_LOCK");
else
ASSERT_VI_LOCKED(a->a_vp, "VOP_LOCK");
+#endif
}
void
vop_lock_post(void *ap, int rc)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_lock_args *a = ap;
ASSERT_VI_UNLOCKED(a->a_vp, "VOP_LOCK");
if (rc == 0)
ASSERT_VOP_LOCKED(a->a_vp, "VOP_LOCK");
+#endif
}
void
vop_unlock_pre(void *ap)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_unlock_args *a = ap;
if (a->a_flags & LK_INTERLOCK)
ASSERT_VI_LOCKED(a->a_vp, "VOP_UNLOCK");
ASSERT_VOP_LOCKED(a->a_vp, "VOP_UNLOCK");
+#endif
}
void
vop_unlock_post(void *ap, int rc)
{
+#ifdef DEBUG_VFS_LOCKS
struct vop_unlock_args *a = ap;
if (a->a_flags & LK_INTERLOCK)
ASSERT_VI_UNLOCKED(a->a_vp, "VOP_UNLOCK");
+#endif
+}
+
+void
+vop_create_post(void *ap, int rc)
+{
+ struct vop_create_args *a = ap;
+
+ if (!rc)
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE);
+}
+
+void
+vop_link_post(void *ap, int rc)
+{
+ struct vop_link_args *a = ap;
+
+ if (!rc) {
+ VFS_SEND_KNOTE(a->a_vp, NOTE_LINK);
+ VFS_SEND_KNOTE(a->a_tdvp, NOTE_WRITE);
+ }
+}
+
+void
+vop_mkdir_post(void *ap, int rc)
+{
+ struct vop_mkdir_args *a = ap;
+
+ if (!rc)
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE | NOTE_LINK);
+}
+
+void
+vop_mknod_post(void *ap, int rc)
+{
+ struct vop_mknod_args *a = ap;
+
+ if (!rc)
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE);
+}
+
+void
+vop_remove_post(void *ap, int rc)
+{
+ struct vop_remove_args *a = ap;
+
+ if (!rc) {
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE);
+ VFS_SEND_KNOTE(a->a_vp, NOTE_DELETE);
+ }
+}
+
+void
+vop_rename_post(void *ap, int rc)
+{
+ struct vop_rename_args *a = ap;
+
+ if (!rc) {
+ VFS_SEND_KNOTE(a->a_fdvp, NOTE_WRITE);
+ VFS_SEND_KNOTE(a->a_tdvp, NOTE_WRITE);
+ VFS_SEND_KNOTE(a->a_fvp, NOTE_RENAME);
+ if (a->a_tvp)
+ VFS_SEND_KNOTE(a->a_tvp, NOTE_DELETE);
+ }
+ if (a->a_tdvp != a->a_fdvp)
+ vdrop(a->a_fdvp);
+ if (a->a_tvp != a->a_fvp)
+ vdrop(a->a_fvp);
+ vdrop(a->a_tdvp);
+ if (a->a_tvp)
+ vdrop(a->a_tvp);
+}
+
+void
+vop_rmdir_post(void *ap, int rc)
+{
+ struct vop_rmdir_args *a = ap;
+
+ if (!rc) {
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE | NOTE_LINK);
+ VFS_SEND_KNOTE(a->a_vp, NOTE_DELETE);
+ }
+}
+
+void
+vop_setattr_post(void *ap, int rc)
+{
+ struct vop_setattr_args *a = ap;
+
+ if (!rc)
+ VFS_SEND_KNOTE(a->a_vp, NOTE_ATTRIB);
+}
+
+void
+vop_symlink_post(void *ap, int rc)
+{
+ struct vop_symlink_args *a = ap;
+
+ if (!rc)
+ VFS_SEND_KNOTE(a->a_dvp, NOTE_WRITE);
}
-#endif /* DEBUG_VFS_LOCKS */
static struct knlist fs_knlist;
@@ -3510,3 +3633,111 @@ init_va_filerev(void)
getbinuptime(&bt);
return (((u_quad_t)bt.sec << 32LL) | (bt.frac >> 32LL));
}
+
+static int filt_vfsread(struct knote *kn, long hint);
+static int filt_vfswrite(struct knote *kn, long hint);
+static int filt_vfsvnode(struct knote *kn, long hint);
+static void filt_vfsdetach(struct knote *kn);
+
+static struct filterops vfsread_filtops =
+ { 1, NULL, filt_vfsdetach, filt_vfsread };
+static struct filterops vfswrite_filtops =
+ { 1, NULL, filt_vfsdetach, filt_vfswrite };
+static struct filterops vfsvnode_filtops =
+ { 1, NULL, filt_vfsdetach, filt_vfsvnode };
+
+int
+vfs_kqfilter(struct vop_kqfilter_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct knote *kn = ap->a_kn;
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ kn->kn_fop = &vfsread_filtops;
+ break;
+ case EVFILT_WRITE:
+ kn->kn_fop = &vfswrite_filtops;
+ break;
+ case EVFILT_VNODE:
+ kn->kn_fop = &vfsvnode_filtops;
+ break;
+ default:
+ return (1);
+ }
+
+ kn->kn_hook = (caddr_t)vp;
+
+ if (vp->v_pollinfo == NULL)
+ v_addpollinfo(vp);
+ if (vp->v_pollinfo == NULL)
+ return (ENOMEM);
+ knlist_add(&vp->v_pollinfo->vpi_selinfo.si_note, kn, 0);
+
+ return (0);
+}
+
+/*
+ * Detach knote from vnode
+ */
+static void
+filt_vfsdetach(struct knote *kn)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_hook;
+
+ KASSERT(vp->v_pollinfo != NULL, ("Missing v_pollinfo"));
+ knlist_remove(&vp->v_pollinfo->vpi_selinfo.si_note, kn, 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_vfsread(struct knote *kn, long hint)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_hook;
+ struct vattr va;
+
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ if (hint == NOTE_REVOKE) {
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ return (1);
+ }
+
+ vn_lock(vp, LK_SHARED | LK_RETRY, curthread);
+ if (VOP_GETATTR(vp, &va, curthread->td_ucred, curthread))
+ return (0);
+ if (VOP_UNLOCK(vp, 0, curthread))
+ return (0);
+
+ kn->kn_data = va.va_size - kn->kn_fp->f_offset;
+ return (kn->kn_data != 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_vfswrite(struct knote *kn, long hint)
+{
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ if (hint == NOTE_REVOKE)
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+
+ kn->kn_data = 0;
+ return (1);
+}
+
+static int
+filt_vfsvnode(struct knote *kn, long hint)
+{
+ if (kn->kn_sfflags & hint)
+ kn->kn_fflags |= hint;
+ if (hint == NOTE_REVOKE) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ return (kn->kn_fflags != 0);
+}
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index b8d3ce5..19780a5 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -95,6 +95,7 @@ vop_cachedlookup {
#
#% create dvp E E E
#% create vpp - L -
+#! create post vop_create_post
#
vop_create {
IN struct vnode *dvp;
@@ -115,6 +116,7 @@ vop_whiteout {
#
#% mknod dvp E E E
#% mknod vpp - L -
+#! mknod post vop_mknod_post
#
vop_mknod {
IN struct vnode *dvp;
@@ -166,6 +168,7 @@ vop_getattr {
#
#% setattr vp E E E
+#! setattr post vop_setattr_post
#
vop_setattr {
IN struct vnode *vp;
@@ -186,6 +189,8 @@ vop_read {
#
#% write vp E E E
+#! write pre VOP_WRITE_PRE
+#! write post VOP_WRITE_POST
#
vop_write {
IN struct vnode *vp;
@@ -254,6 +259,7 @@ vop_fsync {
#
#% remove dvp E E E
#% remove vp E E E
+#! remove post vop_remove_post
#
vop_remove {
IN struct vnode *dvp;
@@ -264,6 +270,7 @@ vop_remove {
#
#% link tdvp E E E
#% link vp E E E
+#! link post vop_link_post
#
vop_link {
IN struct vnode *tdvp;
@@ -277,6 +284,7 @@ vop_link {
# rename tdvp E U U
# rename tvp X U U
#! rename pre vop_rename_pre
+#! rename post vop_rename_post
#
vop_rename {
IN WILLRELE struct vnode *fdvp;
@@ -290,6 +298,7 @@ vop_rename {
#
#% mkdir dvp E E E
#% mkdir vpp - E -
+#! mkdir post vop_mkdir_post
#
vop_mkdir {
IN struct vnode *dvp;
@@ -301,6 +310,7 @@ vop_mkdir {
#
#% rmdir dvp E E E
#% rmdir vp E E E
+#! rmdir post vop_rmdir_post
#
vop_rmdir {
IN struct vnode *dvp;
@@ -311,6 +321,7 @@ vop_rmdir {
#
#% symlink dvp E E E
#% symlink vpp - E -
+#! symlink post vop_symlink_post
#
vop_symlink {
IN struct vnode *dvp;
OpenPOWER on IntegriCloud