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: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
e43ae79c54
Коммит
015c3bbcd8
|
@ -82,13 +82,10 @@ extern struct super_block *user_get_super(dev_t);
|
|||
/*
|
||||
* open.c
|
||||
*/
|
||||
struct nameidata;
|
||||
extern struct file *nameidata_to_filp(struct nameidata *);
|
||||
extern void release_open_intent(struct nameidata *);
|
||||
struct opendata {
|
||||
struct dentry *dentry;
|
||||
struct vfsmount *mnt;
|
||||
struct file **filp;
|
||||
struct file *filp;
|
||||
};
|
||||
struct open_flags {
|
||||
int open_flag;
|
||||
|
|
99
fs/namei.c
99
fs/namei.c
|
@ -463,22 +463,6 @@ err_root:
|
|||
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)
|
||||
{
|
||||
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)
|
|||
}
|
||||
|
||||
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,
|
||||
bool *created)
|
||||
{
|
||||
|
@ -2219,7 +2204,6 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
umode_t mode;
|
||||
int error;
|
||||
int acc_mode;
|
||||
struct opendata od;
|
||||
struct file *filp;
|
||||
int create_error = 0;
|
||||
struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
|
||||
|
@ -2285,14 +2269,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
if (nd->flags & LOOKUP_DIRECTORY)
|
||||
open_flag |= O_DIRECTORY;
|
||||
|
||||
od.dentry = DENTRY_NOT_SET;
|
||||
od.mnt = nd->path.mnt;
|
||||
od.filp = &nd->intent.open.file;
|
||||
filp = dir->i_op->atomic_open(dir, dentry, &od, open_flag, mode,
|
||||
od->dentry = DENTRY_NOT_SET;
|
||||
od->mnt = nd->path.mnt;
|
||||
filp = dir->i_op->atomic_open(dir, dentry, od, open_flag, mode,
|
||||
created);
|
||||
if (IS_ERR(filp)) {
|
||||
if (WARN_ON(od.dentry != DENTRY_NOT_SET))
|
||||
dput(od.dentry);
|
||||
if (WARN_ON(od->dentry != DENTRY_NOT_SET))
|
||||
dput(od->dentry);
|
||||
|
||||
if (create_error && PTR_ERR(filp) == -ENOENT)
|
||||
filp = ERR_PTR(create_error);
|
||||
|
@ -2306,13 +2289,13 @@ static struct file *atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
}
|
||||
|
||||
if (!filp) {
|
||||
if (WARN_ON(od.dentry == DENTRY_NOT_SET)) {
|
||||
if (WARN_ON(od->dentry == DENTRY_NOT_SET)) {
|
||||
filp = ERR_PTR(-EIO);
|
||||
goto out;
|
||||
}
|
||||
if (od.dentry) {
|
||||
if (od->dentry) {
|
||||
dput(dentry);
|
||||
dentry = od.dentry;
|
||||
dentry = od->dentry;
|
||||
}
|
||||
goto looked_up;
|
||||
}
|
||||
|
@ -2375,6 +2358,7 @@ looked_up:
|
|||
* was performed, only lookup.
|
||||
*/
|
||||
static struct file *lookup_open(struct nameidata *nd, struct path *path,
|
||||
struct opendata *od,
|
||||
const struct open_flags *op,
|
||||
int *want_write, bool *created)
|
||||
{
|
||||
|
@ -2394,7 +2378,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path,
|
|||
goto out_no_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);
|
||||
}
|
||||
|
||||
|
@ -2416,7 +2400,7 @@ static struct file *lookup_open(struct nameidata *nd, struct path *path,
|
|||
* rw->ro transition does not occur between
|
||||
* the time when the file is created and when
|
||||
* 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);
|
||||
if (error)
|
||||
|
@ -2444,7 +2428,8 @@ out_dput:
|
|||
* Handle the last step of open()
|
||||
*/
|
||||
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;
|
||||
int open_flag = op->open_flag;
|
||||
|
@ -2521,7 +2506,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||
|
||||
retry_lookup:
|
||||
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);
|
||||
|
||||
if (filp) {
|
||||
|
@ -2627,7 +2612,8 @@ common:
|
|||
error = may_open(&nd->path, acc_mode, open_flag);
|
||||
if (error)
|
||||
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) {
|
||||
BUG_ON(save_parent.dentry != dir);
|
||||
path_put(&nd->path);
|
||||
|
@ -2642,6 +2628,11 @@ common:
|
|||
retried = true;
|
||||
goto retry_lookup;
|
||||
}
|
||||
if (IS_ERR(filp))
|
||||
goto out;
|
||||
error = open_check_o_direct(filp);
|
||||
if (error)
|
||||
goto exit_fput;
|
||||
opened:
|
||||
if (!IS_ERR(filp)) {
|
||||
error = ima_file_check(filp, op->acc_mode);
|
||||
|
@ -2671,24 +2662,26 @@ exit_dput:
|
|||
exit:
|
||||
filp = ERR_PTR(error);
|
||||
goto out;
|
||||
exit_fput:
|
||||
fput(filp);
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
||||
static struct file *path_openat(int dfd, const char *pathname,
|
||||
struct nameidata *nd, const struct open_flags *op, int flags)
|
||||
{
|
||||
struct file *base = NULL;
|
||||
struct file *filp;
|
||||
struct opendata od;
|
||||
struct file *res;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
filp = get_empty_filp();
|
||||
if (!filp)
|
||||
od.filp = get_empty_filp();
|
||||
if (!od.filp)
|
||||
return ERR_PTR(-ENFILE);
|
||||
|
||||
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;
|
||||
od.filp->f_flags = op->open_flag;
|
||||
|
||||
error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
|
||||
if (unlikely(error))
|
||||
|
@ -2699,14 +2692,14 @@ static struct file *path_openat(int dfd, const char *pathname,
|
|||
if (unlikely(error))
|
||||
goto out_filp;
|
||||
|
||||
filp = do_last(nd, &path, op, pathname);
|
||||
while (unlikely(!filp)) { /* trailing symlink */
|
||||
res = do_last(nd, &path, &od, op, pathname);
|
||||
while (unlikely(!res)) { /* trailing symlink */
|
||||
struct path link = path;
|
||||
void *cookie;
|
||||
if (!(nd->flags & LOOKUP_FOLLOW)) {
|
||||
path_put_conditional(&path, nd);
|
||||
path_put(&nd->path);
|
||||
filp = ERR_PTR(-ELOOP);
|
||||
res = ERR_PTR(-ELOOP);
|
||||
break;
|
||||
}
|
||||
nd->flags |= LOOKUP_PARENT;
|
||||
|
@ -2714,7 +2707,7 @@ static struct file *path_openat(int dfd, const char *pathname,
|
|||
error = follow_link(&link, nd, &cookie);
|
||||
if (unlikely(error))
|
||||
goto out_filp;
|
||||
filp = do_last(nd, &path, op, pathname);
|
||||
res = do_last(nd, &path, &od, op, pathname);
|
||||
put_link(nd, &link, cookie);
|
||||
}
|
||||
out:
|
||||
|
@ -2722,17 +2715,20 @@ out:
|
|||
path_put(&nd->root);
|
||||
if (base)
|
||||
fput(base);
|
||||
release_open_intent(nd);
|
||||
if (filp == ERR_PTR(-EOPENSTALE)) {
|
||||
if (flags & LOOKUP_RCU)
|
||||
filp = ERR_PTR(-ECHILD);
|
||||
else
|
||||
filp = ERR_PTR(-ESTALE);
|
||||
if (od.filp) {
|
||||
BUG_ON(od.filp->f_path.dentry);
|
||||
put_filp(od.filp);
|
||||
}
|
||||
return filp;
|
||||
if (res == ERR_PTR(-EOPENSTALE)) {
|
||||
if (flags & LOOKUP_RCU)
|
||||
res = ERR_PTR(-ECHILD);
|
||||
else
|
||||
res = ERR_PTR(-ESTALE);
|
||||
}
|
||||
return res;
|
||||
|
||||
out_filp:
|
||||
filp = ERR_PTR(error);
|
||||
res = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -2788,7 +2784,6 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
|
|||
goto out;
|
||||
nd.flags &= ~LOOKUP_PARENT;
|
||||
nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
|
||||
nd.intent.open.flags = O_EXCL;
|
||||
|
||||
/*
|
||||
* Do the final lookup.
|
||||
|
|
87
fs/open.c
87
fs/open.c
|
@ -770,46 +770,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
|
|||
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
|
||||
* @od: opaque open data
|
||||
|
@ -829,9 +789,9 @@ struct file *finish_open(struct opendata *od, struct dentry *dentry,
|
|||
mntget(od->mnt);
|
||||
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))
|
||||
*od->filp = NULL;
|
||||
od->filp = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -852,49 +812,6 @@ void finish_no_open(struct opendata *od, struct dentry *dentry)
|
|||
}
|
||||
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
|
||||
* error.
|
||||
|
|
|
@ -7,12 +7,6 @@
|
|||
|
||||
struct vfsmount;
|
||||
|
||||
struct open_intent {
|
||||
int flags;
|
||||
int create_mode;
|
||||
struct file *file;
|
||||
};
|
||||
|
||||
enum { MAX_NESTED_LINKS = 8 };
|
||||
|
||||
struct nameidata {
|
||||
|
@ -25,11 +19,6 @@ struct nameidata {
|
|||
int last_type;
|
||||
unsigned depth;
|
||||
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 *);
|
|||
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||
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 int follow_down_one(struct path *);
|
||||
|
|
Загрузка…
Ссылка в новой задаче