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.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index a7015f5..63c15c1 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -1346,11 +1346,16 @@ nfsmout:
/*
* nfs write operation
+ * When called_from_strategy != 0, it should return EIO for an error that
+ * indicates recovery is in progress, so that the buffer will be left
+ * dirty and be written back to the server later. If it loops around,
+ * the recovery thread could get stuck waiting for the buffer and recovery
+ * will then deadlock.
*/
APPLESTATIC int
nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
- void *stuff)
+ void *stuff, int called_from_strategy)
{
int error, expireret = 0, retrycnt, nostateid;
u_int32_t clidrev = 0;
@@ -1410,12 +1415,15 @@ nfscl_dumpstate(nmp, 1, 1, 0, 0);
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
}
retrycnt++;
- } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
- error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
+ } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
+ ((error == NFSERR_STALESTATEID ||
+ error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
expireret == 0 && clidrev != 0 && retrycnt < 4));
- if (error && retrycnt >= 4)
+ if (error != 0 && (retrycnt >= 4 ||
+ ((error == NFSERR_STALESTATEID ||
+ error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
error = EIO;
if (NFSHASNFSV4(nmp) && p == NULL)
NFSFREECRED(newcred);
OpenPOWER on IntegriCloud