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

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)