summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2004-07-06 09:12:03 +0000
committeralfred <alfred@FreeBSD.org>2004-07-06 09:12:03 +0000
commit97a6f04270d14e570225b6e17134c79ed8796903 (patch)
treed23147dc7f69cc14533b1e3cc2d4c729cce24271 /sys/nfsclient
parent4e760d4fc8c58d30c29019b18ce32018543aeefe (diff)
downloadFreeBSD-src-97a6f04270d14e570225b6e17134c79ed8796903.zip
FreeBSD-src-97a6f04270d14e570225b6e17134c79ed8796903.tar.gz
NFS mobility PHASE I, II & III (phase VI, and V pending):
Rebind the client socket when we experience a timeout. This fixes the case where our IP changes for some reason. Signal a VFS event when NFS transitions from up to down and vice versa. Add a placeholder vfs_sysctl where we will put status reporting shortly. Also: Make down NFS mounts return EIO instead of EINTR when there is a soft timeout or force unmount in progress.
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs.h15
-rw-r--r--sys/nfsclient/nfs_bio.c56
-rw-r--r--sys/nfsclient/nfs_socket.c231
-rw-r--r--sys/nfsclient/nfs_vfsops.c26
-rw-r--r--sys/nfsclient/nfs_vnops.c23
-rw-r--r--sys/nfsclient/nfsmount.h10
6 files changed, 267 insertions, 94 deletions
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index ab80ab8..697068b 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -92,6 +92,8 @@
#define NFSSTA_WANTSND 0x02000000 /* Want above */
#define NFSSTA_RCVLOCK 0x04000000 /* Rcv socket lock */
#define NFSSTA_WANTRCV 0x08000000 /* Want above */
+#define NFSSTA_TIMEO 0x10000000 /* Experiencing a timeout */
+
/*
* XXX to allow amd to include nfs.h without nfsproto.h
@@ -170,7 +172,8 @@ struct nameidata;
* For now, ignore them all
*/
#define NFSIGNORE_SOERROR(s, e) \
- ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \
+ ((e) != EINTR && (e) != EIO && \
+ (e) != ERESTART && (e) != EWOULDBLOCK && \
((s) & PR_CONNREQUIRED) == 0)
/*
@@ -191,6 +194,7 @@ struct nfsreq {
int r_timer; /* tick counter on reply */
u_int32_t r_procnum; /* NFS procedure number */
int r_rtt; /* RTT for rpc */
+ int r_lastmsg; /* last tprintf */
struct thread *r_td; /* Proc that did I/O system call */
};
@@ -203,7 +207,7 @@ extern TAILQ_HEAD(nfs_reqq, nfsreq) nfs_reqq;
#define R_TIMING 0x01 /* timing request (in mntp) */
#define R_SENT 0x02 /* request has been sent */
#define R_SOFTTERM 0x04 /* soft mnt, too many retries */
-#define R_INTR 0x08 /* intr mnt, signal pending */
+#define R_RESENDERR 0x08 /* Resend failed */
#define R_SOCKERR 0x10 /* Fatal error on socket */
#define R_TPRINTFMSG 0x20 /* Did a tprintf msg. */
#define R_MUSTRESEND 0x40 /* Must resend request */
@@ -247,6 +251,9 @@ struct nfs_rpcops {
#define HEXSTRTOI(p) \
((HEXTOC(p[0]) << 4) + HEXTOC(p[1]))
+/* nfs_sigintr() helper, when 'rep' has all we need */
+#define NFS_SIGREP(rep) nfs_sigintr((rep)->r_nmp, (rep), (rep)->r_td)
+
#ifdef NFS_DEBUG
extern int nfs_debug;
@@ -287,6 +294,10 @@ int nfs_readdirrpc(struct vnode *, struct uio *, struct ucred *);
int nfs_nfsiodnew(void);
int nfs_asyncio(struct buf *, struct ucred *, struct thread *);
int nfs_doio(struct buf *, struct ucred *, struct thread *);
+void nfs_up(struct nfsreq *, struct nfsmount *, struct thread *,
+ const char *, int);
+void nfs_down(struct nfsreq *, struct nfsmount *, struct thread *,
+ const char *, int, int);
int nfs_readlinkrpc(struct vnode *, struct uio *, struct ucred *);
int nfs_sigintr(struct nfsmount *, struct nfsreq *, struct thread *);
int nfs_readdirplusrpc(struct vnode *, struct uio *, struct ucred *);
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index 20dd033..7f17f8c 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -457,8 +457,10 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
rabn = lbn + 1 + nra;
if (incore(vp, rabn) == NULL) {
rabp = nfs_getcacheblk(vp, rabn, biosize, td);
- if (!rabp)
- return (EINTR);
+ if (!rabp) {
+ error = nfs_sigintr(nmp, NULL, td);
+ return (error ? error : EINTR);
+ }
if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
rabp->b_flags |= B_ASYNC;
rabp->b_iocmd = BIO_READ;
@@ -501,6 +503,8 @@ again:
case ENOLCK:
goto again;
/* not reached */
+ case EIO:
+ return (EIO);
case EINTR:
case ERESTART:
return(EINTR);
@@ -514,8 +518,10 @@ again:
if (bcount != biosize)
nfs_rsunlock(np, td);
- if (!bp)
- return (EINTR);
+ if (!bp) {
+ error = nfs_sigintr(nmp, NULL, td);
+ return (error ? error : EINTR);
+ }
/*
* If B_CACHE is not set, we must issue the read. If this
@@ -547,8 +553,10 @@ again:
case VLNK:
nfsstats.biocache_readlinks++;
bp = nfs_getcacheblk(vp, (daddr_t)0, NFS_MAXPATHLEN, td);
- if (!bp)
- return (EINTR);
+ if (!bp) {
+ error = nfs_sigintr(nmp, NULL, td);
+ return (error ? error : EINTR);
+ }
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_iocmd = BIO_READ;
vfs_busy_pages(bp, 0);
@@ -571,8 +579,10 @@ again:
lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ;
on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td);
- if (!bp)
- return (EINTR);
+ if (!bp) {
+ error = nfs_sigintr(nmp, NULL, td);
+ return (error ? error : EINTR);
+ }
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_iocmd = BIO_READ;
vfs_busy_pages(bp, 0);
@@ -598,8 +608,10 @@ again:
&& (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
return (0);
bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, td);
- if (!bp)
- return (EINTR);
+ if (!bp) {
+ error = nfs_sigintr(nmp, NULL, td);
+ return (error ? error : EINTR);
+ }
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_iocmd = BIO_READ;
vfs_busy_pages(bp, 0);
@@ -790,6 +802,8 @@ restart:
case ENOLCK:
goto restart;
/* not reached */
+ case EIO:
+ return (EIO);
case EINTR:
case ERESTART:
return(EINTR);
@@ -878,7 +892,9 @@ again:
}
if (!bp) {
- error = EINTR;
+ error = nfs_sigintr(nmp, NULL, td);
+ if (!error)
+ error = EINTR;
break;
}
@@ -917,7 +933,9 @@ again:
}
}
if (!bp) {
- error = EINTR;
+ error = nfs_sigintr(nmp, NULL, td);
+ if (!error)
+ error = EINTR;
break;
}
if (bp->b_wcred == NOCRED)
@@ -1120,14 +1138,13 @@ nfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
np->n_flag |= NFLUSHINPROG;
error = vinvalbuf(vp, flags, cred, td, slpflag, 0);
while (error) {
- if (intrflg &&
- nfs_sigintr(nmp, NULL, td)) {
+ if (intrflg && (error = nfs_sigintr(nmp, NULL, td))) {
np->n_flag &= ~NFLUSHINPROG;
if (np->n_flag & NFLUSHWANT) {
np->n_flag &= ~NFLUSHWANT;
wakeup(&np->n_flag);
}
- return (EINTR);
+ return (error);
}
error = vinvalbuf(vp, flags, cred, td, 0, slptimeo);
}
@@ -1155,7 +1172,7 @@ nfs_asyncio(struct buf *bp, struct ucred *cred, struct thread *td)
int gotiod;
int slpflag = 0;
int slptimeo = 0;
- int error;
+ int error, error2;
nmp = VFSTONFS(bp->b_vp->v_mount);
@@ -1234,8 +1251,9 @@ again:
error = tsleep(&nmp->nm_bufq, slpflag | PRIBIO,
"nfsaio", slptimeo);
if (error) {
- if (nfs_sigintr(nmp, NULL, td))
- return (EINTR);
+ error2 = nfs_sigintr(nmp, NULL, td);
+ if (error2)
+ return (error2);
if (slpflag == PCATCH) {
slpflag = 0;
slptimeo = 2 * hz;
@@ -1474,7 +1492,7 @@ nfs_doio(struct buf *bp, struct ucred *cr, struct thread *td)
* bp in this case is not an NFS cache block so we should
* be safe. XXX
*/
- if (error == EINTR
+ if (error == EINTR || error == EIO
|| (!error && (bp->b_flags & B_NEEDCOMMIT))) {
int s;
diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c
index 483f0b0..43a6f7e 100644
--- a/sys/nfsclient/nfs_socket.c
+++ b/sys/nfsclient/nfs_socket.c
@@ -138,7 +138,7 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, "");
static int nfs_backoff[NFS_NBACKOFF] = { 2, 4, 8, 16, 32, 64, 128, 256, };
struct callout nfs_callout;
-static int nfs_msg(struct thread *, char *, char *);
+static int nfs_msg(struct thread *, const char *, const char *, int);
static int nfs_rcvlock(struct nfsreq *);
static void nfs_rcvunlock(struct nfsreq *);
static void nfs_realign(struct mbuf **pm, int hsiz);
@@ -359,8 +359,10 @@ nfs_reconnect(struct nfsreq *rep)
nfs_disconnect(nmp);
while ((error = nfs_connect(nmp, rep)) != 0) {
- if (error == EINTR || error == ERESTART)
- return (EINTR);
+ if (error == ERESTART)
+ error = EINTR;
+ if (error == EIO || error == EINTR)
+ return (error);
(void) tsleep(&lbolt, PSOCK, "nfscon", 0);
}
@@ -417,15 +419,16 @@ nfs_send(struct socket *so, struct sockaddr *nam, struct mbuf *top,
struct nfsreq *rep)
{
struct sockaddr *sendnam;
- int error, soflags, flags;
+ int error, error2, soflags, flags;
NET_ASSERT_GIANT();
KASSERT(rep, ("nfs_send: called with rep == NULL"));
- if (rep->r_flags & R_SOFTTERM) {
+ error = nfs_sigintr(rep->r_nmp, rep, rep->r_td);
+ if (error) {
m_freem(top);
- return (EINTR);
+ return (error);
}
if ((so = rep->r_nmp->nm_so) == NULL) {
rep->r_flags |= R_MUSTRESEND;
@@ -465,15 +468,16 @@ nfs_send(struct socket *so, struct sockaddr *nam, struct mbuf *top,
/*
* Deal with errors for the client side.
*/
- if (rep->r_flags & R_SOFTTERM)
- error = EINTR;
+ error2 = NFS_SIGREP(rep);
+ if (error2)
+ error = error2;
else
rep->r_flags |= R_MUSTRESEND;
/*
* Handle any recoverable (soft) socket errors here. (?)
*/
- if (error != EINTR && error != ERESTART &&
+ if (error != EINTR && error != ERESTART && error != EIO &&
error != EWOULDBLOCK && error != EPIPE)
error = 0;
}
@@ -499,7 +503,7 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp)
struct mbuf *control;
u_int32_t len;
struct sockaddr **getnam;
- int error, sotype, rcvflg;
+ int error, error2, sotype, rcvflg;
struct thread *td = curthread; /* XXX */
NET_ASSERT_GIANT();
@@ -533,9 +537,9 @@ tryagain:
* attempt that has essentially shut down this
* mount point.
*/
- if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
+ if (rep->r_mrep || (error = NFS_SIGREP(rep)) != 0) {
nfs_sndunlock(rep);
- return (EINTR);
+ return (error == 0 ? EINTR : error);
}
so = rep->r_nmp->nm_so;
if (!so) {
@@ -552,6 +556,7 @@ tryagain:
error = nfs_send(so, rep->r_nmp->nm_nam, m, rep);
if (error) {
if (error == EINTR || error == ERESTART ||
+ error == EIO ||
(error = nfs_reconnect(rep)) != 0) {
nfs_sndunlock(rep);
return (error);
@@ -574,11 +579,12 @@ tryagain:
rcvflg = MSG_WAITALL;
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, NULL, &auio, NULL, NULL, &rcvflg);
- if (error == EWOULDBLOCK && rep) {
- if (rep->r_flags & R_SOFTTERM)
- return (EINTR);
+ if (error == EWOULDBLOCK) {
+ error2 = NFS_SIGREP(rep);
+ if (error2)
+ return (error2);
}
- } while (error == EWOULDBLOCK);
+ } while (0);
if (!error && auio.uio_resid > 0) {
/*
* Don't log a 0 byte receive; it means
@@ -615,8 +621,7 @@ tryagain:
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, NULL,
&auio, mp, NULL, &rcvflg);
- } while (error == EWOULDBLOCK || error == EINTR ||
- error == ERESTART);
+ } while (0);
if (!error && auio.uio_resid > 0) {
if (len != auio.uio_resid)
log(LOG_INFO,
@@ -644,11 +649,11 @@ tryagain:
if (control)
m_freem(control);
if (error == EWOULDBLOCK && rep) {
- if (rep->r_flags & R_SOFTTERM)
- return (EINTR);
+ error2 = NFS_SIGREP(rep);
+ if (error2)
+ return (error2);
}
- } while (error == EWOULDBLOCK ||
- (!error && *mp == NULL && control));
+ } while (!error && *mp == NULL && control);
if ((rcvflg & MSG_EOR) == 0)
printf("Egad!!\n");
if (!error && *mp == NULL)
@@ -656,10 +661,11 @@ tryagain:
len -= auio.uio_resid;
}
errout:
- if (error && error != EINTR && error != ERESTART) {
+ if (error && error != EINTR && error != EIO &&
+ error != ERESTART) {
m_freem(*mp);
*mp = NULL;
- if (error != EPIPE)
+ if (error != EPIPE && error != EWOULDBLOCK)
log(LOG_INFO,
"receive error %d from nfs server %s\n",
error,
@@ -674,8 +680,20 @@ errout:
}
}
} else {
- if ((so = rep->r_nmp->nm_so) == NULL)
- return (EACCES);
+ /*
+ * We may have failed while rebinding the datagram socket
+ * so attempt a rebind here.
+ */
+ if ((so = rep->r_nmp->nm_so) == NULL) {
+ error = nfs_sndlock(rep);
+ if (!error) {
+ error = nfs_reconnect(rep);
+ nfs_sndunlock(rep);
+ }
+ if (error)
+ return (error);
+ so = rep->r_nmp->nm_so;
+ }
if (so->so_state & SS_ISCONNECTED)
getnam = NULL;
else
@@ -687,10 +705,28 @@ errout:
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, getnam, &auio, mp,
NULL, &rcvflg);
- if (error == EWOULDBLOCK &&
- (rep->r_flags & R_SOFTTERM))
- return (EINTR);
+ if (error) {
+ error2 = NFS_SIGREP(rep);
+ if (error2) {
+ error = error2;
+ goto dgramout;
+ }
+ }
+ if (error) {
+ error2 = nfs_sndlock(rep);
+ if (!error2) {
+ error2 = nfs_reconnect(rep);
+ if (error2)
+ error = error2;
+ else
+ so = rep->r_nmp->nm_so;
+ nfs_sndunlock(rep);
+ } else {
+ error = error2;
+ }
+ }
} while (error == EWOULDBLOCK);
+dgramout:
len -= auio.uio_resid;
}
if (error) {
@@ -878,6 +914,7 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum,
caddr_t dpos;
int s, error = 0, mrest_len, auth_len, auth_type;
int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0;
+ struct timeval now;
u_int32_t xid;
/* Reject requests while attempting a forced unmount. */
@@ -893,6 +930,10 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum,
rep->r_vp = vp;
rep->r_td = td;
rep->r_procnum = procnum;
+
+ getmicrouptime(&now);
+ rep->r_lastmsg = now.tv_sec -
+ ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));
mrest_len = m_length(mrest, NULL);
/*
@@ -951,13 +992,11 @@ tryagain:
(nmp->nm_flag & NFSMNT_DUMBTIMR) ||
nmp->nm_sent < nmp->nm_cwnd)) {
splx(s);
- if (nmp->nm_soflags & PR_CONNREQUIRED)
- error = nfs_sndlock(rep);
+ error = nfs_sndlock(rep);
if (!error) {
m2 = m_copym(m, 0, M_COPYALL, M_TRYWAIT);
error = nfs_send(nmp->nm_so, nmp->nm_nam, m2, rep);
- if (nmp->nm_soflags & PR_CONNREQUIRED)
- nfs_sndunlock(rep);
+ nfs_sndunlock(rep);
}
if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {
nmp->nm_sent += NFS_CWNDSCALE;
@@ -995,9 +1034,8 @@ tryagain:
* If there was a successful reply and a tprintf msg.
* tprintf a response.
*/
- if (!error && (rep->r_flags & R_TPRINTFMSG))
- nfs_msg(rep->r_td, nmp->nm_mountp->mnt_stat.f_mntfromname,
- "is alive again");
+ if (!error)
+ nfs_up(rep, nmp, rep->r_td, "is alive again", NFSSTA_TIMEO);
mrep = rep->r_mrep;
md = rep->r_md;
dpos = rep->r_dpos;
@@ -1098,16 +1136,32 @@ nfs_timer(void *arg)
int timeo;
int s, error;
struct thread *td;
+ struct timeval now;
+ getmicrouptime(&now);
td = &thread0; /* XXX for credentials, may break if sleep */
s = splnet();
TAILQ_FOREACH(rep, &nfs_reqq, r_chain) {
nmp = rep->r_nmp;
if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
continue;
- if (nfs_sigintr(nmp, rep, rep->r_td)) {
- nfs_softterm(rep);
+ if (nfs_sigintr(nmp, rep, rep->r_td))
continue;
+ if (nmp->nm_tprintf_initial_delay != 0 &&
+ (rep->r_rexmit > 2 || (rep->r_flags & R_RESENDERR)) &&
+ rep->r_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) {
+ rep->r_lastmsg = now.tv_sec;
+ nfs_down(rep, nmp, rep->r_td, "not responding",
+ 0, NFSSTA_TIMEO);
+#if 0
+ if (!(nmp->nm_state & NFSSTA_MOUNTED)) {
+ /* we're not yet completely mounted and */
+ /* we can't complete an RPC, so we fail */
+ nfsstats.rpctimeouts++;
+ nfs_softterm(rep);
+ continue;
+ }
+#endif
}
if (rep->r_rtt >= 0) {
rep->r_rtt++;
@@ -1122,16 +1176,6 @@ nfs_timer(void *arg)
if (nmp->nm_timeouts < NFS_NBACKOFF)
nmp->nm_timeouts++;
}
- /*
- * Check for server not responding
- */
- if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
- rep->r_rexmit > nmp->nm_deadthresh) {
- nfs_msg(rep->r_td,
- nmp->nm_mountp->mnt_stat.f_mntfromname,
- "not responding");
- rep->r_flags |= R_TPRINTFMSG;
- }
if (rep->r_rexmit >= rep->r_retry) { /* too many */
nfsstats.rpctimeouts++;
nfs_softterm(rep);
@@ -1165,12 +1209,14 @@ nfs_timer(void *arg)
if (error) {
if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
so->so_error = 0;
+ rep->r_flags |= R_RESENDERR;
} else {
/*
* Iff first send, start timing
* else turn timing off, backoff timer
* and divide congestion window by 2.
*/
+ rep->r_flags &= ~R_RESENDERR;
if (rep->r_flags & R_SENT) {
rep->r_flags &= ~R_TIMING;
if (++rep->r_rexmit > NFS_MAXREXMIT)
@@ -1256,10 +1302,10 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct thread *td)
if ((nmp->nm_flag & NFSMNT_NFSV4) != 0)
return nfs4_sigintr(nmp, rep, td);
if (rep && (rep->r_flags & R_SOFTTERM))
- return (EINTR);
+ return (EIO);
/* Terminate all requests while attempting a forced unmount. */
if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
- return (EINTR);
+ return (EIO);
if (!(nmp->nm_flag & NFSMNT_INT))
return (0);
if (td == NULL)
@@ -1292,14 +1338,15 @@ nfs_sndlock(struct nfsreq *rep)
{
int *statep = &rep->r_nmp->nm_state;
struct thread *td;
- int slpflag = 0, slptimeo = 0;
+ int error, slpflag = 0, slptimeo = 0;
td = rep->r_td;
if (rep->r_nmp->nm_flag & NFSMNT_INT)
slpflag = PCATCH;
while (*statep & NFSSTA_SNDLOCK) {
- if (nfs_sigintr(rep->r_nmp, rep, td))
- return (EINTR);
+ error = nfs_sigintr(rep->r_nmp, rep, td);
+ if (error)
+ return (error);
*statep |= NFSSTA_WANTSND;
(void) tsleep(statep, slpflag | (PZERO - 1),
"nfsndlck", slptimeo);
@@ -1333,15 +1380,16 @@ static int
nfs_rcvlock(struct nfsreq *rep)
{
int *statep = &rep->r_nmp->nm_state;
- int slpflag, slptimeo = 0;
+ int error, slpflag, slptimeo = 0;
if (rep->r_nmp->nm_flag & NFSMNT_INT)
slpflag = PCATCH;
else
slpflag = 0;
while (*statep & NFSSTA_RCVLOCK) {
- if (nfs_sigintr(rep->r_nmp, rep, rep->r_td))
- return (EINTR);
+ error = nfs_sigintr(rep->r_nmp, rep, rep->r_td);
+ if (error)
+ return (error);
*statep |= NFSSTA_WANTRCV;
(void) tsleep(statep, slpflag | (PZERO - 1), "nfsrcvlk",
slptimeo);
@@ -1359,8 +1407,8 @@ nfs_rcvlock(struct nfsreq *rep)
}
}
/* Always fail if our request has been cancelled. */
- if (rep != NULL && (rep->r_flags & R_SOFTTERM))
- return (EINTR);
+ if (rep != NULL && (error = NFS_SIGREP(rep)) != 0)
+ return (error);
*statep |= NFSSTA_RCVLOCK;
return (0);
}
@@ -1434,10 +1482,71 @@ nfs_realign(struct mbuf **pm, int hsiz)
static int
-nfs_msg(struct thread *td, char *server, char *msg)
+nfs_msg(struct thread *td, const char *server, const char *msg, int error)
{
+ struct proc *p;
- tprintf(td ? td->td_proc : NULL, LOG_INFO,
- "nfs server %s: %s\n", server, msg);
+ p = td ? td->td_proc : NULL;
+ if (error) {
+ tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server,
+ msg, error);
+ } else {
+ tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg);
+ }
return (0);
}
+
+void
+nfs_down(rep, nmp, td, msg, error, flags)
+ struct nfsreq *rep;
+ struct nfsmount *nmp;
+ struct thread *td;
+ const char *msg;
+ int error, flags;
+{
+
+ if (nmp == NULL)
+ return;
+ if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESP, 0);
+ nmp->nm_state |= NFSSTA_TIMEO;
+ }
+#ifdef NFSSTA_LOCKTIMEO
+ if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESPLOCK, 0);
+ nmp->nm_state |= NFSSTA_LOCKTIMEO;
+ }
+#endif
+ if (rep)
+ rep->r_flags |= R_TPRINTFMSG;
+ nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
+}
+
+void
+nfs_up(rep, nmp, td, msg, flags)
+ struct nfsreq *rep;
+ struct nfsmount *nmp;
+ struct thread *td;
+ const char *msg;
+ int flags;
+{
+ if (nmp == NULL)
+ return;
+ if ((rep == NULL) || (rep->r_flags & R_TPRINTFMSG) != 0)
+ nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
+ if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
+ nmp->nm_state &= ~NFSSTA_TIMEO;
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESP, 1);
+ }
+#ifdef NFSSTA_LOCKTIMEO
+ if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) {
+ nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESPLOCK, 1);
+ }
+#endif
+}
+
diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c
index 411faad..5728607 100644
--- a/sys/nfsclient/nfs_vfsops.c
+++ b/sys/nfsclient/nfs_vfsops.c
@@ -91,6 +91,13 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
int nfs_debug;
SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
#endif
+static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
+SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
+ downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
+/* how long between console messages "nfs server foo not responding" */
+static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
+SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
+ downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
static int nfs_iosize(struct nfsmount *nmp);
static void nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp);
@@ -102,6 +109,7 @@ static vfs_unmount_t nfs_unmount;
static vfs_root_t nfs_root;
static vfs_statfs_t nfs_statfs;
static vfs_sync_t nfs_sync;
+static vfs_sysctl_t nfs_sysctl;
/*
* nfs vfs operations.
@@ -114,6 +122,7 @@ static struct vfsops nfs_vfsops = {
.vfs_sync = nfs_sync,
.vfs_uninit = nfs_uninit,
.vfs_unmount = nfs_unmount,
+ .vfs_sysctl = nfs_sysctl,
};
VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK);
@@ -791,6 +800,12 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
nmp->nm_numgrps = NFS_MAXGRPS;
nmp->nm_readahead = NFS_DEFRAHEAD;
nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
+ nmp->nm_tprintf_delay = nfs_tprintf_delay;
+ if (nmp->nm_tprintf_delay < 0)
+ nmp->nm_tprintf_delay = 0;
+ nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
+ if (nmp->nm_tprintf_initial_delay < 0)
+ nmp->nm_tprintf_initial_delay = 0;
nmp->nm_fhsize = argp->fhsize;
bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
@@ -962,3 +977,14 @@ loop:
MNT_IUNLOCK(mp);
return (allerror);
}
+
+static int
+nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
+{
+
+ switch (op) {
+ default:
+ printf("nfs sysctl, op = %0X\n", (int) op);
+ }
+ return (0);
+}
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 44a2f94..adc2219 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -439,8 +439,8 @@ nfs_open(struct vop_open_args *ap)
* Get a valid lease. If cached data is stale, flush it.
*/
if (np->n_flag & NMODIFIED) {
- if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
- ap->a_td, 1)) == EINTR)
+ error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1);
+ if (error == EINTR || error == EIO)
return (error);
np->n_attrstamp = 0;
if (vp->v_type == VDIR)
@@ -456,8 +456,9 @@ nfs_open(struct vop_open_args *ap)
if (np->n_mtime != vattr.va_mtime.tv_sec) {
if (vp->v_type == VDIR)
np->n_direofoffset = 0;
- if ((error = nfs_vinvalbuf(vp, V_SAVE,
- ap->a_cred, ap->a_td, 1)) == EINTR)
+ error = nfs_vinvalbuf(vp, V_SAVE,
+ ap->a_cred, ap->a_td, 1);
+ if (error == EINTR || error == EIO)
return (error);
np->n_mtime = vattr.va_mtime.tv_sec;
}
@@ -669,7 +670,7 @@ nfs_setattr(struct vop_setattr_args *ap)
vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
vp->v_type == VREG &&
(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
- ap->a_td, 1)) == EINTR)
+ ap->a_td, 1)) != 0 && (error == EINTR || error == EIO))
return (error);
error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_td);
if (error && vap->va_size != VNOVAL) {
@@ -1447,7 +1448,7 @@ nfs_remove(struct vop_remove_args *ap)
*/
error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_thread, 1);
/* Do the rpc */
- if (error != EINTR)
+ if (error != EINTR && error != EIO)
error = nfs_removerpc(dvp, cnp->cn_nameptr,
cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread);
/*
@@ -2824,10 +2825,9 @@ loop:
panic("nfs_fsync: inconsistent lock");
if (error == ENOLCK)
goto loop;
- if (nfs_sigintr(nmp, NULL, td)) {
- error = EINTR;
+ error = nfs_sigintr(nmp, NULL, td);
+ if (error)
goto done;
- }
if (slpflag == PCATCH) {
slpflag = 0;
slptimeo = 2 * hz;
@@ -2863,10 +2863,9 @@ loop:
slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
if (error) {
VI_UNLOCK(vp);
- if (nfs_sigintr(nmp, NULL, td)) {
- error = EINTR;
+ error = nfs_sigintr(nmp, NULL, td);
+ if (error)
goto done;
- }
if (slpflag == PCATCH) {
slpflag = 0;
slptimeo = 2 * hz;
diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h
index 9c89ecf..5064370 100644
--- a/sys/nfsclient/nfsmount.h
+++ b/sys/nfsclient/nfsmount.h
@@ -77,6 +77,8 @@ struct nfsmount {
int nm_bufqiods; /* number of iods processing queue */
u_int64_t nm_maxfilesize; /* maximum file size */
struct nfs_rpcops *nm_rpcops;
+ int nm_tprintf_initial_delay; /* initial delay */
+ int nm_tprintf_delay; /* interval for messages */
/* NFSv4 */
uint64_t nm_clientid;
@@ -91,6 +93,14 @@ struct nfsmount {
*/
#define VFSTONFS(mp) ((struct nfsmount *)((mp)->mnt_data))
+#ifndef NFS_TPRINTF_INITIAL_DELAY
+#define NFS_TPRINTF_INITIAL_DELAY 12
+#endif
+
+#ifndef NFS_TPRINTF_DELAY
+#define NFS_TPRINTF_DELAY 30
+#endif
+
#endif
#endif
OpenPOWER on IntegriCloud