patch-2.2.1 linux/fs/nfsd/vfs.c
Next file: linux/fs/proc/array.c
Previous file: linux/drivers/sound/sb_card.c
Back to the patch index
Back to the overall index
- Lines: 70
- Date:
Wed Jan 27 13:49:46 1999
- Orig file:
v2.2.0/linux/fs/nfsd/vfs.c
- Orig date:
Tue Jan 19 11:32:52 1999
diff -u --recursive --new-file v2.2.0/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
@@ -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--;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)