From c713aaaeca2bf78bc9fcdc8fe4242ea823ce3d69 Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Tue, 6 Jul 2004 09:12:03 +0000 Subject: [PATCH] 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. --- sys/kern/vfs_mount.c | 4 +- sys/kern/vfs_subr.c | 2 +- sys/nfsclient/nfs.h | 15 ++- sys/nfsclient/nfs_bio.c | 56 ++++++--- sys/nfsclient/nfs_socket.c | 231 +++++++++++++++++++++++++++---------- sys/nfsclient/nfs_vfsops.c | 26 +++++ sys/nfsclient/nfs_vnops.c | 23 ++-- sys/nfsclient/nfsmount.h | 10 ++ sys/sys/mount.h | 2 +- 9 files changed, 271 insertions(+), 98 deletions(-) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index d759646a4b81..69a434e59765 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -928,7 +928,7 @@ vfs_domount( mtx_lock(&mountlist_mtx); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); mtx_unlock(&mountlist_mtx); - vfs_event_signal(NULL, VQ_MOUNT, NULL); + vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, &newdp)) panic("mount: lost mount"); checkdirs(vp, newdp); @@ -1174,7 +1174,7 @@ dounmount(mp, flags, td) if ((coveredvp = mp->mnt_vnodecovered) != NULL) coveredvp->v_mountedhere = NULL; mtx_unlock(&mountlist_mtx); - vfs_event_signal(NULL, VQ_UNMOUNT, NULL); + vfs_event_signal(NULL, VQ_UNMOUNT, 0); vfs_mount_destroy(mp, td); if (coveredvp != NULL) vrele(coveredvp); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index b04ec4b81165..1c7a7fbe27a0 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -3959,7 +3959,7 @@ vop_unlock_post(void *ap, int rc) static struct klist fs_klist = SLIST_HEAD_INITIALIZER(&fs_klist); void -vfs_event_signal(fsid_t *fsid, u_int32_t event, void *data __unused) +vfs_event_signal(fsid_t *fsid, u_int32_t event, intptr_t data __unused) { KNOTE(&fs_klist, event); diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index ab80ab8a4898..697068b89cba 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 20dd0333dbfe..7f17f8c37902 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 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) case ENOLCK: goto again; /* not reached */ + case EIO: + return (EIO); case EINTR: case ERESTART: return(EINTR); @@ -514,8 +518,10 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) 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 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) 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 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) 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 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) && (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 @@ nfs_write(struct vop_write_args *ap) case ENOLCK: goto restart; /* not reached */ + case EIO: + return (EIO); case EINTR: case ERESTART: return(EINTR); @@ -878,7 +892,9 @@ nfs_write(struct vop_write_args *ap) } if (!bp) { - error = EINTR; + error = nfs_sigintr(nmp, NULL, td); + if (!error) + error = EINTR; break; } @@ -917,7 +933,9 @@ nfs_write(struct vop_write_args *ap) } } 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 @@ nfs_asyncio(struct buf *bp, struct ucred *cred, struct thread *td) 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 483f0b09477e..43a6f7ed9541 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) * 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) } } } 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 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) 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 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum, (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 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum, * 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 411faadfc0ac..57286074306a 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 @@ nfs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct thread *td) 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 44a2f9459b47..adc2219bd5d1 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 @@ nfs_flush(struct vnode *vp, struct ucred *cred, int waitfor, struct thread *td, 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 @@ nfs_flush(struct vnode *vp, struct ucred *cred, int waitfor, struct thread *td, 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 9c89ecf8440b..5064370e0a42 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 diff --git a/sys/sys/mount.h b/sys/sys/mount.h index c1c2b823eeea..9e3afe615a4b 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -554,7 +554,7 @@ extern char *mountrootfsname; int dounmount(struct mount *, int, struct thread *); int kernel_mount(struct iovec *, u_int, int); int kernel_vmount(int flags, ...); -void vfs_event_signal(fsid_t *, u_int32_t, void *); +void vfs_event_signal(fsid_t *, u_int32_t, intptr_t); int vfs_getopt(struct vfsoptlist *, const char *, void **, int *); int vfs_copyopt(struct vfsoptlist *, const char *, void *, int); int vfs_mount(struct thread *, const char *, char *, int, void *);