+ nmp = NFSTONMP(np);
+ if ((msgreq->lmr_errno == ENOTSUP) && nmp &&
+ (nmp->nm_state & NFSSTA_LOCKSWORK)) {
+ /*
+ * We have evidence that locks work, yet lockd
+ * returned ENOTSUP. This is probably because
+ * it was unable to contact the server's lockd
+ * to send it the request.
+ *
+ * Because we know locks work, we'll consider
+ * this failure to be a timeout.
+ */
+ error = EWOULDBLOCK;
+ } else {
+ error = 0;
+ }
+ break;
+ }
+ if (error != EWOULDBLOCK)
+ break;
+ /* check that we still have our mount... */
+ /* ...and that we still support locks */
+ /* ...and that there isn't a recovery pending */
+ nmp = NFSTONMP(np);
+ if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) {
+ error = error2;
+ if (type == F_UNLCK)
+ printf("nfs3_lockd_request: aborting unlock request, error %d\n", error);
+ break;
+ }
+ lck_mtx_lock(&nmp->nm_lock);
+ if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
+ lck_mtx_unlock(&nmp->nm_lock);
+ break;
+ }
+ if ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
+ /* recovery pending... return an error that'll get this operation restarted */
+ error = NFSERR_GRACE;
+ lck_mtx_unlock(&nmp->nm_lock);
+ break;
+ }
+ interruptable = NMFLAG(nmp, INTR);
+ lck_mtx_unlock(&nmp->nm_lock);
+ microuptime(&now);
+ }
+ if (error) {
+ /* check that we still have our mount... */
+ nmp = NFSTONMP(np);
+ if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) {
+ error = error2;
+ if (error2 != EINTR) {
+ if (type == F_UNLCK)
+ printf("nfs3_lockd_request: aborting unlock request, error %d\n", error);
+ break;
+ }
+ }
+ /* ...and that we still support locks */
+ lck_mtx_lock(&nmp->nm_lock);
+ if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
+ if (error == EWOULDBLOCK)
+ error = ENOTSUP;
+ lck_mtx_unlock(&nmp->nm_lock);
+ break;
+ }
+ /* ...and that there isn't a recovery pending */
+ if ((error == EWOULDBLOCK) && (nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
+ /* recovery pending... return to allow recovery to occur */
+ error = NFSERR_DENIED;
+ lck_mtx_unlock(&nmp->nm_lock);
+ break;
+ }
+ interruptable = NMFLAG(nmp, INTR);
+ if ((error != EWOULDBLOCK) ||
+ ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) ||
+ ((flags & R_RECOVER) && ((now.tv_sec - starttime) > 30))) {
+ if ((error == EWOULDBLOCK) && (flags & R_RECOVER)) {
+ /* give up if this is for recovery and taking too long */
+ error = ETIMEDOUT;
+ } else if ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
+ /* recovery pending... return an error that'll get this operation restarted */
+ error = NFSERR_GRACE;
+ }
+ lck_mtx_unlock(&nmp->nm_lock);
+ /*
+ * We're going to bail on this request.
+ * If we were a blocked lock request, send a cancel.
+ */
+ if ((msgreq->lmr_errno == EINPROGRESS) &&
+ !(msg->lm_flags & LOCKD_MSG_CANCEL)) {
+ /* set this request up as a cancel */
+ msg->lm_flags |= LOCKD_MSG_CANCEL;
+ nfs_lockdmsg_dequeue(msgreq);
+ msg->lm_xid = nfs_lockxid_get();
+ nfs_lockdmsg_enqueue(msgreq);
+ msgreq->lmr_saved_errno = error;
+ msgreq->lmr_errno = 0;
+ msgreq->lmr_answered = 0;
+ /* reset timeout */
+ timeo = 2;
+ /* send cancel request */
+ continue;
+ }
+ break;
+ }
+
+ /* warn if we're not getting any response */
+ microuptime(&now);
+ if ((msgreq->lmr_errno != EINPROGRESS) &&
+ !(msg->lm_flags & LOCKD_MSG_DENIED_GRACE) &&
+ (nmp->nm_tprintf_initial_delay != 0) &&
+ ((lastmsg + nmp->nm_tprintf_delay) < now.tv_sec)) {
+ lck_mtx_unlock(&nmp->nm_lock);
+ lastmsg = now.tv_sec;
+ nfs_down(nmp, thd, 0, NFSSTA_LOCKTIMEO, "lockd not responding");
+ wentdown = 1;
+ } else
+ lck_mtx_unlock(&nmp->nm_lock);
+
+ if (msgreq->lmr_errno == EINPROGRESS) {
+ /*
+ * We've got a blocked lock request that we are
+ * going to retry. First, we'll want to try to
+ * send a cancel for the previous request.
+ *
+ * Clear errno so if we don't get a response
+ * to the resend we'll call nfs_down().
+ * Also reset timeout because we'll expect a
+ * quick response to the cancel/resend (even if
+ * it is NLM_BLOCKED).
+ */
+ msg->lm_flags |= LOCKD_MSG_CANCEL;
+ nfs_lockdmsg_dequeue(msgreq);
+ msg->lm_xid = nfs_lockxid_get();
+ nfs_lockdmsg_enqueue(msgreq);
+ msgreq->lmr_saved_errno = msgreq->lmr_errno;
+ msgreq->lmr_errno = 0;
+ msgreq->lmr_answered = 0;
+ timeo = 2;
+ /* send cancel then resend request */