patch-2.2.19 linux/fs/nfs/dir.c
Next file: linux/fs/nfs/file.c
Previous file: linux/fs/locks.c
Back to the patch index
Back to the overall index
- Lines: 570
- Date:
Sun Mar 25 11:37:38 2001
- Orig file:
v2.2.18/fs/nfs/dir.c
- Orig date:
Sun Mar 25 11:28:33 2001
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -45,6 +45,7 @@
static int nfs_safe_remove(struct dentry *);
static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
+static loff_t nfs_dir_llseek(struct file *, loff_t, int);
static int nfs_readdir(struct file *, void *, filldir_t);
static struct dentry *nfs_lookup(struct inode *, struct dentry *);
static int nfs_create(struct inode *, struct dentry *, int);
@@ -58,7 +59,7 @@
struct inode *, struct dentry *);
static struct file_operations nfs_dir_operations = {
- NULL, /* lseek - default */
+ nfs_dir_llseek, /* llseek */
nfs_dir_read, /* read - bad */
NULL, /* write - bad */
nfs_readdir, /* readdir */
@@ -131,7 +132,7 @@
struct file *file = desc->file;
struct dentry *dir = file->f_dentry;
struct inode *inode = dir->d_inode;
- struct nfs_fattr dir_attr;
+ struct rpc_cred *cred = nfs_file_cred(file);
void *buffer = (void *)page_address(page);
int plus = NFS_USE_READDIRPLUS(inode);
int error;
@@ -139,11 +140,9 @@
dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->offset);
again:
- error = NFS_CALL(readdir, inode, (dir, &dir_attr,
- nfs_file_cred(file),
+ error = NFS_PROTO(inode)->readdir(inode, cred,
desc->entry->cookie, buffer,
- NFS_SERVER(inode)->dtsize, plus));
- nfs_refresh_inode(inode, &dir_attr);
+ NFS_SERVER(inode)->dtsize, plus);
/* We requested READDIRPLUS, but the server doesn't grok it */
if (desc->plus && error == -ENOTSUPP) {
NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
@@ -339,7 +338,7 @@
struct file *file = desc->file;
struct dentry *dir = file->f_dentry;
struct inode *inode = dir->d_inode;
- struct nfs_fattr dir_attr;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
unsigned long cache_page;
u32 *p;
@@ -358,11 +357,8 @@
}
page = page_cache_entry(cache_page);
p = (u32 *)page_address(page);
- status = NFS_CALL(readdir, inode, (dir, &dir_attr,
- nfs_file_cred(file),
- desc->target, p,
- NFS_SERVER(inode)->dtsize, 0));
- nfs_refresh_inode(inode, &dir_attr);
+ status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p,
+ NFS_SERVER(inode)->dtsize, 0);
if (status >= 0) {
p = desc->decode(p, desc->entry, 0);
if (IS_ERR(p))
@@ -452,6 +448,22 @@
return 0;
}
+/*
+ * nfs_dir_llseek(): cater for the fact that NFS(v2|v3) readdir
+ * cookies take (32|64)-bit unsigned values.
+ */
+static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+ /* We disallow SEEK_CUR and SEEK_END */
+ if (origin != 0)
+ return -EINVAL;
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_reada = 0;
+ file->f_version = ++global_event;
+ }
+ return (offset > 0) ? offset : 0;
+}
/*
* Whenever an NFS operation succeeds, we know that the dentry
@@ -521,11 +533,10 @@
*/
static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
- struct dentry *dir = dentry->d_parent;
- struct inode *inode = dentry->d_inode,
- *dir_i = dir->d_inode;
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct inode *inode = dentry->d_inode;
struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_attr;
+ struct nfs_fattr fattr;
int error;
/*
@@ -541,7 +552,7 @@
if (is_bad_inode(inode)) {
dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
- dir->d_name.name, dentry->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out_bad;
}
@@ -549,7 +560,7 @@
goto out_valid;
if (IS_ROOT(dentry)) {
- __nfs_revalidate_inode(dentry);
+ __nfs_revalidate_inode(NFS_SERVER(inode), inode);
goto out_valid_renew;
}
@@ -559,8 +570,7 @@
/*
* Do a new lookup and check the dentry attributes.
*/
- error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
- &dentry->d_name, &fhandle, &fattr));
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error < 0)
goto out_bad;
@@ -570,18 +580,12 @@
NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
- /* Filehandle matches? */
- if (NFS_FH(dentry)->size == 0)
- goto out_bad;
+ /* Ok, remember that we successfully checked it.. */
+ nfs_refresh_inode(inode, &fattr);
- if (NFS_FH(dentry)->size != fhandle.size ||
- memcmp(NFS_FH(dentry)->data, fhandle.data, fhandle.size))
+ if (nfs_inode_is_stale(inode, &fhandle, &fattr))
goto out_bad;
- /* Ok, remeber that we successfully checked it.. */
- nfs_refresh_inode(inode, &fattr);
- nfs_refresh_inode(dir_i, &dir_attr);
-
out_valid_renew:
nfs_renew_times(dentry);
out_valid:
@@ -593,10 +597,9 @@
if (have_submounts(dentry))
goto out_valid;
d_drop(dentry);
- if (dentry->d_parent->d_inode)
- NFS_CACHEINV(dentry->d_parent->d_inode);
+ nfs_zap_caches(dir);
if (inode && S_ISDIR(inode->i_mode))
- NFS_CACHEINV(inode);
+ nfs_zap_caches(inode);
return 0;
}
@@ -611,33 +614,6 @@
}
}
-__inline__ struct nfs_fh *nfs_fh_alloc(void)
-{
- struct nfs_fh *p;
-
- p = kmalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return NULL;
- memset(p, 0, sizeof(*p));
- return p;
-}
-
-__inline__ void nfs_fh_free(struct nfs_fh *p)
-{
- kfree(p);
-}
-
-/*
- * Called when the dentry is being freed to release private memory.
- */
-static void nfs_dentry_release(struct dentry *dentry)
-{
- if (dentry->d_fsdata) {
- nfs_fh_free(dentry->d_fsdata);
- dentry->d_fsdata = NULL;
- }
-}
-
/*
* Called when the dentry loses inode.
* We use it to clean up silly-renamed files.
@@ -654,44 +630,33 @@
NULL, /* d_hash */
NULL, /* d_compare */
nfs_dentry_delete, /* d_delete(struct dentry *) */
- nfs_dentry_release, /* d_release(struct dentry *) */
+ NULL, /* d_release(struct dentry *) */
nfs_dentry_iput /* d_iput */
};
-static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
{
- struct dentry *dir = dentry->d_parent;
struct inode *inode;
int error;
struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_attr;
+ struct nfs_fattr fattr;
dfprintk(VFS, "NFS: lookup(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
+ if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
goto out;
dentry->d_op = &nfs_dentry_operations;
- if (!dentry->d_fsdata) {
- dentry->d_fsdata = nfs_fh_alloc();
- if (!dentry->d_fsdata) {
- error = -ENOMEM;
- goto out;
- }
- }
-
#if NFS_FIXME
inode = nfs_dircache_lookup(dir_i, dentry);
if (inode)
goto no_entry;
#endif
- error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
- &dentry->d_name, &fhandle, &fattr));
- nfs_refresh_inode(dir_i, &dir_attr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
@@ -734,16 +699,15 @@
* 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_i, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
- struct nfs_fattr fattr, dir_attr;
+ struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
#ifdef NFSD_BROKEN_UID
/* We set uid/gid in the request because IBM's broken nfsd
@@ -767,10 +731,9 @@
* select the appropriate create strategy. Currently open_namei
* does not pass the create flags.
*/
- nfs_zap_caches(dir_i);
- error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name,
- &attr, 0, &fhandle, &fattr));
- nfs_refresh_inode(dir_i, &dir_attr);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
+ &attr, 0, &fhandle, &fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error || fhandle.size == 0)
@@ -781,16 +744,15 @@
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
- struct nfs_fattr fattr, dir_attr;
+ struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
#ifdef NFSD_BROKEN_UID
attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -803,10 +765,9 @@
#endif
- nfs_zap_caches(dir_i);
- error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name,
- &attr, rdev, &fhandle, &fattr));
- nfs_refresh_inode(dir_i, &dir_attr);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name,
+ &attr, rdev, &fhandle, &fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error || fhandle.size == 0)
@@ -817,16 +778,15 @@
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
- struct nfs_fattr fattr, dir_attr;
+ struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s)\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
#ifdef NFSD_BROKEN_UID
attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -838,10 +798,8 @@
attr.ia_mode = mode | S_IFDIR;
#endif
- nfs_zap_caches(dir_i);
- error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr,
- &dentry->d_name, &attr, &fhandle, &fattr));
- nfs_refresh_inode(dir_i, &dir_attr);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -850,18 +808,15 @@
return error;
}
-static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
- struct nfs_fattr dir_attr;
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- nfs_zap_caches(dir_i);
- error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name));
- nfs_refresh_inode(dir_i, &dir_attr);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Free the inode */
if (!error)
@@ -925,12 +880,10 @@
return sdentry;
}
-static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
static unsigned int sillycounter = 0;
- struct nfs_fattr dir_attr;
- const int i_inosize = sizeof(dir_i->i_ino)*2;
+ const int i_inosize = sizeof(dir->i_ino)*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = strlen(".nfs") + i_inosize + countersize;
struct qstr qsilly;
@@ -985,12 +938,10 @@
goto out;
} while(sdentry->d_inode != NULL); /* need negative lookup */
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
qsilly.name = silly;
qsilly.len = strlen(silly);
- error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name,
- dir, &dir_attr, &qsilly));
- nfs_refresh_inode(dir_i, &dir_attr);
+ error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
@@ -1011,9 +962,7 @@
*/
static int nfs_safe_remove(struct dentry *dentry)
{
- struct nfs_fattr dir_attr;
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode,
+ struct inode *dir = dentry->d_parent->d_inode,
*inode = dentry->d_inode;
int error = 0, rehash = 0;
@@ -1049,11 +998,10 @@
goto out;
}
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
if (inode)
NFS_CACHEINV(inode);
- error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name));
- nfs_refresh_inode(dir_i, &dir_attr);
+ error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
@@ -1096,20 +1044,19 @@
}
static int
-nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- struct dentry *dir = dentry->d_parent;
- struct nfs_fattr dir_attr, sym_attr;
+ struct nfs_fattr sym_attr;
struct nfs_fh sym_fh;
struct iattr attr;
struct qstr qsymname;
int error, mode, maxlen;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
+ dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
error = -ENAMETOOLONG;
- maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+ maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
if (strlen(symname) > maxlen)
goto out;
@@ -1137,11 +1084,9 @@
qsymname.name = symname;
qsymname.len = strlen(symname);
- nfs_zap_caches(dir_i);
- error = NFS_CALL(symlink, dir_i, (dir, &dir_attr,
- &dentry->d_name, &qsymname, &attr,
- &sym_fh, &sym_attr));
- nfs_refresh_inode(dir_i, &dir_attr);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
+ &attr, &sym_fh, &sym_attr);
if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
} else {
@@ -1157,11 +1102,9 @@
}
static int
-nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
struct inode *inode = old_dentry->d_inode;
- struct nfs_fattr old_attr, dir_attr;
int error;
dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
@@ -1174,12 +1117,9 @@
* we can't use the existing dentry.
*/
d_drop(dentry);
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
NFS_CACHEINV(inode);
- error = NFS_CALL(link, inode, (old_dentry, &old_attr,
- dir, &dir_attr, &dentry->d_name));
- nfs_refresh_inode(inode, &old_attr);
- nfs_refresh_inode(dir_i, &dir_attr);
+ error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
return error;
}
@@ -1214,7 +1154,6 @@
static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct nfs_fattr old_attr, new_attr;
struct inode * old_inode = old_dentry->d_inode;
struct inode * new_inode = new_dentry->d_inode;
struct dentry * dentry = NULL, *rehash = NULL;
@@ -1296,12 +1235,8 @@
nfs_zap_caches(new_dir);
nfs_zap_caches(old_dir);
- error = NFS_CALL(rename, old_dir,
- (old_dentry->d_parent, &old_attr, &old_dentry->d_name,
- new_dentry->d_parent, &new_attr, &new_dentry->d_name));
- nfs_refresh_inode(old_dir, &old_attr);
- nfs_refresh_inode(new_dir, &new_attr);
-
+ error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
+ new_dir, &new_dentry->d_name);
out:
/* Update the dcache if needed */
if (rehash)
@@ -1315,14 +1250,11 @@
}
int
-nfs_permission(struct inode *i, int msk)
+nfs_permission(struct inode *inode, int mask)
{
- struct nfs_fattr fattr;
- struct dentry *de = NULL;
- int err = vfs_permission(i, msk);
- struct list_head *start, *tmp;
+ int error = vfs_permission(inode, mask);
- if (!NFS_PROTO(i)->access)
+ if (!NFS_PROTO(inode)->access)
goto out;
/*
* Trust UNIX mode bits except:
@@ -1332,28 +1264,18 @@
* 3) When ACLs may overturn a negative answer */
if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH)
&& (current->fsuid != 0) && (current->fsgid != 0)
- && err != -EACCES)
+ && error != -EACCES)
goto out;
- tmp = start = &i->i_dentry;
- while ((tmp = tmp->next) != start) {
- de = list_entry(tmp, struct dentry, d_alias);
- if (de->d_inode == i)
- break;
- }
- if (!de || de->d_inode != i)
- return 0;
+ error = NFS_PROTO(inode)->access(inode, mask, 0);
- err = NFS_CALL(access, i, (de, msk, &fattr, 0));
-
- if (err == -EACCES && NFS_CLIENT(i)->cl_droppriv &&
+ if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv &&
current->uid != 0 && current->gid != 0 &&
(current->fsuid != current->uid || current->fsgid != current->gid))
- err = NFS_CALL(access, i, (de, msk, &fattr, 1));
+ error = NFS_PROTO(inode)->access(inode, mask, 1);
- nfs_refresh_inode(i, &fattr);
out:
- return err;
+ return error;
}
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)