summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2011-07-31 20:06:11 +0000
committerrmacklem <rmacklem@FreeBSD.org>2011-07-31 20:06:11 +0000
commited9d50749cb2eceeab3a84829fc923e9d8fe3dff (patch)
tree64b258571353c719519c6df66155fcac7f87d9d6 /sys/fs
parente9752126de05c72ff44f9f9a487d8f2d1b8c8f40 (diff)
downloadFreeBSD-src-ed9d50749cb2eceeab3a84829fc923e9d8fe3dff.zip
FreeBSD-src-ed9d50749cb2eceeab3a84829fc923e9d8fe3dff.tar.gz
Fix rename in the new NFS server so that it does not require a
recursive vnode lock on the directory for the case where the new file name is in the same directory as the old one. The patch handles this as a special case, recognized by the new directory having the same file handle as the old one and just VREF()s the old dir vnode for this case, instead of doing a second VFS_FHTOVP() to get it. This is required so that the server will work for file systems like msdosfs, that do not support recursive vnode locking. This problem was discovered during recent testing by pho@ when exporting an msdosfs file system via the new NFS server. Tested by: pho Reviewed by: zkirsch Approved by: re (kib) MFC after: 2 weeks
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index b6a365d..436d44c 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -1425,6 +1425,7 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
struct nfsrvfh tfh;
char *bufp, *tbufp = NULL;
u_long *hashp;
+ fhandle_t fh;
if (nd->nd_repstat) {
nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
@@ -1450,19 +1451,34 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
tnes = *toexp;
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
} else {
+ tfh.nfsrvfh_len = 0;
error = nfsrv_mtofh(nd, &tfh);
+ if (error == 0)
+ error = nfsvno_getfh(dp, &fh, p);
if (error) {
vput(dp);
/* todp is always NULL except NFSv4 */
nfsvno_relpathbuf(&fromnd);
goto out;
}
- nd->nd_cred->cr_uid = nd->nd_saveduid;
- nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p);
- if (tdp) {
+
+ /* If this is the same file handle, just VREF() the vnode. */
+ if (tfh.nfsrvfh_len == NFSX_MYFH &&
+ !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
+ VREF(dp);
+ tdp = dp;
+ tnes = *exp;
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
p, 1);
- NFSVOPUNLOCK(tdp, 0);
+ } else {
+ nd->nd_cred->cr_uid = nd->nd_saveduid;
+ nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
+ 0, p);
+ if (tdp) {
+ tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
+ nd->nd_cred, p, 1);
+ NFSVOPUNLOCK(tdp, 0);
+ }
}
}
NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
OpenPOWER on IntegriCloud