* [PATCH v9 01/11] namei: ignore ERR/NULL names in putname()
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 02/11] namei: change filename_parentat() calling conventions Dmitry Kadashev
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
Supporting ERR/NULL names in putname() makes callers code cleaner, and
is what some other path walking functions already support for the same
reason.
This also removes a few existing IS_ERR checks before putname().
Suggested-by: Linus Torvalds <[email protected]>
Link: https://lore.kernel.org/io-uring/CAHk-=wgCac9hBsYzKMpHk0EbLgQaXR=OUAjHaBtaY+G8A9KhFg@mail.gmail.com/
Cc: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Signed-off-by: Dmitry Kadashev <[email protected]>
---
fs/namei.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 79b0ff9b151e..70caf4ef1134 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -247,6 +247,9 @@ getname_kernel(const char * filename)
void putname(struct filename *name)
{
+ if (IS_ERR_OR_NULL(name))
+ return;
+
BUG_ON(name->refcnt <= 0);
if (--name->refcnt > 0)
@@ -4718,11 +4721,9 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
goto retry;
}
put_both:
- if (!IS_ERR(from))
- putname(from);
+ putname(from);
put_new:
- if (!IS_ERR(to))
- putname(to);
+ putname(to);
return error;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v9 02/11] namei: change filename_parentat() calling conventions
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 01/11] namei: ignore ERR/NULL names in putname() Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 03/11] namei: make do_mkdirat() take struct filename Dmitry Kadashev
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
Since commit 5c31b6cedb675 ("namei: saner calling conventions for
filename_parentat()") filename_parentat() had the following behavior WRT
the passed in struct filename *:
* On error the name is consumed (putname() is called on it);
* On success the name is returned back as the return value;
Now there is a need for filename_create() and filename_lookup() variants
that do not consume the passed filename, and following the same "consume
the name only on error" semantics is proven to be hard to reason about
and result in confusing code.
Hence this preparation change splits filename_parentat() into two: one
that always consumes the name and another that never consumes the name.
This will allow to implement two filename_create() variants in the same
way, and is a consistent and hopefully easier to reason about approach.
Link: https://lore.kernel.org/io-uring/CAOKbgA7MiqZAq3t-HDCpSGUFfco4hMA9ArAE-74fTpU+EkvKPw@mail.gmail.com/
Cc: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Signed-off-by: Dmitry Kadashev <[email protected]>
---
fs/namei.c | 108 ++++++++++++++++++++++++++---------------------------
1 file changed, 53 insertions(+), 55 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 70caf4ef1134..2995b3695724 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2485,7 +2485,7 @@ static int path_parentat(struct nameidata *nd, unsigned flags,
return err;
}
-static struct filename *filename_parentat(int dfd, struct filename *name,
+static int __filename_parentat(int dfd, struct filename *name,
unsigned int flags, struct path *parent,
struct qstr *last, int *type)
{
@@ -2493,7 +2493,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
struct nameidata nd;
if (IS_ERR(name))
- return name;
+ return PTR_ERR(name);
set_nameidata(&nd, dfd, name);
retval = path_parentat(&nd, flags | LOOKUP_RCU, parent);
if (unlikely(retval == -ECHILD))
@@ -2504,29 +2504,34 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
*last = nd.last;
*type = nd.last_type;
audit_inode(name, parent->dentry, AUDIT_INODE_PARENT);
- } else {
- putname(name);
- name = ERR_PTR(retval);
}
restore_nameidata();
- return name;
+ return retval;
+}
+
+static int filename_parentat(int dfd, struct filename *name,
+ unsigned int flags, struct path *parent,
+ struct qstr *last, int *type)
+{
+ int retval = __filename_parentat(dfd, name, flags, parent, last, type);
+
+ putname(name);
+ return retval;
}
/* does lookup, returns the object with parent locked */
struct dentry *kern_path_locked(const char *name, struct path *path)
{
- struct filename *filename;
struct dentry *d;
struct qstr last;
- int type;
+ int type, error;
- filename = filename_parentat(AT_FDCWD, getname_kernel(name), 0, path,
+ error = filename_parentat(AT_FDCWD, getname_kernel(name), 0, path,
&last, &type);
- if (IS_ERR(filename))
- return ERR_CAST(filename);
+ if (error)
+ return ERR_PTR(error);
if (unlikely(type != LAST_NORM)) {
path_put(path);
- putname(filename);
return ERR_PTR(-EINVAL);
}
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
@@ -2535,7 +2540,6 @@ struct dentry *kern_path_locked(const char *name, struct path *path)
inode_unlock(path->dentry->d_inode);
path_put(path);
}
- putname(filename);
return d;
}
@@ -3575,9 +3579,9 @@ static struct dentry *filename_create(int dfd, struct filename *name,
*/
lookup_flags &= LOOKUP_REVAL;
- name = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
- if (IS_ERR(name))
- return ERR_CAST(name);
+ error = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
+ if (error)
+ return ERR_PTR(error);
/*
* Yucky last component or no last component at all?
@@ -3615,7 +3619,6 @@ static struct dentry *filename_create(int dfd, struct filename *name,
error = err2;
goto fail;
}
- putname(name);
return dentry;
fail:
dput(dentry);
@@ -3626,7 +3629,6 @@ static struct dentry *filename_create(int dfd, struct filename *name,
mnt_drop_write(path->mnt);
out:
path_put(path);
- putname(name);
return dentry;
}
@@ -3917,59 +3919,59 @@ EXPORT_SYMBOL(vfs_rmdir);
long do_rmdir(int dfd, struct filename *name)
{
struct user_namespace *mnt_userns;
- int error = 0;
+ int error;
struct dentry *dentry;
struct path path;
struct qstr last;
int type;
unsigned int lookup_flags = 0;
retry:
- name = filename_parentat(dfd, name, lookup_flags,
- &path, &last, &type);
- if (IS_ERR(name))
- return PTR_ERR(name);
+ error = __filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
+ if (error)
+ goto exit1;
switch (type) {
case LAST_DOTDOT:
error = -ENOTEMPTY;
- goto exit1;
+ goto exit2;
case LAST_DOT:
error = -EINVAL;
- goto exit1;
+ goto exit2;
case LAST_ROOT:
error = -EBUSY;
- goto exit1;
+ goto exit2;
}
error = mnt_want_write(path.mnt);
if (error)
- goto exit1;
+ goto exit2;
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- goto exit2;
+ goto exit3;
if (!dentry->d_inode) {
error = -ENOENT;
- goto exit3;
+ goto exit4;
}
error = security_path_rmdir(&path, dentry);
if (error)
- goto exit3;
+ goto exit4;
mnt_userns = mnt_user_ns(path.mnt);
error = vfs_rmdir(mnt_userns, path.dentry->d_inode, dentry);
-exit3:
+exit4:
dput(dentry);
-exit2:
+exit3:
inode_unlock(path.dentry->d_inode);
mnt_drop_write(path.mnt);
-exit1:
+exit2:
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
+exit1:
putname(name);
return error;
}
@@ -4063,17 +4065,17 @@ long do_unlinkat(int dfd, struct filename *name)
struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0;
retry:
- name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
- if (IS_ERR(name))
- return PTR_ERR(name);
+ error = __filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
+ if (error)
+ goto exit1;
error = -EISDIR;
if (type != LAST_NORM)
- goto exit1;
+ goto exit2;
error = mnt_want_write(path.mnt);
if (error)
- goto exit1;
+ goto exit2;
retry_deleg:
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
@@ -4090,11 +4092,11 @@ long do_unlinkat(int dfd, struct filename *name)
ihold(inode);
error = security_path_unlink(&path, dentry);
if (error)
- goto exit2;
+ goto exit3;
mnt_userns = mnt_user_ns(path.mnt);
error = vfs_unlink(mnt_userns, path.dentry->d_inode, dentry,
&delegated_inode);
-exit2:
+exit3:
dput(dentry);
}
inode_unlock(path.dentry->d_inode);
@@ -4107,13 +4109,14 @@ long do_unlinkat(int dfd, struct filename *name)
goto retry_deleg;
}
mnt_drop_write(path.mnt);
-exit1:
+exit2:
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
inode = NULL;
goto retry;
}
+exit1:
putname(name);
return error;
@@ -4124,7 +4127,7 @@ long do_unlinkat(int dfd, struct filename *name)
error = -EISDIR;
else
error = -ENOTDIR;
- goto exit2;
+ goto exit3;
}
SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
@@ -4595,29 +4598,25 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
int error = -EINVAL;
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
- goto put_both;
+ goto put_names;
if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
(flags & RENAME_EXCHANGE))
- goto put_both;
+ goto put_names;
if (flags & RENAME_EXCHANGE)
target_flags = 0;
retry:
- from = filename_parentat(olddfd, from, lookup_flags, &old_path,
+ error = __filename_parentat(olddfd, from, lookup_flags, &old_path,
&old_last, &old_type);
- if (IS_ERR(from)) {
- error = PTR_ERR(from);
- goto put_new;
- }
+ if (error)
+ goto put_names;
- to = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
+ error = __filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
&new_type);
- if (IS_ERR(to)) {
- error = PTR_ERR(to);
+ if (error)
goto exit1;
- }
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
@@ -4720,9 +4719,8 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-put_both:
+put_names:
putname(from);
-put_new:
putname(to);
return error;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v9 03/11] namei: make do_mkdirat() take struct filename
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 01/11] namei: ignore ERR/NULL names in putname() Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 02/11] namei: change filename_parentat() calling conventions Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 04/11] namei: make do_mknodat() " Dmitry Kadashev
` (8 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
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 <[email protected]>
Cc: Linus Torvalds <[email protected]>
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 1 +
fs/namei.c | 26 +++++++++++++++++++-------
2 files changed, 20 insertions(+), 7 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 2995b3695724..54d5f19ee1ce 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3563,7 +3563,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);
@@ -3579,7 +3579,7 @@ static struct dentry *filename_create(int dfd, struct filename *name,
*/
lookup_flags &= LOOKUP_REVAL;
- error = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
+ error = __filename_parentat(dfd, name, lookup_flags, path, &last, &type);
if (error)
return ERR_PTR(error);
@@ -3632,6 +3632,15 @@ 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);
+
+ putname(name);
+ return res;
+}
+
struct dentry *kern_path_create(int dfd, const char *pathname,
struct path *path, unsigned int lookup_flags)
{
@@ -3822,7 +3831,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;
@@ -3830,9 +3839,10 @@ 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);
+ error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ goto out_putname;
if (!IS_POSIXACL(path.dentry->d_inode))
mode &= ~current_umask();
@@ -3848,17 +3858,19 @@ static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
+out_putname:
+ 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] 17+ messages in thread
* [PATCH v9 04/11] namei: make do_mknodat() take struct filename
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (2 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 03/11] namei: make do_mkdirat() take struct filename Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 05/11] namei: make do_symlinkat() " Dmitry Kadashev
` (7 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
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: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/namei.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 54d5f19ee1ce..0bc8ff637934 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3729,7 +3729,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;
@@ -3740,17 +3740,18 @@ 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);
+ error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ goto out1;
if (!IS_POSIXACL(path.dentry->d_inode))
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) {
@@ -3769,24 +3770,26 @@ 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:
+ 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] 17+ messages in thread
* [PATCH v9 05/11] namei: make do_symlinkat() take struct filename
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (3 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 04/11] namei: make do_mknodat() " Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 06/11] namei: add getname_uflags() Dmitry Kadashev
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
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: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/namei.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 0bc8ff637934..add984e4bfd0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4197,23 +4197,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_putnames;
+ }
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_putnames;
error = security_path_symlink(&path, dentry, from->name);
if (!error) {
@@ -4228,7 +4228,8 @@ static long do_symlinkat(const char __user *oldname, int newdfd,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out_putname:
+out_putnames:
+ putname(to);
putname(from);
return error;
}
@@ -4236,12 +4237,12 @@ static long do_symlinkat(const char __user *oldname, int newdfd,
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] 17+ messages in thread
* [PATCH v9 06/11] namei: add getname_uflags()
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (4 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 05/11] namei: make do_symlinkat() " Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 07/11] namei: make do_linkat() take struct filename Dmitry Kadashev
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
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: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210415100815.edrn4a7cy26wkowe@wittgenstein/
Signed-off-by: Christian Brauner <[email protected]>
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
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 add984e4bfd0..ab7979f9daaa 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 c3c88fdb9b2a..5885a68d2c12 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2781,6 +2781,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] 17+ messages in thread
* [PATCH v9 07/11] namei: make do_linkat() take struct filename
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (5 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 06/11] namei: add getname_uflags() Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 08/11] namei: update do_*() helpers to return ints Dmitry Kadashev
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
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: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210330071700.kpjoyp5zlni7uejm@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/namei.c | 45 +++++++++++++++++++++++++++++----------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ab7979f9daaa..c4e13bd8652f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2450,7 +2450,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;
@@ -2472,6 +2472,14 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
audit_inode(name, path->dentry,
flags & LOOKUP_MOUNTPOINT ? AUDIT_INODE_NOEVAL : 0);
restore_nameidata();
+ 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);
+
putname(name);
return retval;
}
@@ -4351,8 +4359,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;
@@ -4361,31 +4369,32 @@ 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_putnames;
- 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;
+ goto out_putpath;
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
@@ -4413,8 +4422,11 @@ 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:
+ putname(old);
+ putname(new);
return error;
}
@@ -4422,12 +4434,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] 17+ messages in thread
* [PATCH v9 08/11] namei: update do_*() helpers to return ints
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (6 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 07/11] namei: make do_linkat() take struct filename Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 09/11] io_uring: add support for IORING_OP_MKDIRAT Dmitry Kadashev
` (3 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
Update the following to return int rather than long, for uniformity with
the rest of the do_* helpers in namei.c:
* do_rmdir()
* do_unlinkat()
* do_mkdirat()
* do_mknodat()
* do_symlinkat()
Cc: Linus Torvalds <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210514143202.dmzfcgz5hnauy7ze@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 6 +++---
fs/namei.c | 10 +++++-----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 848e165ef0f1..207a455e32d3 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -72,12 +72,12 @@ extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
struct path *path, struct path *root);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct path *);
-long do_rmdir(int dfd, struct filename *name);
-long do_unlinkat(int dfd, struct filename *name);
+int do_rmdir(int dfd, struct filename *name);
+int 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);
+int do_mkdirat(int dfd, struct filename *name, umode_t mode);
/*
* namespace.c
diff --git a/fs/namei.c b/fs/namei.c
index c4e13bd8652f..d06aeaf5da00 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3745,7 +3745,7 @@ static int may_mknod(umode_t mode)
}
}
-static long do_mknodat(int dfd, struct filename *name, umode_t mode,
+static int do_mknodat(int dfd, struct filename *name, umode_t mode,
unsigned int dev)
{
struct user_namespace *mnt_userns;
@@ -3850,7 +3850,7 @@ int vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
}
EXPORT_SYMBOL(vfs_mkdir);
-long do_mkdirat(int dfd, struct filename *name, umode_t mode)
+int do_mkdirat(int dfd, struct filename *name, umode_t mode)
{
struct dentry *dentry;
struct path path;
@@ -3947,7 +3947,7 @@ int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
}
EXPORT_SYMBOL(vfs_rmdir);
-long do_rmdir(int dfd, struct filename *name)
+int do_rmdir(int dfd, struct filename *name)
{
struct user_namespace *mnt_userns;
int error;
@@ -4085,7 +4085,7 @@ EXPORT_SYMBOL(vfs_unlink);
* writeout happening, and we don't want to prevent access to the directory
* while waiting on the I/O.
*/
-long do_unlinkat(int dfd, struct filename *name)
+int do_unlinkat(int dfd, struct filename *name)
{
int error;
struct dentry *dentry;
@@ -4213,7 +4213,7 @@ int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
}
EXPORT_SYMBOL(vfs_symlink);
-static long do_symlinkat(struct filename *from, int newdfd,
+static int do_symlinkat(struct filename *from, int newdfd,
struct filename *to)
{
int error;
--
2.30.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v9 09/11] io_uring: add support for IORING_OP_MKDIRAT
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (7 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 08/11] namei: update do_*() helpers to return ints Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 10/11] io_uring: add support for IORING_OP_SYMLINKAT Dmitry Kadashev
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
IORING_OP_MKDIRAT behaves like mkdirat(2) and takes the same flags
and arguments.
Cc: Linus Torvalds <[email protected]>
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/io_uring.c | 59 +++++++++++++++++++++++++++++++++++
include/uapi/linux/io_uring.h | 1 +
2 files changed, 60 insertions(+)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 5b840bb1e8ec..42d54f9bbbb2 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -674,6 +674,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;
@@ -831,6 +838,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;
};
@@ -1042,6 +1050,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);
@@ -3545,6 +3554,48 @@ 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->ctx->flags & IORING_SETUP_IOPOLL))
+ return -EINVAL;
+ if (sqe->ioprio || sqe->off || sqe->rw_flags || sqe->buf_index)
+ return -EINVAL;
+ 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(req);
+ io_req_complete(req, ret);
+ return 0;
+}
+
static int io_shutdown_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
@@ -5953,6 +6004,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",
@@ -6114,6 +6167,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;
}
}
if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6242,6 +6298,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 79126d5cd289..a926407c230e 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -133,6 +133,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] 17+ messages in thread
* [PATCH v9 10/11] io_uring: add support for IORING_OP_SYMLINKAT
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (8 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 09/11] io_uring: add support for IORING_OP_MKDIRAT Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 6:34 ` [PATCH v9 11/11] io_uring: add support for IORING_OP_LINKAT Dmitry Kadashev
2021-07-08 18:34 ` [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Linus Torvalds
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
IORING_OP_SYMLINKAT behaves like symlinkat(2) and takes the same flags
and arguments.
Cc: Linus Torvalds <[email protected]>
Suggested-by: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210514145259.wtl4xcsp52woi6ab@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 1 +
fs/io_uring.c | 66 +++++++++++++++++++++++++++++++++++
fs/namei.c | 3 +-
include/uapi/linux/io_uring.h | 1 +
4 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 207a455e32d3..3b3954214385 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -78,6 +78,7 @@ 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);
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
+int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
/*
* namespace.c
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 42d54f9bbbb2..a0f681ec25bb 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -681,6 +681,13 @@ struct io_mkdir {
struct filename *filename;
};
+struct io_symlink {
+ struct file *file;
+ int new_dfd;
+ struct filename *oldpath;
+ struct filename *newpath;
+};
+
struct io_completion {
struct file *file;
struct list_head list;
@@ -839,6 +846,7 @@ struct io_kiocb {
struct io_rename rename;
struct io_unlink unlink;
struct io_mkdir mkdir;
+ struct io_symlink symlink;
/* use only after cleaning per-op data, see io_clean_op() */
struct io_completion compl;
};
@@ -1051,6 +1059,7 @@ static const struct io_op_def io_op_defs[] = {
[IORING_OP_RENAMEAT] = {},
[IORING_OP_UNLINKAT] = {},
[IORING_OP_MKDIRAT] = {},
+ [IORING_OP_SYMLINKAT] = {},
};
static bool io_disarm_next(struct io_kiocb *req);
@@ -3596,6 +3605,54 @@ static int io_mkdirat(struct io_kiocb *req, int issue_flags)
return 0;
}
+static int io_symlinkat_prep(struct io_kiocb *req,
+ const struct io_uring_sqe *sqe)
+{
+ struct io_symlink *sl = &req->symlink;
+ const char __user *oldpath, *newpath;
+
+ if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+ return -EINVAL;
+ if (sqe->ioprio || sqe->len || sqe->rw_flags || sqe->buf_index)
+ return -EINVAL;
+ if (unlikely(req->flags & REQ_F_FIXED_FILE))
+ return -EBADF;
+
+ sl->new_dfd = READ_ONCE(sqe->fd);
+ oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
+ newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+
+ sl->oldpath = getname(oldpath);
+ if (IS_ERR(sl->oldpath))
+ return PTR_ERR(sl->oldpath);
+
+ sl->newpath = getname(newpath);
+ if (IS_ERR(sl->newpath)) {
+ putname(sl->oldpath);
+ return PTR_ERR(sl->newpath);
+ }
+
+ req->flags |= REQ_F_NEED_CLEANUP;
+ return 0;
+}
+
+static int io_symlinkat(struct io_kiocb *req, int issue_flags)
+{
+ struct io_symlink *sl = &req->symlink;
+ int ret;
+
+ if (issue_flags & IO_URING_F_NONBLOCK)
+ return -EAGAIN;
+
+ ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ if (ret < 0)
+ req_set_fail(req);
+ io_req_complete(req, ret);
+ return 0;
+}
+
static int io_shutdown_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
@@ -6006,6 +6063,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_unlinkat_prep(req, sqe);
case IORING_OP_MKDIRAT:
return io_mkdirat_prep(req, sqe);
+ case IORING_OP_SYMLINKAT:
+ return io_symlinkat_prep(req, sqe);
}
printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6170,6 +6229,10 @@ static void io_clean_op(struct io_kiocb *req)
case IORING_OP_MKDIRAT:
putname(req->mkdir.filename);
break;
+ case IORING_OP_SYMLINKAT:
+ putname(req->symlink.oldpath);
+ putname(req->symlink.newpath);
+ break;
}
}
if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6301,6 +6364,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
case IORING_OP_MKDIRAT:
ret = io_mkdirat(req, issue_flags);
break;
+ case IORING_OP_SYMLINKAT:
+ ret = io_symlinkat(req, issue_flags);
+ break;
default:
ret = -EINVAL;
break;
diff --git a/fs/namei.c b/fs/namei.c
index d06aeaf5da00..f241348e64f4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4213,8 +4213,7 @@ int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
}
EXPORT_SYMBOL(vfs_symlink);
-static int do_symlinkat(struct filename *from, int newdfd,
- struct filename *to)
+int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
{
int error;
struct dentry *dentry;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index a926407c230e..61fd347ab176 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -134,6 +134,7 @@ enum {
IORING_OP_RENAMEAT,
IORING_OP_UNLINKAT,
IORING_OP_MKDIRAT,
+ IORING_OP_SYMLINKAT,
/* this goes last, obviously */
IORING_OP_LAST,
--
2.30.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v9 11/11] io_uring: add support for IORING_OP_LINKAT
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (9 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 10/11] io_uring: add support for IORING_OP_SYMLINKAT Dmitry Kadashev
@ 2021-07-08 6:34 ` Dmitry Kadashev
2021-07-08 18:34 ` [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Linus Torvalds
11 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-07-08 6:34 UTC (permalink / raw)
To: Jens Axboe, Alexander Viro, Christian Brauner, Linus Torvalds
Cc: Pavel Begunkov, linux-fsdevel, io-uring, Dmitry Kadashev
IORING_OP_LINKAT behaves like linkat(2) and takes the same flags and
arguments.
In some internal places 'hardlink' is used instead of 'link' to avoid
confusion with the SQE links. Name 'link' conflicts with the existing
'link' member of io_kiocb.
Cc: Linus Torvalds <[email protected]>
Suggested-by: Christian Brauner <[email protected]>
Link: https://lore.kernel.org/io-uring/20210514145259.wtl4xcsp52woi6ab@wittgenstein/
Signed-off-by: Dmitry Kadashev <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 2 +
fs/io_uring.c | 71 +++++++++++++++++++++++++++++++++++
fs/namei.c | 2 +-
include/uapi/linux/io_uring.h | 2 +
4 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/fs/internal.h b/fs/internal.h
index 3b3954214385..15a7d210cc67 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -79,6 +79,8 @@ int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
struct filename *newname, unsigned int flags);
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
+int do_linkat(int olddfd, struct filename *old, int newdfd,
+ struct filename *new, int flags);
/*
* namespace.c
diff --git a/fs/io_uring.c b/fs/io_uring.c
index a0f681ec25bb..d18ca8afd1fb 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -688,6 +688,15 @@ struct io_symlink {
struct filename *newpath;
};
+struct io_hardlink {
+ struct file *file;
+ int old_dfd;
+ int new_dfd;
+ struct filename *oldpath;
+ struct filename *newpath;
+ int flags;
+};
+
struct io_completion {
struct file *file;
struct list_head list;
@@ -847,6 +856,7 @@ struct io_kiocb {
struct io_unlink unlink;
struct io_mkdir mkdir;
struct io_symlink symlink;
+ struct io_hardlink hardlink;
/* use only after cleaning per-op data, see io_clean_op() */
struct io_completion compl;
};
@@ -1060,6 +1070,7 @@ static const struct io_op_def io_op_defs[] = {
[IORING_OP_UNLINKAT] = {},
[IORING_OP_MKDIRAT] = {},
[IORING_OP_SYMLINKAT] = {},
+ [IORING_OP_LINKAT] = {},
};
static bool io_disarm_next(struct io_kiocb *req);
@@ -3653,6 +3664,57 @@ static int io_symlinkat(struct io_kiocb *req, int issue_flags)
return 0;
}
+static int io_linkat_prep(struct io_kiocb *req,
+ const struct io_uring_sqe *sqe)
+{
+ struct io_hardlink *lnk = &req->hardlink;
+ const char __user *oldf, *newf;
+
+ if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+ return -EINVAL;
+ if (sqe->ioprio || sqe->rw_flags || sqe->buf_index)
+ return -EINVAL;
+ if (unlikely(req->flags & REQ_F_FIXED_FILE))
+ return -EBADF;
+
+ lnk->old_dfd = READ_ONCE(sqe->fd);
+ lnk->new_dfd = READ_ONCE(sqe->len);
+ oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
+ newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+ lnk->flags = READ_ONCE(sqe->hardlink_flags);
+
+ lnk->oldpath = getname(oldf);
+ if (IS_ERR(lnk->oldpath))
+ return PTR_ERR(lnk->oldpath);
+
+ lnk->newpath = getname(newf);
+ if (IS_ERR(lnk->newpath)) {
+ putname(lnk->oldpath);
+ return PTR_ERR(lnk->newpath);
+ }
+
+ req->flags |= REQ_F_NEED_CLEANUP;
+ return 0;
+}
+
+static int io_linkat(struct io_kiocb *req, int issue_flags)
+{
+ struct io_hardlink *lnk = &req->hardlink;
+ int ret;
+
+ if (issue_flags & IO_URING_F_NONBLOCK)
+ return -EAGAIN;
+
+ ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
+ lnk->newpath, lnk->flags);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ if (ret < 0)
+ req_set_fail(req);
+ io_req_complete(req, ret);
+ return 0;
+}
+
static int io_shutdown_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
@@ -6065,6 +6127,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_mkdirat_prep(req, sqe);
case IORING_OP_SYMLINKAT:
return io_symlinkat_prep(req, sqe);
+ case IORING_OP_LINKAT:
+ return io_linkat_prep(req, sqe);
}
printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6233,6 +6297,10 @@ static void io_clean_op(struct io_kiocb *req)
putname(req->symlink.oldpath);
putname(req->symlink.newpath);
break;
+ case IORING_OP_LINKAT:
+ putname(req->hardlink.oldpath);
+ putname(req->hardlink.newpath);
+ break;
}
}
if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6367,6 +6435,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
case IORING_OP_SYMLINKAT:
ret = io_symlinkat(req, issue_flags);
break;
+ case IORING_OP_LINKAT:
+ ret = io_linkat(req, issue_flags);
+ break;
default:
ret = -EINVAL;
break;
diff --git a/fs/namei.c b/fs/namei.c
index f241348e64f4..b5adfd4f7de6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4358,7 +4358,7 @@ 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, struct filename *old, int newdfd,
+int do_linkat(int olddfd, struct filename *old, int newdfd,
struct filename *new, int flags)
{
struct user_namespace *mnt_userns;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 61fd347ab176..10eb38d2864f 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -44,6 +44,7 @@ struct io_uring_sqe {
__u32 splice_flags;
__u32 rename_flags;
__u32 unlink_flags;
+ __u32 hardlink_flags;
};
__u64 user_data; /* data to be passed back at completion time */
/* pack this to avoid bogus arm OABI complaints */
@@ -135,6 +136,7 @@ enum {
IORING_OP_UNLINKAT,
IORING_OP_MKDIRAT,
IORING_OP_SYMLINKAT,
+ IORING_OP_LINKAT,
/* this goes last, obviously */
IORING_OP_LAST,
--
2.30.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support
2021-07-08 6:34 [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Dmitry Kadashev
` (10 preceding siblings ...)
2021-07-08 6:34 ` [PATCH v9 11/11] io_uring: add support for IORING_OP_LINKAT Dmitry Kadashev
@ 2021-07-08 18:34 ` Linus Torvalds
2021-07-08 19:25 ` Jens Axboe
11 siblings, 1 reply; 17+ messages in thread
From: Linus Torvalds @ 2021-07-08 18:34 UTC (permalink / raw)
To: Dmitry Kadashev
Cc: Jens Axboe, Alexander Viro, Christian Brauner, Pavel Begunkov,
linux-fsdevel, io-uring
On Wed, Jul 7, 2021 at 11:35 PM Dmitry Kadashev <[email protected]> wrote:
>
> v9:
> - reorder commits to keep io_uring ones nicely grouped at the end
> - change 'fs:' to 'namei:' in related commit subjects, since this is
> what seems to be usually used in such cases
Ok, ack from me on this series, and as far as I'm concerned it can go
through the io_uring branch.
Al, please holler if you have any concerns.
I do see a few cleanups - the ones I've already mentioned to try to
remove some of the goto spaghetti, and I think we end up with just two
users of filename_create(), and we might just make those convert to
the new world order, and get rid of the __filename_create() vs
filename_creat() distinction.
But those cleanups might as well be left for later, so I don't think
that needs to hold the series up.
Al - one last chance to speak up..
Linus
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support
2021-07-08 18:34 ` [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support Linus Torvalds
@ 2021-07-08 19:25 ` Jens Axboe
2021-08-13 9:32 ` Dmitry Kadashev
0 siblings, 1 reply; 17+ messages in thread
From: Jens Axboe @ 2021-07-08 19:25 UTC (permalink / raw)
To: Linus Torvalds, Dmitry Kadashev
Cc: Alexander Viro, Christian Brauner, Pavel Begunkov, linux-fsdevel,
io-uring
On 7/8/21 12:34 PM, Linus Torvalds wrote:
> On Wed, Jul 7, 2021 at 11:35 PM Dmitry Kadashev <[email protected]> wrote:
>>
>> v9:
>> - reorder commits to keep io_uring ones nicely grouped at the end
>> - change 'fs:' to 'namei:' in related commit subjects, since this is
>> what seems to be usually used in such cases
>
> Ok, ack from me on this series, and as far as I'm concerned it can go
> through the io_uring branch.
I'll queue it up in a separate branch. I'm assuming we're talking 5.15
at this point.
> Al, please holler if you have any concerns.
Indeed.
--
Jens Axboe
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support
2021-07-08 19:25 ` Jens Axboe
@ 2021-08-13 9:32 ` Dmitry Kadashev
2021-08-13 14:12 ` Jens Axboe
0 siblings, 1 reply; 17+ messages in thread
From: Dmitry Kadashev @ 2021-08-13 9:32 UTC (permalink / raw)
To: Jens Axboe
Cc: Linus Torvalds, Alexander Viro, Christian Brauner, Pavel Begunkov,
linux-fsdevel, io-uring
On Fri, Jul 9, 2021 at 2:25 AM Jens Axboe <[email protected]> wrote:
>
> On 7/8/21 12:34 PM, Linus Torvalds wrote:
> > On Wed, Jul 7, 2021 at 11:35 PM Dmitry Kadashev <[email protected]> wrote:
> >>
> >> v9:
> >> - reorder commits to keep io_uring ones nicely grouped at the end
> >> - change 'fs:' to 'namei:' in related commit subjects, since this is
> >> what seems to be usually used in such cases
> >
> > Ok, ack from me on this series, and as far as I'm concerned it can go
> > through the io_uring branch.
>
> I'll queue it up in a separate branch. I'm assuming we're talking 5.15
> at this point.
Is this going to be merged into 5.15? I'm still working on the follow-up
patch (well, right at this moment I'm actually on vacation, but will be
working on it when I'm back), but hopefully it does not have to be
merged in the same merge window / version? Especially given the fact
that Al prefers it to be a bigger refactoring of the ESTALE retries
rather than just moving bits and pieces to helper functions to simplify
the flow, see here:
https://lore.kernel.org/io-uring/[email protected]/
--
Dmitry Kadashev
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support
2021-08-13 9:32 ` Dmitry Kadashev
@ 2021-08-13 14:12 ` Jens Axboe
2021-08-16 10:24 ` Dmitry Kadashev
0 siblings, 1 reply; 17+ messages in thread
From: Jens Axboe @ 2021-08-13 14:12 UTC (permalink / raw)
To: Dmitry Kadashev
Cc: Linus Torvalds, Alexander Viro, Christian Brauner, Pavel Begunkov,
linux-fsdevel, io-uring
On 8/13/21 3:32 AM, Dmitry Kadashev wrote:
> On Fri, Jul 9, 2021 at 2:25 AM Jens Axboe <[email protected]> wrote:
>>
>> On 7/8/21 12:34 PM, Linus Torvalds wrote:
>>> On Wed, Jul 7, 2021 at 11:35 PM Dmitry Kadashev <[email protected]> wrote:
>>>>
>>>> v9:
>>>> - reorder commits to keep io_uring ones nicely grouped at the end
>>>> - change 'fs:' to 'namei:' in related commit subjects, since this is
>>>> what seems to be usually used in such cases
>>>
>>> Ok, ack from me on this series, and as far as I'm concerned it can go
>>> through the io_uring branch.
>>
>> I'll queue it up in a separate branch. I'm assuming we're talking 5.15
>> at this point.
>
> Is this going to be merged into 5.15? I'm still working on the follow-up
> patch (well, right at this moment I'm actually on vacation, but will be
> working on it when I'm back), but hopefully it does not have to be
> merged in the same merge window / version? Especially given the fact
> that Al prefers it to be a bigger refactoring of the ESTALE retries
> rather than just moving bits and pieces to helper functions to simplify
> the flow, see here:
>
> https://lore.kernel.org/io-uring/[email protected]/
I added this to the for-5.15/io_uring-vfs branch:
https://git.kernel.dk/cgit/linux-block/log/?h=for-5.15/io_uring-vfs
had one namei.c conflict, set_nameidata() taking one more parameter, and
just a trivial conflict in each io_uring patch at the end. Can you double
check them?
--
Jens Axboe
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v9 00/11] io_uring: add mkdir and [sym]linkat support
2021-08-13 14:12 ` Jens Axboe
@ 2021-08-16 10:24 ` Dmitry Kadashev
0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Kadashev @ 2021-08-16 10:24 UTC (permalink / raw)
To: Jens Axboe
Cc: Linus Torvalds, Alexander Viro, Christian Brauner, Pavel Begunkov,
linux-fsdevel, io-uring
On Fri, Aug 13, 2021 at 9:12 PM Jens Axboe <[email protected]> wrote:
>
> On 8/13/21 3:32 AM, Dmitry Kadashev wrote:
> > On Fri, Jul 9, 2021 at 2:25 AM Jens Axboe <[email protected]> wrote:
> >>
> >> On 7/8/21 12:34 PM, Linus Torvalds wrote:
> >>> On Wed, Jul 7, 2021 at 11:35 PM Dmitry Kadashev <[email protected]> wrote:
> >>>>
> >>>> v9:
> >>>> - reorder commits to keep io_uring ones nicely grouped at the end
> >>>> - change 'fs:' to 'namei:' in related commit subjects, since this is
> >>>> what seems to be usually used in such cases
> >>>
> >>> Ok, ack from me on this series, and as far as I'm concerned it can go
> >>> through the io_uring branch.
> >>
> >> I'll queue it up in a separate branch. I'm assuming we're talking 5.15
> >> at this point.
> >
> > Is this going to be merged into 5.15? I'm still working on the follow-up
> > patch (well, right at this moment I'm actually on vacation, but will be
> > working on it when I'm back), but hopefully it does not have to be
> > merged in the same merge window / version? Especially given the fact
> > that Al prefers it to be a bigger refactoring of the ESTALE retries
> > rather than just moving bits and pieces to helper functions to simplify
> > the flow, see here:
> >
> > https://lore.kernel.org/io-uring/[email protected]/
>
> I added this to the for-5.15/io_uring-vfs branch:
>
> https://git.kernel.dk/cgit/linux-block/log/?h=for-5.15/io_uring-vfs
>
> had one namei.c conflict, set_nameidata() taking one more parameter, and
> just a trivial conflict in each io_uring patch at the end. Can you double
> check them?
Looks good to me, thanks!
--
Dmitry Kadashev
^ permalink raw reply [flat|nested] 17+ messages in thread