summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient/nfs_clrpcops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clrpcops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c162
1 files changed, 79 insertions, 83 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index b42415a..627f521 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -81,8 +81,6 @@ static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
struct nfscllockowner *, u_int64_t, u_int64_t,
u_int32_t, struct ucred *, NFSPROC_T *, int);
-static void nfsrpc_doclose(struct nfsmount *, struct nfsclopenhead *,
- NFSPROC_T *);
#ifdef NFS4_ACL_EXTATTR_NAME
static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
struct acl *, nfsv4stateid_t *, void *);
@@ -553,119 +551,117 @@ APPLESTATIC int
nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
{
struct nfsclclient *clp;
- struct nfsclopenhead oh;
int error;
if (vnode_vtype(vp) != VREG)
return (0);
if (doclose)
- error = nfscl_getclose(vp, &clp, &oh);
+ error = nfscl_doclose(vp, &clp, p);
else
- error = nfscl_getclose(vp, &clp, NULL);
+ error = nfscl_getclose(vp, &clp);
if (error)
return (error);
- if (doclose && !LIST_EMPTY(&oh))
- nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), &oh, p);
nfscl_clientrelease(clp);
return (0);
}
/*
- * Close/free all the opens in the list.
+ * Close the open.
*/
-static void
-nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopenhead *ohp, NFSPROC_T *p)
+APPLESTATIC void
+nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
{
struct nfsrv_descript nfsd, *nd = &nfsd;
- struct nfsclopen *op, *nop;
struct nfscllockowner *lp;
struct nfscllock *lop, *nlop;
struct ucred *tcred;
u_int64_t off = 0, len = 0;
u_int32_t type = NFSV4LOCKT_READ;
- int error;
+ int error, do_unlock, trycnt;
tcred = newnfs_getcred();
- op = LIST_FIRST(ohp);
- while (op != NULL) {
- nop = LIST_NEXT(op, nfso_list);
- newnfs_copycred(&op->nfso_cred, tcred);
- /*
- * (Theoretically this could be done in the same
- * compound as the close, but having multiple
- * sequenced Ops in the same compound might be
- * too scary for some servers.)
- */
- if (op->nfso_posixlock) {
- off = 0;
- len = NFS64BITSSET;
- type = NFSV4LOCKT_READ;
- }
- LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
- lop = LIST_FIRST(&lp->nfsl_lock);
- while (lop != NULL) {
- nlop = LIST_NEXT(lop, nfslo_list);
+ newnfs_copycred(&op->nfso_cred, tcred);
+ /*
+ * (Theoretically this could be done in the same
+ * compound as the close, but having multiple
+ * sequenced Ops in the same compound might be
+ * too scary for some servers.)
+ */
+ if (op->nfso_posixlock) {
+ off = 0;
+ len = NFS64BITSSET;
+ type = NFSV4LOCKT_READ;
+ }
+
+ /*
+ * Since this function is only called from VOP_INACTIVE(), no
+ * other thread will be manipulating this Open. As such, the
+ * lock lists are not being changed by other threads, so it should
+ * be safe to do this without locking.
+ */
+ LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
+ do_unlock = 1;
+ LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
if (op->nfso_posixlock == 0) {
- off = lop->nfslo_first;
- len = lop->nfslo_end - lop->nfslo_first;
- if (lop->nfslo_type == F_WRLCK)
- type = NFSV4LOCKT_WRITE;
- else
- type = NFSV4LOCKT_READ;
+ off = lop->nfslo_first;
+ len = lop->nfslo_end - lop->nfslo_first;
+ if (lop->nfslo_type == F_WRLCK)
+ type = NFSV4LOCKT_WRITE;
+ else
+ type = NFSV4LOCKT_READ;
}
- if (lop == LIST_FIRST(&lp->nfsl_lock) ||
- op->nfso_posixlock == 0) {
- NFSLOCKCLSTATE();
- nfscl_lockexcl(&lp->nfsl_rwlock,
- NFSCLSTATEMUTEXPTR);
- NFSUNLOCKCLSTATE();
- do {
- error = nfsrpc_locku(nd, nmp, lp, off, len,
- type, tcred, p, 0);
- if ((nd->nd_repstat == NFSERR_GRACE ||
- nd->nd_repstat == NFSERR_DELAY) &&
- error == 0)
- (void) nfs_catnap(PZERO, "nfs_close");
- } while ((nd->nd_repstat == NFSERR_GRACE ||
- nd->nd_repstat == NFSERR_DELAY) && error == 0);
- NFSLOCKCLSTATE();
- nfscl_lockunlock(&lp->nfsl_rwlock);
- NFSUNLOCKCLSTATE();
+ if (do_unlock) {
+ trycnt = 0;
+ do {
+ error = nfsrpc_locku(nd, nmp, lp, off,
+ len, type, tcred, p, 0);
+ if ((nd->nd_repstat == NFSERR_GRACE ||
+ nd->nd_repstat == NFSERR_DELAY) &&
+ error == 0)
+ (void) nfs_catnap(PZERO,
+ "nfs_close");
+ } while ((nd->nd_repstat == NFSERR_GRACE ||
+ nd->nd_repstat == NFSERR_DELAY) &&
+ error == 0 && trycnt++ < 5);
+ if (op->nfso_posixlock)
+ do_unlock = 0;
}
nfscl_freelock(lop, 0);
- lop = nlop;
- }
}
- NFSLOCKCLSTATE();
- nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
- NFSUNLOCKCLSTATE();
- do {
- error = nfscl_tryclose(op, tcred, nmp, p);
- if (error == NFSERR_GRACE)
- (void) nfs_catnap(PZERO, "nfs_close");
- } while (error == NFSERR_GRACE);
- NFSLOCKCLSTATE();
- nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
- NFSUNLOCKCLSTATE();
+ }
- /*
- * Move the lockowner to nfsc_defunctlockowner,
- * so the Renew thread will do the ReleaseLockOwner
- * Op on it later. There might still be other
- * opens using the same lockowner name.
- */
- lp = LIST_FIRST(&op->nfso_lock);
- if (lp != NULL) {
- while (LIST_NEXT(lp, nfsl_list) != NULL)
+ /*
+ * There could be other Opens for different files on the same
+ * OpenOwner, so locking is required.
+ */
+ NFSLOCKCLSTATE();
+ nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
+ NFSUNLOCKCLSTATE();
+ do {
+ error = nfscl_tryclose(op, tcred, nmp, p);
+ if (error == NFSERR_GRACE)
+ (void) nfs_catnap(PZERO, "nfs_close");
+ } while (error == NFSERR_GRACE);
+ NFSLOCKCLSTATE();
+ nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
+
+ /*
+ * Move the lockowner to nfsc_defunctlockowner,
+ * so the Renew thread will do the ReleaseLockOwner
+ * Op on it later. There might still be other
+ * opens using the same lockowner name.
+ */
+ lp = LIST_FIRST(&op->nfso_lock);
+ if (lp != NULL) {
+ while (LIST_NEXT(lp, nfsl_list) != NULL)
lp = LIST_NEXT(lp, nfsl_list);
- LIST_PREPEND(&nmp->nm_clp->nfsc_defunctlockowner,
- &op->nfso_lock, lp, nfsl_list);
- LIST_INIT(&op->nfso_lock);
- }
- nfscl_freeopen(op, 0);
- op = nop;
+ LIST_PREPEND(&nmp->nm_clp->nfsc_defunctlockowner,
+ &op->nfso_lock, lp, nfsl_list);
+ LIST_INIT(&op->nfso_lock);
}
+ nfscl_freeopen(op, 0);
+ NFSUNLOCKCLSTATE();
NFSFREECRED(tcred);
}
OpenPOWER on IntegriCloud