summaryrefslogtreecommitdiffstats
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
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
-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