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:
parent
95347a8ee0
commit
c713aaaeca
@ -928,7 +928,7 @@ update:
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user