patch-2.4.0-test12 linux/fs/nfs/dir.c
Next file: linux/fs/nfs/file.c
Previous file: linux/fs/ncpfs/ncplib_kernel.h
Back to the patch index
Back to the overall index
- Lines: 469
- Date:
Sun Dec 10 09:55:48 2000
- Orig file:
v2.4.0-test11/linux/fs/nfs/dir.c
- Orig date:
Sun Nov 19 18:44:19 2000
diff -u --recursive --new-file v2.4.0-test11/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -63,6 +63,7 @@
rmdir: nfs_rmdir,
mknod: nfs_mknod,
rename: nfs_rename,
+ permission: nfs_permission,
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
@@ -97,6 +98,7 @@
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
+ struct rpc_cred *cred = nfs_file_cred(file);
void *buffer = kmap(page);
int plus = NFS_USE_READDIRPLUS(inode);
int error;
@@ -104,7 +106,7 @@
dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
again:
- error = NFS_PROTO(inode)->readdir(file, desc->entry->cookie, buffer,
+ error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
NFS_SERVER(inode)->dtsize, plus);
/* We requested READDIRPLUS, but the server doesn't grok it */
if (desc->plus && error == -ENOTSUPP) {
@@ -308,6 +310,7 @@
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
u32 *p;
int status = -EIO;
@@ -324,7 +327,7 @@
goto out;
}
p = kmap(page);
- status = NFS_PROTO(inode)->readdir(file, desc->target, p,
+ 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);
@@ -483,16 +486,15 @@
*/
static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
- struct inode * inode = dentry->d_inode;
+ struct inode *dir;
+ struct inode *inode;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
lock_kernel();
- dir = dentry->d_parent;
- dir_i = dir->d_inode;
+ dir = dentry->d_parent->d_inode;
+ inode = dentry->d_inode;
/*
* If we don't have an inode, let's look at the parent
* directory mtime to get a hint about how often we
@@ -506,7 +508,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;
}
@@ -514,15 +516,14 @@
goto out_valid;
if (IS_ROOT(dentry)) {
- __nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ __nfs_revalidate_inode(NFS_SERVER(inode), inode);
goto out_valid_renew;
}
/*
* Do a new lookup and check the dentry attributes.
*/
- error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
- &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -532,13 +533,12 @@
NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
- /* Filehandle matches? */
- if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
- goto out_bad;
-
- /* Ok, remeber that we successfully checked it.. */
+ /* Ok, remember that we successfully checked it.. */
nfs_refresh_inode(inode, &fattr);
+ if (nfs_inode_is_stale(inode, &fhandle, &fattr))
+ goto out_bad;
+
out_valid_renew:
nfs_renew_times(dentry);
out_valid:
@@ -551,7 +551,7 @@
goto out_valid;
d_drop(dentry);
/* Purge readdir caches. */
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
if (inode && S_ISDIR(inode->i_mode))
nfs_zap_caches(inode);
unlock_kernel();
@@ -575,30 +575,6 @@
}
-static kmem_cache_t *nfs_fh_cachep;
-
-__inline__ struct nfs_fh *nfs_fh_alloc(void)
-{
- return kmem_cache_alloc(nfs_fh_cachep, SLAB_KERNEL);
-}
-
-__inline__ void nfs_fh_free(struct nfs_fh *p)
-{
- kmem_cache_free(nfs_fh_cachep, p);
-}
-
-/*
- * Called when the dentry is being freed to release private memory.
- */
-static void nfs_dentry_release(struct dentry *dentry)
-{
- if (dentry->d_fsdata) {
- lock_kernel();
- nfs_fh_free(dentry->d_fsdata);
- unlock_kernel();
- }
-}
-
/*
* Called when the dentry loses inode.
* We use it to clean up silly-renamed files.
@@ -616,35 +592,27 @@
struct dentry_operations nfs_dentry_operations = {
d_revalidate: nfs_lookup_revalidate,
d_delete: nfs_dentry_delete,
- d_release: nfs_dentry_release,
d_iput: nfs_dentry_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;
dfprintk(VFS, "NFS: lookup(%s/%s)\n",
- dir->d_name.name, dentry->d_name.name);
+ 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;
error = -ENOMEM;
- if (!dentry->d_fsdata) {
- dentry->d_fsdata = nfs_fh_alloc();
- if (!dentry->d_fsdata)
- goto out;
- }
dentry->d_op = &nfs_dentry_operations;
- error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
- &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
@@ -686,16 +654,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;
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);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -706,8 +673,8 @@
* select the appropriate create strategy. Currently open_namei
* does not pass the create flags.
*/
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->create(dir, &dentry->d_name,
+ 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);
@@ -719,22 +686,21 @@
/*
* 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;
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);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->mknod(dir, &dentry->d_name, &attr, rdev,
+ 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);
@@ -746,16 +712,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;
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);
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
@@ -769,8 +734,8 @@
*/
d_drop(dentry);
#endif
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
+ 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);
@@ -779,25 +744,23 @@
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;
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_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
return error;
}
-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;
- 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;
char silly[slen+1];
@@ -848,10 +811,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_PROTO(dir_i)->rename(dir, &dentry->d_name, dir, &qsilly);
+ error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
@@ -872,8 +835,7 @@
*/
static int nfs_safe_remove(struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
+ struct inode *dir = dentry->d_parent->d_inode;
struct inode *inode = dentry->d_inode;
int error = -EBUSY, rehash = 0;
@@ -902,10 +864,10 @@
goto out_delete;
}
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
if (inode)
NFS_CACHEINV(inode);
- error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
+ error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
@@ -943,9 +905,8 @@
}
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 iattr attr;
struct nfs_fattr sym_attr;
struct nfs_fh sym_fh;
@@ -954,10 +915,10 @@
int error;
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;
@@ -976,15 +937,15 @@
qsymname.name = symname;
qsymname.len = strlen(symname);
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->symlink(dir, &dentry->d_name, &qsymname,
+ 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 {
if (error == -EEXIST)
printk("nfs_proc_symlink: %s/%s already exists??\n",
- dir->d_name.name, dentry->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
d_drop(dentry);
}
@@ -993,9 +954,8 @@
}
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;
int error;
@@ -1009,9 +969,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_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
+ error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
return error;
}
@@ -1116,10 +1076,8 @@
nfs_zap_caches(new_dir);
nfs_zap_caches(old_dir);
- error = NFS_PROTO(old_dir)->rename(old_dentry->d_parent,
- &old_dentry->d_name,
- new_dentry->d_parent,
- &new_dentry->d_name);
+ error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
+ new_dir, &new_dentry->d_name);
out:
if (rehash)
d_rehash(rehash);
@@ -1132,22 +1090,33 @@
return error;
}
-int nfs_init_fhcache(void)
+int
+nfs_permission(struct inode *inode, int mask)
{
- nfs_fh_cachep = kmem_cache_create("nfs_fh",
- sizeof(struct nfs_fh),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (nfs_fh_cachep == NULL)
- return -ENOMEM;
+ int error = vfs_permission(inode, mask);
- return 0;
-}
+ if (!NFS_PROTO(inode)->access)
+ goto out;
+ /*
+ * Trust UNIX mode bits except:
+ *
+ * 1) When override capabilities may have been invoked
+ * 2) When root squashing may be involved
+ * 3) When ACLs may overturn a negative answer */
+ if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH)
+ && (current->fsuid != 0) && (current->fsgid != 0)
+ && error != -EACCES)
+ goto out;
-void nfs_destroy_fhcache(void)
-{
- if (kmem_cache_destroy(nfs_fh_cachep))
- printk(KERN_INFO "nfs_fh: not all structures were freed\n");
+ error = NFS_PROTO(inode)->access(inode, mask, 0);
+
+ if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv &&
+ current->uid != 0 && current->gid != 0 &&
+ (current->fsuid != current->uid || current->fsgid != current->gid))
+ error = NFS_PROTO(inode)->access(inode, mask, 1);
+
+ out:
+ return error;
}
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)