diff options
-rw-r--r-- | sys/fs/nfs/nfs_var.h | 4 | ||||
-rw-r--r-- | sys/fs/nfsclient/nfs_clrpcops.c | 162 | ||||
-rw-r--r-- | sys/fs/nfsclient/nfs_clstate.c | 195 |
3 files changed, 178 insertions, 183 deletions
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 08bcafc..2556e35 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -457,7 +457,9 @@ void nfscl_initiate_recovery(struct nfsclclient *); int nfscl_hasexpired(struct nfsclclient *, u_int32_t, NFSPROC_T *); void nfscl_dumpstate(struct nfsmount *, int, int, int, int); void nfscl_dupopen(vnode_t, int); -int nfscl_getclose(vnode_t, struct nfsclclient **, struct nfsclopenhead *); +int nfscl_getclose(vnode_t, struct nfsclclient **); +int nfscl_doclose(vnode_t, struct nfsclclient **, NFSPROC_T *); +void nfsrpc_doclose(struct nfsmount *, struct nfsclopen *, NFSPROC_T *); int nfscl_deleg(mount_t, struct nfsclclient *, u_int8_t *, int, struct ucred *, NFSPROC_T *, struct nfscldeleg **); void nfscl_lockinit(struct nfsv4lock *); 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); } diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index a564325..bb6c322 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -450,7 +450,7 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode, { struct nfsclclient *clp; struct nfsclowner *owp; - struct nfsclopen *op; + struct nfsclopen *op = NULL; struct nfscllockowner *lp; struct nfscldeleg *dp; struct nfsnode *np; @@ -512,40 +512,40 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode, nfscl_filllockowner(p, own); error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p, mode, NULL, &op); - if (error) { - NFSUNLOCKCLSTATE(); - return (error); - } - - /* now look for a lockowner */ - LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { - if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) { - stateidp->seqid = lp->nfsl_stateid.seqid; - stateidp->other[0] = lp->nfsl_stateid.other[0]; - stateidp->other[1] = lp->nfsl_stateid.other[1]; - stateidp->other[2] = lp->nfsl_stateid.other[2]; - NFSUNLOCKCLSTATE(); - return (0); - } + if (error == 0) { + /* now look for a lockowner */ + LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { + if (!NFSBCMP(lp->nfsl_owner, own, + NFSV4CL_LOCKNAMELEN)) { + stateidp->seqid = + lp->nfsl_stateid.seqid; + stateidp->other[0] = + lp->nfsl_stateid.other[0]; + stateidp->other[1] = + lp->nfsl_stateid.other[1]; + stateidp->other[2] = + lp->nfsl_stateid.other[2]; + NFSUNLOCKCLSTATE(); + return (0); + } + } } - } else { - /* - * If p == NULL, it is a read ahead or write behind, - * so just look for any OpenOwner that will work. - */ + } + if (op == NULL) { + /* If not found, just look for any OpenOwner that will work. */ done = 0; owp = LIST_FIRST(&clp->nfsc_owner); while (!done && owp != NULL) { - LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { - if (op->nfso_fhlen == fhlen && - !NFSBCMP(op->nfso_fh, nfhp, fhlen) && - (mode & op->nfso_mode) == mode) { - done = 1; - break; + LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { + if (op->nfso_fhlen == fhlen && + !NFSBCMP(op->nfso_fh, nfhp, fhlen) && + (mode & op->nfso_mode) == mode) { + done = 1; + break; + } } - } - if (!done) - owp = LIST_NEXT(owp, nfsow_list); + if (!done) + owp = LIST_NEXT(owp, nfsow_list); } if (!done) { NFSUNLOCKCLSTATE(); @@ -2752,33 +2752,30 @@ nfscl_dupopen(vnode_t vp, int dupopens) /* * During close, find an open that needs to be dereferenced and * dereference it. If there are no more opens for this file, - * return the list of opens, so they can be closed on the - * server. As such, opens aren't closed on the server until - * all the opens for the file are closed off. + * log a message to that effect. + * Opens aren't actually Close'd until VOP_INACTIVE() is performed + * on the file's vnode. * This is the safe way, since it is difficult to identify - * which open the close is for. + * which open the close is for and I/O can be performed after the + * close(2) system call when a file is mmap'd. * If it returns 0 for success, there will be a referenced - * clp returned via clpp and a list of opens to close/free - * on ohp. + * clp returned via clpp. */ APPLESTATIC int -nfscl_getclose(vnode_t vp, struct nfsclclient **clpp, - struct nfsclopenhead *ohp) +nfscl_getclose(vnode_t vp, struct nfsclclient **clpp) { struct nfsclclient *clp; - struct nfsclowner *owp, *nowp; - struct nfsclopen *op, *nop; + struct nfsclowner *owp; + struct nfsclopen *op; struct nfscldeleg *dp; struct nfsfh *nfhp; - int error, notdecr, candelete; + int error, notdecr; error = nfscl_getcl(vp, NULL, NULL, &clp); if (error) return (error); *clpp = clp; - if (ohp != NULL) - LIST_INIT(ohp); nfhp = VTONFS(vp)->n_fhp; notdecr = 1; NFSLOCKCLSTATE(); @@ -2788,7 +2785,7 @@ nfscl_getclose(vnode_t vp, struct nfsclclient **clpp, * the server are DENY_NONE, I don't see a problem with hanging * onto them. (It is much easier to use one of the extant Opens * that I already have on the server when a Delegation is recalled - * than to do fresh Opens.) Someday, I might need to rethink this, but.. + * than to do fresh Opens.) Someday, I might need to rethink this, but. */ dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); if (dp != NULL) { @@ -2813,9 +2810,7 @@ nfscl_getclose(vnode_t vp, struct nfsclclient **clpp, /* Now process the opens against the server. */ LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { - op = LIST_FIRST(&owp->nfsow_open); - while (op != NULL) { - nop = LIST_NEXT(op, nfso_list); + LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { if (op->nfso_fhlen == nfhp->nfh_len && !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, nfhp->nfh_len)) { @@ -2825,74 +2820,76 @@ nfscl_getclose(vnode_t vp, struct nfsclclient **clpp, op->nfso_opencnt--; } /* - * There are more opens, so just return after - * putting any opens already found back in the - * state list. + * There are more opens, so just return. */ if (op->nfso_opencnt > 0) { - if (ohp != NULL) { - /* Reattach open until later */ - op = LIST_FIRST(ohp); - while (op != NULL) { - nop = LIST_NEXT(op, nfso_list); - LIST_REMOVE(op, nfso_list); - LIST_INSERT_HEAD( - &op->nfso_own->nfsow_open, - op, nfso_list); - op = nop; - } - LIST_INIT(ohp); - } NFSUNLOCKCLSTATE(); return (0); } - - /* - * Move this entry to the list of opens to be - * returned. (If we find other open(s) still in - * use, it will be put back in the state list - * in the code just above.) - */ - if (ohp != NULL) { - LIST_REMOVE(op, nfso_list); - LIST_INSERT_HEAD(ohp, op, nfso_list); - } } - op = nop; } } + NFSUNLOCKCLSTATE(); + if (notdecr) + printf("nfscl: never fnd open\n"); + return (0); +} - if (dp != NULL && ohp != NULL) { - /* - * If we are flushing all writes against the server for this - * file upon close, we do not need to keep the local opens - * (against the delegation) if they all have an opencnt == 0, - * since there are now no opens on the file and no dirty blocks. - * If the writes aren't being flushed upon close, - * a test for "no dirty blocks to write back" would have to - * be added to this code. - */ - candelete = 1; - LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { +APPLESTATIC int +nfscl_doclose(vnode_t vp, struct nfsclclient **clpp, NFSPROC_T *p) +{ + struct nfsclclient *clp; + struct nfsclowner *owp, *nowp; + struct nfsclopen *op; + struct nfscldeleg *dp; + struct nfsfh *nfhp; + int error; + + error = nfscl_getcl(vp, NULL, NULL, &clp); + if (error) + return (error); + *clpp = clp; + + nfhp = VTONFS(vp)->n_fhp; + NFSLOCKCLSTATE(); + /* + * First get rid of the local Open structures, which should be no + * longer in use. + */ + dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); + if (dp != NULL) { + LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) { op = LIST_FIRST(&owp->nfsow_open); - if (op != NULL && op->nfso_opencnt > 0) { - candelete = 0; - break; + if (op != NULL) { + KASSERT((op->nfso_opencnt == 0), + ("nfscl: bad open cnt on deleg")); + nfscl_freeopen(op, 1); } + nfscl_freeopenowner(owp, 1); } - if (candelete) { - LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, - nowp) { - op = LIST_FIRST(&owp->nfsow_open); - if (op != NULL) - nfscl_freeopen(op, 1); - nfscl_freeopenowner(owp, 1); + } + + /* Now process the opens against the server. */ +lookformore: + LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { + op = LIST_FIRST(&owp->nfsow_open); + while (op != NULL) { + if (op->nfso_fhlen == nfhp->nfh_len && + !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, + nfhp->nfh_len)) { + /* Found an open, close it. */ + KASSERT((op->nfso_opencnt == 0), + ("nfscl: bad open cnt on server")); + NFSUNLOCKCLSTATE(); + nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), op, + p); + NFSLOCKCLSTATE(); + goto lookformore; } + op = LIST_NEXT(op, nfso_list); } } NFSUNLOCKCLSTATE(); - if (notdecr && ohp == NULL) - printf("nfscl: never fnd open\n"); return (0); } |