diff mbox

[03/13] VFS: remove nameidata args from ->follow_link and ->put_link

Message ID 20150316044319.23648.2840.stgit@notabene.brown (mailing list archive)
State New, archived
Headers show

Commit Message

NeilBrown March 16, 2015, 4:43 a.m. UTC
Now that current->nameidata is available, nd_set_link() and
nd_get_link() can use that directly, so 'nd' doesn't need to
be passed through ->follow_link and  ->put_link.

->follow_link gains a 'flags' argument instead which will
be useful for adding RCU-walk support.
For now, any filesystem which cannot trivially handle RCU-walk
support simply returns -ECHILD if LOOKUP_RCU is set in 'flags'.

security_inode_follow_link() all gets 'flags' in place of 'nd',
as does the inode_follow_link() security_op.

As a result of this change, 'nameidata' is almost entirely
local to namei.c.  It is only exposed externally as an opaque struct
pointed to by current->nameidata.

Note: Documentation/filesystemd/automount-support.txt mentions
 nameidata in ways that have been wrong for a while and are still
 wrong.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 Documentation/filesystems/Locking               |    4 +--
 Documentation/filesystems/automount-support.txt |    3 ++
 Documentation/filesystems/porting               |    5 +++
 Documentation/filesystems/vfs.txt               |    4 +--
 drivers/staging/lustre/lustre/llite/symlink.c   |    8 +++--
 fs/9p/v9fs.h                                    |    3 +-
 fs/9p/vfs_inode.c                               |   13 ++++----
 fs/9p/vfs_inode_dotl.c                          |    8 +++--
 fs/autofs4/symlink.c                            |    4 +--
 fs/befs/linuxvfs.c                              |   14 ++++-----
 fs/ceph/inode.c                                 |    4 +--
 fs/cifs/cifsfs.h                                |    2 +
 fs/cifs/link.c                                  |    6 ++--
 fs/configfs/symlink.c                           |   11 +++----
 fs/debugfs/file.c                               |    4 +--
 fs/ecryptfs/inode.c                             |    8 ++---
 fs/exofs/symlink.c                              |    4 +--
 fs/ext2/symlink.c                               |    4 +--
 fs/ext3/symlink.c                               |    4 +--
 fs/ext4/symlink.c                               |    4 +--
 fs/freevxfs/vxfs_immed.c                        |    8 +++--
 fs/fuse/dir.c                                   |   10 +++---
 fs/gfs2/inode.c                                 |   10 +++---
 fs/hostfs/hostfs_kern.c                         |   10 +++---
 fs/hppfs/hppfs.c                                |    9 +++---
 fs/jffs2/symlink.c                              |    6 ++--
 fs/jfs/symlink.c                                |    4 +--
 fs/kernfs/symlink.c                             |   11 +++----
 fs/libfs.c                                      |    5 +--
 fs/namei.c                                      |   36 +++++++++++++----------
 fs/nfs/symlink.c                                |    8 +++--
 fs/ntfs/namei.c                                 |    1 -
 fs/overlayfs/inode.c                            |   12 ++++----
 fs/proc/base.c                                  |    6 ++--
 fs/proc/inode.c                                 |    6 ++--
 fs/proc/namespaces.c                            |    6 ++--
 fs/proc/self.c                                  |    6 ++--
 fs/proc/thread_self.c                           |    6 ++--
 fs/sysv/symlink.c                               |    4 +--
 fs/ubifs/file.c                                 |    4 +--
 fs/ufs/symlink.c                                |    4 +--
 fs/xfs/xfs_iops.c                               |    8 +++--
 include/linux/fs.h                              |   12 +++-----
 include/linux/namei.h                           |    7 ++--
 include/linux/sched.h                           |    1 +
 include/linux/security.h                        |    9 +++---
 mm/shmem.c                                      |   14 ++++-----
 security/capability.c                           |    2 +
 security/security.c                             |    4 +--
 security/selinux/hooks.c                        |    2 +
 50 files changed, 175 insertions(+), 173 deletions(-)



--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Al Viro March 16, 2015, 8:47 p.m. UTC | #1
On Mon, Mar 16, 2015 at 03:43:19PM +1100, NeilBrown wrote:
> Now that current->nameidata is available, nd_set_link() and
> nd_get_link() can use that directly, so 'nd' doesn't need to
> be passed through ->follow_link and  ->put_link.

FWIW, I would rather pass nd_get_link(nd) to ->put_link() instead of nd.
Note that that's the only thing instances were ever using nd for; what's more,
that's the only thing nd_get_link() is ever used for outside of fs/namei.c,
so with that change it could become static in fs/namei.c.  After such change
we would have it used in
	* follow_link().  We have nd right there.
	* put_link().  Ditto.
	* generic_readlink().  Again, nd is right there (and we obviously
only need to call nd_get_link() once).
Hell, it can even become static inline...

>  	nd->last_type = LAST_BIND;
> -	*p = dentry->d_inode->i_op->follow_link(dentry, nd);
> +	*p = dentry->d_inode->i_op->follow_link(dentry, nd->flags);

I'm not sure if it's a good idea to expose all flags here - it's really
asking for somebody trying to be "smart" and acting differently depending
on what we are doing pathname resolution for/where in lookup we are/etc.
nd->flags & LOOKUP_RCU might be less tempting.

> @@ -4458,13 +4464,13 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
>  	int res;
>  
>  	nd.depth = 0;
> -	cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
> +	cookie = dentry->d_inode->i_op->follow_link(dentry, nd.flags);

...(dentry, 0);  nd.flags is uninitialized, for pity sake...
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index f91926f2f482..8a772d4bb51f 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -50,8 +50,8 @@  prototypes:
 	int (*rename2) (struct inode *, struct dentry *,
 			struct inode *, struct dentry *, unsigned int);
 	int (*readlink) (struct dentry *, char __user *,int);
-	void * (*follow_link) (struct dentry *, struct nameidata *);
-	void (*put_link) (struct dentry *, struct nameidata *, void *);
+	void * (*follow_link) (struct dentry *, int flags);
+	void (*put_link) (struct dentry *, void *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, unsigned int);
 	int (*get_acl)(struct inode *, int);
diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt
index 7cac200e2a85..b68370fcc8f8 100644
--- a/Documentation/filesystems/automount-support.txt
+++ b/Documentation/filesystems/automount-support.txt
@@ -8,6 +8,9 @@  requested. The latter can also be requested by userspace.
 IN-KERNEL AUTOMOUNTING
 ======================
 
+THE FOLLOWING IS WRONG AND NEED TO BE UPDATED
+
+
 A filesystem can now mount another filesystem on one of its directories by the
 following procedure:
 
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index fa2db081505e..d6d228d54993 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -471,3 +471,8 @@  in your dentry operations instead.
 [mandatory]
 	f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid
 	it entirely.
+--
+[mandatory]
+	->follow_link and ->put_link no longer receive 'struct nameidata *'.
+	->follow_link receives flags which may contains LOOKUP_RCU.
+	When that is set code must not block, but can return -ECHILD.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 966b22829f3b..a813af5ee097 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -350,8 +350,8 @@  struct inode_operations {
 	int (*rename2) (struct inode *, struct dentry *,
 			struct inode *, struct dentry *, unsigned int);
 	int (*readlink) (struct dentry *, char __user *,int);
-        void * (*follow_link) (struct dentry *, struct nameidata *);
-        void (*put_link) (struct dentry *, struct nameidata *, void *);
+        void * (*follow_link) (struct dentry *, int flags);
+        void (*put_link) (struct dentry *, void *);
 	int (*permission) (struct inode *, int);
 	int (*get_acl)(struct inode *, int);
 	int (*setattr) (struct dentry *, struct iattr *);
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index e8a8d25fcabf..e1f4ef3356ae 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -118,14 +118,14 @@  failed:
 	return rc;
 }
 
-static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ll_follow_link(struct dentry *dentry, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	struct ptlrpc_request *request = NULL;
 	int rc;
 	char *symname = NULL;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	CDEBUG(D_VFSTRACE, "VFS Op\n");
@@ -139,14 +139,14 @@  static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
 		symname = ERR_PTR(rc);
 	}
 
-	nd_set_link(nd, symname);
+	nd_set_link(symname);
 	/* symname may contain a pointer to the request message buffer,
 	 * we delay request releasing until ll_put_link then.
 	 */
 	return request;
 }
 
-static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+static void ll_put_link(struct dentry *dentry, void *cookie)
 {
 	ptlrpc_req_finished(cookie);
 }
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 099c7712631c..b50310bf5bac 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -150,8 +150,7 @@  extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry);
-extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd,
-			void *p);
+extern void v9fs_vfs_put_link(struct dentry *dentry, void *p);
 extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
 					 struct p9_fid *fid,
 					 struct super_block *sb, int new);
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8aff5d684154..f3bc0640dd4c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1274,16 +1274,16 @@  done:
 /**
  * v9fs_vfs_follow_link - follow a symlink path
  * @dentry: dentry for symlink
- * @nd: nameidata
+ * @flags: lookup flags
  *
  */
 
-static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *v9fs_vfs_follow_link(struct dentry *dentry, int flags)
 {
 	int len = 0;
 	char *link;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	link = __getname();
 
@@ -1300,7 +1300,7 @@  static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 		} else
 			link[min(len, PATH_MAX-1)] = 0;
 	}
-	nd_set_link(nd, link);
+	nd_set_link(link);
 
 	return NULL;
 }
@@ -1308,15 +1308,14 @@  static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 /**
  * v9fs_vfs_put_link - release a symlink path
  * @dentry: dentry for symlink
- * @nd: nameidata
  * @p: unused
  *
  */
 
 void
-v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
+v9fs_vfs_put_link(struct dentry *dentry, void *p)
 {
-	char *s = nd_get_link(nd);
+	char *s = nd_get_link();
 
 	p9_debug(P9_DEBUG_VFS, " %pd %s\n",
 		 dentry, IS_ERR(s) ? "<error>" : s);
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 51776a3cc842..5862720911aa 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -905,19 +905,19 @@  error:
 /**
  * v9fs_vfs_follow_link_dotl - follow a symlink path
  * @dentry: dentry for symlink
- * @nd: nameidata
+ * @flags: lookup flags
  *
  */
 
 static void *
-v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
+v9fs_vfs_follow_link_dotl(struct dentry *dentry, int flags)
 {
 	int retval;
 	struct p9_fid *fid;
 	char *link;
 	char *target;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	link = __getname();
 	p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
@@ -941,7 +941,7 @@  v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
 	__putname(link);
 	link = ERR_PTR(retval);
 ndset:
-	nd_set_link(nd, link);
+	nd_set_link(link);
 	return NULL;
 }
 
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
index 1e8ea192be2b..311f176708ae 100644
--- a/fs/autofs4/symlink.c
+++ b/fs/autofs4/symlink.c
@@ -12,13 +12,13 @@ 
 
 #include "autofs_i.h"
 
-static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *autofs4_follow_link(struct dentry *dentry, int flags)
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 	if (ino && !autofs4_oz_mode(sbi))
 		ino->last_used = jiffies;
-	nd_set_link(nd, dentry->d_inode->i_private);
+	nd_set_link(dentry->d_inode->i_private);
 	return NULL;
 }
 
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index bbe8f90924b2..b129966e7277 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -42,8 +42,8 @@  static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
 static void befs_destroy_inodecache(void);
-static void *befs_follow_link(struct dentry *, struct nameidata *);
-static void *befs_fast_follow_link(struct dentry *, struct nameidata *);
+static void *befs_follow_link(struct dentry *, int);
+static void *befs_fast_follow_link(struct dentry *, int);
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@@ -469,7 +469,7 @@  befs_destroy_inodecache(void)
  * flag is set.
  */
 static void *
-befs_follow_link(struct dentry *dentry, struct nameidata *nd)
+befs_follow_link(struct dentry *dentry, int flags)
 {
 	struct super_block *sb = dentry->d_sb;
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
@@ -477,7 +477,7 @@  befs_follow_link(struct dentry *dentry, struct nameidata *nd)
 	befs_off_t len = data->size;
 	char *link;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	if (len == 0) {
 		befs_error(sb, "Long symlink with illegal length");
@@ -496,16 +496,16 @@  befs_follow_link(struct dentry *dentry, struct nameidata *nd)
 			link[len - 1] = '\0';
 		}
 	}
-	nd_set_link(nd, link);
+	nd_set_link(link);
 	return NULL;
 }
 
 
 static void *
-befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd)
+befs_fast_follow_link(struct dentry *dentry, int flags)
 {
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
-	nd_set_link(nd, befs_ino->i_data.symlink);
+	nd_set_link(befs_ino->i_data.symlink);
 	return NULL;
 }
 
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 119c43c80638..ceaa82d3a157 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1691,10 +1691,10 @@  retry:
 /*
  * symlinks
  */
-static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ceph_sym_follow_link(struct dentry *dentry, int flags)
 {
 	struct ceph_inode_info *ci = ceph_inode(dentry->d_inode);
-	nd_set_link(nd, ci->i_symlink);
+	nd_set_link(ci->i_symlink);
 	return NULL;
 }
 
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 252f5c15806b..f40f664a8c51 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -120,7 +120,7 @@  extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
 #endif
 
 /* Functions related to symlinks */
-extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
+extern void *cifs_follow_link(struct dentry *direntry, int flags);
 extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
 			 int buflen);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 0dbe1a326632..148a9b54669f 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -627,7 +627,7 @@  cifs_hl_exit:
 }
 
 void *
-cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
+cifs_follow_link(struct dentry *direntry, int flags)
 {
 	struct inode *inode = direntry->d_inode;
 	int rc = -ENOMEM;
@@ -639,7 +639,7 @@  cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	xid = get_xid();
 
@@ -681,7 +681,7 @@  out:
 	free_xid(xid);
 	if (tlink)
 		cifs_put_tlink(tlink);
-	nd_set_link(nd, target_path);
+	nd_set_link(target_path);
 	return NULL;
 }
 
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index 1397342aad5b..a83685894e1c 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -279,12 +279,12 @@  static int configfs_getlink(struct dentry *dentry, char * path)
 
 }
 
-static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *configfs_follow_link(struct dentry *dentry, int flags)
 {
 	int error = -ENOMEM;
 	unsigned long page;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	page = get_zeroed_page(GFP_KERNEL);
@@ -292,17 +292,16 @@  static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 	if (page) {
 		error = configfs_getlink(dentry, (char *)page);
 		if (!error) {
-			nd_set_link(nd, (char *)page);
+			nd_set_link((char *)page);
 			return (void *)page;
 		}
 	}
 
-	nd_set_link(nd, ERR_PTR(error));
+	nd_set_link(ERR_PTR(error));
 	return NULL;
 }
 
