patch-2.1.72 linux/fs/nfs/dir.c
Next file: linux/fs/nfsd/lockd.c
Previous file: linux/fs/namei.c
Back to the patch index
Back to the overall index
- Lines: 209
- Date:
Sat Dec 6 11:23:06 1997
- Orig file:
v2.1.71/linux/fs/nfs/dir.c
- Orig date:
Thu Dec 4 14:53:56 1997
diff -u --recursive --new-file v2.1.71/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -498,6 +498,12 @@
error = -EACCES;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
if (inode) {
+#ifdef NFS_PARANOIA
+if (inode->i_count > 1)
+printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+#endif
no_entry:
dentry->d_op = &nfs_dentry_operations;
d_add(dentry, inode);
@@ -512,14 +518,20 @@
/*
* Code common to create, mkdir, and mknod.
*/
-static int nfs_instantiate(struct inode *dir, struct dentry *dentry,
- struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle)
{
struct inode *inode;
int error = -EACCES;
- inode = nfs_fhget(dir->i_sb, fhandle, fattr);
+ inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode) {
+#ifdef NFS_PARANOIA
+if (inode->i_count > 1)
+printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+#endif
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
error = 0;
@@ -563,14 +575,9 @@
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_create: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ else
d_drop(dentry);
- }
out:
return error;
}
@@ -606,14 +613,9 @@
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_mknod: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ else
d_drop(dentry);
- }
return error;
}
@@ -645,13 +647,22 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
- if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_mkdir: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ 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 (!S_ISDIR(fattr.mode)) {
+ static int complain = 0;
+ if (!complain++)
+ printk("NFS: buggy server! fattr mode=%x\n",
+ fattr.mode);
+ goto drop;
+ }
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ } else {
+ drop:
d_drop(dentry);
}
return error;
@@ -662,12 +673,12 @@
* use count prior to the operation, and return EBUSY if it has
* multiple users.
*
- * Update inode->i_nlink immediately after a successful operation.
- * (See comments for nfs_unlink.)
+ * We update inode->i_nlink and free the inode prior to the operation
+ * to avoid possible races if the server reuses the inode.
*/
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
- int error;
+ int error, rehash = 0;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -688,13 +699,31 @@
if (dentry->d_count > 1)
goto out;
}
- /* Drop the dentry to force a new lookup */
- d_drop(dentry);
- error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+#ifdef NFS_PARANOIA
+if (dentry->d_inode->i_count > 1)
+printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+dentry->d_inode->i_count, dentry->d_inode->i_nlink);
+#endif
+ /*
+ * Unhash the dentry while we remove the directory.
+ */
+ if (!list_empty(&dentry->d_hash)) {
+ d_drop(dentry);
+ rehash = 1;
+ }
+ /*
+ * Update i_nlink and free the inode before unlinking.
+ */
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ d_delete(dentry);
+ nfs_invalidate_dircache(dir);
+ error = nfs_proc_rmdir(NFS_SERVER(dir),
+ NFS_FH(dir), dentry->d_name.name);
if (!error) {
- if (dentry->d_inode->i_nlink)
- dentry->d_inode->i_nlink --;
- nfs_invalidate_dircache(dir);
+ if (rehash)
+ d_add(dentry, NULL);
nfs_renew_times(dentry);
}
out:
@@ -867,6 +896,12 @@
#endif
goto out;
}
+#ifdef NFS_PARANOIA
+if (inode && inode->i_count > 1)
+printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_count, inode->i_nlink);
+#endif
/*
* Unhash the dentry while we remove the file ...
*/
@@ -874,29 +909,22 @@
d_drop(dentry);
rehash = 1;
}
- error = nfs_proc_remove(NFS_SERVER(dir),
- NFS_FH(dir), dentry->d_name.name);
/*
- * ... then restore the hashed state. This ensures that the
- * dentry can't become busy after having its file deleted.
+ * Update i_nlink and free the inode before unlinking.
*/
- if (rehash) {
- d_add(dentry, inode);
- }
-#ifdef NFS_PARANOIA
-if (dentry->d_count > 1)
-printk("nfs_safe_remove: %s/%s busy after delete?? d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-if (inode && inode->i_count > 1)
-printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
-#endif
- if (!error) {
- nfs_invalidate_dircache(dir);
- if (inode && inode->i_nlink)
+ if (inode) {
+ if (inode->i_nlink)
inode->i_nlink --;
d_delete(dentry);
}
+ nfs_invalidate_dircache(dir);
+ error = nfs_proc_remove(NFS_SERVER(dir),
+ NFS_FH(dir), dentry->d_name.name);
+ /*
+ * Rehash the negative dentry if the operation succeeded.
+ */
+ if (!error && rehash)
+ d_add(dentry, NULL);
out:
return error;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov