summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorgt29601 <none@none>2007-12-17 15:52:34 -0800
committergt29601 <none@none>2007-12-17 15:52:34 -0800
commit7ccce15c128bb5aab7196fe8a73c274a66d87b07 (patch)
treedab374fa1baef9d195246fc23068d0009d8f5381 /usr/src
parentb4625e144349c1ef903a75b1ba2cead8d2bb5d7e (diff)
downloadillumos-joyent-7ccce15c128bb5aab7196fe8a73c274a66d87b07.tar.gz
6586422 A deadlock occurs when an nfsv4 recover thread calls nfs4_start_fop
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c191
1 files changed, 105 insertions, 86 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index 0874503806..c9b921b847 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -3118,6 +3118,7 @@ nfs4write(vnode_t *vp, caddr_t base, u_offset_t offset, int count, cred_t *cr,
nfs4_recov_state_t recov_state;
nfs4_stateid_types_t sid_types;
nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
+ int recov;
rp = VTOR4(vp);
mi = VTOMI4(vp);
@@ -3132,15 +3133,22 @@ nfs4write(vnode_t *vp, caddr_t base, u_offset_t offset, int count, cred_t *cr,
recov_state.rs_num_retry_despite_err = 0;
nfs4_init_stateid_types(&sid_types);
+ /* Is curthread the recovery thread? */
+ mutex_enter(&mi->mi_lock);
+ recov = (mi->mi_recovthread == curthread);
+ mutex_exit(&mi->mi_lock);
+
recov_retry:
args.ctag = TAG_WRITE;
args.array_len = 2;
args.array = argop;
- e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, NULL);
- if (e.error)
- return (e.error);
+ if (!recov) {
+ e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
+ &recov_state, NULL);
+ if (e.error)
+ return (e.error);
+ }
/* 0. putfh target fh */
argop[0].argop = OP_CPUTFH;
@@ -3175,110 +3183,119 @@ recov_retry:
mutex_exit(&mi->mi_lock);
}
- needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
- if (e.error && !needrecov) {
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- return (e.error);
- }
+ if (!recov) {
+ needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
+ if (e.error && !needrecov) {
+ nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
+ &recov_state, needrecov);
+ return (e.error);
+ }
- /*
- * Do handling of OLD_STATEID outside
- * of the normal recovery framework.
- *
- * If write receives a BAD stateid error while using a
- * delegation stateid, retry using the open stateid (if it
- * exists). If it doesn't have an open stateid, reopen the
- * file first, then retry.
- */
- if (!e.error && res.status == NFS4ERR_OLD_STATEID &&
- sid_types.cur_sid_type != SPEC_SID) {
- nfs4_save_stateid(&wargs->stateid, &sid_types);
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
- goto recov_retry;
- } else if (e.error == 0 && res.status == NFS4ERR_BAD_STATEID &&
- sid_types.cur_sid_type == DEL_SID) {
- nfs4_save_stateid(&wargs->stateid, &sid_types);
- mutex_enter(&rp->r_statev4_lock);
- rp->r_deleg_return_pending = TRUE;
- mutex_exit(&rp->r_statev4_lock);
- if (nfs4rdwr_check_osid(vp, &e, cr)) {
+ /*
+ * Do handling of OLD_STATEID outside
+ * of the normal recovery framework.
+ *
+ * If write receives a BAD stateid error while using a
+ * delegation stateid, retry using the open stateid
+ * (if it exists). If it doesn't have an open stateid,
+ * reopen the * file first, then retry.
+ */
+ if (!e.error && res.status == NFS4ERR_OLD_STATEID &&
+ sid_types.cur_sid_type != SPEC_SID) {
+ nfs4_save_stateid(&wargs->stateid, &sid_types);
+ nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
+ &recov_state, needrecov);
+ (void) xdr_free(xdr_COMPOUND4res_clnt,
+ (caddr_t)&res);
+ goto recov_retry;
+ } else if (e.error == 0 &&
+ res.status == NFS4ERR_BAD_STATEID &&
+ sid_types.cur_sid_type == DEL_SID) {
+ nfs4_save_stateid(&wargs->stateid, &sid_types);
+ mutex_enter(&rp->r_statev4_lock);
+ rp->r_deleg_return_pending = TRUE;
+ mutex_exit(&rp->r_statev4_lock);
+ if (nfs4rdwr_check_osid(vp, &e, cr)) {
+ nfs4_end_fop(mi, vp, NULL, OH_WRITE,
+ &recov_state, needrecov);
+ (void) xdr_free(xdr_COMPOUND4res_clnt,
+ (caddr_t)&res);
+ return (EIO);
+ }
nfs4_end_fop(mi, vp, NULL, OH_WRITE,
&recov_state, needrecov);
+ /* hold needed for nfs4delegreturn_thread */
+ VN_HOLD(vp);
+ nfs4delegreturn_async(rp,
+ (NFS4_DR_PUSH|NFS4_DR_REOPEN|
+ NFS4_DR_DISCARD), FALSE);
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
- return (EIO);
+ goto recov_retry;
}
- nfs4_end_fop(mi, vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- /* hold needed for nfs4delegreturn_thread */
- VN_HOLD(vp);
- nfs4delegreturn_async(rp, (NFS4_DR_PUSH|NFS4_DR_REOPEN|
- NFS4_DR_DISCARD), FALSE);
- (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
- goto recov_retry;
- }
- if (needrecov) {
- bool_t abort;
+ if (needrecov) {
+ bool_t abort;
- NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
- "nfs4write: client got error %d, res.status %d"
- ", so start recovery", e.error, res.status));
+ NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
+ "nfs4write: client got error %d, "
+ "res.status %d, so start recovery",
+ e.error, res.status));
+
+ abort = nfs4_start_recovery(&e,
+ VTOMI4(vp), vp, NULL, &wargs->stateid,
+ NULL, OP_WRITE, NULL);
+ if (!e.error) {
+ e.error = geterrno4(res.status);
+ (void) xdr_free(xdr_COMPOUND4res_clnt,
+ (caddr_t)&res);
+ }
+ nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
+ &recov_state, needrecov);
+ if (abort == FALSE)
+ goto recov_retry;
+ return (e.error);
+ }
- abort = nfs4_start_recovery(&e,
- VTOMI4(vp), vp, NULL, &wargs->stateid,
- NULL, OP_WRITE, NULL);
- if (!e.error) {
+ if (res.status) {
e.error = geterrno4(res.status);
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
+ nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
+ &recov_state, needrecov);
+ return (e.error);
}
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- if (abort == FALSE)
- goto recov_retry;
- return (e.error);
- }
-
- if (res.status) {
- e.error = geterrno4(res.status);
- (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- return (e.error);
- }
-
- resop = &res.array[1]; /* write res */
- wres = &resop->nfs_resop4_u.opwrite;
- if ((int)wres->count > tsize) {
- (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
+ resop = &res.array[1]; /* write res */
+ wres = &resop->nfs_resop4_u.opwrite;
- zcmn_err(getzoneid(), CE_WARN,
- "nfs4write: server wrote %u, requested was %u",
- (int)wres->count, tsize);
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
- &recov_state, needrecov);
- return (EIO);
- }
- if (wres->committed == UNSTABLE4) {
- *stab_comm = UNSTABLE4;
- if (wargs->stable == DATA_SYNC4 ||
- wargs->stable == FILE_SYNC4) {
+ if ((int)wres->count > tsize) {
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
+
zcmn_err(getzoneid(), CE_WARN,
- "nfs4write: server %s did not commit "
- "to stable storage",
- rp->r_server->sv_hostname);
+ "nfs4write: server wrote %u, requested "
+ "was %u", (int)wres->count, tsize);
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
&recov_state, needrecov);
return (EIO);
}
+ if (wres->committed == UNSTABLE4) {
+ *stab_comm = UNSTABLE4;
+ if (wargs->stable == DATA_SYNC4 ||
+ wargs->stable == FILE_SYNC4) {
+ (void) xdr_free(xdr_COMPOUND4res_clnt,
+ (caddr_t)&res);
+ zcmn_err(getzoneid(), CE_WARN,
+ "nfs4write: server %s did not "
+ "commit to stable storage",
+ rp->r_server->sv_hostname);
+ nfs4_end_fop(VTOMI4(vp), vp, NULL,
+ OH_WRITE, &recov_state, needrecov);
+ return (EIO);
+ }
+ }
}
tsize = (int)wres->count;
@@ -3311,7 +3328,9 @@ recov_retry:
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
} while (count);
- nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, &recov_state, needrecov);
+ if (!recov)
+ nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, &recov_state,
+ needrecov);
return (e.error);
}