diff options
author | tjr <tjr@FreeBSD.org> | 2004-02-10 05:53:02 +0000 |
---|---|---|
committer | tjr <tjr@FreeBSD.org> | 2004-02-10 05:53:02 +0000 |
commit | 40b810244fbce5f951ac0c46dbf1181adb21a0b7 (patch) | |
tree | ba73a74265f497f6e197c646b862844380ff2f4b /sys/fs/smbfs | |
parent | 72c7aa83c9ff6fcca227bada024389ad5063cce1 (diff) | |
download | FreeBSD-src-40b810244fbce5f951ac0c46dbf1181adb21a0b7.zip FreeBSD-src-40b810244fbce5f951ac0c46dbf1181adb21a0b7.tar.gz |
Fixes problems that occurred when a file was removed and a directory
created with the same name, and vice versa:
- Immediately recycle vnodes of files & directories that have been deleted
or renamed.
- When looking an entry in the VFS name cache or smbfs's private
cache, make sure the vnode type is consistent with the type of file
the server thinks it is, and re-create the vnode if it isn't.
The alternative to this is to recycle vnodes unconditionally when their
use count drops to 0, but this would make all the caching we do
mostly useless.
PR: 62342
MFC after: 2 weeks
Diffstat (limited to 'sys/fs/smbfs')
-rw-r--r-- | sys/fs/smbfs/smbfs_node.c | 17 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_node.h | 1 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_vnops.c | 25 |
3 files changed, 42 insertions, 1 deletions
diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c index dcc0ada..830e1e5 100644 --- a/sys/fs/smbfs/smbfs_node.c +++ b/sys/fs/smbfs/smbfs_node.c @@ -164,6 +164,7 @@ static int smbfs_node_alloc(struct mount *mp, struct vnode *dvp, const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp) { + struct vattr vattr; struct thread *td = curthread; /* XXX */ struct smbmount *smp = VFSTOSMBFS(mp); struct smbnode_hashhead *nhpp; @@ -208,6 +209,20 @@ loop: smbfs_hash_unlock(smp, td); if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0) goto retry; + /* Force cached attributes to be refreshed if stale. */ + (void)VOP_GETATTR(vp, &vattr, td->td_ucred, td); + /* + * If the file type on the server is inconsistent with + * what it was when we created the vnode, kill the + * bogus vnode now and fall through to the code below + * to create a new one with the right type. + */ + if ((vp->v_type == VDIR && (np->n_dosattr & SMB_FA_DIR) == 0) || + (vp->v_type == VREG && (np->n_dosattr & SMB_FA_DIR) != 0)) { + vput(vp); + vgone(vp); + break; + } *vpp = vp; return 0; } @@ -361,6 +376,8 @@ smbfs_inactive(ap) smbfs_attr_cacheremove(vp); } VOP_UNLOCK(vp, 0, td); + if (np->n_flag & NGONE) + vrecycle(vp, NULL, td); return (0); } /* diff --git a/sys/fs/smbfs/smbfs_node.h b/sys/fs/smbfs/smbfs_node.h index 884831c..7a8d545 100644 --- a/sys/fs/smbfs/smbfs_node.h +++ b/sys/fs/smbfs/smbfs_node.h @@ -44,6 +44,7 @@ #define NREFPARENT 0x0010 /* node holds parent from recycling */ #define NFLUSHWIRE 0x1000 /* pending flush request */ #define NOPEN 0x2000 /* file is open */ +#define NGONE 0x4000 /* file has been removed/renamed */ struct smbfs_fctx; diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c index e9fc5a8..c6e031f 100644 --- a/sys/fs/smbfs/smbfs_vnops.c +++ b/sys/fs/smbfs/smbfs_vnops.c @@ -538,6 +538,8 @@ smbfs_remove(ap) return EPERM; smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); error = smbfs_smb_delete(np, &scred); + if (error == 0) + np->n_flag |= NGONE; cache_purge(vp); return error; } @@ -604,6 +606,7 @@ smbfs_rename(ap) error = smbfs_smb_delete(VTOSMB(tvp), &scred); if (error) goto out_cacherem; + VTOSMB(fvp)->n_flag |= NGONE; } error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), tcnp->cn_nameptr, tcnp->cn_namelen, &scred); @@ -739,6 +742,8 @@ smbfs_rmdir(ap) smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); error = smbfs_smb_rmdir(np, &scred); + if (error == 0) + np->n_flag |= NGONE; dnp->n_flag |= NMODIFIED; smbfs_attr_cacheremove(dvp); /* cache_purge(dvp);*/ @@ -1096,6 +1101,7 @@ smbfs_lookup(ap) int nameiop = cnp->cn_nameiop; int nmlen = cnp->cn_namelen; int lockparent, wantparent, error, islastcn, isdot; + int killit; SMBVDEBUG("\n"); cnp->cn_flags &= ~PDIRUNLOCK; @@ -1165,8 +1171,23 @@ smbfs_lookup(ap) } } if (!error) { + killit = 0; if (vpid == vp->v_id) { - if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, td) + error = VOP_GETATTR(vp, &vattr, cnp->cn_cred, td); + /* + * If the file type on the server is inconsistent + * with what it was when we created the vnode, + * kill the bogus vnode now and fall through to + * the code below to create a new one with the + * right type. + */ + if (error == 0 && + ((vp->v_type == VDIR && + (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || + (vp->v_type == VREG && + (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) + killit = 1; + else if (error == 0 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { if (nameiop != LOOKUP && islastcn) cnp->cn_flags |= SAVENAME; @@ -1176,6 +1197,8 @@ smbfs_lookup(ap) cache_purge(vp); } vput(vp); + if (killit) + vgone(vp); if (lockparent && dvp != vp && islastcn) VOP_UNLOCK(dvp, 0, td); } |