2022-05-25 06:13:00 +03:00
// SPDX-License-Identifier: GPL-2.0
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/file.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/namei.h>
# include <linux/io_uring.h>
# include <uapi/linux/io_uring.h>
# include "../fs/internal.h"
# include "io_uring.h"
# include "fs.h"
struct io_rename {
struct file * file ;
int old_dfd ;
int new_dfd ;
struct filename * oldpath ;
struct filename * newpath ;
int flags ;
} ;
struct io_unlink {
struct file * file ;
int dfd ;
int flags ;
struct filename * filename ;
} ;
struct io_mkdir {
struct file * file ;
int dfd ;
umode_t mode ;
struct filename * filename ;
} ;
struct io_link {
struct file * file ;
int old_dfd ;
int new_dfd ;
struct filename * oldpath ;
struct filename * newpath ;
int flags ;
} ;
int io_renameat_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
2022-08-11 10:11:15 +03:00
struct io_rename * ren = io_kiocb_to_cmd ( req , struct io_rename ) ;
2022-05-25 06:13:00 +03:00
const char __user * oldf , * newf ;
if ( sqe - > buf_index | | sqe - > splice_fd_in )
return - EINVAL ;
if ( unlikely ( req - > flags & REQ_F_FIXED_FILE ) )
return - EBADF ;
ren - > old_dfd = READ_ONCE ( sqe - > fd ) ;
oldf = u64_to_user_ptr ( READ_ONCE ( sqe - > addr ) ) ;
newf = u64_to_user_ptr ( READ_ONCE ( sqe - > addr2 ) ) ;
ren - > new_dfd = READ_ONCE ( sqe - > len ) ;
ren - > flags = READ_ONCE ( sqe - > rename_flags ) ;
ren - > oldpath = getname ( oldf ) ;
if ( IS_ERR ( ren - > oldpath ) )
return PTR_ERR ( ren - > oldpath ) ;
ren - > newpath = getname ( newf ) ;
if ( IS_ERR ( ren - > newpath ) ) {
putname ( ren - > oldpath ) ;
return PTR_ERR ( ren - > newpath ) ;
}
req - > flags | = REQ_F_NEED_CLEANUP ;
return 0 ;
}
int io_renameat ( struct io_kiocb * req , unsigned int issue_flags )
{
2022-08-11 10:11:15 +03:00
struct io_rename * ren = io_kiocb_to_cmd ( req , struct io_rename ) ;
2022-05-25 06:13:00 +03:00
int ret ;
if ( issue_flags & IO_URING_F_NONBLOCK )
return - EAGAIN ;
ret = do_renameat2 ( ren - > old_dfd , ren - > oldpath , ren - > new_dfd ,
ren - > newpath , ren - > flags ) ;
req - > flags & = ~ REQ_F_NEED_CLEANUP ;
io_req_set_res ( req , ret , 0 ) ;
return IOU_OK ;
}
void io_renameat_cleanup ( struct io_kiocb * req )
{
2022-08-11 10:11:15 +03:00
struct io_rename * ren = io_kiocb_to_cmd ( req , struct io_rename ) ;
2022-05-25 06:13:00 +03:00
putname ( ren - > oldpath ) ;
putname ( ren - > newpath ) ;
}
int io_unlinkat_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
2022-08-11 10:11:15 +03:00
struct io_unlink * un = io_kiocb_to_cmd ( req , struct io_unlink ) ;
2022-05-25 06:13:00 +03:00
const char __user * fname ;
if ( sqe - > off | | sqe - > len | | sqe - > buf_index | | sqe - > splice_fd_in )
return - EINVAL ;
if ( unlikely ( req - > flags & REQ_F_FIXED_FILE ) )
return - EBADF ;
un - > dfd = READ_ONCE ( sqe - > fd ) ;
un - > flags = READ_ONCE ( sqe - > unlink_flags ) ;
if ( un - > flags & ~ AT_REMOVEDIR )
return - EINVAL ;
fname = u64_to_user_ptr ( READ_ONCE ( sqe - > addr ) ) ;
un - > filename = getname ( fname ) ;
if ( IS_ERR ( un - > filename ) )
return PTR_ERR ( un - > filename ) ;
req - > flags | = REQ_F_NEED_CLEANUP ;
return 0 ;
}
int io_unlinkat ( struct io_kiocb * req , unsigned int issue_flags )
{
2022-08-11 10:11:15 +03:00
struct io_unlink * un = io_kiocb_to_cmd ( req , struct io_unlink ) ;
2022-05-25 06:13:00 +03:00
int ret ;
if ( issue_flags & IO_URING_F_NONBLOCK )
return - EAGAIN ;
if ( un - > flags & AT_REMOVEDIR )
ret = do_rmdir ( un - > dfd , un - > filename ) ;
else
ret = do_unlinkat ( un - > dfd , un - > filename ) ;
req - > flags & = ~ REQ_F_NEED_CLEANUP ;
io_req_set_res ( req , ret , 0 ) ;
return IOU_OK ;
}
void io_unlinkat_cleanup ( struct io_kiocb * req )
{
2022-08-11 10:11:15 +03:00
struct io_unlink * ul = io_kiocb_to_cmd ( req , struct io_unlink ) ;
2022-05-25 06:13:00 +03:00
putname ( ul - > filename ) ;
}
int io_mkdirat_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
2022-08-11 10:11:15 +03:00
struct io_mkdir * mkd = io_kiocb_to_cmd ( req , struct io_mkdir ) ;
2022-05-25 06:13:00 +03:00
const char __user * fname ;
if ( sqe - > off | | sqe - > rw_flags | | sqe - > buf_index | | sqe - > splice_fd_in )
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 ;
}
int io_mkdirat ( struct io_kiocb * req , unsigned int issue_flags )
{
2022-08-11 10:11:15 +03:00
struct io_mkdir * mkd = io_kiocb_to_cmd ( req , struct io_mkdir ) ;
2022-05-25 06:13:00 +03:00
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 ;
io_req_set_res ( req , ret , 0 ) ;
return IOU_OK ;
}
void io_mkdirat_cleanup ( struct io_kiocb * req )
{
2022-08-11 10:11:15 +03:00
struct io_mkdir * md = io_kiocb_to_cmd ( req , struct io_mkdir ) ;
2022-05-25 06:13:00 +03:00
putname ( md - > filename ) ;
}
int io_symlinkat_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
2022-08-11 10:11:15 +03:00
struct io_link * sl = io_kiocb_to_cmd ( req , struct io_link ) ;
2022-05-25 06:13:00 +03:00
const char __user * oldpath , * newpath ;
if ( sqe - > len | | sqe - > rw_flags | | sqe - > buf_index | | sqe - > splice_fd_in )
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 ;
}
int io_symlinkat ( struct io_kiocb * req , unsigned int issue_flags )
{
2022-08-11 10:11:15 +03:00
struct io_link * sl = io_kiocb_to_cmd ( req , struct io_link ) ;
2022-05-25 06:13:00 +03:00
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 ;
io_req_set_res ( req , ret , 0 ) ;
return IOU_OK ;
}
int io_linkat_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
2022-08-11 10:11:15 +03:00
struct io_link * lnk = io_kiocb_to_cmd ( req , struct io_link ) ;
2022-05-25 06:13:00 +03:00
const char __user * oldf , * newf ;
if ( sqe - > rw_flags | | sqe - > buf_index | | sqe - > splice_fd_in )
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 ;
}
int io_linkat ( struct io_kiocb * req , unsigned int issue_flags )
{
2022-08-11 10:11:15 +03:00
struct io_link * lnk = io_kiocb_to_cmd ( req , struct io_link ) ;
2022-05-25 06:13:00 +03:00
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 ;
io_req_set_res ( req , ret , 0 ) ;
return IOU_OK ;
}
void io_link_cleanup ( struct io_kiocb * req )
{
2022-08-11 10:11:15 +03:00
struct io_link * sl = io_kiocb_to_cmd ( req , struct io_link ) ;
2022-05-25 06:13:00 +03:00
putname ( sl - > oldpath ) ;
putname ( sl - > newpath ) ;
}