Add checks for VI_DOOMED and vn_lock() failures to the
experimental NFS server, to handle the case where an exported file system is forced dismounted while an RPC is in progress. Further commits will fix the cases where a mount point is used when the associated vnode isn't locked. Reviewed by: kib MFC after: 2 weeks
This commit is contained in:
parent
10ce910949
commit
5808c2408e
@ -153,6 +153,10 @@ nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
|
||||
struct vattr vattr;
|
||||
int error = 0, getret = 0;
|
||||
|
||||
if (vpislocked == 0) {
|
||||
if (vn_lock(vp, LK_SHARED) != 0)
|
||||
return (EPERM);
|
||||
}
|
||||
if (accmode & VWRITE) {
|
||||
/* Just vn_writechk() changed to check rdonly */
|
||||
/*
|
||||
@ -166,7 +170,7 @@ nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
|
||||
case VREG:
|
||||
case VDIR:
|
||||
case VLNK:
|
||||
return (EROFS);
|
||||
error = EROFS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -176,11 +180,14 @@ nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
|
||||
* the inode, try to free it up once. If
|
||||
* we fail, we can't allow writing.
|
||||
*/
|
||||
if (vp->v_vflag & VV_TEXT)
|
||||
return (ETXTBSY);
|
||||
if ((vp->v_vflag & VV_TEXT) != 0 && error == 0)
|
||||
error = ETXTBSY;
|
||||
}
|
||||
if (error != 0) {
|
||||
if (vpislocked == 0)
|
||||
VOP_UNLOCK(vp, 0);
|
||||
return (error);
|
||||
}
|
||||
if (vpislocked == 0)
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
|
||||
/*
|
||||
* Should the override still be applied when ACLs are enabled?
|
||||
@ -1097,9 +1104,11 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
|
||||
goto out;
|
||||
}
|
||||
if (ndflag & ND_NFSV4) {
|
||||
NFSVOPLOCK(fvp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
error = nfsrv_checkremove(fvp, 0, p);
|
||||
NFSVOPUNLOCK(fvp, 0, p);
|
||||
if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
|
||||
error = nfsrv_checkremove(fvp, 0, p);
|
||||
VOP_UNLOCK(fvp, 0);
|
||||
} else
|
||||
error = EPERM;
|
||||
if (tvp && !error)
|
||||
error = nfsrv_checkremove(tvp, 1, p);
|
||||
} else {
|
||||
@ -1156,13 +1165,16 @@ nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
|
||||
error = EXDEV;
|
||||
}
|
||||
if (!error) {
|
||||
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
if ((vp->v_iflag & VI_DOOMED) == 0)
|
||||
error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
|
||||
else
|
||||
error = EPERM;
|
||||
if (ndp->ni_dvp == vp)
|
||||
vrele(ndp->ni_dvp);
|
||||
else
|
||||
vput(ndp->ni_dvp);
|
||||
NFSVOPUNLOCK(vp, 0, p);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
} else {
|
||||
if (ndp->ni_dvp == ndp->ni_vp)
|
||||
vrele(ndp->ni_dvp);
|
||||
@ -2793,6 +2805,11 @@ nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first,
|
||||
|
||||
if (nfsrv_dolocallocks == 0)
|
||||
return (0);
|
||||
|
||||
/* Check for VI_DOOMED here, so that VOP_ADVLOCK() isn't performed. */
|
||||
if ((vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EPERM);
|
||||
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_type = ftype;
|
||||
fl.l_start = (off_t)first;
|
||||
|
@ -2676,9 +2676,12 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
};
|
||||
stp->ls_flags |= NFSLCK_RECLAIM;
|
||||
vp = dp;
|
||||
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
|
||||
nd, p, nd->nd_repstat);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
if ((vp->v_iflag & VI_DOOMED) == 0)
|
||||
nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
|
||||
stp, vp, nd, p, nd->nd_repstat);
|
||||
else
|
||||
nd->nd_repstat = NFSERR_PERM;
|
||||
} else {
|
||||
nd->nd_repstat = NFSERR_BADXDR;
|
||||
vrele(dp);
|
||||
|
@ -902,13 +902,15 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
|
||||
nd->nd_repstat = NFSERR_XDEV;
|
||||
break;
|
||||
}
|
||||
VREF(vp);
|
||||
VREF(savevp);
|
||||
if (nfsv4_opflag[op].modifyfs)
|
||||
NFS_STARTWRITE(NULL, &mp);
|
||||
NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
|
||||
vp, p, &savevpnes, &vpnes);
|
||||
if (vn_lock(savevp, LK_EXCLUSIVE) == 0) {
|
||||
VREF(vp);
|
||||
VREF(savevp);
|
||||
error = (*(nfsrv4_ops2[op]))(nd, isdgram,
|
||||
savevp, vp, p, &savevpnes, &vpnes);
|
||||
} else
|
||||
nd->nd_repstat = NFSERR_PERM;
|
||||
if (nfsv4_opflag[op].modifyfs)
|
||||
NFS_ENDWRITE(mp);
|
||||
} else {
|
||||
@ -916,12 +918,15 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
|
||||
panic("nfsrvd_compound");
|
||||
if (nfsv4_opflag[op].needscfh) {
|
||||
if (vp != NULL) {
|
||||
if (nfsv4_opflag[op].modifyfs)
|
||||
NFS_STARTWRITE(NULL, &mp);
|
||||
if (vn_lock(vp, nfsv4_opflag[op].lktype)
|
||||
!= 0)
|
||||
== 0)
|
||||
VREF(vp);
|
||||
else
|
||||
nd->nd_repstat = NFSERR_PERM;
|
||||
} else
|
||||
} else {
|
||||
nd->nd_repstat = NFSERR_NOFILEHANDLE;
|
||||
if (nd->nd_repstat != 0) {
|
||||
if (op == NFSV4OP_SETATTR) {
|
||||
/*
|
||||
* Setattr reply requires a
|
||||
@ -934,11 +939,9 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
|
||||
}
|
||||
break;
|
||||
}
|
||||
VREF(vp);
|
||||
if (nfsv4_opflag[op].modifyfs)
|
||||
NFS_STARTWRITE(NULL, &mp);
|
||||
error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
|
||||
p, &vpnes);
|
||||
if (nd->nd_repstat == 0)
|
||||
error = (*(nfsrv4_ops0[op]))(nd,
|
||||
isdgram, vp, p, &vpnes);
|
||||
if (nfsv4_opflag[op].modifyfs)
|
||||
NFS_ENDWRITE(mp);
|
||||
} else {
|
||||
|
@ -1659,7 +1659,7 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
|
||||
if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) {
|
||||
ret = nfsrv_clientconflict(tstp->ls_clp, &haslock,
|
||||
vp, p);
|
||||
if (ret) {
|
||||
if (ret == 1) {
|
||||
/*
|
||||
* nfsrv_clientconflict unlocks state
|
||||
* when it returns non-zero.
|
||||
@ -1667,13 +1667,17 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
|
||||
lckstp = NULL;
|
||||
goto tryagain;
|
||||
}
|
||||
NFSUNLOCKSTATE();
|
||||
if (ret == 0)
|
||||
NFSUNLOCKSTATE();
|
||||
if (haslock) {
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
}
|
||||
return (NFSERR_OPENMODE);
|
||||
if (ret == 2)
|
||||
return (NFSERR_PERM);
|
||||
else
|
||||
return (NFSERR_OPENMODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1826,7 +1830,7 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
|
||||
other_lop = NULL;
|
||||
}
|
||||
ret = nfsrv_clientconflict(lop->lo_stp->ls_clp,&haslock,vp,p);
|
||||
if (ret) {
|
||||
if (ret == 1) {
|
||||
if (filestruct_locked != 0) {
|
||||
/* Roll back local locks. */
|
||||
nfsrv_locallock_rollback(vp, lfp, p);
|
||||
@ -1845,7 +1849,7 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
|
||||
* Found a conflicting lock, so record the conflict and
|
||||
* return the error.
|
||||
*/
|
||||
if (cfp) {
|
||||
if (cfp != NULL && ret == 0) {
|
||||
cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0];
|
||||
cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1];
|
||||
cfp->cl_first = lop->lo_first;
|
||||
@ -1855,20 +1859,23 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
|
||||
NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner,
|
||||
cfp->cl_ownerlen);
|
||||
}
|
||||
if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
if (ret == 2)
|
||||
error = NFSERR_PERM;
|
||||
else if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
error = NFSERR_RECLAIMCONFLICT;
|
||||
else if (new_stp->ls_flags & NFSLCK_CHECK)
|
||||
error = NFSERR_LOCKED;
|
||||
else
|
||||
error = NFSERR_DENIED;
|
||||
if (filestruct_locked != 0) {
|
||||
if (filestruct_locked != 0 && ret == 0) {
|
||||
/* Roll back local locks. */
|
||||
NFSUNLOCKSTATE();
|
||||
nfsrv_locallock_rollback(vp, lfp, p);
|
||||
NFSLOCKSTATE();
|
||||
nfsrv_unlocklf(lfp);
|
||||
}
|
||||
NFSUNLOCKSTATE();
|
||||
if (ret == 0)
|
||||
NFSUNLOCKSTATE();
|
||||
if (haslock) {
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
@ -2120,18 +2127,21 @@ nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp,
|
||||
((stp->ls_flags & NFSLCK_ACCESSBITS) &
|
||||
((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){
|
||||
ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p);
|
||||
if (ret) {
|
||||
if (ret == 1) {
|
||||
/*
|
||||
* nfsrv_clientconflict() unlocks
|
||||
* state when it returns non-zero.
|
||||
*/
|
||||
goto tryagain;
|
||||
}
|
||||
if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
if (ret == 2)
|
||||
error = NFSERR_PERM;
|
||||
else if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
error = NFSERR_RECLAIMCONFLICT;
|
||||
else
|
||||
error = NFSERR_SHAREDENIED;
|
||||
NFSUNLOCKSTATE();
|
||||
if (ret == 0)
|
||||
NFSUNLOCKSTATE();
|
||||
if (haslock) {
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
@ -2394,7 +2404,7 @@ nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp,
|
||||
((stp->ls_flags & NFSLCK_ACCESSBITS) &
|
||||
((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){
|
||||
ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p);
|
||||
if (ret) {
|
||||
if (ret == 1) {
|
||||
/*
|
||||
* nfsrv_clientconflict() unlocks state
|
||||
* when it returns non-zero.
|
||||
@ -2404,11 +2414,14 @@ nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp,
|
||||
openstp = NULL;
|
||||
goto tryagain;
|
||||
}
|
||||
if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
if (ret == 2)
|
||||
error = NFSERR_PERM;
|
||||
else if (new_stp->ls_flags & NFSLCK_RECLAIM)
|
||||
error = NFSERR_RECLAIMCONFLICT;
|
||||
else
|
||||
error = NFSERR_SHAREDENIED;
|
||||
NFSUNLOCKSTATE();
|
||||
if (ret == 0)
|
||||
NFSUNLOCKSTATE();
|
||||
if (haslock) {
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
@ -4080,10 +4093,13 @@ nfsrv_updatestable(NFSPROC_T *p)
|
||||
NFSVNO_SETATTRVAL(&nva, size, 0);
|
||||
vp = NFSFPVNODE(sf->nsf_fp);
|
||||
NFS_STARTWRITE(vp, &mp);
|
||||
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, NULL);
|
||||
if (vn_lock(vp, LK_EXCLUSIVE) == 0) {
|
||||
error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p,
|
||||
NULL);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
} else
|
||||
error = EPERM;
|
||||
NFS_ENDWRITE(mp);
|
||||
NFSVOPUNLOCK(vp, 0, p);
|
||||
if (!error)
|
||||
error = NFSD_RDWR(UIO_WRITE, vp,
|
||||
(caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0,
|
||||
@ -4211,10 +4227,11 @@ nfsrv_checkstable(struct nfsclient *clp)
|
||||
* Return 0 to indicate the conflict can't be revoked and 1 to indicate
|
||||
* the revocation worked and the conflicting client is "bye, bye", so it
|
||||
* can be tried again.
|
||||
* Return 2 to indicate that the vnode is VI_DOOMED after vn_lock().
|
||||
* Unlocks State before a non-zero value is returned.
|
||||
*/
|
||||
static int
|
||||
nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, __unused vnode_t vp,
|
||||
nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp,
|
||||
NFSPROC_T *p)
|
||||
{
|
||||
int gotlock, lktype;
|
||||
@ -4238,7 +4255,10 @@ nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, __unused vnode_t vp,
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
*haslockp = 1;
|
||||
vn_lock(vp, lktype | LK_RETRY);
|
||||
return (1);
|
||||
if ((vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (2);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
NFSUNLOCKSTATE();
|
||||
|
||||
@ -4254,7 +4274,6 @@ nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, __unused vnode_t vp,
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Resolve a delegation conflict.
|
||||
* Returns 0 to indicate the conflict was resolved without sleeping.
|
||||
@ -4403,6 +4422,13 @@ nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p,
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
*haslockp = 1;
|
||||
vn_lock(vp, lktype | LK_RETRY);
|
||||
if ((vp->v_iflag & VI_DOOMED) != 0) {
|
||||
*haslockp = 0;
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
return (NFSERR_PERM);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -4594,12 +4620,11 @@ nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p)
|
||||
NFSGETNANOTIME(&mytime);
|
||||
starttime = (u_int32_t)mytime.tv_sec;
|
||||
do {
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
if ((vp->v_iflag & VI_DOOMED) == 0)
|
||||
if (vn_lock(vp, LK_EXCLUSIVE) == 0) {
|
||||
error = nfsrv_checkremove(vp, 0, p);
|
||||
else
|
||||
VOP_UNLOCK(vp, 0);
|
||||
} else
|
||||
error = EPERM;
|
||||
VOP_UNLOCK(vp, 0);
|
||||
if (error == NFSERR_DELAY) {
|
||||
NFSGETNANOTIME(&mytime);
|
||||
if (((u_int32_t)mytime.tv_sec - starttime) >
|
||||
|
Loading…
Reference in New Issue
Block a user