@@ -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);
@@ -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:
@@ -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.
@@ -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 *);
@@ -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);
}
@@ -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);
@@ -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);
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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,
@@ -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;
}
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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)
@@ -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;
}
@@ -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);
}
@@ -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 = {
@@ -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
@@ -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;
}
@@ -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);
}
@@ -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);
}
@@ -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;
@@ -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;
}
@@ -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
@@ -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);
}
@@ -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);
@@ -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);
}
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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);
@@ -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)
{
@@ -1267,6 +1267,7 @@ union rcu_special {
short s;
};
struct rcu_node;
+struct nameidata;
enum perf_event_task_context {
perf_invalid_context = -1,
@@ -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;
}
@@ -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);
@@ -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;
}
@@ -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)
@@ -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();
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