[PATCH] vfs: namei operations should pass nameidata when available

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch replaces calls to lookup_hash with calls to __lookup_hash at the
vfs level where complete paths (struct nameidata) are available. 

AF_UNIX sockets also open a complete path terminated with a lookup_hash. Since
it's conceivable for modules to do the same, I've exported __lookup_hash and
made lookup_hash a static inline.

The reason for the change is that I recently reworked subfs to eliminate
rather questionable behavior, such as walking the vfsmount tree lockless and
then caching a pointer. Since the mountpoint is still required to mount the
sub-filesystem, I chose to use nameidata->nd_mnt at ->open or ->lookup. This
led to quick oopsen when any create/remove/rename operation was performed with
the sub-filesystem umounted. This patch supplies the needed data.

This change shouldn't have any effect on the call paths, since the lookup path
for each filesystem is already passed valid nameidata from open_namei in the
existing code. 

Signed-off-by: Jeff Mahoney <[email protected]>

Index: linux-2.6.11/fs/namei.c
===================================================================
--- linux-2.6.11.orig/fs/namei.c
+++ linux-2.6.11/fs/namei.c
@@ -992,7 +992,7 @@ int fastcall path_lookup(const char *nam
  * needs parent already locked. Doesn't follow mounts.
  * SMP-safe.
  */
-static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
+struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
 {
 	struct dentry * dentry;
 	struct inode *inode;
@@ -1031,11 +1031,6 @@ out:
 	return dentry;
 }
 
-struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
-{
-	return __lookup_hash(name, base, NULL);
-}
-
 /* SMP-safe */
 struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
 {
@@ -1519,7 +1519,7 @@ struct dentry *lookup_create(struct name
 	if (nd->last_type != LAST_NORM)
 		goto fail;
 	nd->flags &= ~LOOKUP_PARENT;
-	dentry = lookup_hash(&nd->last, nd->dentry);
+	dentry = __lookup_hash(&nd->last, nd->dentry, nd);
 	if (IS_ERR(dentry))
 		goto fail;
 	if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
@@ -1760,7 +1755,7 @@ asmlinkage long sys_rmdir(const char __u
 			goto exit1;
 	}
 	down(&nd.dentry->d_inode->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = __lookup_hash(&nd.last, nd.dentry, &nd);
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		error = vfs_rmdir(nd.dentry->d_inode, dentry);
@@ -1829,7 +1824,7 @@ asmlinkage long sys_unlink(const char __
 	if (nd.last_type != LAST_NORM)
 		goto exit1;
 	down(&nd.dentry->d_inode->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = __lookup_hash(&nd.last, nd.dentry, &nd);
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		/* Why not before? Because we want correct error value */
@@ -2178,7 +2173,7 @@ static inline int do_rename(const char *
 
 	trap = lock_rename(new_dir, old_dir);
 
-	old_dentry = lookup_hash(&oldnd.last, old_dir);
+	old_dentry = __lookup_hash(&oldnd.last, old_dir, &oldnd);
 	error = PTR_ERR(old_dentry);
 	if (IS_ERR(old_dentry))
 		goto exit3;
@@ -2198,7 +2193,7 @@ static inline int do_rename(const char *
 	error = -EINVAL;
 	if (old_dentry == trap)
 		goto exit4;
-	new_dentry = lookup_hash(&newnd.last, new_dir);
+	new_dentry = __lookup_hash(&newnd.last, new_dir, &oldnd);
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
 		goto exit4;
@@ -2391,7 +2386,7 @@ EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(lock_rename);
-EXPORT_SYMBOL(lookup_hash);
+EXPORT_SYMBOL(__lookup_hash);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link_light);
 EXPORT_SYMBOL(page_put_link);
Index: linux-2.6.11/include/linux/namei.h
===================================================================
--- linux-2.6.11.orig/include/linux/namei.h
+++ linux-2.6.11/include/linux/namei.h
@@ -64,7 +64,11 @@ extern void path_release(struct nameidat
 extern void path_release_on_umount(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+extern struct dentry * __lookup_hash(struct qstr *, struct dentry *, struct nameidata *);
+static inline struct dentry * lookup_hash(struct qstr *name, struct dentry *base)
+{
+	return __lookup_hash(name, base, NULL);
+}
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
Index: linux-2.6.11/net/unix/af_unix.c
===================================================================
--- linux-2.6.11.orig/net/unix/af_unix.c
+++ linux-2.6.11/net/unix/af_unix.c
@@ -776,7 +776,7 @@ static int unix_bind(struct socket *sock
 		/*
 		 * Do the final lookup.
 		 */
-		dentry = lookup_hash(&nd.last, nd.dentry);
+		dentry = __lookup_hash(&nd.last, nd.dentry, &nd);
 		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto out_mknod_unlock;
-- 
Jeff Mahoney
SuSE Labs

Attachment: pgpQLk5RHjsjC.pgp
Description: PGP signature


[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux