111aeb714SJens Axboe // SPDX-License-Identifier: GPL-2.0 211aeb714SJens Axboe #include <linux/kernel.h> 311aeb714SJens Axboe #include <linux/errno.h> 411aeb714SJens Axboe #include <linux/fs.h> 511aeb714SJens Axboe #include <linux/file.h> 611aeb714SJens Axboe #include <linux/mm.h> 711aeb714SJens Axboe #include <linux/slab.h> 811aeb714SJens Axboe #include <linux/namei.h> 911aeb714SJens Axboe #include <linux/io_uring.h> 1011aeb714SJens Axboe 1111aeb714SJens Axboe #include <uapi/linux/io_uring.h> 1211aeb714SJens Axboe 1311aeb714SJens Axboe #include "../fs/internal.h" 1411aeb714SJens Axboe 1511aeb714SJens Axboe #include "io_uring.h" 1611aeb714SJens Axboe #include "fs.h" 1711aeb714SJens Axboe 1811aeb714SJens Axboe struct io_rename { 1911aeb714SJens Axboe struct file *file; 2011aeb714SJens Axboe int old_dfd; 2111aeb714SJens Axboe int new_dfd; 2211aeb714SJens Axboe struct filename *oldpath; 2311aeb714SJens Axboe struct filename *newpath; 2411aeb714SJens Axboe int flags; 2511aeb714SJens Axboe }; 2611aeb714SJens Axboe 2711aeb714SJens Axboe struct io_unlink { 2811aeb714SJens Axboe struct file *file; 2911aeb714SJens Axboe int dfd; 3011aeb714SJens Axboe int flags; 3111aeb714SJens Axboe struct filename *filename; 3211aeb714SJens Axboe }; 3311aeb714SJens Axboe 3411aeb714SJens Axboe struct io_mkdir { 3511aeb714SJens Axboe struct file *file; 3611aeb714SJens Axboe int dfd; 3711aeb714SJens Axboe umode_t mode; 3811aeb714SJens Axboe struct filename *filename; 3911aeb714SJens Axboe }; 4011aeb714SJens Axboe 4111aeb714SJens Axboe struct io_link { 4211aeb714SJens Axboe struct file *file; 4311aeb714SJens Axboe int old_dfd; 4411aeb714SJens Axboe int new_dfd; 4511aeb714SJens Axboe struct filename *oldpath; 4611aeb714SJens Axboe struct filename *newpath; 4711aeb714SJens Axboe int flags; 4811aeb714SJens Axboe }; 4911aeb714SJens Axboe 5011aeb714SJens Axboe int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 5111aeb714SJens Axboe { 52*f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename); 5311aeb714SJens Axboe const char __user *oldf, *newf; 5411aeb714SJens Axboe 5511aeb714SJens Axboe if (sqe->buf_index || sqe->splice_fd_in) 5611aeb714SJens Axboe return -EINVAL; 5711aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 5811aeb714SJens Axboe return -EBADF; 5911aeb714SJens Axboe 6011aeb714SJens Axboe ren->old_dfd = READ_ONCE(sqe->fd); 6111aeb714SJens Axboe oldf = u64_to_user_ptr(READ_ONCE(sqe->addr)); 6211aeb714SJens Axboe newf = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 6311aeb714SJens Axboe ren->new_dfd = READ_ONCE(sqe->len); 6411aeb714SJens Axboe ren->flags = READ_ONCE(sqe->rename_flags); 6511aeb714SJens Axboe 6611aeb714SJens Axboe ren->oldpath = getname(oldf); 6711aeb714SJens Axboe if (IS_ERR(ren->oldpath)) 6811aeb714SJens Axboe return PTR_ERR(ren->oldpath); 6911aeb714SJens Axboe 7011aeb714SJens Axboe ren->newpath = getname(newf); 7111aeb714SJens Axboe if (IS_ERR(ren->newpath)) { 7211aeb714SJens Axboe putname(ren->oldpath); 7311aeb714SJens Axboe return PTR_ERR(ren->newpath); 7411aeb714SJens Axboe } 7511aeb714SJens Axboe 7611aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 7711aeb714SJens Axboe return 0; 7811aeb714SJens Axboe } 7911aeb714SJens Axboe 8011aeb714SJens Axboe int io_renameat(struct io_kiocb *req, unsigned int issue_flags) 8111aeb714SJens Axboe { 82*f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename); 8311aeb714SJens Axboe int ret; 8411aeb714SJens Axboe 8511aeb714SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 8611aeb714SJens Axboe return -EAGAIN; 8711aeb714SJens Axboe 8811aeb714SJens Axboe ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd, 8911aeb714SJens Axboe ren->newpath, ren->flags); 9011aeb714SJens Axboe 9111aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 9211aeb714SJens Axboe io_req_set_res(req, ret, 0); 9311aeb714SJens Axboe return IOU_OK; 9411aeb714SJens Axboe } 9511aeb714SJens Axboe 9611aeb714SJens Axboe void io_renameat_cleanup(struct io_kiocb *req) 9711aeb714SJens Axboe { 98*f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename); 9911aeb714SJens Axboe 10011aeb714SJens Axboe putname(ren->oldpath); 10111aeb714SJens Axboe putname(ren->newpath); 10211aeb714SJens Axboe } 10311aeb714SJens Axboe 10411aeb714SJens Axboe int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 10511aeb714SJens Axboe { 106*f2ccb5aeSStefan Metzmacher struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink); 10711aeb714SJens Axboe const char __user *fname; 10811aeb714SJens Axboe 10911aeb714SJens Axboe if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in) 11011aeb714SJens Axboe return -EINVAL; 11111aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 11211aeb714SJens Axboe return -EBADF; 11311aeb714SJens Axboe 11411aeb714SJens Axboe un->dfd = READ_ONCE(sqe->fd); 11511aeb714SJens Axboe 11611aeb714SJens Axboe un->flags = READ_ONCE(sqe->unlink_flags); 11711aeb714SJens Axboe if (un->flags & ~AT_REMOVEDIR) 11811aeb714SJens Axboe return -EINVAL; 11911aeb714SJens Axboe 12011aeb714SJens Axboe fname = u64_to_user_ptr(READ_ONCE(sqe->addr)); 12111aeb714SJens Axboe un->filename = getname(fname); 12211aeb714SJens Axboe if (IS_ERR(un->filename)) 12311aeb714SJens Axboe return PTR_ERR(un->filename); 12411aeb714SJens Axboe 12511aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 12611aeb714SJens Axboe return 0; 12711aeb714SJens Axboe } 12811aeb714SJens Axboe 12911aeb714SJens Axboe int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags) 13011aeb714SJens Axboe { 131*f2ccb5aeSStefan Metzmacher struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink); 13211aeb714SJens Axboe int ret; 13311aeb714SJens Axboe 13411aeb714SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 13511aeb714SJens Axboe return -EAGAIN; 13611aeb714SJens Axboe 13711aeb714SJens Axboe if (un->flags & AT_REMOVEDIR) 13811aeb714SJens Axboe ret = do_rmdir(un->dfd, un->filename); 13911aeb714SJens Axboe else 14011aeb714SJens Axboe ret = do_unlinkat(un->dfd, un->filename); 14111aeb714SJens Axboe 14211aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 14311aeb714SJens Axboe io_req_set_res(req, ret, 0); 14411aeb714SJens Axboe return IOU_OK; 14511aeb714SJens Axboe } 14611aeb714SJens Axboe 14711aeb714SJens Axboe void io_unlinkat_cleanup(struct io_kiocb *req) 14811aeb714SJens Axboe { 149*f2ccb5aeSStefan Metzmacher struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink); 15011aeb714SJens Axboe 15111aeb714SJens Axboe putname(ul->filename); 15211aeb714SJens Axboe } 15311aeb714SJens Axboe 15411aeb714SJens Axboe int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 15511aeb714SJens Axboe { 156*f2ccb5aeSStefan Metzmacher struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir); 15711aeb714SJens Axboe const char __user *fname; 15811aeb714SJens Axboe 15911aeb714SJens Axboe if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in) 16011aeb714SJens Axboe return -EINVAL; 16111aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 16211aeb714SJens Axboe return -EBADF; 16311aeb714SJens Axboe 16411aeb714SJens Axboe mkd->dfd = READ_ONCE(sqe->fd); 16511aeb714SJens Axboe mkd->mode = READ_ONCE(sqe->len); 16611aeb714SJens Axboe 16711aeb714SJens Axboe fname = u64_to_user_ptr(READ_ONCE(sqe->addr)); 16811aeb714SJens Axboe mkd->filename = getname(fname); 16911aeb714SJens Axboe if (IS_ERR(mkd->filename)) 17011aeb714SJens Axboe return PTR_ERR(mkd->filename); 17111aeb714SJens Axboe 17211aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 17311aeb714SJens Axboe return 0; 17411aeb714SJens Axboe } 17511aeb714SJens Axboe 17611aeb714SJens Axboe int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags) 17711aeb714SJens Axboe { 178*f2ccb5aeSStefan Metzmacher struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir); 17911aeb714SJens Axboe int ret; 18011aeb714SJens Axboe 18111aeb714SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 18211aeb714SJens Axboe return -EAGAIN; 18311aeb714SJens Axboe 18411aeb714SJens Axboe ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode); 18511aeb714SJens Axboe 18611aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 18711aeb714SJens Axboe io_req_set_res(req, ret, 0); 18811aeb714SJens Axboe return IOU_OK; 18911aeb714SJens Axboe } 19011aeb714SJens Axboe 19111aeb714SJens Axboe void io_mkdirat_cleanup(struct io_kiocb *req) 19211aeb714SJens Axboe { 193*f2ccb5aeSStefan Metzmacher struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir); 19411aeb714SJens Axboe 19511aeb714SJens Axboe putname(md->filename); 19611aeb714SJens Axboe } 19711aeb714SJens Axboe 19811aeb714SJens Axboe int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 19911aeb714SJens Axboe { 200*f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link); 20111aeb714SJens Axboe const char __user *oldpath, *newpath; 20211aeb714SJens Axboe 20311aeb714SJens Axboe if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in) 20411aeb714SJens Axboe return -EINVAL; 20511aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 20611aeb714SJens Axboe return -EBADF; 20711aeb714SJens Axboe 20811aeb714SJens Axboe sl->new_dfd = READ_ONCE(sqe->fd); 20911aeb714SJens Axboe oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr)); 21011aeb714SJens Axboe newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 21111aeb714SJens Axboe 21211aeb714SJens Axboe sl->oldpath = getname(oldpath); 21311aeb714SJens Axboe if (IS_ERR(sl->oldpath)) 21411aeb714SJens Axboe return PTR_ERR(sl->oldpath); 21511aeb714SJens Axboe 21611aeb714SJens Axboe sl->newpath = getname(newpath); 21711aeb714SJens Axboe if (IS_ERR(sl->newpath)) { 21811aeb714SJens Axboe putname(sl->oldpath); 21911aeb714SJens Axboe return PTR_ERR(sl->newpath); 22011aeb714SJens Axboe } 22111aeb714SJens Axboe 22211aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 22311aeb714SJens Axboe return 0; 22411aeb714SJens Axboe } 22511aeb714SJens Axboe 22611aeb714SJens Axboe int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags) 22711aeb714SJens Axboe { 228*f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link); 22911aeb714SJens Axboe int ret; 23011aeb714SJens Axboe 23111aeb714SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 23211aeb714SJens Axboe return -EAGAIN; 23311aeb714SJens Axboe 23411aeb714SJens Axboe ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath); 23511aeb714SJens Axboe 23611aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 23711aeb714SJens Axboe io_req_set_res(req, ret, 0); 23811aeb714SJens Axboe return IOU_OK; 23911aeb714SJens Axboe } 24011aeb714SJens Axboe 24111aeb714SJens Axboe int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 24211aeb714SJens Axboe { 243*f2ccb5aeSStefan Metzmacher struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link); 24411aeb714SJens Axboe const char __user *oldf, *newf; 24511aeb714SJens Axboe 24611aeb714SJens Axboe if (sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in) 24711aeb714SJens Axboe return -EINVAL; 24811aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 24911aeb714SJens Axboe return -EBADF; 25011aeb714SJens Axboe 25111aeb714SJens Axboe lnk->old_dfd = READ_ONCE(sqe->fd); 25211aeb714SJens Axboe lnk->new_dfd = READ_ONCE(sqe->len); 25311aeb714SJens Axboe oldf = u64_to_user_ptr(READ_ONCE(sqe->addr)); 25411aeb714SJens Axboe newf = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 25511aeb714SJens Axboe lnk->flags = READ_ONCE(sqe->hardlink_flags); 25611aeb714SJens Axboe 25711aeb714SJens Axboe lnk->oldpath = getname(oldf); 25811aeb714SJens Axboe if (IS_ERR(lnk->oldpath)) 25911aeb714SJens Axboe return PTR_ERR(lnk->oldpath); 26011aeb714SJens Axboe 26111aeb714SJens Axboe lnk->newpath = getname(newf); 26211aeb714SJens Axboe if (IS_ERR(lnk->newpath)) { 26311aeb714SJens Axboe putname(lnk->oldpath); 26411aeb714SJens Axboe return PTR_ERR(lnk->newpath); 26511aeb714SJens Axboe } 26611aeb714SJens Axboe 26711aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 26811aeb714SJens Axboe return 0; 26911aeb714SJens Axboe } 27011aeb714SJens Axboe 27111aeb714SJens Axboe int io_linkat(struct io_kiocb *req, unsigned int issue_flags) 27211aeb714SJens Axboe { 273*f2ccb5aeSStefan Metzmacher struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link); 27411aeb714SJens Axboe int ret; 27511aeb714SJens Axboe 27611aeb714SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 27711aeb714SJens Axboe return -EAGAIN; 27811aeb714SJens Axboe 27911aeb714SJens Axboe ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd, 28011aeb714SJens Axboe lnk->newpath, lnk->flags); 28111aeb714SJens Axboe 28211aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 28311aeb714SJens Axboe io_req_set_res(req, ret, 0); 28411aeb714SJens Axboe return IOU_OK; 28511aeb714SJens Axboe } 28611aeb714SJens Axboe 28711aeb714SJens Axboe void io_link_cleanup(struct io_kiocb *req) 28811aeb714SJens Axboe { 289*f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link); 29011aeb714SJens Axboe 29111aeb714SJens Axboe putname(sl->oldpath); 29211aeb714SJens Axboe putname(sl->newpath); 29311aeb714SJens Axboe } 294