patch for 2.1.76 nfs client

Bill Hawes (whawes@star.net)
Fri, 02 Jan 1998 09:12:11 -0500


This is a multi-part message in MIME format.
--------------401B4957292B84C589084EB3
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached patch reworks the NFS rename procedure to release the
target inode in advance, following the model used in unlink and rmdir.
This should correct the last known cause of busy inodes after unlinking
a file on the server. It also implicitly handles the case of pending
writes to the target inode, which we weren't testing for previously.

I've also made a minor change to the code to detect invalid fattrs after
a mkdir, to work around problems in certain servers. The fattr mtime
field is now initialized to -1, and if it doesn't change the fattr is
assumed to be invalid.

The next set of NFS patches will address the problem with filehandles
for hardlinks, and will probably be much more extensive. Since it may
take a while to get everything working again, I wanted to release these
changes for testing now.

Regards,
Bill
--------------401B4957292B84C589084EB3
Content-Type: text/plain; charset=us-ascii; name="nfs_76-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="nfs_76-patch"

--- linux-2.1.76/fs/nfs/dir.c.old Tue Dec 30 16:08:59 1997
+++ linux-2.1.76/fs/nfs/dir.c Wed Dec 31 18:09:13 1997
@@ -411,7 +411,7 @@
int error;

dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-#ifdef NFS_DEBUG
+#ifdef NFS_DEBUG_VERBOSE
printk("nfs_dentry_delete: unlinking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
@@ -652,6 +652,7 @@
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ fattr.mtime.seconds = (unsigned) -1;

nfs_invalidate_dircache(dir);
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
@@ -659,14 +660,14 @@
if (!error) {
/*
* Some AIX servers reportedly fail to fill out the fattr.
- * Check for a bad mode value and complain, then drop the
- * dentry to force a new lookup.
+ * If the modify time hasn't been set, we drop the dentry
+ * to force a new lookup.
*/
- if (!S_ISDIR(fattr.mode)) {
+ if (fattr.mtime.seconds == (unsigned) -1) {
static int complain = 0;
+ /* N.B. Make this a flag in the superblock */
if (!complain++)
- printk("NFS: buggy server! fattr mode=%x\n",
- fattr.mode);
+ printk("NFS: no fattr after mkdir!\n");
goto drop;
}
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -1109,10 +1110,8 @@
* First check whether the target is busy ... we can't
* safely do _any_ rename if the target is in use.
*/
- if (new_dentry->d_count > 1) {
- if (new_inode && S_ISDIR(new_inode->i_mode))
- shrink_dcache_parent(new_dentry);
- }
+ if (new_dentry->d_count > 1 && !list_empty(&new_dentry->d_subdirs))
+ shrink_dcache_parent(new_dentry);
error = -EBUSY;
if (new_dentry->d_count > 1) {
#ifdef NFS_PARANOIA
@@ -1176,28 +1175,33 @@

do_rename:
/*
- * We must prevent any new references to the target while
- * the rename is in progress, so we unhash the dentry.
+ * To prevent any new references to the target during the rename,
+ * we unhash the dentry and free the inode in advance.
*/
+#ifdef NFS_PARANOIA
+if (new_inode &&
+ new_inode->i_count > (S_ISDIR(new_inode->i_mode) ? 1 : new_inode->i_nlink))
+printk("nfs_rename: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+new_inode->i_count, new_inode->i_nlink);
+#endif
if (!list_empty(&new_dentry->d_hash)) {
d_drop(new_dentry);
rehash = update;
}
+ if (new_inode) {
+ d_delete(new_dentry);
+ }
+
nfs_invalidate_dircache(new_dir);
nfs_invalidate_dircache(old_dir);
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_dentry->d_name.name,
NFS_FH(new_dir), new_dentry->d_name.name);
- if (rehash) {
- d_add(new_dentry, new_inode);
- }
-#ifdef NFS_PARANOIA
-if (new_dentry->d_count > 1)
-printk("nfs_rename: %s/%s busy after rename, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
-#endif
if (!error) {
/* Update the dcache if needed */
+ if (rehash)
+ d_add(new_dentry, NULL);
if (update)
d_move(old_dentry, new_dentry);
}

--------------401B4957292B84C589084EB3--