Skip to content

Commit

Permalink
Cache root in nameidata
Browse files Browse the repository at this point in the history
New field: nd->root.  When pathname resolution wants to know the root,
check if nd->root.mnt is non-NULL; use nd->root if it is, otherwise
copy current->fs->root there.  After path_walk() is finished, we check
if we'd got a cached value in nd->root and drop it.  Before calling
path_walk() we should either set nd->root.mnt to NULL *or* copy (and
pin down) some path to nd->root.  In the latter case we won't be
looking at current->fs->root at all.

Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed Jun 12, 2009
1 parent 9b4a9b1 commit 2a73787
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 19 deletions.
53 changes: 34 additions & 19 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,17 @@ static __always_inline int link_path_walk(const char *name, struct nameidata *nd
return result;
}

static __always_inline void set_root(struct nameidata *nd)
{
if (!nd->root.mnt) {
struct fs_struct *fs = current->fs;
read_lock(&fs->lock);
nd->root = fs->root;
path_get(&nd->root);
read_unlock(&fs->lock);
}
}

static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
int res = 0;
Expand All @@ -560,14 +571,10 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
goto fail;

if (*link == '/') {
struct fs_struct *fs = current->fs;

set_root(nd);
path_put(&nd->path);

read_lock(&fs->lock);
nd->path = fs->root;
path_get(&fs->root);
read_unlock(&fs->lock);
nd->path = nd->root;
path_get(&nd->root);
}

res = link_path_walk(link, nd);
Expand Down Expand Up @@ -741,19 +748,16 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)

static __always_inline void follow_dotdot(struct nameidata *nd)
{
struct fs_struct *fs = current->fs;
set_root(nd);

while(1) {
struct vfsmount *parent;
struct dentry *old = nd->path.dentry;

read_lock(&fs->lock);
if (nd->path.dentry == fs->root.dentry &&
nd->path.mnt == fs->root.mnt) {
read_unlock(&fs->lock);
if (nd->path.dentry == nd->root.dentry &&
nd->path.mnt == nd->root.mnt) {
break;
}
read_unlock(&fs->lock);
spin_lock(&dcache_lock);
if (nd->path.dentry != nd->path.mnt->mnt_root) {
nd->path.dentry = dget(nd->path.dentry->d_parent);
Expand Down Expand Up @@ -1022,18 +1026,18 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
int retval = 0;
int fput_needed;
struct file *file;
struct fs_struct *fs = current->fs;

nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
nd->depth = 0;
nd->root.mnt = NULL;

if (*name=='/') {
read_lock(&fs->lock);
nd->path = fs->root;
path_get(&fs->root);
read_unlock(&fs->lock);
set_root(nd);
nd->path = nd->root;
path_get(&nd->root);
} else if (dfd == AT_FDCWD) {
struct fs_struct *fs = current->fs;
read_lock(&fs->lock);
nd->path = fs->pwd;
path_get(&fs->pwd);
Expand Down Expand Up @@ -1079,6 +1083,10 @@ static int do_path_lookup(int dfd, const char *name,
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
nd->path.dentry->d_inode))
audit_inode(name, nd->path.dentry);
if (nd->root.mnt) {
path_put(&nd->root);
nd->root.mnt = NULL;
}
return retval;
}

Expand Down Expand Up @@ -1115,6 +1123,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
nd->last_type = LAST_ROOT;
nd->flags = flags;
nd->depth = 0;
nd->root.mnt = NULL;

nd->path.dentry = dentry;
nd->path.mnt = mnt;
Expand All @@ -1125,8 +1134,12 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
nd->path.dentry->d_inode))
audit_inode(name, nd->path.dentry);

return retval;
if (nd->root.mnt) {
path_put(&nd->root);
nd->root.mnt = NULL;
}

return retval;
}

/**
Expand Down Expand Up @@ -1817,6 +1830,8 @@ struct file *do_filp_open(int dfd, const char *pathname,
if (!IS_ERR(nd.intent.open.file))
release_open_intent(&nd);
exit_parent:
if (nd.root.mnt)
path_put(&nd.root);
path_put(&nd.path);
return ERR_PTR(error);

Expand Down
1 change: 1 addition & 0 deletions include/linux/namei.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum { MAX_NESTED_LINKS = 8 };
struct nameidata {
struct path path;
struct qstr last;
struct path root;
unsigned int flags;
int last_type;
unsigned depth;
Expand Down

0 comments on commit 2a73787

Please sign in to comment.