linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] io_uring: add mkdirat support
@ 2021-05-13 11:06 Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 1/6] fs: make do_mkdirat() take struct filename Dmitry Kadashev
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

This adds mkdirat support to io_uring and is heavily based on recently
added renameat() / unlinkat() support.

The first patch is preparation with no functional changes, makes
do_mkdirat accept struct filename pointer rather than the user string.

The second one leverages that to implement mkdirat in io_uring.

The rest of the patches just convert other similar do_* functions in
namei.c to accept struct filename, for uniformity with do_mkdirat,
do_renameat and do_unlinkat. No functional changes there.

Based on io_uring-5.13.

v4:
- update do_mknodat, do_symlinkat and do_linkat to accept struct
  filename for uniformity with do_mkdirat, do_renameat and do_unlinkat;

v3:
- rebase;

v2:
- do not mess with struct filename's refcount in do_mkdirat, instead add
  and use __filename_create() that does not drop the name on success;

Dmitry Kadashev (6):
  fs: make do_mkdirat() take struct filename
  io_uring: add support for IORING_OP_MKDIRAT
  fs: make do_mknodat() take struct filename
  fs: make do_symlinkat() take struct filename
  namei: add getname_uflags()
  fs: make do_linkat() take struct filename

 fs/exec.c                     |   8 +-
 fs/internal.h                 |   1 +
 fs/io_uring.c                 |  55 ++++++++++++++
 fs/namei.c                    | 135 +++++++++++++++++++++++-----------
 include/linux/fs.h            |   1 +
 include/uapi/linux/io_uring.h |   1 +
 6 files changed, 152 insertions(+), 49 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4 1/6] fs: make do_mkdirat() take struct filename
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-14 14:32   ` Christian Brauner
  2021-05-13 11:06 ` [PATCH v4 2/6] io_uring: add support for IORING_OP_MKDIRAT Dmitry Kadashev
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

Pass in the struct filename pointers instead of the user string, and
update the three callers to do the same. This is heavily based on
commit dbea8d345177 ("fs: make do_renameat2() take struct filename").

This behaves like do_unlinkat() and do_renameat2().

Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---
 fs/internal.h |  1 +
 fs/namei.c    | 22 ++++++++++++++++------
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 6aeae7ef3380..848e165ef0f1 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -77,6 +77,7 @@ long do_unlinkat(int dfd, struct filename *name);
 int may_linkat(struct user_namespace *mnt_userns, struct path *link);
 int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
 		 struct filename *newname, unsigned int flags);
+long do_mkdirat(int dfd, struct filename *name, umode_t mode);
 
 /*
  * namespace.c
diff --git a/fs/namei.c b/fs/namei.c
index 79b0ff9b151e..49317c018341 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3556,7 +3556,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 	return file;
 }
 
-static struct dentry *filename_create(int dfd, struct filename *name,
+static struct dentry *__filename_create(int dfd, struct filename *name,
 				struct path *path, unsigned int lookup_flags)
 {
 	struct dentry *dentry = ERR_PTR(-EEXIST);
@@ -3612,7 +3612,6 @@ static struct dentry *filename_create(int dfd, struct filename *name,
 		error = err2;
 		goto fail;
 	}
-	putname(name);
 	return dentry;
 fail:
 	dput(dentry);
@@ -3627,6 +3626,16 @@ static struct dentry *filename_create(int dfd, struct filename *name,
 	return dentry;
 }
 
+static inline struct dentry *filename_create(int dfd, struct filename *name,
+				struct path *path, unsigned int lookup_flags)
+{
+	struct dentry *res = __filename_create(dfd, name, path, lookup_flags);
+
+	if (!IS_ERR(res))
+		putname(name);
+	return res;
+}
+
 struct dentry *kern_path_create(int dfd, const char *pathname,
 				struct path *path, unsigned int lookup_flags)
 {
@@ -3817,7 +3826,7 @@ int vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 }
 EXPORT_SYMBOL(vfs_mkdir);
 
-static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
+long do_mkdirat(int dfd, struct filename *name, umode_t mode)
 {
 	struct dentry *dentry;
 	struct path path;
@@ -3825,7 +3834,7 @@ static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
 	unsigned int lookup_flags = LOOKUP_DIRECTORY;
 
 retry:
-	dentry = user_path_create(dfd, pathname, &path, lookup_flags);
+	dentry = __filename_create(dfd, name, &path, lookup_flags);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
@@ -3843,17 +3852,18 @@ static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
 		lookup_flags |= LOOKUP_REVAL;
 		goto retry;
 	}
+	putname(name);
 	return error;
 }
 
 SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 {
-	return do_mkdirat(dfd, pathname, mode);
+	return do_mkdirat(dfd, getname(pathname), mode);
 }
 
 SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
 {
-	return do_mkdirat(AT_FDCWD, pathname, mode);
+	return do_mkdirat(AT_FDCWD, getname(pathname), mode);
 }
 
 /**
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 2/6] io_uring: add support for IORING_OP_MKDIRAT
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 1/6] fs: make do_mkdirat() take struct filename Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 3/6] fs: make do_mknodat() take struct filename Dmitry Kadashev
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

IORING_OP_MKDIRAT behaves like mkdirat(2) and takes the same flags
and arguments.

Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---
 fs/io_uring.c                 | 55 +++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |  1 +
 2 files changed, 56 insertions(+)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 9ac5e278a91e..0486ee6f0dd3 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -668,6 +668,13 @@ struct io_unlink {
 	struct filename			*filename;
 };
 
+struct io_mkdir {
+	struct file			*file;
+	int				dfd;
+	umode_t				mode;
+	struct filename			*filename;
+};
+
 struct io_completion {
 	struct file			*file;
 	struct list_head		list;
@@ -812,6 +819,7 @@ struct io_kiocb {
 		struct io_shutdown	shutdown;
 		struct io_rename	rename;
 		struct io_unlink	unlink;
+		struct io_mkdir		mkdir;
 		/* use only after cleaning per-op data, see io_clean_op() */
 		struct io_completion	compl;
 	};
@@ -1024,6 +1032,7 @@ static const struct io_op_def io_op_defs[] = {
 	},
 	[IORING_OP_RENAMEAT] = {},
 	[IORING_OP_UNLINKAT] = {},
+	[IORING_OP_MKDIRAT] = {},
 };
 
 static bool io_disarm_next(struct io_kiocb *req);
@@ -3531,6 +3540,44 @@ static int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
 	return 0;
 }
 
+static int io_mkdirat_prep(struct io_kiocb *req,
+			    const struct io_uring_sqe *sqe)
+{
+	struct io_mkdir *mkd = &req->mkdir;
+	const char __user *fname;
+
+	if (unlikely(req->flags & REQ_F_FIXED_FILE))
+		return -EBADF;
+
+	mkd->dfd = READ_ONCE(sqe->fd);
+	mkd->mode = READ_ONCE(sqe->len);
+
+	fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	mkd->filename = getname(fname);
+	if (IS_ERR(mkd->filename))
+		return PTR_ERR(mkd->filename);
+
+	req->flags |= REQ_F_NEED_CLEANUP;
+	return 0;
+}
+
+static int io_mkdirat(struct io_kiocb *req, int issue_flags)
+{
+	struct io_mkdir *mkd = &req->mkdir;
+	int ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		return -EAGAIN;
+
+	ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
+
+	req->flags &= ~REQ_F_NEED_CLEANUP;
+	if (ret < 0)
+		req_set_fail_links(req);
+	io_req_complete(req, ret);
+	return 0;
+}
+
 static int io_shutdown_prep(struct io_kiocb *req,
 			    const struct io_uring_sqe *sqe)
 {
@@ -5939,6 +5986,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 		return io_renameat_prep(req, sqe);
 	case IORING_OP_UNLINKAT:
 		return io_unlinkat_prep(req, sqe);
+	case IORING_OP_MKDIRAT:
+		return io_mkdirat_prep(req, sqe);
 	}
 
 	printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6080,6 +6129,9 @@ static void io_clean_op(struct io_kiocb *req)
 		case IORING_OP_UNLINKAT:
 			putname(req->unlink.filename);
 			break;
+		case IORING_OP_MKDIRAT:
+			putname(req->mkdir.filename);
+			break;
 		}
 		req->flags &= ~REQ_F_NEED_CLEANUP;
 	}
@@ -6206,6 +6258,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
 	case IORING_OP_UNLINKAT:
 		ret = io_unlinkat(req, issue_flags);
 		break;
+	case IORING_OP_MKDIRAT:
+		ret = io_mkdirat(req, issue_flags);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index e1ae46683301..bf9d720d371f 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -137,6 +137,7 @@ enum {
 	IORING_OP_SHUTDOWN,
 	IORING_OP_RENAMEAT,
 	IORING_OP_UNLINKAT,
+	IORING_OP_MKDIRAT,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 3/6] fs: make do_mknodat() take struct filename
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 1/6] fs: make do_mkdirat() take struct filename Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 2/6] io_uring: add support for IORING_OP_MKDIRAT Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 4/6] fs: make do_symlinkat() " Dmitry Kadashev
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

Pass in the struct filename pointers instead of the user string, for
uniformity with the recently converted do_unlinkat(), do_renameat(),
do_mkdirat().

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---
 fs/namei.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 49317c018341..9fc981e28788 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3724,7 +3724,7 @@ static int may_mknod(umode_t mode)
 	}
 }
 
-static long do_mknodat(int dfd, const char __user *filename, umode_t mode,
+static long do_mknodat(int dfd, struct filename *name, umode_t mode,
 		unsigned int dev)
 {
 	struct user_namespace *mnt_userns;
@@ -3735,9 +3735,9 @@ static long do_mknodat(int dfd, const char __user *filename, umode_t mode,
 
 	error = may_mknod(mode);
 	if (error)
-		return error;
+		goto out1;
 retry:
-	dentry = user_path_create(dfd, filename, &path, lookup_flags);
+	dentry = __filename_create(dfd, name, &path, lookup_flags);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
@@ -3745,7 +3745,7 @@ static long do_mknodat(int dfd, const char __user *filename, umode_t mode,
 		mode &= ~current_umask();
 	error = security_path_mknod(&path, dentry, mode, dev);
 	if (error)
-		goto out;
+		goto out2;
 
 	mnt_userns = mnt_user_ns(path.mnt);
 	switch (mode & S_IFMT) {
@@ -3764,24 +3764,27 @@ static long do_mknodat(int dfd, const char __user *filename, umode_t mode,
 					  dentry, mode, 0);
 			break;
 	}
-out:
+out2:
 	done_path_create(&path, dentry);
 	if (retry_estale(error, lookup_flags)) {
 		lookup_flags |= LOOKUP_REVAL;
 		goto retry;
 	}
+out1:
+	if (!IS_ERR(name))
+		putname(name);
 	return error;
 }
 
 SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 		unsigned int, dev)
 {
-	return do_mknodat(dfd, filename, mode, dev);
+	return do_mknodat(dfd, getname(filename), mode, dev);
 }
 
 SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
 {
-	return do_mknodat(AT_FDCWD, filename, mode, dev);
+	return do_mknodat(AT_FDCWD, getname(filename), mode, dev);
 }
 
 /**
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 4/6] fs: make do_symlinkat() take struct filename
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
                   ` (2 preceding siblings ...)
  2021-05-13 11:06 ` [PATCH v4 3/6] fs: make do_mknodat() take struct filename Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-13 11:06 ` [PATCH v4 5/6] namei: add getname_uflags() Dmitry Kadashev
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

Pass in the struct filename pointers instead of the user string, for
uniformity with the recently converted do_mkdnodat(), do_unlinkat(),
do_renameat(), do_mkdirat().

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---
 fs/namei.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 9fc981e28788..76572d703e82 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4189,23 +4189,23 @@ int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 }
 EXPORT_SYMBOL(vfs_symlink);
 
-static long do_symlinkat(const char __user *oldname, int newdfd,
-		  const char __user *newname)
+static long do_symlinkat(struct filename *from, int newdfd,
+		  struct filename *to)
 {
 	int error;
-	struct filename *from;
 	struct dentry *dentry;
 	struct path path;
 	unsigned int lookup_flags = 0;
 
-	from = getname(oldname);
-	if (IS_ERR(from))
-		return PTR_ERR(from);
+	if (IS_ERR(from)) {
+		error = PTR_ERR(from);
+		goto out_putboth;
+	}
 retry:
-	dentry = user_path_create(newdfd, newname, &path, lookup_flags);
+	dentry = __filename_create(newdfd, to, &path, lookup_flags);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
-		goto out_putname;
+		goto out_putfrom;
 
 	error = security_path_symlink(&path, dentry, from->name);
 	if (!error) {
@@ -4220,20 +4220,24 @@ static long do_symlinkat(const char __user *oldname, int newdfd,
 		lookup_flags |= LOOKUP_REVAL;
 		goto retry;
 	}
-out_putname:
-	putname(from);
+out_putboth:
+	if (!IS_ERR(to))
+		putname(to);
+out_putfrom:
+	if (!IS_ERR(from))
+		putname(from);
 	return error;
 }
 
 SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 		int, newdfd, const char __user *, newname)
 {
-	return do_symlinkat(oldname, newdfd, newname);
+	return do_symlinkat(getname(oldname), newdfd, getname(newname));
 }
 
 SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname)
 {
-	return do_symlinkat(oldname, AT_FDCWD, newname);
+	return do_symlinkat(getname(oldname), AT_FDCWD, getname(newname));
 }
 
 /**
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 5/6] namei: add getname_uflags()
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
                   ` (3 preceding siblings ...)
  2021-05-13 11:06 ` [PATCH v4 4/6] fs: make do_symlinkat() " Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-14 14:59   ` Christian Brauner
  2021-05-13 11:06 ` [PATCH v4 6/6] fs: make do_linkat() take struct filename Dmitry Kadashev
  2021-05-14 14:52 ` [PATCH v4 0/6] io_uring: add mkdirat support Christian Brauner
  6 siblings, 1 reply; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

There are a couple of places where we already open-code the (flags &
AT_EMPTY_PATH) check and io_uring will likely add another one in the
future.  Let's just add a simple helper getname_uflags() that handles
this directly and use it.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/io-uring/20210415100815.edrn4a7cy26wkowe@wittgenstein/
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---

Christian, I've kept your Signed-off-by here, even though I took only
part of the change (leaving getname_flags() switch to boolean out to
keep the change smaller). Please let me know if that is OK or not and/or
if you prefer the rest of the change be restored.

 fs/exec.c          | 8 ++------
 fs/namei.c         | 8 ++++++++
 include/linux/fs.h | 1 +
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 18594f11c31f..df33ecaf2111 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -2069,10 +2069,8 @@ SYSCALL_DEFINE5(execveat,
 		const char __user *const __user *, envp,
 		int, flags)
 {
-	int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
-
 	return do_execveat(fd,
-			   getname_flags(filename, lookup_flags, NULL),
+			   getname_uflags(filename, flags),
 			   argv, envp, flags);
 }
 
@@ -2090,10 +2088,8 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd,
 		       const compat_uptr_t __user *, envp,
 		       int,  flags)
 {
-	int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
-
 	return compat_do_execveat(fd,
-				  getname_flags(filename, lookup_flags, NULL),
+				  getname_uflags(filename, flags),
 				  argv, envp, flags);
 }
 #endif
diff --git a/fs/namei.c b/fs/namei.c
index 76572d703e82..010455938826 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -203,6 +203,14 @@ getname_flags(const char __user *filename, int flags, int *empty)
 	return result;
 }
 
+struct filename *
+getname_uflags(const char __user *filename, int uflags)
+{
+	int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
+
+	return getname_flags(filename, flags, NULL);
+}
+
 struct filename *
 getname(const char __user * filename)
 {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bf4e90d3ab18..c46e70682fc0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2783,6 +2783,7 @@ static inline struct file *file_clone_open(struct file *file)
 extern int filp_close(struct file *, fl_owner_t id);
 
 extern struct filename *getname_flags(const char __user *, int, int *);
+extern struct filename *getname_uflags(const char __user *, int);
 extern struct filename *getname(const char __user *);
 extern struct filename *getname_kernel(const char *);
 extern void putname(struct filename *name);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 6/6] fs: make do_linkat() take struct filename
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
                   ` (4 preceding siblings ...)
  2021-05-13 11:06 ` [PATCH v4 5/6] namei: add getname_uflags() Dmitry Kadashev
@ 2021-05-13 11:06 ` Dmitry Kadashev
  2021-05-14 14:52 ` [PATCH v4 0/6] io_uring: add mkdirat support Christian Brauner
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-13 11:06 UTC (permalink / raw)
  To: Jens Axboe, Alexander Viro, Christian Brauner
  Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev

Pass in the struct filename pointers instead of the user string, for
uniformity with do_renameat2, do_unlinkat, do_mknodat, etc.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
---

Several things concern me about this change:

* Separation of getname_uflags() that uses the AT_EMPTY_PATH flag, and
  the capability / permissions check for that AT_EMPTY_PATH flag;
* Ugly new = ERR_PTR(error); to avoid double free;

Feedback / hints on better approaches will be really appreciated.

 fs/namei.c | 59 +++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 010455938826..07b1619dd343 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2447,7 +2447,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
 	return err;
 }
 
-int filename_lookup(int dfd, struct filename *name, unsigned flags,
+static int __filename_lookup(int dfd, struct filename *name, unsigned flags,
 		    struct path *path, struct path *root)
 {
 	int retval;
@@ -2469,7 +2469,18 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
 		audit_inode(name, path->dentry,
 			    flags & LOOKUP_MOUNTPOINT ? AUDIT_INODE_NOEVAL : 0);
 	restore_nameidata();
-	putname(name);
+	if (retval)
+		putname(name);
+	return retval;
+}
+
+int filename_lookup(int dfd, struct filename *name, unsigned flags,
+		    struct path *path, struct path *root)
+{
+	int retval = __filename_lookup(dfd, name, flags, path, root);
+
+	if (!retval)
+		putname(name);
 	return retval;
 }
 
@@ -4346,8 +4357,8 @@ EXPORT_SYMBOL(vfs_link);
  * with linux 2.0, and to avoid hard-linking to directories
  * and other special files.  --ADM
  */
-static int do_linkat(int olddfd, const char __user *oldname, int newdfd,
-	      const char __user *newname, int flags)
+static int do_linkat(int olddfd, struct filename *old, int newdfd,
+	      struct filename *new, int flags)
 {
 	struct user_namespace *mnt_userns;
 	struct dentry *new_dentry;
@@ -4356,31 +4367,36 @@ static int do_linkat(int olddfd, const char __user *oldname, int newdfd,
 	int how = 0;
 	int error;
 
-	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
-		return -EINVAL;
+	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) {
+		error = -EINVAL;
+		goto out_putnames;
+	}
 	/*
 	 * To use null names we require CAP_DAC_READ_SEARCH
 	 * This ensures that not everyone will be able to create
 	 * handlink using the passed filedescriptor.
 	 */
-	if (flags & AT_EMPTY_PATH) {
-		if (!capable(CAP_DAC_READ_SEARCH))
-			return -ENOENT;
-		how = LOOKUP_EMPTY;
+	if (flags & AT_EMPTY_PATH && !capable(CAP_DAC_READ_SEARCH)) {
+		error = -ENOENT;
+		goto out_putnames;
 	}
 
 	if (flags & AT_SYMLINK_FOLLOW)
 		how |= LOOKUP_FOLLOW;
 retry:
-	error = user_path_at(olddfd, oldname, how, &old_path);
+	error = __filename_lookup(olddfd, old, how, &old_path, NULL);
 	if (error)
-		return error;
+		goto out_putnew;
 
-	new_dentry = user_path_create(newdfd, newname, &new_path,
+	new_dentry = __filename_create(newdfd, new, &new_path,
 					(how & LOOKUP_REVAL));
 	error = PTR_ERR(new_dentry);
-	if (IS_ERR(new_dentry))
-		goto out;
+	if (IS_ERR(new_dentry)) {
+		// On error `new` is freed by __filename_create, prevent extra freeing
+		// below
+		new = ERR_PTR(error);
+		goto out_putpath;
+	}
 
 	error = -EXDEV;
 	if (old_path.mnt != new_path.mnt)
@@ -4408,8 +4424,14 @@ static int do_linkat(int olddfd, const char __user *oldname, int newdfd,
 		how |= LOOKUP_REVAL;
 		goto retry;
 	}
-out:
+out_putpath:
 	path_put(&old_path);
+out_putnames:
+	if (!IS_ERR(old))
+		putname(old);
+out_putnew:
+	if (!IS_ERR(new))
+		putname(new);
 
 	return error;
 }
@@ -4417,12 +4439,13 @@ static int do_linkat(int olddfd, const char __user *oldname, int newdfd,
 SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 		int, newdfd, const char __user *, newname, int, flags)
 {
-	return do_linkat(olddfd, oldname, newdfd, newname, flags);
+	return do_linkat(olddfd, getname_uflags(oldname, flags),
+		newdfd, getname(newname), flags);
 }
 
 SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
 {
-	return do_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
+	return do_linkat(AT_FDCWD, getname(oldname), AT_FDCWD, getname(newname), 0);
 }
 
 /**
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 1/6] fs: make do_mkdirat() take struct filename
  2021-05-13 11:06 ` [PATCH v4 1/6] fs: make do_mkdirat() take struct filename Dmitry Kadashev
@ 2021-05-14 14:32   ` Christian Brauner
  2021-05-17  9:48     ` Dmitry Kadashev
  0 siblings, 1 reply; 11+ messages in thread
From: Christian Brauner @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Dmitry Kadashev
  Cc: Jens Axboe, Alexander Viro, Pavel Begunkov, linux-fsdevel, io-uring

On Thu, May 13, 2021 at 06:06:07PM +0700, Dmitry Kadashev wrote:
> Pass in the struct filename pointers instead of the user string, and
> update the three callers to do the same. This is heavily based on
> commit dbea8d345177 ("fs: make do_renameat2() take struct filename").
> 
> This behaves like do_unlinkat() and do_renameat2().
> 
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
> ---

Independent of the following patches I think this is ok and with
do_renameat2() that form of conversion has precedence.
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>

>  fs/internal.h |  1 +
>  fs/namei.c    | 22 ++++++++++++++++------
>  2 files changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/internal.h b/fs/internal.h
> index 6aeae7ef3380..848e165ef0f1 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -77,6 +77,7 @@ long do_unlinkat(int dfd, struct filename *name);
>  int may_linkat(struct user_namespace *mnt_userns, struct path *link);
>  int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
>  		 struct filename *newname, unsigned int flags);
> +long do_mkdirat(int dfd, struct filename *name, umode_t mode);

(We should probably have all helpers just return either long or int
instead of alternating between long and int.)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/6] io_uring: add mkdirat support
  2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
                   ` (5 preceding siblings ...)
  2021-05-13 11:06 ` [PATCH v4 6/6] fs: make do_linkat() take struct filename Dmitry Kadashev
@ 2021-05-14 14:52 ` Christian Brauner
  6 siblings, 0 replies; 11+ messages in thread
From: Christian Brauner @ 2021-05-14 14:52 UTC (permalink / raw)
  To: Dmitry Kadashev
  Cc: Jens Axboe, Alexander Viro, Pavel Begunkov, linux-fsdevel, io-uring

On Thu, May 13, 2021 at 06:06:06PM +0700, Dmitry Kadashev wrote:
> This adds mkdirat support to io_uring and is heavily based on recently
> added renameat() / unlinkat() support.
> 
> The first patch is preparation with no functional changes, makes
> do_mkdirat accept struct filename pointer rather than the user string.
> 
> The second one leverages that to implement mkdirat in io_uring.
> 
> The rest of the patches just convert other similar do_* functions in
> namei.c to accept struct filename, for uniformity with do_mkdirat,
> do_renameat and do_unlinkat. No functional changes there.
> 
> Based on io_uring-5.13.
> 
> v4:
> - update do_mknodat, do_symlinkat and do_linkat to accept struct
>   filename for uniformity with do_mkdirat, do_renameat and do_unlinkat;

Dmitry,

If Jens prefers to just run with the conversion of do_mkdirat() and
ignore the rest that's quite alright of course. But I really appreciate
the time spent on the additional conversions.
One question I have is whether we shouldn't just be honest and add
support for linkat, symlinkat, and mknodat in one go instead of being
shy about it. uring does already have mkdirat, renamat2(), and we
already have open(). It seems kinda silly to delay the others... Unless
there's genuinely no interest or need of course.

Christian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 5/6] namei: add getname_uflags()
  2021-05-13 11:06 ` [PATCH v4 5/6] namei: add getname_uflags() Dmitry Kadashev
@ 2021-05-14 14:59   ` Christian Brauner
  0 siblings, 0 replies; 11+ messages in thread
From: Christian Brauner @ 2021-05-14 14:59 UTC (permalink / raw)
  To: Dmitry Kadashev
  Cc: Jens Axboe, Alexander Viro, Pavel Begunkov, linux-fsdevel, io-uring

On Thu, May 13, 2021 at 06:06:11PM +0700, Dmitry Kadashev wrote:
> There are a couple of places where we already open-code the (flags &
> AT_EMPTY_PATH) check and io_uring will likely add another one in the
> future.  Let's just add a simple helper getname_uflags() that handles
> this directly and use it.
> 
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Christian Brauner <christian.brauner@ubuntu.com>
> Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
> Link: https://lore.kernel.org/io-uring/20210415100815.edrn4a7cy26wkowe@wittgenstein/
> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
> Signed-off-by: Dmitry Kadashev <dkadashev@gmail.com>
> ---
> 
> Christian, I've kept your Signed-off-by here, even though I took only
> part of the change (leaving getname_flags() switch to boolean out to
> keep the change smaller). Please let me know if that is OK or not and/or
> if you prefer the rest of the change be restored.

I don't mind either way. I think this change is already worth it as it
gets rid of the open coding. (Would be better if it could be inline in
the header but you need access to LOOKUP_EMPTY for that.)

Acked-by: Christian Brauner <christian.brauner@ubuntu.com>

> 
>  fs/exec.c          | 8 ++------
>  fs/namei.c         | 8 ++++++++
>  include/linux/fs.h | 1 +
>  3 files changed, 11 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/exec.c b/fs/exec.c
> index 18594f11c31f..df33ecaf2111 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -2069,10 +2069,8 @@ SYSCALL_DEFINE5(execveat,
>  		const char __user *const __user *, envp,
>  		int, flags)
>  {
> -	int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
> -
>  	return do_execveat(fd,
> -			   getname_flags(filename, lookup_flags, NULL),
> +			   getname_uflags(filename, flags),
>  			   argv, envp, flags);
>  }
>  
> @@ -2090,10 +2088,8 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd,
>  		       const compat_uptr_t __user *, envp,
>  		       int,  flags)
>  {
> -	int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
> -
>  	return compat_do_execveat(fd,
> -				  getname_flags(filename, lookup_flags, NULL),
> +				  getname_uflags(filename, flags),
>  				  argv, envp, flags);
>  }
>  #endif
> diff --git a/fs/namei.c b/fs/namei.c
> index 76572d703e82..010455938826 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -203,6 +203,14 @@ getname_flags(const char __user *filename, int flags, int *empty)
>  	return result;
>  }
>  
> +struct filename *
> +getname_uflags(const char __user *filename, int uflags)
> +{
> +	int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
> +
> +	return getname_flags(filename, flags, NULL);
> +}
> +
>  struct filename *
>  getname(const char __user * filename)
>  {
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index bf4e90d3ab18..c46e70682fc0 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2783,6 +2783,7 @@ static inline struct file *file_clone_open(struct file *file)
>  extern int filp_close(struct file *, fl_owner_t id);
>  
>  extern struct filename *getname_flags(const char __user *, int, int *);
> +extern struct filename *getname_uflags(const char __user *, int);
>  extern struct filename *getname(const char __user *);
>  extern struct filename *getname_kernel(const char *);
>  extern void putname(struct filename *name);
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 1/6] fs: make do_mkdirat() take struct filename
  2021-05-14 14:32   ` Christian Brauner
@ 2021-05-17  9:48     ` Dmitry Kadashev
  0 siblings, 0 replies; 11+ messages in thread
From: Dmitry Kadashev @ 2021-05-17  9:48 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Jens Axboe, Alexander Viro, Pavel Begunkov, linux-fsdevel, io-uring

On Fri, May 14, 2021 at 9:32 PM Christian Brauner
<christian.brauner@ubuntu.com> wrote:
>
> (We should probably have all helpers just return either long or int
> instead of alternating between long and int.)

Looks like all the helpers are using int internally, and syscalls using
these helpers return int as well. So I will add a patch to make all of
them return ints.

--
Dmitry Kadashev

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-05-17  9:48 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-13 11:06 [PATCH v4 0/6] io_uring: add mkdirat support Dmitry Kadashev
2021-05-13 11:06 ` [PATCH v4 1/6] fs: make do_mkdirat() take struct filename Dmitry Kadashev
2021-05-14 14:32   ` Christian Brauner
2021-05-17  9:48     ` Dmitry Kadashev
2021-05-13 11:06 ` [PATCH v4 2/6] io_uring: add support for IORING_OP_MKDIRAT Dmitry Kadashev
2021-05-13 11:06 ` [PATCH v4 3/6] fs: make do_mknodat() take struct filename Dmitry Kadashev
2021-05-13 11:06 ` [PATCH v4 4/6] fs: make do_symlinkat() " Dmitry Kadashev
2021-05-13 11:06 ` [PATCH v4 5/6] namei: add getname_uflags() Dmitry Kadashev
2021-05-14 14:59   ` Christian Brauner
2021-05-13 11:06 ` [PATCH v4 6/6] fs: make do_linkat() take struct filename Dmitry Kadashev
2021-05-14 14:52 ` [PATCH v4 0/6] io_uring: add mkdirat support Christian Brauner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).