diff options
author | ssouhlal <ssouhlal@FreeBSD.org> | 2005-06-09 20:20:31 +0000 |
---|---|---|
committer | ssouhlal <ssouhlal@FreeBSD.org> | 2005-06-09 20:20:31 +0000 |
commit | 0835f7b4a9a7e80823912ce250d4082b5a23a401 (patch) | |
tree | f884ddce34ea556a36562577b6b807ab201ffb03 /sys/kern | |
parent | bf3a7d1c45580ecf11f34f58fcdb57fba76c9d40 (diff) | |
download | FreeBSD-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.c | 8 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 233 | ||||
-rw-r--r-- | sys/kern/vnode_if.src | 11 |
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; |