patch-2.1.78 linux/fs/nfs/dir.c
Next file: linux/fs/nfs/file.c
Previous file: linux/fs/ncpfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 296
- Date:
Sun Jan 4 01:33:18 1998
- Orig file:
v2.1.77/linux/fs/nfs/dir.c
- Orig date:
Fri Jan 2 14:37:02 1998
diff -u --recursive --new-file v2.1.77/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -64,7 +64,7 @@
static int nfs_rmdir(struct inode *, struct dentry *);
static int nfs_unlink(struct inode *, struct dentry *);
static int nfs_symlink(struct inode *, struct dentry *, const char *);
-static int nfs_link(struct inode *, struct inode *, struct dentry *);
+static int nfs_link(struct dentry *, struct inode *, struct dentry *);
static int nfs_mknod(struct inode *, struct dentry *, int, int);
static int nfs_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
@@ -108,8 +108,11 @@
static int
nfs_dir_open(struct inode *dir, struct file *file)
{
- dfprintk(VFS, "NFS: nfs_dir_open(%x/%ld)\n", dir->i_dev, dir->i_ino);
- return nfs_revalidate_inode(NFS_SERVER(dir), dir);
+ struct dentry *dentry = file->f_dentry;
+
+ dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
}
static ssize_t
@@ -133,7 +136,8 @@
static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
static struct wait_queue *readdir_wait = NULL;
struct wait_queue **waitp = NULL;
struct nfs_dirent *cache, *free;
@@ -144,14 +148,17 @@
__u32 *entry;
char *name, *start;
- dfprintk(VFS, "NFS: nfs_readdir(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ result = -EBADF;
if (!inode || !S_ISDIR(inode->i_mode)) {
printk("nfs_readdir: inode is NULL or not a directory\n");
- return -EBADF;
+ goto out;
}
- if ((result = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0)
- return result;
+ result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ if (result < 0)
+ goto out;
/*
* Try to find the entry in the cache
@@ -250,7 +257,7 @@
goto done;
}
- result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode),
+ result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(dentry),
cookie, PAGE_SIZE, cache->entry);
if (result <= 0)
goto done;
@@ -300,6 +307,7 @@
wake_up(&cache->wait);
wake_up(&readdir_wait);
+out:
return result;
}
@@ -449,11 +457,21 @@
#endif
}
-static struct dentry_operations nfs_dentry_operations = {
+/*
+ * Called when the dentry is being freed to release private memory.
+ */
+static void nfs_dentry_release(struct dentry *dentry)
+{
+ if (dentry->d_fsdata)
+ kfree(dentry->d_fsdata);
+}
+
+struct dentry_operations nfs_dentry_operations = {
nfs_lookup_revalidate, /* d_validate(struct dentry *) */
- 0, /* d_hash */
- 0, /* d_compare */
- nfs_dentry_delete /* d_delete(struct dentry *) */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ nfs_dentry_delete, /* d_delete(struct dentry *) */
+ nfs_dentry_release /* d_release(struct dentry *) */
};
/*
@@ -470,16 +488,20 @@
}
}
+static void nfs_set_fh(struct dentry *dentry, struct nfs_fh *fhandle)
+{
+ *((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
+}
+
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;
- dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
- dir->i_dev, dir->i_ino, len, dentry->d_name.name);
+ dfprintk(VFS, "NFS: lookup(%s/%s)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_lookup: inode is NULL or not a directory\n");
@@ -487,17 +509,26 @@
}
error = -ENAMETOOLONG;
- if (len > NFS_MAXNAMLEN)
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
goto out;
- error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ error = -ENOMEM;
+ if (!dentry->d_fsdata) {
+ dentry->d_fsdata = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+ if (!dentry->d_fsdata)
+ goto out;
+ }
+ dentry->d_op = &nfs_dentry_operations;
+
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &fhandle, &fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
if (!error) {
error = -EACCES;
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ nfs_set_fh(dentry, &fhandle);
+ inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
if (inode) {
#ifdef NFS_PARANOIA
if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink))
@@ -506,7 +537,6 @@
inode->i_ino, inode->i_count, inode->i_nlink);
#endif
no_entry:
- dentry->d_op = &nfs_dentry_operations;
d_add(dentry, inode);
nfs_renew_times(dentry);
error = 0;
@@ -530,6 +560,7 @@
struct inode *inode;
int error = -EACCES;
+ nfs_set_fh(dentry, fhandle);
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode) {
#ifdef NFS_PARANOIA
@@ -578,7 +609,7 @@
* Invalidate the dir cache before the operation to avoid a race.
*/
nfs_invalidate_dircache(dir);
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -616,7 +647,7 @@
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
nfs_invalidate_dircache(dir);
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -652,7 +683,7 @@
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
nfs_invalidate_dircache(dir);
- error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
+ error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
/*
@@ -717,8 +748,8 @@
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);
+ error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
+ dentry->d_name.name);
if (!error) {
if (rehash)
d_add(dentry, NULL);
@@ -839,8 +870,8 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_rename(NFS_SERVER(dir),
- NFS_FH(dir), dentry->d_name.name,
- NFS_FH(dir), silly);
+ NFS_FH(dentry->d_parent), dentry->d_name.name,
+ NFS_FH(dentry->d_parent), silly);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
@@ -914,8 +945,8 @@
d_delete(dentry);
}
nfs_invalidate_dircache(dir);
- error = nfs_proc_remove(NFS_SERVER(dir),
- NFS_FH(dir), dentry->d_name.name);
+ error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
+ dentry->d_name.name);
/*
* Rehash the negative dentry if the operation succeeded.
*/
@@ -998,7 +1029,7 @@
*/
d_drop(dentry);
nfs_invalidate_dircache(dir);
- error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
+ error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, symname, &sattr);
if (!error) {
nfs_renew_times(dentry->d_parent);
@@ -1012,13 +1043,14 @@
}
static int
-nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode = old_dentry->d_inode;
int error;
- dfprintk(VFS, "NFS: link(%x/%ld -> %x/%ld, %s)\n",
- inode->i_dev, inode->i_ino,
- dir->i_dev, dir->i_ino, dentry->d_name.name);
+ dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
+ old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+ dentry->d_parent->d_name.name, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_link: dir is NULL or not a directory\n");
@@ -1029,13 +1061,21 @@
if (dentry->d_name.len > NFS_MAXNAMLEN)
goto out;
+ /*
+ * Drop the dentry in advance to force a new lookup.
+ * Since nfs_proc_link doesn't return a filehandle,
+ * we can't use the existing dentry.
+ */
+ d_drop(dentry);
nfs_invalidate_dircache(dir);
- error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
- dentry->d_name.name);
+ error = nfs_proc_link(NFS_DSERVER(old_dentry), NFS_FH(old_dentry),
+ NFS_FH(dentry->d_parent), dentry->d_name.name);
if (!error) {
- inode->i_count ++;
- inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
- d_instantiate(dentry, inode);
+ /*
+ * Update the link count immediately, as some apps
+ * (e.g. pine) test this after making a link.
+ */
+ inode->i_nlink++;
}
out:
return error;
@@ -1181,9 +1221,9 @@
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);
+ error = nfs_proc_rename(NFS_DSERVER(old_dentry),
+ NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
+ NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
if (!error) {
/* Update the dcache if needed */
if (rehash)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov