2022-05-25 14:59:19 +03:00
// SPDX-License-Identifier: GPL-2.0
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/file.h>
# include <linux/io_uring.h>
# include <uapi/linux/io_uring.h>
# include "io_uring.h"
# include "uring_cmd.h"
static void io_uring_cmd_work ( struct io_kiocb * req , bool * locked )
{
struct io_uring_cmd * ioucmd = io_kiocb_to_cmd ( req ) ;
ioucmd - > task_work_cb ( ioucmd ) ;
}
void io_uring_cmd_complete_in_task ( struct io_uring_cmd * ioucmd ,
void ( * task_work_cb ) ( struct io_uring_cmd * ) )
{
struct io_kiocb * req = cmd_to_io_kiocb ( ioucmd ) ;
ioucmd - > task_work_cb = task_work_cb ;
req - > io_task_work . func = io_uring_cmd_work ;
io_req_task_work_add ( req ) ;
}
EXPORT_SYMBOL_GPL ( io_uring_cmd_complete_in_task ) ;
static inline void io_req_set_cqe32_extra ( struct io_kiocb * req ,
u64 extra1 , u64 extra2 )
{
req - > extra1 = extra1 ;
req - > extra2 = extra2 ;
req - > flags | = REQ_F_CQE32_INIT ;
}
/*
* Called by consumers of io_uring_cmd , if they originally returned
* - EIOCBQUEUED upon receiving the command .
*/
void io_uring_cmd_done ( struct io_uring_cmd * ioucmd , ssize_t ret , ssize_t res2 )
{
struct io_kiocb * req = cmd_to_io_kiocb ( ioucmd ) ;
if ( ret < 0 )
req_set_fail ( req ) ;
2022-08-03 15:07:57 +03:00
io_req_set_res ( req , ret , 0 ) ;
2022-05-25 14:59:19 +03:00
if ( req - > ctx - > flags & IORING_SETUP_CQE32 )
io_req_set_cqe32_extra ( req , res2 , 0 ) ;
__io_req_complete ( req , 0 ) ;
}
EXPORT_SYMBOL_GPL ( io_uring_cmd_done ) ;
int io_uring_cmd_prep_async ( struct io_kiocb * req )
{
struct io_uring_cmd * ioucmd = io_kiocb_to_cmd ( req ) ;
size_t cmd_size ;
cmd_size = uring_cmd_pdu_size ( req - > ctx - > flags & IORING_SETUP_SQE128 ) ;
memcpy ( req - > async_data , ioucmd - > cmd , cmd_size ) ;
return 0 ;
}
int io_uring_cmd_prep ( struct io_kiocb * req , const struct io_uring_sqe * sqe )
{
struct io_uring_cmd * ioucmd = io_kiocb_to_cmd ( req ) ;
if ( sqe - > rw_flags | | sqe - > __pad1 )
return - EINVAL ;
ioucmd - > cmd = sqe - > cmd ;
ioucmd - > cmd_op = READ_ONCE ( sqe - > cmd_op ) ;
return 0 ;
}
int io_uring_cmd ( struct io_kiocb * req , unsigned int issue_flags )
{
struct io_uring_cmd * ioucmd = io_kiocb_to_cmd ( req ) ;
struct io_ring_ctx * ctx = req - > ctx ;
struct file * file = req - > file ;
int ret ;
if ( ! req - > file - > f_op - > uring_cmd )
return - EOPNOTSUPP ;
if ( ctx - > flags & IORING_SETUP_SQE128 )
issue_flags | = IO_URING_F_SQE128 ;
if ( ctx - > flags & IORING_SETUP_CQE32 )
issue_flags | = IO_URING_F_CQE32 ;
if ( ctx - > flags & IORING_SETUP_IOPOLL )
issue_flags | = IO_URING_F_IOPOLL ;
if ( req_has_async_data ( req ) )
ioucmd - > cmd = req - > async_data ;
ret = file - > f_op - > uring_cmd ( ioucmd , issue_flags ) ;
if ( ret = = - EAGAIN ) {
if ( ! req_has_async_data ( req ) ) {
if ( io_alloc_async_data ( req ) )
return - ENOMEM ;
io_uring_cmd_prep_async ( req ) ;
}
return - EAGAIN ;
}
if ( ret ! = - EIOCBQUEUED ) {
2022-08-11 12:14:59 +03:00
if ( ret < 0 )
req_set_fail ( req ) ;
io_req_set_res ( req , ret , 0 ) ;
2022-05-25 14:59:19 +03:00
return IOU_OK ;
}
return IOU_ISSUE_SKIP_COMPLETE ;
}