[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.