summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-03 01:22:27 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-03 01:22:27 +0000
commitf9bbe9da79dbc8557c74efeb158b431cd67ace52 (patch)
tree3220d014a35f9d88a48668a1468524e988daebff /fs/nfs
parent3d697109c1ff85ef563aec3d5e113ef225ed2792 (diff)
Upgrade to 2.1.73.
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c75
-rw-r--r--fs/nfs/inode.c16
-rw-r--r--fs/nfs/write.c7
3 files changed, 64 insertions, 34 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c74c73243..aaf17187b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -471,11 +471,11 @@ void nfs_renew_times(struct dentry * dentry)
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 @@ out:
}
/*
+ * 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 @@ inode->i_ino, inode->i_count, inode->i_nlink);
* 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 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
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 @@ out:
*/
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 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
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_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
*/
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 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
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 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
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 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
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 @@ out:
* 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 @@ static int nfs_safe_remove(struct dentry *dentry)
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 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
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);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c070d130b..eb56950eb 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -35,9 +35,6 @@
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
-extern void nfs_invalidate_dircache_sb(struct super_block *);
-extern int check_failed_request(struct inode *);
-
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
@@ -99,8 +96,9 @@ nfs_delete_inode(struct inode * inode)
*/
if (NFS_WRITEBACK(inode) != NULL) {
unsigned long timeout = jiffies + 5*HZ;
- printk("NFS: inode %ld, invalidating pending RPC requests\n",
- inode->i_ino);
+#ifdef NFS_DEBUG_VERBOSE
+printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
+#endif
nfs_invalidate_pages(inode);
while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) {
current->state = TASK_INTERRUPTIBLE;
@@ -112,7 +110,7 @@ nfs_delete_inode(struct inode * inode)
printk("NFS: Arghhh, stuck RPC requests!\n");
}
- failed = check_failed_request(inode);
+ failed = nfs_check_failed_request(inode);
if (failed)
printk("NFS: inode %ld had %d failed requests\n",
inode->i_ino, failed);
@@ -355,8 +353,6 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
* instead of inode number. We use this technique instead of using
* the vfs read_inode function because there is no way to pass the
* file handle or current attributes into the read_inode function.
- * We just have to be careful not to subvert iget's special handling
- * of mount points.
*/
struct inode *
nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
@@ -422,8 +418,10 @@ printk("nfs_fhget: impossible\n");
inode->i_size = fattr->size;
inode->i_mtime = fattr->mtime.seconds;
NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ *NFS_FH(inode) = *fhandle;
}
- *NFS_FH(inode) = *fhandle;
+ if (memcmp(NFS_FH(inode), fhandle, sizeof(struct nfs_fh)))
+ printk("nfs_fhget: fhandle changed!\n");
nfs_refresh_inode(inode, fattr);
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 97663cc11..53c227e58 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -68,8 +68,6 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-int check_failed_request(struct inode *);
-
static void nfs_wback_lock(struct rpc_task *task);
static void nfs_wback_result(struct rpc_task *task);
@@ -331,7 +329,7 @@ remove_failed_request(struct nfs_wreq * req)
* Find and release all failed requests for this inode.
*/
int
-check_failed_request(struct inode * inode)
+nfs_check_failed_request(struct inode * inode)
{
struct nfs_wreq * req;
int found = 0;
@@ -496,8 +494,7 @@ wait_on_write_request(struct nfs_wreq *req)
}
remove_wait_queue(&page->wait, &wait);
current->state = TASK_RUNNING;
- if (atomic_read(&page->count) == 1)
- printk("NFS: page unused while waiting\n");
+ /* N.B. page may have been unused, so we must use free_page() */
free_page(page_address(page));
return retval;
}