summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2009-06-17 14:10:18 +0000
committerrmacklem <rmacklem@FreeBSD.org>2009-06-17 14:10:18 +0000
commitf0ea4f4c9fd72e2b5dd8ad896d1b7a7e6fb96058 (patch)
treebaca52fd25c14020314944a7fa94ec1e5cd0c6b4 /sys/fs
parent5a77f36af99ef427ad87650df052a10b37883b23 (diff)
downloadFreeBSD-src-f0ea4f4c9fd72e2b5dd8ad896d1b7a7e6fb96058.zip
FreeBSD-src-f0ea4f4c9fd72e2b5dd8ad896d1b7a7e6fb96058.tar.gz
Fix handling of ".." in nfs_lookup() for the forced dismount case
by cribbing the change made to the regular nfs client in r194358. Approved by: kib (mentor)
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c50
1 files changed, 36 insertions, 14 deletions
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index a1f2701..be5e4c3 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -992,22 +992,23 @@ nfs_lookup(struct vop_lookup_args *ap)
struct componentname *cnp = ap->a_cnp;
struct vnode *dvp = ap->a_dvp;
struct vnode **vpp = ap->a_vpp;
+ struct mount *mp = dvp->v_mount;
int flags = cnp->cn_flags;
struct vnode *newvp;
struct nfsmount *nmp;
struct nfsnode *np;
- int error = 0, attrflag, dattrflag;
+ int error = 0, attrflag, dattrflag, ltype;
struct thread *td = cnp->cn_thread;
struct nfsfh *nfhp;
struct nfsvattr dnfsva, nfsva;
*vpp = NULLVP;
- if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
return (EROFS);
if (dvp->v_type != VDIR)
return (ENOTDIR);
- nmp = VFSTONFS(dvp->v_mount);
+ nmp = VFSTONFS(mp);
np = VTONFS(dvp);
/* For NFSv4, wait until any remove is done. */
@@ -1073,7 +1074,7 @@ nfs_lookup(struct vop_lookup_args *ap)
}
if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
(flags & ISLASTCN) && error == ENOENT) {
- if (dvp->v_mount->mnt_flag & MNT_RDONLY)
+ if (mp->mnt_flag & MNT_RDONLY)
error = EROFS;
else
error = EJUSTRETURN;
@@ -1093,8 +1094,7 @@ nfs_lookup(struct vop_lookup_args *ap)
FREE((caddr_t)nfhp, M_NFSFH);
return (EISDIR);
}
- error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, td, &np,
- NULL);
+ error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL);
if (error)
return (error);
newvp = NFSTOV(np);
@@ -1106,14 +1106,37 @@ nfs_lookup(struct vop_lookup_args *ap)
return (0);
}
- if ((flags & ISDOTDOT)) {
+ if (flags & ISDOTDOT) {
+ ltype = VOP_ISLOCKED(dvp);
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error != 0) {
+ VOP_UNLOCK(dvp, 0);
+ error = vfs_busy(mp, 0);
+ vn_lock(dvp, ltype | LK_RETRY);
+ if (error == 0 && (dvp->v_iflag & VI_DOOMED)) {
+ vfs_unbusy(mp);
+ error = ENOENT;
+ }
+ if (error != 0)
+ return (error);
+ }
VOP_UNLOCK(dvp, 0);
- error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, td, &np,
- NULL);
- vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
- if (error)
+ error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL);
+ if (error == 0)
+ newvp = NFSTOV(np);
+ vfs_unbusy(mp);
+ vn_lock(dvp, ltype | LK_RETRY);
+ if (dvp->v_iflag & VI_DOOMED) {
+ if (error == 0) {
+ if (newvp == dvp)
+ vrele(newvp);
+ else
+ vput(newvp);
+ }
+ error = ENOENT;
+ }
+ if (error != 0)
return (error);
- newvp = NFSTOV(np);
if (attrflag)
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL,
0, 1);
@@ -1125,8 +1148,7 @@ nfs_lookup(struct vop_lookup_args *ap)
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL,
0, 1);
} else {
- error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, td, &np,
- NULL);
+ error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL);
if (error)
return (error);
newvp = NFSTOV(np);
OpenPOWER on IntegriCloud