summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2014-12-31 00:34:37 +0000
committerrmacklem <rmacklem@FreeBSD.org>2014-12-31 00:34:37 +0000
commit0a205a55e38f6cbcf29e2da1548e934f6fd941be (patch)
tree01e1a09b438ec6835e22d1820f7a086d7fad4ee6
parentbb94e30e60eb81e11ad88e00cd7c8255afe38048 (diff)
downloadFreeBSD-src-0a205a55e38f6cbcf29e2da1548e934f6fd941be.zip
FreeBSD-src-0a205a55e38f6cbcf29e2da1548e934f6fd941be.tar.gz
MFC: r276192, r276200
Modify vop_stdadvlock{async}() so that it only locks/unlocks the vnode and does a VOP_GETATTR() for the SEEK_END case. This is safe to do, since lf_advlock{async}() only uses the size argument for the SEEK_END case. The NFSv4 server needs this when vfs.nfsd.enable_locallocks!=0 since locking the vnode results in a LOR that can cause a deadlock for the nfsd threads.
-rw-r--r--sys/kern/vfs_default.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index 2c01117..94b8149 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -399,17 +399,24 @@ int
vop_stdadvlock(struct vop_advlock_args *ap)
{
struct vnode *vp;
- struct ucred *cred;
struct vattr vattr;
int error;
vp = ap->a_vp;
- cred = curthread->td_ucred;
- vn_lock(vp, LK_SHARED | LK_RETRY);
- error = VOP_GETATTR(vp, &vattr, cred);
- VOP_UNLOCK(vp, 0);
- if (error)
- return (error);
+ if (ap->a_fl->l_whence == SEEK_END) {
+ /*
+ * The NFSv4 server must avoid doing a vn_lock() here, since it
+ * can deadlock the nfsd threads, due to a LOR. Fortunately
+ * the NFSv4 server always uses SEEK_SET and this code is
+ * only required for the SEEK_END case.
+ */
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_GETATTR(vp, &vattr, curthread->td_ucred);
+ VOP_UNLOCK(vp, 0);
+ if (error)
+ return (error);
+ } else
+ vattr.va_size = 0;
return (lf_advlock(ap, &(vp->v_lockf), vattr.va_size));
}
@@ -418,17 +425,19 @@ int
vop_stdadvlockasync(struct vop_advlockasync_args *ap)
{
struct vnode *vp;
- struct ucred *cred;
struct vattr vattr;
int error;
vp = ap->a_vp;
- cred = curthread->td_ucred;
- vn_lock(vp, LK_SHARED | LK_RETRY);
- error = VOP_GETATTR(vp, &vattr, cred);
- VOP_UNLOCK(vp, 0);
- if (error)
- return (error);
+ if (ap->a_fl->l_whence == SEEK_END) {
+ /* The size argument is only needed for SEEK_END. */
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_GETATTR(vp, &vattr, curthread->td_ucred);
+ VOP_UNLOCK(vp, 0);
+ if (error)
+ return (error);
+ } else
+ vattr.va_size = 0;
return (lf_advlockasync(ap, &(vp->v_lockf), vattr.va_size));
}
OpenPOWER on IntegriCloud