forked from Minki/linux
open-style analog of vfs_path_lookup()
new function: file_open_root(dentry, mnt, name, flags) opens the file vfs_path_lookup would arrive to. Note that name can be empty; in that case the usual requirement that dentry should be a directory is lifted. open-coded equivalents switched to it, may_open() got down exactly one caller and became static. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
5b6ca027d8
commit
73d049a40f
@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req)
|
||||
#if 0
|
||||
void mconsole_proc(struct mc_request *req)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
|
||||
struct file *file;
|
||||
int n, err;
|
||||
int n;
|
||||
char *ptr = req->request.data, *buf;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
ptr += strlen("proc");
|
||||
ptr = skip_spaces(ptr);
|
||||
|
||||
err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
|
||||
if (err) {
|
||||
mconsole_reply(req, "Failed to look up file", 1, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = may_open(&nd.path, MAY_READ, O_RDONLY);
|
||||
if (result) {
|
||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||
path_put(&nd.path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
|
||||
current_cred());
|
||||
err = PTR_ERR(file);
|
||||
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
|
||||
if (IS_ERR(file)) {
|
||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||
path_put(&nd.path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,8 @@ struct open_flags {
|
||||
};
|
||||
extern struct file *do_filp_open(int dfd, const char *pathname,
|
||||
const struct open_flags *op, int lookup_flags);
|
||||
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
|
||||
const char *, const struct open_flags *, int lookup_flags);
|
||||
|
||||
/*
|
||||
* inode.c
|
||||
|
80
fs/namei.c
80
fs/namei.c
@ -1487,11 +1487,13 @@ static int path_init(int dfd, const char *name, unsigned int flags,
|
||||
nd->depth = 0;
|
||||
if (flags & LOOKUP_ROOT) {
|
||||
struct inode *inode = nd->root.dentry->d_inode;
|
||||
if (!inode->i_op->lookup)
|
||||
return -ENOTDIR;
|
||||
retval = inode_permission(inode, MAY_EXEC);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (*name) {
|
||||
if (!inode->i_op->lookup)
|
||||
return -ENOTDIR;
|
||||
retval = inode_permission(inode, MAY_EXEC);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
nd->path = nd->root;
|
||||
nd->inode = inode;
|
||||
if (flags & LOOKUP_RCU) {
|
||||
@ -1937,7 +1939,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
return error;
|
||||
}
|
||||
|
||||
int may_open(struct path *path, int acc_mode, int flag)
|
||||
static int may_open(struct path *path, int acc_mode, int flag)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@ -2250,11 +2252,10 @@ exit:
|
||||
}
|
||||
|
||||
static struct file *path_openat(int dfd, const char *pathname,
|
||||
const struct open_flags *op, int flags)
|
||||
struct nameidata *nd, const struct open_flags *op, int flags)
|
||||
{
|
||||
struct file *base = NULL;
|
||||
struct file *filp;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int count = 0;
|
||||
int error;
|
||||
@ -2264,27 +2265,27 @@ static struct file *path_openat(int dfd, const char *pathname,
|
||||
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;
|
||||
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))
|
||||
goto out_filp;
|
||||
|
||||
current->total_link_count = 0;
|
||||
error = link_path_walk(pathname, &nd);
|
||||
error = link_path_walk(pathname, nd);
|
||||
if (unlikely(error))
|
||||
goto out_filp;
|
||||
|
||||
filp = do_last(&nd, &path, op, pathname);
|
||||
filp = do_last(nd, &path, op, pathname);
|
||||
while (unlikely(!filp)) { /* trailing symlink */
|
||||
struct path link = path;
|
||||
struct inode *linki = link.dentry->d_inode;
|
||||
void *cookie;
|
||||
if (!(nd.flags & LOOKUP_FOLLOW) || count++ == 32) {
|
||||
path_put_conditional(&path, &nd);
|
||||
path_put(&nd.path);
|
||||
if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) {
|
||||
path_put_conditional(&path, nd);
|
||||
path_put(&nd->path);
|
||||
filp = ERR_PTR(-ELOOP);
|
||||
break;
|
||||
}
|
||||
@ -2299,23 +2300,23 @@ static struct file *path_openat(int dfd, const char *pathname,
|
||||
* have to putname() it when we are done. Procfs-like symlinks
|
||||
* just set LAST_BIND.
|
||||
*/
|
||||
nd.flags |= LOOKUP_PARENT;
|
||||
nd.flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
|
||||
error = __do_follow_link(&link, &nd, &cookie);
|
||||
nd->flags |= LOOKUP_PARENT;
|
||||
nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
|
||||
error = __do_follow_link(&link, nd, &cookie);
|
||||
if (unlikely(error))
|
||||
filp = ERR_PTR(error);
|
||||
else
|
||||
filp = do_last(&nd, &path, op, pathname);
|
||||
filp = do_last(nd, &path, op, pathname);
|
||||
if (!IS_ERR(cookie) && linki->i_op->put_link)
|
||||
linki->i_op->put_link(link.dentry, &nd, cookie);
|
||||
linki->i_op->put_link(link.dentry, nd, cookie);
|
||||
path_put(&link);
|
||||
}
|
||||
out:
|
||||
if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT))
|
||||
path_put(&nd.root);
|
||||
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
|
||||
path_put(&nd->root);
|
||||
if (base)
|
||||
fput(base);
|
||||
release_open_intent(&nd);
|
||||
release_open_intent(nd);
|
||||
return filp;
|
||||
|
||||
out_filp:
|
||||
@ -2326,16 +2327,39 @@ out_filp:
|
||||
struct file *do_filp_open(int dfd, const char *pathname,
|
||||
const struct open_flags *op, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct file *filp;
|
||||
|
||||
filp = path_openat(dfd, pathname, op, flags | LOOKUP_RCU);
|
||||
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(filp == ERR_PTR(-ECHILD)))
|
||||
filp = path_openat(dfd, pathname, op, flags);
|
||||
filp = path_openat(dfd, pathname, &nd, op, flags);
|
||||
if (unlikely(filp == ERR_PTR(-ESTALE)))
|
||||
filp = path_openat(dfd, pathname, op, flags | LOOKUP_REVAL);
|
||||
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL);
|
||||
return filp;
|
||||
}
|
||||
|
||||
struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const struct open_flags *op, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct file *file;
|
||||
|
||||
nd.root.mnt = mnt;
|
||||
nd.root.dentry = dentry;
|
||||
|
||||
flags |= LOOKUP_ROOT;
|
||||
|
||||
if (dentry->d_inode->i_op->follow_link)
|
||||
return ERR_PTR(-ELOOP);
|
||||
|
||||
file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(file == ERR_PTR(-ECHILD)))
|
||||
file = path_openat(-1, name, &nd, op, flags);
|
||||
if (unlikely(file == ERR_PTR(-ESTALE)))
|
||||
file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup_create - lookup a dentry, creating it if it doesn't exist
|
||||
* @nd: nameidata info
|
||||
|
21
fs/nfsctl.c
21
fs/nfsctl.c
@ -22,30 +22,17 @@
|
||||
|
||||
static struct file *do_open(char *name, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct vfsmount *mnt;
|
||||
int error;
|
||||
struct file *file;
|
||||
|
||||
mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
|
||||
if (IS_ERR(mnt))
|
||||
return (struct file *)mnt;
|
||||
|
||||
error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);
|
||||
file = file_open_root(mnt->mnt_root, mnt, name, flags);
|
||||
|
||||
mntput(mnt); /* drop do_kern_mount reference */
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
if (flags == O_RDWR)
|
||||
error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags);
|
||||
else
|
||||
error = may_open(&nd.path, MAY_WRITE, flags);
|
||||
|
||||
if (!error)
|
||||
return dentry_open(nd.path.dentry, nd.path.mnt, flags,
|
||||
current_cred());
|
||||
|
||||
path_put(&nd.path);
|
||||
return ERR_PTR(error);
|
||||
return file;
|
||||
}
|
||||
|
||||
static struct {
|
||||
|
14
fs/open.c
14
fs/open.c
@ -959,6 +959,20 @@ struct file *filp_open(const char *filename, int flags, int mode)
|
||||
}
|
||||
EXPORT_SYMBOL(filp_open);
|
||||
|
||||
struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *filename, int flags)
|
||||
{
|
||||
struct open_flags op;
|
||||
int lookup = build_open_flags(flags, 0, &op);
|
||||
if (flags & O_CREAT)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (!filename && (flags & O_DIRECTORY))
|
||||
if (!dentry->d_inode->i_op->lookup)
|
||||
return ERR_PTR(-ENOTDIR);
|
||||
return do_file_open_root(dentry, mnt, filename, &op, lookup);
|
||||
}
|
||||
EXPORT_SYMBOL(file_open_root);
|
||||
|
||||
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
|
||||
{
|
||||
struct open_flags op;
|
||||
|
@ -1990,6 +1990,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset,
|
||||
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||
int mode);
|
||||
extern struct file *filp_open(const char *, int, int);
|
||||
extern struct file *file_open_root(struct dentry *, struct vfsmount *,
|
||||
const char *, int);
|
||||
extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
|
||||
const struct cred *);
|
||||
extern int filp_close(struct file *, fl_owner_t id);
|
||||
@ -2205,8 +2207,6 @@ extern struct file *create_read_pipe(struct file *f, int flags);
|
||||
extern struct file *create_write_pipe(int flags);
|
||||
extern void free_write_pipe(struct file *);
|
||||
|
||||
extern int may_open(struct path *, int, int);
|
||||
|
||||
extern int kernel_read(struct file *, loff_t, char *, unsigned long);
|
||||
extern struct file * open_exec(const char *);
|
||||
|
||||
|
@ -1321,13 +1321,11 @@ static ssize_t binary_sysctl(const int *name, int nlen,
|
||||
void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
|
||||
{
|
||||
const struct bin_table *table = NULL;
|
||||
struct nameidata nd;
|
||||
struct vfsmount *mnt;
|
||||
struct file *file;
|
||||
ssize_t result;
|
||||
char *pathname;
|
||||
int flags;
|
||||
int acc_mode;
|
||||
|
||||
pathname = sysctl_getname(name, nlen, &table);
|
||||
result = PTR_ERR(pathname);
|
||||
@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen,
|
||||
/* How should the sysctl be accessed? */
|
||||
if (oldval && oldlen && newval && newlen) {
|
||||
flags = O_RDWR;
|
||||
acc_mode = MAY_READ | MAY_WRITE;
|
||||
} else if (newval && newlen) {
|
||||
flags = O_WRONLY;
|
||||
acc_mode = MAY_WRITE;
|
||||
} else if (oldval && oldlen) {
|
||||
flags = O_RDONLY;
|
||||
acc_mode = MAY_READ;
|
||||
} else {
|
||||
result = 0;
|
||||
goto out_putname;
|
||||
}
|
||||
|
||||
mnt = current->nsproxy->pid_ns->proc_mnt;
|
||||
result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
|
||||
if (result)
|
||||
goto out_putname;
|
||||
|
||||
result = may_open(&nd.path, acc_mode, flags);
|
||||
if (result)
|
||||
goto out_putpath;
|
||||
|
||||
file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred());
|
||||
file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
|
||||
result = PTR_ERR(file);
|
||||
if (IS_ERR(file))
|
||||
goto out_putname;
|
||||
@ -1370,10 +1357,6 @@ out_putname:
|
||||
putname(pathname);
|
||||
out:
|
||||
return result;
|
||||
|
||||
out_putpath:
|
||||
path_put(&nd.path);
|
||||
goto out_putname;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user