diff options
author | kib <kib@FreeBSD.org> | 2009-06-10 20:59:32 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-06-10 20:59:32 +0000 |
commit | e1cb2941d4424de90eb68716d6c4d95f4c0af0ba (patch) | |
tree | 9c12d3a92805f512ad054e2b8fa5618e0bd9cc71 /sys/kern/vfs_subr.c | |
parent | a9806592196870f6605860715c0edac4deb6a55d (diff) | |
download | FreeBSD-src-e1cb2941d4424de90eb68716d6c4d95f4c0af0ba.zip FreeBSD-src-e1cb2941d4424de90eb68716d6c4d95f4c0af0ba.tar.gz |
Adapt vfs kqfilter to the shared vnode lock used by zfs write vop. Use
vnode interlock to protect the knote fields [1]. The locking assumes
that shared vnode lock is held, thus we get exclusive access to knote
either by exclusive vnode lock protection, or by shared vnode lock +
vnode interlock.
Do not use kl_locked() method to assert either lock ownership or the
fact that curthread does not own the lock. For shared locks, ownership
is not recorded, e.g. VOP_ISLOCKED can return LK_SHARED for the shared
lock not owned by curthread, causing false positives in kqueue subsystem
assertions about knlist lock.
Remove kl_locked method from knlist lock vector, and add two separate
assertion methods kl_assert_locked and kl_assert_unlocked, that are
supposed to use proper asserts. Change knlist_init accordingly.
Add convenience function knlist_init_mtx to reduce number of arguments
for typical knlist initialization.
Submitted by: jhb [1]
Noted by: jhb [2]
Reviewed by: jhb
Tested by: rnoland
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 47a5046..7aca90ac 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -110,7 +110,8 @@ static void vnlru_free(int); static void vgonel(struct vnode *); static void vfs_knllock(void *arg); static void vfs_knlunlock(void *arg); -static int vfs_knllocked(void *arg); +static void vfs_knl_assert_locked(void *arg); +static void vfs_knl_assert_unlocked(void *arg); static void destroy_vpollinfo(struct vpollinfo *vi); /* @@ -3271,7 +3272,7 @@ v_addpollinfo(struct vnode *vp) vi = uma_zalloc(vnodepoll_zone, M_WAITOK); mtx_init(&vi->vpi_lock, "vnode pollinfo", NULL, MTX_DEF); knlist_init(&vi->vpi_selinfo.si_note, vp, vfs_knllock, - vfs_knlunlock, vfs_knllocked); + vfs_knlunlock, vfs_knl_assert_locked, vfs_knl_assert_unlocked); VI_LOCK(vp); if (vp->v_pollinfo != NULL) { VI_UNLOCK(vp); @@ -3986,7 +3987,7 @@ static struct knlist fs_knlist; static void vfs_event_init(void *arg) { - knlist_init(&fs_knlist, NULL, NULL, NULL, NULL); + knlist_init_mtx(&fs_knlist, NULL); } /* XXX - correct order? */ SYSINIT(vfs_knlist, SI_SUB_VFS, SI_ORDER_ANY, vfs_event_init, NULL); @@ -4099,12 +4100,24 @@ vfs_knlunlock(void *arg) VOP_UNLOCK(vp, 0); } -static int -vfs_knllocked(void *arg) +static void +vfs_knl_assert_locked(void *arg) +{ +#ifdef DEBUG_VFS_LOCKS + struct vnode *vp = arg; + + ASSERT_VOP_LOCKED(vp, "vfs_knl_assert_locked"); +#endif +} + +static void +vfs_knl_assert_unlocked(void *arg) { +#ifdef DEBUG_VFS_LOCKS struct vnode *vp = arg; - return (VOP_ISLOCKED(vp) == LK_EXCLUSIVE); + ASSERT_VOP_UNLOCKED(vp, "vfs_knl_assert_unlocked"); +#endif } int @@ -4157,27 +4170,37 @@ filt_vfsread(struct knote *kn, long hint) { struct vnode *vp = (struct vnode *)kn->kn_hook; struct vattr va; + int res; /* * filesystem is gone, so set the EOF flag and schedule * the knote for deletion. */ if (hint == NOTE_REVOKE) { + VI_LOCK(vp); kn->kn_flags |= (EV_EOF | EV_ONESHOT); + VI_UNLOCK(vp); return (1); } if (VOP_GETATTR(vp, &va, curthread->td_ucred)) return (0); + VI_LOCK(vp); kn->kn_data = va.va_size - kn->kn_fp->f_offset; - return (kn->kn_data != 0); + res = (kn->kn_data != 0); + VI_UNLOCK(vp); + return (res); } /*ARGSUSED*/ static int filt_vfswrite(struct knote *kn, long hint) { + struct vnode *vp = (struct vnode *)kn->kn_hook; + + VI_LOCK(vp); + /* * filesystem is gone, so set the EOF flag and schedule * the knote for deletion. @@ -4186,19 +4209,27 @@ filt_vfswrite(struct knote *kn, long hint) kn->kn_flags |= (EV_EOF | EV_ONESHOT); kn->kn_data = 0; + VI_UNLOCK(vp); return (1); } static int filt_vfsvnode(struct knote *kn, long hint) { + struct vnode *vp = (struct vnode *)kn->kn_hook; + int res; + + VI_LOCK(vp); if (kn->kn_sfflags & hint) kn->kn_fflags |= hint; if (hint == NOTE_REVOKE) { kn->kn_flags |= EV_EOF; + VI_UNLOCK(vp); return (1); } - return (kn->kn_fflags != 0); + res = (kn->kn_fflags != 0); + VI_UNLOCK(vp); + return (res); } int |