]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
non-consuming variant of do_linkat()
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 7 Jan 2026 04:23:05 +0000 (23:23 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 16 Jan 2026 17:47:42 +0000 (12:47 -0500)
similar to previous commit; replacement is filename_linkat()

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Documentation/filesystems/porting.rst
fs/init.c
fs/internal.h
fs/namei.c
io_uring/fs.c

index 459ec2f57794d85cc3133012060e930b9576a6ec..e93ba90e3e4fec345e7f9dc447198717eb18b918 100644 (file)
@@ -1342,4 +1342,4 @@ in-tree filesystems have done).
 fs/namei.c primitives that consume filesystem references (do_renameat2(),
 do_linkat(), do_symlinkat(), do_mkdirat(), do_mknodat(), do_unlinkat()
 and do_rmdir()) are getting replaced with non-consuming analogues
-(filename_renameat2(), etc.)  Replaced so far: do_renameat2().
+(filename_renameat2(), etc.)  Replaced so far: do_renameat2(), do_linkat().
index da6500d2ee98d86c6c4849725ad516af5b56b6fe..f46e545529315f054e843aac5e672908366b903a 100644 (file)
--- a/fs/init.c
+++ b/fs/init.c
@@ -145,8 +145,9 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
 
 int __init init_link(const char *oldname, const char *newname)
 {
-       return do_linkat(AT_FDCWD, getname_kernel(oldname),
-                        AT_FDCWD, getname_kernel(newname), 0);
+       CLASS(filename_kernel, old)(oldname);
+       CLASS(filename_kernel, new)(newname);
+       return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
 }
 
 int __init init_symlink(const char *oldname, const char *newname)
index 5047cfbb8c93c531ac3d0fa01abd4ceeade86195..c9b70c2716d1ab0e4e2230b4a0d5a450e273895c 100644 (file)
@@ -62,7 +62,7 @@ int filename_renameat2(int olddfd, struct filename *oldname, int newdfd,
 int do_mkdirat(int dfd, struct filename *name, umode_t mode);
 int do_mknodat(int dfd, struct filename *name, umode_t mode, unsigned int dev);
 int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
-int do_linkat(int olddfd, struct filename *old, int newdfd,
+int filename_linkat(int olddfd, struct filename *old, int newdfd,
                        struct filename *new, int flags);
 int vfs_tmpfile(struct mnt_idmap *idmap,
                const struct path *parentpath,
index 5354f240b86a9a241db10ed85deaa62c5e2c41e8..e5d494610c2c32228531fbe1021e0acf44d5a128 100644 (file)
@@ -5729,9 +5729,9 @@ EXPORT_SYMBOL(vfs_link);
  * We don't follow them on the oldname either to be compatible
  * with linux 2.0, and to avoid hard-linking to directories
  * and other special files.  --ADM
- */
-int do_linkat(int olddfd, struct filename *old, int newdfd,
-             struct filename *new, int flags)
+*/
+int filename_linkat(int olddfd, struct filename *old,
+                   int newdfd, struct filename *new, int flags)
 {
        struct mnt_idmap *idmap;
        struct dentry *new_dentry;
@@ -5740,10 +5740,8 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
        int how = 0;
        int error;
 
-       if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) {
-               error = -EINVAL;
-               goto out_putnames;
-       }
+       if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
+               return -EINVAL;
        /*
         * To use null names we require CAP_DAC_READ_SEARCH or
         * that the open-time creds of the dfd matches current.
@@ -5758,7 +5756,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
 retry:
        error = filename_lookup(olddfd, old, how, &old_path, NULL);
        if (error)
-               goto out_putnames;
+               return error;
 
        new_dentry = filename_create(newdfd, new, &new_path,
                                        (how & LOOKUP_REVAL));
@@ -5794,23 +5792,22 @@ out_dput:
        }
 out_putpath:
        path_put(&old_path);
-out_putnames:
-       putname(old);
-       putname(new);
-
        return error;
 }
 
 SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname, int, flags)
 {
-       return do_linkat(olddfd, getname_uflags(oldname, flags),
-               newdfd, getname(newname), flags);
+       CLASS(filename_uflags, old)(oldname, flags);
+       CLASS(filename, new)(newname);
+       return filename_linkat(olddfd, old, newdfd, new, flags);
 }
 
 SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
 {
-       return do_linkat(AT_FDCWD, getname(oldname), AT_FDCWD, getname(newname), 0);
+       CLASS(filename, old)(oldname);
+       CLASS(filename, new)(newname);
+       return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
 }
 
 /**
index e5829d112c9e9f3350cb01308d287fcfeb176ac7..e39cd1ca194236f11a3ea3025d3902e74863febe 100644 (file)
@@ -280,12 +280,13 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
+       CLASS(filename_complete_delayed, old)(&lnk->oldpath);
+       CLASS(filename_complete_delayed, new)(&lnk->newpath);
        int ret;
 
        WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
 
-       ret = do_linkat(lnk->old_dfd, complete_getname(&lnk->oldpath),
-                       lnk->new_dfd, complete_getname(&lnk->newpath), lnk->flags);
+       ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags);
 
        req->flags &= ~REQ_F_NEED_CLEANUP;
        io_req_set_res(req, ret, 0);