-static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
-			      void *cookie)
+static void configfs_put_link(struct dentry *dentry, void *cookie)
 {
 	if (cookie) {
 		unsigned long page = (unsigned long)cookie;
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 517e64938438..3dd676a2a4c0 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -43,9 +43,9 @@  const struct file_operations debugfs_file_operations = {
 	.llseek =	noop_llseek,
 };
 
-static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *debugfs_follow_link(struct dentry *dentry, int flags)
 {
-	nd_set_link(nd, dentry->d_inode->i_private);
+	nd_set_link(dentry->d_inode->i_private);
 	return NULL;
 }
 
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 49d3dd96344c..47f8d3a3ff48 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -170,7 +170,6 @@  out_unlock:
  * @directory_inode: inode of the new file's dentry's parent in ecryptfs
  * @ecryptfs_dentry: New file's dentry in ecryptfs
  * @mode: The mode of the new file
- * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
  *
  * Creates the underlying file and the eCryptfs inode which will link to
  * it. It will also update the eCryptfs directory inode to mimic the
@@ -384,7 +383,6 @@  static int ecryptfs_lookup_interpose(struct dentry *dentry,
  * ecryptfs_lookup
  * @ecryptfs_dir_inode: The eCryptfs directory inode
  * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
- * @ecryptfs_nd: nameidata; may be NULL
  *
  * Find a file on disk. If the file does not exist, then we'll add it to the
  * dentry cache and continue on to read it from the disk.
@@ -675,12 +673,12 @@  out:
 	return rc ? ERR_PTR(rc) : buf;
 }
 
-static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ecryptfs_follow_link(struct dentry *dentry, int flags)
 {
 	size_t len;
 	char *buf;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	buf = ecryptfs_readlink_lower(dentry, &len);
@@ -690,7 +688,7 @@  static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 				ecryptfs_dentry_to_lower(dentry)->d_inode);
 	buf[len] = '\0';
 out:
-	nd_set_link(nd, buf);
+	nd_set_link(buf);
 	return NULL;
 }
 
diff --git a/fs/exofs/symlink.c b/fs/exofs/symlink.c
index 832e2624b80b..5565f457358c 100644
--- a/fs/exofs/symlink.c
+++ b/fs/exofs/symlink.c
@@ -35,11 +35,11 @@ 
 
 #include "exofs.h"
 
-static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *exofs_follow_link(struct dentry *dentry, int flags)
 {
 	struct exofs_i_info *oi = exofs_i(dentry->d_inode);
 
-	nd_set_link(nd, (char *)oi->i_data);
+	nd_set_link((char *)oi->i_data);
 	return NULL;
 }
 
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 565cf817bbf1..dbad23054842 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -21,10 +21,10 @@ 
 #include "xattr.h"
 #include <linux/namei.h>
 
-static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ext2_follow_link(struct dentry *dentry, int flags)
 {
 	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
-	nd_set_link(nd, (char *)ei->i_data);
+	nd_set_link((char *)ei->i_data);
 	return NULL;
 }
 
diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c
index 6b01c3eab1f3..28bee0541bc1 100644
--- a/fs/ext3/symlink.c
+++ b/fs/ext3/symlink.c
@@ -21,10 +21,10 @@ 
 #include "ext3.h"
 #include "xattr.h"
 
-static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void * ext3_follow_link(struct dentry *dentry, int flags)
 {
 	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
-	nd_set_link(nd, (char*)ei->i_data);
+	nd_set_link((char*)ei->i_data);
 	return NULL;
 }
 
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index ff3711932018..eb987cc01c85 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -23,10 +23,10 @@ 
 #include "ext4.h"
 #include "xattr.h"
 
-static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ext4_follow_link(struct dentry *dentry, int flags)
 {
 	struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
-	nd_set_link(nd, (char *) ei->i_data);
+	nd_set_link((char *) ei->i_data);
 	return NULL;
 }
 
diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
index c36aeaf92e41..ea20270f46f8 100644
--- a/fs/freevxfs/vxfs_immed.c
+++ b/fs/freevxfs/vxfs_immed.c
@@ -39,7 +39,7 @@ 
 #include "vxfs_inode.h"
 
 
-static void *	vxfs_immed_follow_link(struct dentry *, struct nameidata *);
+static void *	vxfs_immed_follow_link(struct dentry *, int);
 
 static int	vxfs_immed_readpage(struct file *, struct page *);
 
@@ -64,7 +64,7 @@  const struct address_space_operations vxfs_immed_aops = {
 /**
  * vxfs_immed_follow_link - follow immed symlink
  * @dp:		dentry for the link
- * @np:		pathname lookup data for the current path walk
+ * @flags:	lookup flags for the current path walk
  *
  * Description:
  *   vxfs_immed_follow_link restarts the pathname lookup with
@@ -74,10 +74,10 @@  const struct address_space_operations vxfs_immed_aops = {
  *   Zero on success, else a negative error code.
  */
 static void *
-vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
+vxfs_immed_follow_link(struct dentry *dp, int flags)
 {
 	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
-	nd_set_link(np, vip->vii_immed.vi_immed);
+	nd_set_link(vip->vii_immed.vi_immed);
 	return NULL;
 }
 
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 15d326ec5943..9a4ca5dc62f1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1400,17 +1400,17 @@  static void free_link(char *link)
 		free_page((unsigned long) link);
 }
 
-static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *fuse_follow_link(struct dentry *dentry, int flags)
 {
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
-	nd_set_link(nd, read_link(dentry));
+	nd_set_link(read_link(dentry));
 	return NULL;
 }
 
-static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
+static void fuse_put_link(struct dentry *dentry, void *c)
 {
-	free_link(nd_get_link(nd));
+	free_link(nd_get_link());
 }
 
 static int fuse_dir_open(struct inode *inode, struct file *file)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 21086c7870f1..f0691c863956 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1541,14 +1541,14 @@  out:
 /**
  * gfs2_follow_link - Follow a symbolic link
  * @dentry: The dentry of the link
- * @nd: Data that we pass to vfs_follow_link()
+ * @flags: Lookup flags
  *
  * This can handle symlinks of any size.
  *
  * Returns: 0 on success or error code
  */
 
-static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *gfs2_follow_link(struct dentry *dentry, int flags)
 {
 	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
 	struct gfs2_holder i_gh;
@@ -1557,13 +1557,13 @@  static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 	char *buf;
 	int error;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
 	error = gfs2_glock_nq(&i_gh);
 	if (error) {
 		gfs2_holder_uninit(&i_gh);
-		nd_set_link(nd, ERR_PTR(error));
+		nd_set_link(ERR_PTR(error));
 		return NULL;
 	}
 
@@ -1588,7 +1588,7 @@  static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 	brelse(dibh);
 out:
 	gfs2_glock_dq_uninit(&i_gh);
-	nd_set_link(nd, buf);
+	nd_set_link(buf);
 	return NULL;
 }
 
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 374d04909538..da224778b1be 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -882,11 +882,11 @@  static const struct inode_operations hostfs_dir_iops = {
 	.setattr	= hostfs_setattr,
 };
 
-static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *hostfs_follow_link(struct dentry *dentry, int flags)
 {
 	char *link;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	link = __getname();
@@ -907,13 +907,13 @@  static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 		link = ERR_PTR(-ENOMEM);
 	}
 
-	nd_set_link(nd, link);
+	nd_set_link(link);
 	return NULL;
 }
 
-static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+static void hostfs_put_link(struct dentry *dentry, void *cookie)
 {
-	char *s = nd_get_link(nd);
+	char *s = nd_get_link();
 	if (!IS_ERR(s))
 		__putname(s);
 }
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 043ac9d77262..37d9a777f8e0 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -642,20 +642,19 @@  static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
 						    buflen);
 }
 
