Commit 015c3bbc authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro

vfs: remove open intents from nameidata

All users of open intents have been converted to use ->atomic_{open,create}.

This patch gets rid of nd->intent.open and related infrastructure.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent e43ae79c
...@@ -82,13 +82,10 @@ extern struct super_block *user_get_super(dev_t); ...@@ -82,13 +82,10 @@ extern struct super_block *user_get_super(dev_t);
/* /*
* open.c * open.c
*/ */
struct nameidata;
extern struct file *nameidata_to_filp(struct nameidata *);
extern void release_open_intent(struct nameidata *);
struct opendata { struct opendata {
struct dentry *dentry; struct dentry *dentry;
struct vfsmount *mnt; struct vfsmount *mnt;
struct file **filp; struct file *filp;
}; };
struct open_flags { struct open_flags {
int open_flag; int open_flag;
......
...@@ -463,22 +463,6 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) ...@@ -463,22 +463,6 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
return -ECHILD; return -ECHILD;
} }
/**
* release_open_intent - free up open intent resources
* @nd: pointer to nameidata
*/
void release_open_intent(struct nameidata *nd)
{
struct file *file = nd->intent.open.file;
if (file && !IS_ERR(file)) {
if (file->f_path.dentry == NULL)
put_filp(file);
else
fput(file);
}
}
static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
return dentry->d_op->d_revalidate(dentry, nd); return dentry->d_op->d_revalidate(dentry, nd);
...@@ -2210,7 +2194,8 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) ...@@ -2210,7 +2194,8 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
} }
static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry, static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
struct path *path, const struct open_flags *op, struct path *path, struct opendata *od,
const struct open_flags *op,
int *want_write, bool need_lookup, int *want_write, bool need_lookup,
bool *created) bool *created)
{ {
...@@ -2219,7 +2204,6 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry, ...@@ -2219,7 +2204,6 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
umode_t mode; umode_t mode;
int error; int error;
int acc_mode; int acc_mode;
struct opendata od;
struct file *filp; struct file *filp;
int create_error = 0; int create_error = 0;
struct dentry *const DENTRY_NOT_SET = (void *) -1UL; struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
...@@ -2285,14 +2269,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry, ...@@ -2285,14 +2269,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
if (nd->flags & LOOKUP_DIRECTORY) if (nd->flags & LOOKUP_DIRECTORY)
open_flag |= O_DIRECTORY; open_flag |= O_DIRECTORY;
od.dentry = DENTRY_NOT_SET; od->dentry = DENTRY_NOT_SET;
od.mnt = nd->path.mnt; od->mnt = nd->path.mnt;
od.filp = &nd->intent.open.file; filp = dir->i_op->atomic_open(dir, dentry, od, open_flag, mode,
filp = dir->i_op->atomic_open(dir, dentry, &od, open_flag, mode,
created); created);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
if (WARN_ON(od.dentry != DENTRY_NOT_SET)) if (WARN_ON(od->dentry != DENTRY_NOT_SET))
dput(od.dentry); dput(od->dentry);
if (create_error && PTR_ERR(filp) == -ENOENT) if (create_error && PTR_ERR(filp) == -ENOENT)
filp = ERR_PTR(create_error); filp = ERR_PTR(create_error);
...@@ -2306,13 +2289,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry, ...@@ -2306,13 +2289,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
} }
if (!filp) { if (!filp) {
if (WARN_ON(od.dentry == DENTRY_NOT_SET)) { if (WARN_ON(od->dentry == DENTRY_NOT_SET)) {
filp = ERR_PTR(-EIO); filp = ERR_PTR(-EIO);
goto out; goto out;
} }
if (od.dentry) { if (od->dentry) {
dput(dentry); dput(dentry);
dentry = od.dentry; dentry = od->dentry;
} }
goto looked_up; goto looked_up;
} }
...@@ -2375,6 +2358,7 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry, ...@@ -2375,6 +2358,7 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
* was performed, only lookup. * was performed, only lookup.
*/ */
static struct file *lookup_open(struct nameidata *nd, struct path *path, static struct file *lookup_open(struct nameidata *nd, struct path *path,
struct opendata *od,
const struct open_flags *op, const struct open_flags *op,
int *want_write, bool *created) int *want_write, bool *created)
{ {
...@@ -2394,7 +2378,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path, ...@@ -2394,7 +2378,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path,
goto out_no_open; goto out_no_open;
if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) { if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
return atomic_open(nd, dentry, path, op, want_write, return atomic_open(nd, dentry, path, od, op, want_write,
need_lookup, created); need_lookup, created);
} }
...@@ -2416,7 +2400,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path, ...@@ -2416,7 +2400,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path,
* rw->ro transition does not occur between * rw->ro transition does not occur between
* the time when the file is created and when * the time when the file is created and when
* a permanent write count is taken through * a permanent write count is taken through
* the 'struct file' in nameidata_to_filp(). * the 'struct file' in finish_open().
*/ */
error = mnt_want_write(nd->path.mnt); error = mnt_want_write(nd->path.mnt);
if (error) if (error)
...@@ -2444,7 +2428,8 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path, ...@@ -2444,7 +2428,8 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path,
* Handle the last step of 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) struct opendata *od, const struct open_flags *op,
const char *pathname)
{ {
struct dentry *dir = nd->path.dentry; struct dentry *dir = nd->path.dentry;
int open_flag = op->open_flag; int open_flag = op->open_flag;
...@@ -2521,7 +2506,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, ...@@ -2521,7 +2506,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
retry_lookup: retry_lookup:
mutex_lock(&dir->d_inode->i_mutex); mutex_lock(&dir->d_inode->i_mutex);
filp = lookup_open(nd, path, op, &want_write, &created); filp = lookup_open(nd, path, od, op, &want_write, &created);
mutex_unlock(&dir->d_inode->i_mutex); mutex_unlock(&dir->d_inode->i_mutex);
if (filp) { if (filp) {
...@@ -2627,7 +2612,8 @@ static struct file *do_last(struct nameidata *nd, struct path *path, ...@@ -2627,7 +2612,8 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
error = may_open(&nd->path, acc_mode, open_flag); error = may_open(&nd->path, acc_mode, open_flag);
if (error) if (error)
goto exit; goto exit;
filp = nameidata_to_filp(nd); od->mnt = nd->path.mnt;
filp = finish_open(od, nd->path.dentry, NULL);
if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) { if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) {
BUG_ON(save_parent.dentry != dir); BUG_ON(save_parent.dentry != dir);
path_put(&nd->path); path_put(&nd->path);
...@@ -2642,6 +2628,11 @@ static struct file *do_last(struct nameidata *nd, struct path *path, ...@@ -2642,6 +2628,11 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
retried = true; retried = true;
goto retry_lookup; goto retry_lookup;
} }
if (IS_ERR(filp))
goto out;
error = open_check_o_direct(filp);
if (error)
goto exit_fput;
opened: opened:
if (!IS_ERR(filp)) { if (!IS_ERR(filp)) {
error = ima_file_check(filp, op->acc_mode); error = ima_file_check(filp, op->acc_mode);
...@@ -2671,24 +2662,26 @@ static struct file *do_last(struct nameidata *nd, struct path *path, ...@@ -2671,24 +2662,26 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
exit: exit:
filp = ERR_PTR(error); filp = ERR_PTR(error);
goto out; goto out;
exit_fput:
fput(filp);
goto exit;
} }
static struct file *path_openat(int dfd, const char *pathname, static struct file *path_openat(int dfd, const char *pathname,
struct nameidata *nd, const struct open_flags *op, int flags) struct nameidata *nd, const struct open_flags *op, int flags)
{ {
struct file *base = NULL; struct file *base = NULL;
struct file *filp; struct opendata od;
struct file *res;
struct path path; struct path path;
int error; int error;
filp = get_empty_filp(); od.filp = get_empty_filp();
if (!filp) if (!od.filp)
return ERR_PTR(-ENFILE); return ERR_PTR(-ENFILE);
filp->f_flags = op->open_flag; od.filp->f_flags = op->open_flag;
nd->intent.open.file = filp;
nd->intent.open.flags = open_to_namei_flags(op->open_flag);
nd->intent.open.create_mode = op->mode;
error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
if (unlikely(error)) if (unlikely(error))
...@@ -2699,14 +2692,14 @@ static struct file *path_openat(int dfd, const char *pathname, ...@@ -2699,14 +2692,14 @@ static struct file *path_openat(int dfd, const char *pathname,
if (unlikely(error)) if (unlikely(error))
goto out_filp; goto out_filp;
filp = do_last(nd, &path, op, pathname); res = do_last(nd, &path, &od, op, pathname);
while (unlikely(!filp)) { /* trailing symlink */ while (unlikely(!res)) { /* trailing symlink */
struct path link = path; struct path link = path;
void *cookie; void *cookie;
if (!(nd->flags & LOOKUP_FOLLOW)) { if (!(nd->flags & LOOKUP_FOLLOW)) {
path_put_conditional(&path, nd); path_put_conditional(&path, nd);
path_put(&nd->path); path_put(&nd->path);
filp = ERR_PTR(-ELOOP); res = ERR_PTR(-ELOOP);
break; break;
} }
nd->flags |= LOOKUP_PARENT; nd->flags |= LOOKUP_PARENT;
...@@ -2714,7 +2707,7 @@ static struct file *path_openat(int dfd, const char *pathname, ...@@ -2714,7 +2707,7 @@ static struct file *path_openat(int dfd, const char *pathname,
error = follow_link(&link, nd, &cookie); error = follow_link(&link, nd, &cookie);
if (unlikely(error)) if (unlikely(error))
goto out_filp; goto out_filp;
filp = do_last(nd, &path, op, pathname); res = do_last(nd, &path, &od, op, pathname);
put_link(nd, &link, cookie); put_link(nd, &link, cookie);
} }
out: out:
...@@ -2722,17 +2715,20 @@ static struct file *path_openat(int dfd, const char *pathname, ...@@ -2722,17 +2715,20 @@ static struct file *path_openat(int dfd, const char *pathname,
path_put(&nd->root); path_put(&nd->root);
if (base) if (base)
fput(base); fput(base);
release_open_intent(nd); if (od.filp) {
if (filp == ERR_PTR(-EOPENSTALE)) { BUG_ON(od.filp->f_path.dentry);
put_filp(od.filp);
}
if (res == ERR_PTR(-EOPENSTALE)) {
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
filp = ERR_PTR(-ECHILD); res = ERR_PTR(-ECHILD);
else else
filp = ERR_PTR(-ESTALE); res = ERR_PTR(-ESTALE);
} }
return filp; return res;
out_filp: out_filp:
filp = ERR_PTR(error); res = ERR_PTR(error);
goto out; goto out;
} }
...@@ -2788,7 +2784,6 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path ...@@ -2788,7 +2784,6 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
goto out; goto out;
nd.flags &= ~LOOKUP_PARENT; nd.flags &= ~LOOKUP_PARENT;
nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL; nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
nd.intent.open.flags = O_EXCL;
/* /*
* Do the final lookup. * Do the final lookup.
......
...@@ -770,46 +770,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, ...@@ -770,46 +770,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
return res; return res;
} }
/**
* lookup_instantiate_filp - instantiates the open intent filp
* @nd: pointer to nameidata
* @dentry: pointer to dentry
* @open: open callback
*
* Helper for filesystems that want to use lookup open intents and pass back
* a fully instantiated struct file to the caller.
* This function is meant to be called from within a filesystem's
* lookup method.
* Beware of calling it for non-regular files! Those ->open methods might block
* (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
* leading to a deadlock, as nobody can open that fifo anymore, because
* another process to open fifo will block on locked parent when doing lookup).
* Note that in case of error, nd->intent.open.file is destroyed, but the
* path information remains valid.
* If the open callback is set to NULL, then the standard f_op->open()
* filesystem callback is substituted.
*/
struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
int (*open)(struct inode *, struct file *))
{
const struct cred *cred = current_cred();
if (IS_ERR(nd->intent.open.file))
goto out;
if (IS_ERR(dentry))
goto out_err;
nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
nd->intent.open.file,
open, cred);
out:
return nd->intent.open.file;
out_err:
release_open_intent(nd);
nd->intent.open.file = ERR_CAST(dentry);
goto out;
}
EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
/** /**
* finish_open - finish opening a file * finish_open - finish opening a file
* @od: opaque open data * @od: opaque open data
...@@ -829,9 +789,9 @@ struct file *finish_open(struct opendata *od, struct dentry *dentry, ...@@ -829,9 +789,9 @@ struct file *finish_open(struct opendata *od, struct dentry *dentry,
mntget(od->mnt); mntget(od->mnt);
dget(dentry); dget(dentry);
res = do_dentry_open(dentry, od->mnt, *od->filp, open, current_cred()); res = do_dentry_open(dentry, od->mnt, od->filp, open, current_cred());
if (!IS_ERR(res)) if (!IS_ERR(res))
*od->filp = NULL; od->filp = NULL;
return res; return res;
} }
...@@ -852,49 +812,6 @@ void finish_no_open(struct opendata *od, struct dentry *dentry) ...@@ -852,49 +812,6 @@ void finish_no_open(struct opendata *od, struct dentry *dentry)
} }
EXPORT_SYMBOL(finish_no_open); EXPORT_SYMBOL(finish_no_open);
/**
* nameidata_to_filp - convert a nameidata to an open filp.
* @nd: pointer to nameidata
* @flags: open flags
*
* Note that this function destroys the original nameidata
*/
struct file *nameidata_to_filp(struct nameidata *nd)
{
const struct cred *cred = current_cred();
struct file *filp;
/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
/* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry != NULL) {
nd->intent.open.file = NULL;
} else {
struct file *res;
path_get(&nd->path);
res = do_dentry_open(nd->path.dentry, nd->path.mnt,
filp, NULL, cred);
if (!IS_ERR(res)) {
int error;
nd->intent.open.file = NULL;
BUG_ON(res != filp);
error = open_check_o_direct(filp);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
} else {
/* Allow nd->intent.open.file to be recycled */
filp = res;
}
}
return filp;
}
/* /*
* dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
* error. * error.
......
...@@ -7,12 +7,6 @@ ...@@ -7,12 +7,6 @@
struct vfsmount; struct vfsmount;
struct open_intent {
int flags;
int create_mode;
struct file *file;
};
enum { MAX_NESTED_LINKS = 8 }; enum { MAX_NESTED_LINKS = 8 };
struct nameidata { struct nameidata {
...@@ -25,11 +19,6 @@ struct nameidata { ...@@ -25,11 +19,6 @@ struct nameidata {
int last_type; int last_type;
unsigned depth; unsigned depth;
char *saved_names[MAX_NESTED_LINKS + 1]; char *saved_names[MAX_NESTED_LINKS + 1];
/* Intent data */
union {
struct open_intent open;
} intent;
}; };
/* /*
...@@ -82,9 +71,6 @@ extern int kern_path_parent(const char *, struct nameidata *); ...@@ -82,9 +71,6 @@ extern int kern_path_parent(const char *, struct nameidata *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *, extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct path *); const char *, unsigned int, struct path *);
extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
int (*open)(struct inode *, struct file *));
extern struct dentry *lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
extern int follow_down_one(struct path *); extern int follow_down_one(struct path *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment