mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 04:30:52 +07:00
switch non-create side of open() to use of do_last()
Instead of path_lookupat() doing trailing symlink resolution, use the same scheme as on the O_CREAT side. Walk with LOOKUP_PARENT, then (in do_last()) look the final component up, then either open it or return error or, if it's a symlink, give the symlink back to path_openat() to be resolved there. The really messy complication here is RCU. We don't want to drop out of RCU mode before the final lookup, since we don't want to bounce parent directory ->d_count without a good reason. Result is _not_ pretty; later in the series we'll clean it up. For now we are roughly back where we'd been before the revert done by Nick's series - top-level logics of path_openat() is cleaned up, do_last() does actual opening, symlink resolution is done uniformly. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
70e9b35711
commit
fe2d35ff0d
100
fs/namei.c
100
fs/namei.c
@ -2178,13 +2178,14 @@ static struct file *finish_open(struct nameidata *nd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle O_CREAT case for do_filp_open
|
* Handle the last step of open()
|
||||||
*/
|
*/
|
||||||
static struct file *do_last(struct nameidata *nd, struct path *path,
|
static struct file *do_last(struct nameidata *nd, struct path *path,
|
||||||
const struct open_flags *op, const char *pathname)
|
const struct open_flags *op, const char *pathname)
|
||||||
{
|
{
|
||||||
struct dentry *dir = nd->path.dentry;
|
struct dentry *dir = nd->path.dentry;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
|
struct inode *inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
nd->flags &= ~LOOKUP_PARENT;
|
nd->flags &= ~LOOKUP_PARENT;
|
||||||
@ -2192,17 +2193,27 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
|
|
||||||
switch (nd->last_type) {
|
switch (nd->last_type) {
|
||||||
case LAST_DOTDOT:
|
case LAST_DOTDOT:
|
||||||
follow_dotdot(nd);
|
|
||||||
dir = nd->path.dentry;
|
|
||||||
case LAST_DOT:
|
case LAST_DOT:
|
||||||
|
error = handle_dots(nd, nd->last_type);
|
||||||
|
if (error)
|
||||||
|
return ERR_PTR(error);
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case LAST_ROOT:
|
case LAST_ROOT:
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
if (nameidata_drop_rcu_last(nd))
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
}
|
||||||
error = handle_reval_path(nd);
|
error = handle_reval_path(nd);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit;
|
goto exit;
|
||||||
error = -EISDIR;
|
audit_inode(pathname, nd->path.dentry);
|
||||||
goto exit;
|
if (op->open_flag & O_CREAT) {
|
||||||
|
error = -EISDIR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
goto ok;
|
||||||
case LAST_BIND:
|
case LAST_BIND:
|
||||||
|
/* can't be RCU mode here */
|
||||||
error = handle_reval_path(nd);
|
error = handle_reval_path(nd);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -2210,6 +2221,51 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(op->open_flag & O_CREAT)) {
|
||||||
|
if (nd->last.name[nd->last.len])
|
||||||
|
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
|
||||||
|
/* we _can_ be in RCU mode here */
|
||||||
|
error = do_lookup(nd, &nd->last, path, &inode);
|
||||||
|
if (error) {
|
||||||
|
terminate_walk(nd);
|
||||||
|
return ERR_PTR(error);
|
||||||
|
}
|
||||||
|
if (!inode) {
|
||||||
|
path_to_nameidata(path, nd);
|
||||||
|
terminate_walk(nd);
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
if (unlikely(inode->i_op->follow_link)) {
|
||||||
|
/* We drop rcu-walk here */
|
||||||
|
if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
path_to_nameidata(path, nd);
|
||||||
|
nd->inode = inode;
|
||||||
|
/* sayonara */
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
if (nameidata_drop_rcu_last(nd))
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = -ENOTDIR;
|
||||||
|
if (nd->flags & LOOKUP_DIRECTORY) {
|
||||||
|
if (!inode->i_op->lookup)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
audit_inode(pathname, nd->path.dentry);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create side of things */
|
||||||
|
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
if (nameidata_drop_rcu_last(nd))
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
}
|
||||||
|
|
||||||
|
audit_inode(pathname, dir);
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
/* trailing slashes? */
|
/* trailing slashes? */
|
||||||
if (nd->last.name[nd->last.len])
|
if (nd->last.name[nd->last.len])
|
||||||
@ -2303,6 +2359,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
static struct file *path_openat(int dfd, const char *pathname,
|
static struct file *path_openat(int dfd, const char *pathname,
|
||||||
const struct open_flags *op, int flags)
|
const struct open_flags *op, int flags)
|
||||||
{
|
{
|
||||||
|
struct file *base = NULL;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
struct nameidata nd;
|
struct nameidata nd;
|
||||||
struct path path;
|
struct path path;
|
||||||
@ -2318,39 +2375,15 @@ static struct file *path_openat(int dfd, const char *pathname,
|
|||||||
nd.intent.open.flags = open_to_namei_flags(op->open_flag);
|
nd.intent.open.flags = open_to_namei_flags(op->open_flag);
|
||||||
nd.intent.open.create_mode = op->mode;
|
nd.intent.open.create_mode = op->mode;
|
||||||
|
|
||||||
if (op->open_flag & O_CREAT)
|
error = path_init(dfd, pathname, flags | LOOKUP_PARENT, &nd, &base);
|
||||||
goto creat;
|
|
||||||
|
|
||||||
/* !O_CREAT, simple open */
|
|
||||||
error = path_lookupat(dfd, pathname, flags | op->intent, &nd);
|
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto out_filp;
|
goto out_filp;
|
||||||
error = -ELOOP;
|
|
||||||
if (!(nd.flags & LOOKUP_FOLLOW)) {
|
|
||||||
if (nd.inode->i_op->follow_link)
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
error = -ENOTDIR;
|
|
||||||
if (nd.flags & LOOKUP_DIRECTORY) {
|
|
||||||
if (!nd.inode->i_op->lookup)
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
audit_inode(pathname, nd.path.dentry);
|
|
||||||
filp = finish_open(&nd, op->open_flag, op->acc_mode);
|
|
||||||
release_open_intent(&nd);
|
|
||||||
return filp;
|
|
||||||
|
|
||||||
creat:
|
current->total_link_count = 0;
|
||||||
/* OK, have to create the file. Find the parent. */
|
error = link_path_walk(pathname, &nd);
|
||||||
error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd);
|
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto out_filp;
|
goto out_filp;
|
||||||
if (unlikely(!audit_dummy_context()))
|
|
||||||
audit_inode(pathname, nd.path.dentry);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We have the parent and last component.
|
|
||||||
*/
|
|
||||||
filp = do_last(&nd, &path, op, pathname);
|
filp = do_last(&nd, &path, op, pathname);
|
||||||
while (unlikely(!filp)) { /* trailing symlink */
|
while (unlikely(!filp)) { /* trailing symlink */
|
||||||
struct path link = path;
|
struct path link = path;
|
||||||
@ -2386,12 +2419,13 @@ static struct file *path_openat(int dfd, const char *pathname,
|
|||||||
out:
|
out:
|
||||||
if (nd.root.mnt)
|
if (nd.root.mnt)
|
||||||
path_put(&nd.root);
|
path_put(&nd.root);
|
||||||
|
if (base)
|
||||||
|
fput(base);
|
||||||
release_open_intent(&nd);
|
release_open_intent(&nd);
|
||||||
return filp;
|
return filp;
|
||||||
|
|
||||||
exit_dput:
|
exit_dput:
|
||||||
path_put_conditional(&path, &nd);
|
path_put_conditional(&path, &nd);
|
||||||
out_path:
|
|
||||||
path_put(&nd.path);
|
path_put(&nd.path);
|
||||||
out_filp:
|
out_filp:
|
||||||
filp = ERR_PTR(error);
|
filp = ERR_PTR(error);
|
||||||
|
Loading…
Reference in New Issue
Block a user