From 52243403eb48561abd7b33995f5a4be6a56fa1f0 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 16 Apr 2008 11:33:32 +0000 Subject: Move the head of byte-level advisory lock list from the filesystem-specific vnode data to the struct vnode. Provide the default implementation for the vop_advlock and vop_advlockasync. Purge the locks on the vnode reclaim by using the lf_purgelocks(). The default implementation is augmented for the nfs and smbfs. In the nfs_advlock, push the Giant inside the nfs_dolock. Before the change, the vop_advlock and vop_advlockasync have taken the unlocked vnode and dereferenced the fs-private inode data, racing with with the vnode reclamation due to forced unmount. Now, the vop_getattr under the shared vnode lock is used to obtain the inode size, and later, in the lf_advlockasync, after locking the vnode interlock, the VI_DOOMED flag is checked to prevent an operation on the doomed vnode. The implementation of the lf_purgelocks() is submitted by dfr. Reported by: kris Tested by: kris, pho Discussed with: jeff, dfr MFC after: 2 weeks --- sys/nfsclient/nfs_lock.c | 26 ++++++++++++++++++-------- sys/nfsclient/nfs_vnops.c | 42 +++++++++++++++++++++++------------------- sys/nfsclient/nfsnode.h | 1 - 3 files changed, 41 insertions(+), 28 deletions(-) (limited to 'sys/nfsclient') diff --git a/sys/nfsclient/nfs_lock.c b/sys/nfsclient/nfs_lock.c index bdb20d8..bf52706 100644 --- a/sys/nfsclient/nfs_lock.c +++ b/sys/nfsclient/nfs_lock.c @@ -226,6 +226,9 @@ MODULE_VERSION(nfslock, 1); /* * nfs_advlock -- * NFS advisory byte-level locks. + * + * The vnode shall be (shared) locked on the entry, it is + * unconditionally unlocked after. */ int nfs_dolock(struct vop_advlock_args *ap) @@ -243,6 +246,15 @@ nfs_dolock(struct vop_advlock_args *ap) vp = ap->a_vp; fl = ap->a_fl; + ASSERT_VOP_LOCKED(vp, "nfs_dolock"); + + bcopy(VFSTONFS(vp->v_mount)->nm_nam, &msg.lm_addr, + min(sizeof msg.lm_addr, VFSTONFS(vp->v_mount)->nm_nam->sa_len)); + msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH; + bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len); + msg.lm_nfsv3 = NFS_ISV3(vp); + VOP_UNLOCK(vp, 0); + /* * the NLM protocol doesn't allow the server to return an error * on ranges, so we do it. @@ -263,6 +275,8 @@ nfs_dolock(struct vop_advlock_args *ap) */ msg.lm_version = LOCKD_MSG_VERSION; msg.lm_msg_ident.pid = p->p_pid; + + mtx_lock(&Giant); /* * if there is no nfsowner table yet, allocate one. */ @@ -278,21 +292,16 @@ nfs_dolock(struct vop_advlock_args *ap) msg.lm_fl = *fl; msg.lm_wait = ap->a_flags & F_WAIT; msg.lm_getlk = ap->a_op == F_GETLK; - bcopy(VFSTONFS(vp->v_mount)->nm_nam, &msg.lm_addr, - min(sizeof msg.lm_addr, VFSTONFS(vp->v_mount)->nm_nam->sa_len)); - msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH; - bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len); - msg.lm_nfsv3 = NFS_ISV3(vp); cru2x(td->td_ucred, &msg.lm_cred); for (;;) { error = nfslock_send(&msg); if (error) - return (error); + goto out; /* Unlocks succeed immediately. */ if (fl->l_type == F_UNLCK) - return (error); + goto out; /* * Retry after 20 seconds if we haven't gotten a response yet. @@ -333,7 +342,8 @@ nfs_dolock(struct vop_advlock_args *ap) error = p->p_nlminfo->retcode; break; } - + out: + mtx_unlock(&Giant); return (error); } diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index 14a50c1..8b4b1e1 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -3038,18 +3038,19 @@ done: static int nfs_advlock(struct vop_advlock_args *ap) { + struct vnode *vp = ap->a_vp; + u_quad_t size; int error; - - mtx_lock(&Giant); - if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { - struct nfsnode *np = VTONFS(ap->a_vp); - error = lf_advlock(ap, &(np->n_lockf), np->n_size); - goto out; - } - error = nfs_dolock(ap); -out: - mtx_unlock(&Giant); + error = vn_lock(vp, LK_SHARED); + if (error) + return (error); + if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { + size = VTONFS(vp)->n_size; + VOP_UNLOCK(vp, 0); + error = lf_advlock(ap, &(vp->v_lockf), size); + } else + error = nfs_dolock(ap); return (error); } @@ -3059,18 +3060,21 @@ out: static int nfs_advlockasync(struct vop_advlockasync_args *ap) { + struct vnode *vp = ap->a_vp; + u_quad_t size; int error; - mtx_lock(&Giant); - if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { - struct nfsnode *np = VTONFS(ap->a_vp); - - error = lf_advlockasync(ap, &(np->n_lockf), np->n_size); - goto out; + error = vn_lock(vp, LK_SHARED); + if (error) + return (error); + if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { + size = VTONFS(vp)->n_size; + VOP_UNLOCK(vp, 0); + error = lf_advlockasync(ap, &(vp->v_lockf), size); + } else { + VOP_UNLOCK(vp, 0); + error = EOPNOTSUPP; } - error = EOPNOTSUPP; -out: - mtx_unlock(&Giant); return (error); } diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h index 7f05fa4..f227361 100644 --- a/sys/nfsclient/nfsnode.h +++ b/sys/nfsclient/nfsnode.h @@ -113,7 +113,6 @@ struct nfsnode { nfsfh_t *n_fhp; /* NFS File Handle */ struct vnode *n_vnode; /* associated vnode */ struct vnode *n_dvp; /* parent vnode */ - struct lockf *n_lockf; /* Locking record of file */ int n_error; /* Save write error value */ union { struct timespec nf_atim; /* Special file times */ -- cgit v1.1