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.
This commit is contained in:
Alfred Perlstein 2004-07-06 09:12:03 +00:00
parent 95347a8ee0
commit c713aaaeca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=131691
9 changed files with 271 additions and 98 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 *);

View File

@ -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;

View File

@ -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
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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 *);