Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 234245
b: refs/heads/master
c: 16c2cd7
h: refs/heads/master
i:
  234243: b1b4663
v: v3
  • Loading branch information
Al Viro committed Mar 14, 2011
1 parent 21580ae commit 0c78045
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 64 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fe479a580dc9c737c4eb49ff7fdb31d41d2c7003
refs/heads/master: 16c2cd7179881d5dd87779512ca5a0d657c64f62
107 changes: 44 additions & 63 deletions trunk/fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,19 +613,8 @@ do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
return dentry;
}

static inline int need_reval_dot(struct dentry *dentry)
{
if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
return 0;

if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
return 0;

return 1;
}

/*
* force_reval_path - force revalidation of a dentry
* handle_reval_path - force revalidation of a dentry
*
* In some situations the path walking code will trust dentries without
* revalidating them. This causes problems for filesystems that depend on
Expand All @@ -639,27 +628,28 @@ static inline int need_reval_dot(struct dentry *dentry)
* invalidate the dentry. It's up to the caller to handle putting references
* to the path if necessary.
*/
static int
force_reval_path(struct path *path, struct nameidata *nd)
static inline int handle_reval_path(struct nameidata *nd)
{
struct dentry *dentry = nd->path.dentry;
int status;
struct dentry *dentry = path->dentry;

/*
* only check on filesystems where it's possible for the dentry to
* become stale.
*/
if (!need_reval_dot(dentry))
if (likely(!(nd->flags & LOOKUP_JUMPED)))
return 0;

if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
return 0;

if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
return 0;

/* Note: we do not d_invalidate() */
status = d_revalidate(dentry, nd);
if (status > 0)
return 0;

if (!status) {
d_invalidate(dentry);
if (!status)
status = -ESTALE;
}

return status;
}

Expand Down Expand Up @@ -728,6 +718,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
path_put(&nd->path);
nd->path = nd->root;
path_get(&nd->root);
nd->flags |= LOOKUP_JUMPED;
}
nd->inode = nd->path.dentry->d_inode;

Expand Down Expand Up @@ -779,11 +770,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
error = 0;
if (s)
error = __vfs_follow_link(nd, s);
else if (nd->last_type == LAST_BIND) {
error = force_reval_path(&nd->path, nd);
if (error)
path_put(&nd->path);
}
else if (nd->last_type == LAST_BIND)
nd->flags |= LOOKUP_JUMPED;
}
return error;
}
Expand Down Expand Up @@ -1351,7 +1339,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
while (*name=='/')
name++;
if (!*name)
goto return_reval;
goto return_base;

if (nd->depth)
lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
Expand Down Expand Up @@ -1385,12 +1373,16 @@ static int link_path_walk(const char *name, struct nameidata *nd)
type = LAST_NORM;
if (this.name[0] == '.') switch (this.len) {
case 2:
if (this.name[1] == '.')
if (this.name[1] == '.') {
type = LAST_DOTDOT;
nd->flags |= LOOKUP_JUMPED;
}
break;
case 1:
type = LAST_DOT;
}
if (likely(type == LAST_NORM))
nd->flags &= ~LOOKUP_JUMPED;

/* remove trailing slashes? */
if (!c)
Expand Down Expand Up @@ -1456,7 +1448,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
} else
follow_dotdot(nd);
}
goto return_reval;
goto return_base;
}
err = do_lookup(nd, &this, &next, &inode);
if (err)
Expand All @@ -1483,24 +1475,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
lookup_parent:
nd->last = this;
nd->last_type = type;
if (type == LAST_NORM)
goto return_base;
return_reval:
/*
* We bypassed the ordinary revalidation routines.
* We may need to check the cached dentry for staleness.
*/
if (need_reval_dot(nd->path.dentry)) {
if (nameidata_drop_rcu_last_maybe(nd))
return -ECHILD;
/* Note: we do not d_invalidate() */
err = d_revalidate(nd->path.dentry, nd);
if (!err)
err = -ESTALE;
if (err < 0)
break;
return 0;
}
return_base:
if (nameidata_drop_rcu_last_maybe(nd))
return -ECHILD;
Expand All @@ -1523,7 +1497,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
struct file *file;

nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
nd->flags = flags | LOOKUP_JUMPED;
nd->depth = 0;
nd->root.mnt = NULL;
nd->file = NULL;
Expand Down Expand Up @@ -1630,6 +1604,9 @@ static int path_lookupat(int dfd, const char *name,
br_read_unlock(vfsmount_lock);
}

if (!retval)
retval = handle_reval_path(nd);

if (nd->file) {
fput(nd->file);
nd->file = NULL;
Expand Down Expand Up @@ -1690,7 +1667,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,

/* same as do_path_lookup */
nd->last_type = LAST_ROOT;
nd->flags = flags;
nd->flags = flags | LOOKUP_JUMPED;
nd->depth = 0;

nd->path.dentry = dentry;
Expand All @@ -1703,15 +1680,20 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
current->total_link_count = 0;

result = link_path_walk(name, nd);
if (!result)
result = handle_reval_path(nd);
if (result == -ESTALE) {
/* nd->path had been dropped */
current->total_link_count = 0;
nd->path.dentry = dentry;
nd->path.mnt = mnt;
nd->inode = dentry->d_inode;
path_get(&nd->path);
nd->flags |= LOOKUP_REVAL;
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_REVAL;

result = link_path_walk(name, nd);
if (!result)
result = handle_reval_path(nd);
}
if (unlikely(!result && !audit_dummy_context() && nd->path.dentry &&
nd->inode))
Expand Down Expand Up @@ -2198,30 +2180,29 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
{
struct dentry *dir = nd->path.dentry;
struct file *filp;
int error = -EISDIR;
int error;

switch (nd->last_type) {
case LAST_DOTDOT:
follow_dotdot(nd);
dir = nd->path.dentry;
case LAST_DOT:
if (need_reval_dot(dir)) {
int status = d_revalidate(nd->path.dentry, nd);
if (!status)
status = -ESTALE;
if (status < 0) {
error = status;
goto exit;
}
}
/* fallthrough */
case LAST_ROOT:
error = handle_reval_path(nd);
if (error)
goto exit;
error = -EISDIR;
goto exit;
case LAST_BIND:
error = handle_reval_path(nd);
if (error)
goto exit;
audit_inode(pathname, dir);
goto ok;
}

error = -EISDIR;
/* trailing slashes? */
if (nd->last.name[nd->last.len])
goto exit;
Expand Down Expand Up @@ -2422,7 +2403,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
/*
* We have the parent and last component.
*/
nd.flags = flags;
nd.flags = (nd.flags & ~LOOKUP_PARENT) | flags;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
while (unlikely(!filp)) { /* trailing symlink */
struct path link = path;
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/namei.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_EXCL 0x0400
#define LOOKUP_RENAME_TARGET 0x0800

#define LOOKUP_JUMPED 0x1000

extern int user_path_at(int, const char __user *, unsigned, struct path *);

#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
Expand Down

0 comments on commit 0c78045

Please sign in to comment.