-static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *hppfs_follow_link(struct dentry *dentry, int flags)
 {
 	struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
 
-	return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
+	return proc_dentry->d_inode->i_op->follow_link(proc_dentry, flags);
 }
 
-static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd,
-			   void *cookie)
+static void hppfs_put_link(struct dentry *dentry, void *cookie)
 {
 	struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
 
 	if (proc_dentry->d_inode->i_op->put_link)
-		proc_dentry->d_inode->i_op->put_link(proc_dentry, nd, cookie);
+		proc_dentry->d_inode->i_op->put_link(proc_dentry, cookie);
 }
 
 static const struct inode_operations hppfs_dir_iops = {
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index c7c77b0dfccd..c2bebe5c7c42 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -16,7 +16,7 @@ 
 #include <linux/namei.h>
 #include "nodelist.h"
 
-static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
+static void *jffs2_follow_link(struct dentry *dentry, int flags);
 
 const struct inode_operations jffs2_symlink_inode_operations =
 {
@@ -29,7 +29,7 @@  const struct inode_operations jffs2_symlink_inode_operations =
 	.removexattr =	jffs2_removexattr
 };
 
-static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *jffs2_follow_link(struct dentry *dentry, int flags)
 {
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
 	char *p = (char *)f->target;
@@ -54,7 +54,7 @@  static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 	jffs2_dbg(1, "%s(): target path is '%s'\n",
 		  __func__, (char *)f->target);
 
-	nd_set_link(nd, p);
+	nd_set_link(p);
 
 	/*
 	 * We will unlock the f->sem mutex but VFS will use the f->target string. This is safe
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index 205b946d8e0d..1cfae27aa6a8 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -22,10 +22,10 @@ 
 #include "jfs_inode.h"
 #include "jfs_xattr.h"
 
-static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *jfs_follow_link(struct dentry *dentry, int flags)
 {
 	char *s = JFS_IP(dentry->d_inode)->i_inline;
-	nd_set_link(nd, s);
+	nd_set_link(s);
 	return NULL;
 }
 
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 8e5421f386c0..88694e0df282 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -112,12 +112,12 @@  static int kernfs_getlink(struct dentry *dentry, char *path)
 	return error;
 }
 
-static void *kernfs_iop_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *kernfs_iop_follow_link(struct dentry *dentry, int flags)
 {
 	int error = -ENOMEM;
 	unsigned long page;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	page = get_zeroed_page(GFP_KERNEL);
@@ -126,14 +126,13 @@  static void *kernfs_iop_follow_link(struct dentry *dentry, struct nameidata *nd)
 		if (error < 0)
 			free_page((unsigned long)page);
 	}
-	nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
+	nd_set_link(error ? ERR_PTR(error) : (char *)page);
 	return NULL;
 }
 
-static void kernfs_iop_put_link(struct dentry *dentry, struct nameidata *nd,
-				void *cookie)
+static void kernfs_iop_put_link(struct dentry *dentry, void *cookie)
 {
-	char *page = nd_get_link(nd);
+	char *page = nd_get_link();
 	if (!IS_ERR(page))
 		free_page((unsigned long)page);
 }
diff --git a/fs/libfs.c b/fs/libfs.c
index 0ab65122ee45..f437c8489998 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1024,10 +1024,9 @@  int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 }
 EXPORT_SYMBOL(noop_fsync);
 
-void kfree_put_link(struct dentry *dentry, struct nameidata *nd,
-				void *cookie)
+void kfree_put_link(struct dentry *dentry, void *cookie)
 {
-	char *s = nd_get_link(nd);
+	char *s = nd_get_link();
 	if (!IS_ERR(s))
 		kfree(s);
 }
diff --git a/fs/namei.c b/fs/namei.c
index eefa4a00501a..9a5d429f2a8a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -722,8 +722,10 @@  static inline void path_to_nameidata(const struct path *path,
  * Helper to directly jump to a known parsed path from ->follow_link,
  * caller must have taken a reference to path beforehand.
  */
-void nd_jump_link(struct nameidata *nd, struct path *path)
+void nd_jump_link(struct path *path)
 {
+	struct nameidata *nd = current->nameidata;
+
 	path_put(&nd->path);
 
 	nd->path = *path;
@@ -731,14 +733,18 @@  void nd_jump_link(struct nameidata *nd, struct path *path)
 	nd->flags |= LOOKUP_JUMPED;
 }
 
-void nd_set_link(struct nameidata *nd, char *path)
+void nd_set_link(char *path)
 {
+	struct nameidata *nd = current->nameidata;
+
 	nd->saved_names[nd->depth] = path;
 }
 EXPORT_SYMBOL(nd_set_link);
 
-char *nd_get_link(struct nameidata *nd)
+char *nd_get_link(void)
 {
+	struct nameidata *nd = current->nameidata;
+
 	return nd->saved_names[nd->depth];
 }
 EXPORT_SYMBOL(nd_get_link);
@@ -747,7 +753,7 @@  static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
 {
 	struct inode *inode = link->dentry->d_inode;
 	if (inode->i_op->put_link)
-		inode->i_op->put_link(link->dentry, nd, cookie);
+		inode->i_op->put_link(link->dentry, cookie);
 	path_put(link);
 }
 
@@ -887,20 +893,20 @@  follow_link(struct path *link, struct nameidata *nd, void **p)
 	current->nameidata->total_link_count++;
 
 	touch_atime(link);
-	nd_set_link(nd, NULL);
+	nd_set_link(NULL);
 
-	error = security_inode_follow_link(link->dentry, nd);
+	error = security_inode_follow_link(link->dentry, nd->flags);
 	if (error)
 		goto out_put_nd_path;
 
 	nd->last_type = LAST_BIND;
-	*p = dentry->d_inode->i_op->follow_link(dentry, nd);
+	*p = dentry->d_inode->i_op->follow_link(dentry, nd->flags);
 	error = PTR_ERR(*p);
 	if (IS_ERR(*p))
 		goto out_put_nd_path;
 
 	error = 0;
-	s = nd_get_link(nd);
+	s = nd_get_link();
 	if (s) {
 		if (unlikely(IS_ERR(s))) {
 			path_put(&nd->path);
@@ -4458,13 +4464,13 @@  int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 	int res;
 
 	nd.depth = 0;
-	cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
+	cookie = dentry->d_inode->i_op->follow_link(dentry, nd.flags);
 	if (IS_ERR(cookie))
 		return PTR_ERR(cookie);
 
-	res = readlink_copy(buffer, buflen, nd_get_link(&nd));
+	res = readlink_copy(buffer, buflen, nd_get_link());
 	if (dentry->d_inode->i_op->put_link)
-		dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
+		dentry->d_inode->i_op->put_link(dentry,  cookie);
 	set_nameidata(saved);
 	return res;
 }
@@ -4497,17 +4503,17 @@  int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 }
 EXPORT_SYMBOL(page_readlink);
 
-void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
+void *page_follow_link_light(struct dentry *dentry, int flags)
 {
 	struct page *page = NULL;
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
-	nd_set_link(nd, page_getlink(dentry, &page));
+	nd_set_link(page_getlink(dentry, &page));
 	return page;
 }
 EXPORT_SYMBOL(page_follow_link_light);
 
-void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+void page_put_link(struct dentry *dentry, void *cookie)
 {
 	struct page *page = cookie;
 
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index c9a2d3cc4619..43e43d2c8c5b 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -43,13 +43,13 @@  error:
 	return -EIO;
 }
 
-static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *nfs_follow_link(struct dentry *dentry, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	struct page *page;
 	void *err;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
 	if (err)
@@ -60,11 +60,11 @@  static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 		err = page;
 		goto read_failed;
 	}
-	nd_set_link(nd, kmap(page));
+	nd_set_link(kmap(page));
 	return page;
 
 read_failed:
-	nd_set_link(nd, err);
+	nd_set_link(err);
 	return NULL;
 }
 
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index b3973c2fd190..a6a240ecf878 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -35,7 +35,6 @@ 
  * ntfs_lookup - find the inode represented by a dentry in a directory inode
  * @dir_ino:	directory inode in which to look for the inode
  * @dent:	dentry representing the inode to look for
- * @nd:		lookup nameidata
  *
  * In short, ntfs_lookup() looks for the inode represented by the dentry @dent
  * in the directory inode @dir_ino and if found attaches the inode to the
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index db370d5d84c4..e8ef9f44af12 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -141,13 +141,13 @@  struct ovl_link_data {
 	void *cookie;
 };
 
-static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ovl_follow_link(struct dentry *dentry, int flags)
 {
 	void *ret;
 	struct dentry *realdentry;
 	struct inode *realinode;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	realdentry = ovl_dentry_real(dentry);
 	realinode = realdentry->d_inode;
@@ -155,7 +155,7 @@  static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
 	if (WARN_ON(!realinode->i_op->follow_link))
 		return ERR_PTR(-EPERM);
 
-	ret = realinode->i_op->follow_link(realdentry, nd);
+	ret = realinode->i_op->follow_link(realdentry, flags);
 	if (IS_ERR(ret))
 		return ret;
 
@@ -164,7 +164,7 @@  static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
 
 		data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
 		if (!data) {
-			realinode->i_op->put_link(realdentry, nd, ret);
+			realinode->i_op->put_link(realdentry, ret);
 			return ERR_PTR(-ENOMEM);
 		}
 		data->realdentry = realdentry;
@@ -176,7 +176,7 @@  static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
 	}
 }
 
