patch-2.1.73 linux/fs/nfs/dir.c
Next file: linux/fs/nfs/inode.c
Previous file: linux/fs/namei.c
Back to the patch index
Back to the overall index
- Lines: 183
- Date:
Fri Dec 12 09:17:09 1997
- Orig file:
v2.1.72/linux/fs/nfs/dir.c
- Orig date:
Wed Dec 10 11:12:44 1997
diff -u --recursive --new-file v2.1.72/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -471,11 +471,11 @@
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
+ int len = dentry->d_name.len;
struct inode *inode;
+ int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- int len = dentry->d_name.len;
- int error;
dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
dir->i_dev, dir->i_ino, len, dentry->d_name.name);
@@ -516,10 +516,38 @@
}
/*
+ * Attempt to patch up certain errors following a create or
+ * mkdir operation. We clear the original error if the new
+ * lookup succeeds and has the correct mode.
+ */
+static int nfs_fixup(struct inode *dir, struct dentry *dentry, int mode,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr, int error)
+{
+ int newerr;
+
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: %s/%s, error=%d, mode=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error, mode);
+#endif
+ if (error == -EEXIST) {
+ newerr = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, fhandle, fattr);
+ if (!newerr) {
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: lookup OK, got mode=%x, want mode=%x\n", fattr->mode, mode);
+#endif
+ if ((fattr->mode & S_IFMT) == (mode & S_IFMT))
+ error = 0;
+ }
+ }
+ return error;
+}
+
+/*
* Code common to create, mkdir, and mknod.
*/
-static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr,
- struct nfs_fh *fhandle)
+static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
struct inode *inode;
int error = -EACCES;
@@ -545,12 +573,12 @@
* that the operation succeeded on the server, but an error in the
* reply path made it appear to have failed.
*/
-static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -574,9 +602,11 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error)
+ error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error)
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- else
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ if (error)
d_drop(dentry);
out:
return error;
@@ -587,10 +617,10 @@
*/
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -612,9 +642,11 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error)
+ error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error)
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- else
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ if (error)
d_drop(dentry);
return error;
}
@@ -624,10 +656,10 @@
*/
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -640,6 +672,8 @@
if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
+ /* For some reason mode doesn't have the S_IFDIR flag ... */
+ mode |= S_IFDIR;
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -647,6 +681,8 @@
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_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error) {
/*
* Some AIX servers reportedly fail to fill out the fattr.
@@ -660,8 +696,9 @@
fattr.mode);
goto drop;
}
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- } else {
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ }
+ if (error) {
drop:
d_drop(dentry);
}
@@ -858,11 +895,8 @@
* Remove a file after making sure there are no pending writes,
* and after checking that the file has only one user.
*
- * Updating inode->i_nlink here rather than waiting for the next
- * nfs_refresh_inode() is not merely cosmetic; once an object has
- * been deleted, we want to get rid of the inode locally. The NFS
- * server may reuse the fileid for a new inode, and we don't want
- * that to be confused with this inode.
+ * 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_safe_remove(struct dentry *dentry)
{
@@ -870,6 +904,7 @@
struct inode *inode = dentry->d_inode;
int error, rehash = 0;
+ /* N.B. not needed now that d_delete is done in advance? */
error = -EBUSY;
if (inode) {
if (NFS_WRITEBACK(inode)) {
@@ -897,7 +932,7 @@
goto out;
}
#ifdef NFS_PARANOIA
-if (inode && inode->i_count > 1)
+if (inode && inode->i_count > inode->i_nlink)
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);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov