+wait_for_granted:
+ error = EWOULDBLOCK;
+ slpflag = (interruptable && (type != F_UNLCK)) ? PCATCH : 0;
+ ts.tv_sec = 2;
+ ts.tv_nsec = 0;
+ microuptime(&now);
+ endtime = now.tv_sec + timeo;
+ while (now.tv_sec < endtime) {
+ error = error2 = 0;
+ if (!msgreq->lmr_answered) {
+ error = msleep(msgreq, nfs_lock_mutex, slpflag | PUSER, "lockd", &ts);
+ slpflag = 0;
+ }
+ if (msgreq->lmr_answered) {
+ /*
+ * Note: it's possible to have a lock granted at
+ * essentially the same time that we get interrupted.
+ * Since the lock may be granted, we can't return an
+ * error from this request or we might not unlock the
+ * lock that's been granted.
+ */
+ 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);