-static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
+static void ovl_put_link(struct dentry *dentry, void *c)
 {
 	struct inode *realinode;
 	struct ovl_link_data *data = c;
@@ -185,7 +185,7 @@  static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
 		return;
 
 	realinode = data->realdentry->d_inode;
-	realinode->i_op->put_link(data->realdentry, nd, data->cookie);
+	realinode->i_op->put_link(data->realdentry, data->cookie);
 	kfree(data);
 }
 
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6f5dbfe68516..7e6f95c0d58d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1371,13 +1371,13 @@  static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 		return -ENOENT;
 }
 
-static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *proc_pid_follow_link(struct dentry *dentry, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	struct path path;
 	int error = -EACCES;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	/* Are we allowed to snoop on the tasks file descriptors? */
 	if (!proc_fd_access_allowed(inode))
@@ -1387,7 +1387,7 @@  static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 	if (error)
 		goto out;
 
-	nd_jump_link(nd, &path);
+	nd_jump_link(&path);
 	return NULL;
 out:
 	return ERR_PTR(error);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 7697b6621cfd..f9980443427c 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -394,16 +394,16 @@  static const struct file_operations proc_reg_file_ops_no_compat = {
 };
 #endif
 
-static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *proc_follow_link(struct dentry *dentry, int flags)
 {
 	struct proc_dir_entry *pde = PDE(dentry->d_inode);
 	if (unlikely(!use_pde(pde)))
 		return ERR_PTR(-EINVAL);
-	nd_set_link(nd, pde->data);
+	nd_set_link(pde->data);
 	return pde;
 }
 
-static void proc_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
+static void proc_put_link(struct dentry *dentry, void *p)
 {
 	unuse_pde(p);
 }
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index c89a51401bb5..46c7ab225e17 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -30,7 +30,7 @@  static const struct proc_ns_operations *ns_entries[] = {
 	&mntns_operations,
 };
 
-static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *proc_ns_follow_link(struct dentry *dentry, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
@@ -38,7 +38,7 @@  static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
 	struct path ns_path;
 	void *error = ERR_PTR(-EACCES);
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	task = get_proc_task(inode);
@@ -48,7 +48,7 @@  static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
 	if (ptrace_may_access(task, PTRACE_MODE_READ)) {
 		error = ns_get_path(&ns_path, task, ns_ops);
 		if (!error)
-			nd_jump_link(nd, &ns_path);
+			nd_jump_link(&ns_path);
 	}
 	put_task_struct(task);
 	return error;
diff --git a/fs/proc/self.c b/fs/proc/self.c
index c094ea04e1bb..c56e282b84b8 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -19,13 +19,13 @@  static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
 	return readlink_copy(buffer, buflen, tmp);
 }
 
-static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *proc_self_follow_link(struct dentry *dentry, int flags)
 {
 	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
 	pid_t tgid;
 	char *name = ERR_PTR(-ENOENT);
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	tgid = task_tgid_nr_ns(current, ns);
@@ -37,7 +37,7 @@  static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 		else
 			sprintf(name, "%d", tgid);
 	}
-	nd_set_link(nd, name);
+	nd_set_link(name);
 	return NULL;
 }
 
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index 5d3144d51018..78b35e18a042 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -20,14 +20,14 @@  static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
 	return readlink_copy(buffer, buflen, tmp);
 }
 
-static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *proc_thread_self_follow_link(struct dentry *dentry, int flags)
 {
 	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
 	pid_t tgid;
 	pid_t pid;
 	char *name = ERR_PTR(-ENOENT);
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 
 	tgid = task_tgid_nr_ns(current, ns);
@@ -39,7 +39,7 @@  static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidat
 		else
 			sprintf(name, "%d/task/%d", tgid, pid);
 	}
-	nd_set_link(nd, name);
+	nd_set_link(name);
 	return NULL;
 }
 
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
index 00d2f8a43e4e..ad285577a928 100644
--- a/fs/sysv/symlink.c
+++ b/fs/sysv/symlink.c
@@ -8,9 +8,9 @@ 
 #include "sysv.h"
 #include <linux/namei.h>
 
-static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *sysv_follow_link(struct dentry *dentry, int flags)
 {
-	nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data);
+	nd_set_link((char *)SYSV_I(dentry->d_inode)->i_data);
 	return NULL;
 }
 
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index e627c0acf626..ccc83837f078 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1300,11 +1300,11 @@  static void ubifs_invalidatepage(struct page *page, unsigned int offset,
 	ClearPageChecked(page);
 }
 
-static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ubifs_follow_link(struct dentry *dentry, int flags)
 {
 	struct ubifs_inode *ui = ubifs_inode(dentry->d_inode);
 
-	nd_set_link(nd, ui->data);
+	nd_set_link(ui->data);
 	return NULL;
 }
 
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
index d283628b4778..29622d6beaa4 100644
--- a/fs/ufs/symlink.c
+++ b/fs/ufs/symlink.c
@@ -32,10 +32,10 @@ 
 #include "ufs.h"
 
 
