[PATCH] knfsd problmes (fwd)

G. Allen Morris III (gam3@harpo.ixlabs.com)
Wed, 27 Jan 1999 13:45:22 -0800


This patch solves two problems with knfsd:

1. The Oops generated if a rename was done on a file that had
been deleted on the sever (test odentry->d_inode).

2. rename and rmdir now test for a race condition (check_parent).

--- linux-2.2.0.orig/fs/nfsd/vfs.c Tue Jan 19 11:22:18 1999
+++ linux/fs/nfsd/vfs.c Wed Jan 27 13:19:17 1999
@@ -988,6 +988,20 @@
}

/*
+ * We need to do a check-parent every time
+ * after we have locked the parent - to verify
+ * that the parent is still our parent and
+ * that we are still hashed onto it..
+ *
+ * This is requied in case two processes race
+ * on removing (or moving) the same entry: the
+ * parent lock will serialize them, but the
+ * other process will be too late..
+ */
+#define check_parent(dir, dentry) \
+ ((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
+
+/*
* This follows the model of double_lock() in the VFS.
*/
static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
@@ -1048,6 +1062,10 @@
if (IS_ERR(odentry))
goto out_nfserr;

+ err = -ENOENT;
+ if (!odentry->d_inode)
+ goto out_dput_old;
+
ndentry = lookup_dentry(tname, dget(tdentry), 0);
err = PTR_ERR(ndentry);
if (IS_ERR(ndentry))
@@ -1057,13 +1075,18 @@
* Lock the parent directories.
*/
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
- /* N.B. check for parent changes after locking?? */
-
- err = vfs_rename(fdir, odentry, tdir, ndentry);
- if (!err && EX_ISSYNC(tfhp->fh_export)) {
- write_inode_now(fdir);
- write_inode_now(tdir);
- }
+ err = -ENOENT;
+ /* GAM3 check for parent changes after locking. */
+ if (check_parent(fdir, odentry) &&
+ check_parent(tdir, ndentry)) {
+
+ err = vfs_rename(fdir, odentry, tdir, ndentry);
+ if (!err && EX_ISSYNC(tfhp->fh_export)) {
+ write_inode_now(fdir);
+ write_inode_now(tdir);
+ }
+ } else
+ dprintk("nfsd: Caught race in nfsd_rename");
DQUOT_DROP(fdir);
DQUOT_DROP(tdir);

@@ -1137,10 +1160,9 @@
if (!fhp->fh_pre_mtime)
fhp->fh_pre_mtime = dirp->i_mtime;
fhp->fh_locked = 1;
- /* CHECKME: Should we do something with the child? */

err = -ENOENT;
- if (rdentry->d_parent->d_inode == dirp)
+ if (check_parent(dirp, rdentry))
err = vfs_rmdir(dirp, rdentry);

rdentry->d_count--;

---------------------------------
G. Allen Morris III

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/