[PATCH 04/18] VFS: add vfs_lookup_open()
NeilBrown <[email protected]>
| Newsgroups | gmane.linux.nfs,gmane.linux.file-systems |
|---|---|
| Message-ID | <[email protected]> |
From: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]> vfs_lookup_open() is a limited version of lookup_open() which is exported for nfsd to use - to replace dentry_create(). It is limited in that no filename is given (thus no auditing) and no LOOKUP_ flags are passed. A few "intent" LOOKUP flags are deduced from the open flags. Signed-off-by: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]> --- fs/namei.c | 54 +++++++++++++++++++++++++++++++++++++++++++ include/linux/namei.h | 3 +++ 2 files changed, 57 insertions(+) diff --git a/fs/namei.c b/fs/namei.c index 18a43c24d7f1..db3fddbccd21 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4571,6 +4571,60 @@ static struct dentry *lookup_open(const struct path *path, struct file *file, goto out; } +/** + * vfs_lookup_open - open and possibly create a regular file + * @parent: directory to contain file + * @last: final component of file name + * @open_flag: O_flags + * @mode: initial permissions for file + * + * Open a file after lookup and/or create. This provides similar + * functionality open_last_lookups() for in-kernel users, particularly + * nfsd. + * It uses ->atomic_open or ->lookup / ->create / ->open as appropriate. + * + * Returns: the opened struct file, or an error. + */ +struct file *vfs_lookup_open(struct path *parent, struct qstr *last, + int open_flag, umode_t mode) +{ + struct file *file __free(fput) = NULL; + unsigned int lookup_flags = LOOKUP_OPEN; + struct dentry *dentry; + int error = 0; + + error = lookup_noperm_common(last, parent->dentry); + if (error) + return ERR_PTR(error); + + file = alloc_empty_file(open_flag, current_cred()); + if (IS_ERR(file)) + return file; + + if (open_flag & O_CREAT) { + lookup_flags |= LOOKUP_CREATE; + if (open_flag & O_EXCL) + lookup_flags |= LOOKUP_EXCL; + } + dentry = lookup_open(parent, file, last, lookup_flags, NULL, + open_flag, S_IFREG | mode); + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + + if (d_really_is_negative(dentry)) { + error = -ENOENT; + } else if (!(file->f_mode & FMODE_OPENED)) { + struct path path = {.mnt = parent->mnt, .dentry = dentry }; + + error = vfs_open(&path, file); + } + dput(dentry); + + if (error) + return ERR_PTR(error); + return no_free_ptr(file); +} + static inline bool trailing_slashes(struct nameidata *nd) { return (bool)nd->last.name[nd->last.len]; diff --git a/include/linux/namei.h b/include/linux/namei.h index 2ad6dd9987b9..8c048c97a7f7 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -103,6 +103,9 @@ struct dentry *start_creating_dentry(struct dentry *parent, struct dentry *start_removing_dentry(struct dentry *parent, struct dentry *child); +struct file *vfs_lookup_open(struct path *parent, struct qstr *last, + int open_flag, umode_t mode); + /* end_creating - finish action started with start_creating * @child: dentry returned by start_creating() or vfs_mkdir() * -- 2.50.0.107.gf914562f5916.dirty