-static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ufs_follow_link(struct dentry *dentry, int flags)
 {
 	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
-	nd_set_link(nd, (char*)p->i_u1.i_symlink);
+	nd_set_link((char*)p->i_u1.i_symlink);
 	return NULL;
 }
 
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 23cea798b777..8fd416ae935a 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -412,12 +412,12 @@  xfs_vn_rename(
 STATIC void *
 xfs_vn_follow_link(
 	struct dentry		*dentry,
-	struct nameidata	*nd)
+	int			flags)
 {
 	char			*link;
 	int			error = -ENOMEM;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
 	if (!link)
@@ -427,13 +427,13 @@  xfs_vn_follow_link(
 	if (unlikely(error))
 		goto out_kfree;
 
-	nd_set_link(nd, link);
+	nd_set_link(link);
 	return NULL;
 
  out_kfree:
 	kfree(link);
  out_err:
-	nd_set_link(nd, ERR_PTR(error));
+	nd_set_link(ERR_PTR(error));
 	return NULL;
 }
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index eaef987ae3cf..b7d578d552bf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -38,7 +38,6 @@  struct backing_dev_info;
 struct export_operations;
 struct hd_geometry;
 struct iovec;
-struct nameidata;
 struct kiocb;
 struct kobject;
 struct pipe_inode_info;
@@ -1574,12 +1573,12 @@  struct file_operations {
 
 struct inode_operations {
 	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
-	void * (*follow_link) (struct dentry *, struct nameidata *);
+	void * (*follow_link) (struct dentry *, int);
 	int (*permission) (struct inode *, int);
 	struct posix_acl * (*get_acl)(struct inode *, int);
 
 	int (*readlink) (struct dentry *, char __user *,int);
-	void (*put_link) (struct dentry *, struct nameidata *, void *);
+	void (*put_link) (struct dentry *, void *);
 
 	int (*create) (struct inode *,struct dentry *, umode_t, bool);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
@@ -2167,7 +2166,6 @@  extern struct filename *getname_flags(const char __user *, int, int *);
 extern struct filename *getname(const char __user *);
 extern struct filename *getname_kernel(const char *);
 extern void putname(struct filename *name);
-extern int nd_is_rcu(struct nameidata *nd);
 
 enum {
 	FILE_CREATED = 1,
@@ -2650,13 +2648,13 @@  extern const struct file_operations generic_ro_fops;
 
 extern int readlink_copy(char __user *, int, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
-extern void *page_follow_link_light(struct dentry *, struct nameidata *);
-extern void page_put_link(struct dentry *, struct nameidata *, void *);
+extern void *page_follow_link_light(struct dentry *, int);
+extern void page_put_link(struct dentry *, void *);
 extern int __page_symlink(struct inode *inode, const char *symname, int len,
 		int nofs);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
-extern void kfree_put_link(struct dentry *, struct nameidata *, void *);
+extern void kfree_put_link(struct dentry *, void *);
 extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 int vfs_getattr_nosec(struct path *path, struct kstat *stat);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index c8990779f0c3..368eb3d721b8 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -7,7 +7,6 @@ 
 #include <linux/path.h>
 
 struct vfsmount;
-struct nameidata;
 
 enum { MAX_NESTED_LINKS = 8 };
 
@@ -70,9 +69,9 @@  extern int follow_up(struct path *);
 extern struct dentry *lock_rename(struct dentry *, struct dentry *);
 extern void unlock_rename(struct dentry *, struct dentry *);
 
-extern void nd_jump_link(struct nameidata *nd, struct path *path);
-extern void nd_set_link(struct nameidata *nd, char *path);
-extern char *nd_get_link(struct nameidata *nd);
+extern void nd_jump_link(struct path *path);
+extern void nd_set_link(char *path);
+extern char *nd_get_link(void);
 
 static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
 {
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b88b9eea169a..5d85ef2b64c3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1267,6 +1267,7 @@  union rcu_special {
 	short s;
 };
 struct rcu_node;
+struct nameidata;
 
 enum perf_event_task_context {
 	perf_invalid_context = -1,
diff --git a/include/linux/security.h b/include/linux/security.h
index a1b7dbd127ff..587f7b0849b6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -43,7 +43,6 @@  struct file;
 struct vfsmount;
 struct path;
 struct qstr;
-struct nameidata;
 struct iattr;
 struct fown_struct;
 struct file_operations;
@@ -477,7 +476,7 @@  static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  * @inode_follow_link:
  *	Check permission to follow a symbolic link when looking up a pathname.
  *	@dentry contains the dentry structure for the link.
- *	@nd contains the nameidata structure for the parent directory.
+ *	@flags contains lookup flags
  *	Return 0 if permission is granted.
  * @inode_permission:
  *	Check permission before accessing an inode.  This hook is called by the
@@ -1553,7 +1552,7 @@  struct security_operations {
 	int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
 			     struct inode *new_dir, struct dentry *new_dentry);
 	int (*inode_readlink) (struct dentry *dentry);
-	int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
+	int (*inode_follow_link) (struct dentry *dentry, int flags);
 	int (*inode_permission) (struct inode *inode, int mask);
 	int (*inode_setattr)	(struct dentry *dentry, struct iattr *attr);
 	int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
@@ -1840,7 +1839,7 @@  int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
 			  struct inode *new_dir, struct dentry *new_dentry,
 			  unsigned int flags);
 int security_inode_readlink(struct dentry *dentry);
-int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
+int security_inode_follow_link(struct dentry *dentry, int flags);
 int security_inode_permission(struct inode *inode, int mask);
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
 int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
@@ -2243,7 +2242,7 @@  static inline int security_inode_readlink(struct dentry *dentry)
 }
 
 static inline int security_inode_follow_link(struct dentry *dentry,
-					      struct nameidata *nd)
+					      int flags)
 {
 	return 0;
 }
diff --git a/mm/shmem.c b/mm/shmem.c
index fdf6ba18fce3..8f23e0f5e050 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2474,29 +2474,29 @@  static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 	return 0;
 }
 
-static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
+static void *shmem_follow_short_symlink(struct dentry *dentry, int flags)
 {
-	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
+	nd_set_link(SHMEM_I(dentry->d_inode)->symlink);
 	return NULL;
 }
 
-static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *shmem_follow_link(struct dentry *dentry, int flags)
 {
 	struct page *page = NULL;
 	int error;
 
-	if (nd_is_rcu(nd))
+	if (flags & LOOKUP_RCU)
 		return ERR_PTR(-ECHILD);
 	error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-	nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
+	nd_set_link(error ? ERR_PTR(error) : kmap(page));
 	if (page)
 		unlock_page(page);
 	return page;
 }
 
-static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+static void shmem_put_link(struct dentry *dentry, void *cookie)
 {
-	if (!IS_ERR(nd_get_link(nd))) {
+	if (!IS_ERR(nd_get_link())) {
 		struct page *page = cookie;
 		kunmap(page);
 		mark_page_accessed(page);
diff --git a/security/capability.c b/security/capability.c
index 070dd46f62f4..569e4253343c 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -210,7 +210,7 @@  static int cap_inode_readlink(struct dentry *dentry)
 }
 
 static int cap_inode_follow_link(struct dentry *dentry,
-				 struct nameidata *nameidata)
+				 int flags)
 {
 	return 0;
 }
diff --git a/security/security.c b/security/security.c
index e81d5bbe7363..5798987b2a18 100644
--- a/security/security.c
+++ b/security/security.c
@@ -581,11 +581,11 @@  int security_inode_readlink(struct dentry *dentry)
 	return security_ops->inode_readlink(dentry);
 }
 
-int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+int security_inode_follow_link(struct dentry *dentry, int flags)
 {
 	if (unlikely(IS_PRIVATE(dentry->d_inode)))
 		return 0;
-	return security_ops->inode_follow_link(dentry, nd);
+	return security_ops->inode_follow_link(dentry, flags);
 }
 
 int security_inode_permission(struct inode *inode, int mask)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4d1a54190388..e3074e01f058 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2862,7 +2862,7 @@  static int selinux_inode_readlink(struct dentry *dentry)
 	return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
-static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
+static int selinux_inode_follow_link(struct dentry *dentry, int flags)
 {
 	const struct cred *cred = current_cred();