Skip to content

Commit e32dcdb

Browse files
maharmstonekdave
authored andcommitted
btrfs: add io_uring interface for encoded writes
Add an io_uring interface for encoded writes, with the same parameters as the BTRFS_IOC_ENCODED_WRITE ioctl. As with the encoded reads code, there's a test program for this at https://github.com/maharmstone/io_uring-encoded, and I'll get this worked into an fstest. How io_uring works is that it initially calls btrfs_uring_cmd with the IO_URING_F_NONBLOCK flag set, and if we return -EAGAIN it tries again in a kthread with the flag cleared. Ideally we'd honour this and call try_lock etc., but there's still a lot of work to be done to create non-blocking versions of all the functions in our write path. Instead, just validate the input in btrfs_uring_encoded_write() on the first pass and return -EAGAIN, with a view to properly optimizing the optimistic path later on. Signed-off-by: Mark Harmstone <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent bf50aca commit e32dcdb

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

fs/btrfs/ioctl.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4936,6 +4936,128 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue
49364936
return ret;
49374937
}
49384938

4939+
static int btrfs_uring_encoded_write(struct io_uring_cmd *cmd, unsigned int issue_flags)
4940+
{
4941+
loff_t pos;
4942+
struct kiocb kiocb;
4943+
struct file *file;
4944+
ssize_t ret;
4945+
void __user *sqe_addr;
4946+
struct btrfs_uring_encoded_data *data = io_uring_cmd_get_async_data(cmd)->op_data;
4947+
4948+
if (!capable(CAP_SYS_ADMIN)) {
4949+
ret = -EPERM;
4950+
goto out_acct;
4951+
}
4952+
4953+
file = cmd->file;
4954+
sqe_addr = u64_to_user_ptr(READ_ONCE(cmd->sqe->addr));
4955+
4956+
if (!(file->f_mode & FMODE_WRITE)) {
4957+
ret = -EBADF;
4958+
goto out_acct;
4959+
}
4960+
4961+
if (!data) {
4962+
data = kzalloc(sizeof(*data), GFP_NOFS);
4963+
if (!data) {
4964+
ret = -ENOMEM;
4965+
goto out_acct;
4966+
}
4967+
4968+
io_uring_cmd_get_async_data(cmd)->op_data = data;
4969+
4970+
if (issue_flags & IO_URING_F_COMPAT) {
4971+
#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
4972+
struct btrfs_ioctl_encoded_io_args_32 args32;
4973+
4974+
if (copy_from_user(&args32, sqe_addr, sizeof(args32))) {
4975+
ret = -EFAULT;
4976+
goto out_acct;
4977+
}
4978+
data->args.iov = compat_ptr(args32.iov);
4979+
data->args.iovcnt = args32.iovcnt;
4980+
data->args.offset = args32.offset;
4981+
data->args.flags = args32.flags;
4982+
data->args.len = args32.len;
4983+
data->args.unencoded_len = args32.unencoded_len;
4984+
data->args.unencoded_offset = args32.unencoded_offset;
4985+
data->args.compression = args32.compression;
4986+
data->args.encryption = args32.encryption;
4987+
memcpy(data->args.reserved, args32.reserved,
4988+
sizeof(data->args.reserved));
4989+
#else
4990+
ret = -ENOTTY;
4991+
goto out_acct;
4992+
#endif
4993+
} else {
4994+
if (copy_from_user(&data->args, sqe_addr, sizeof(data->args))) {
4995+
ret = -EFAULT;
4996+
goto out_acct;
4997+
}
4998+
}
4999+
5000+
ret = -EINVAL;
5001+
if (data->args.flags != 0)
5002+
goto out_acct;
5003+
if (memchr_inv(data->args.reserved, 0, sizeof(data->args.reserved)))
5004+
goto out_acct;
5005+
if (data->args.compression == BTRFS_ENCODED_IO_COMPRESSION_NONE &&
5006+
data->args.encryption == BTRFS_ENCODED_IO_ENCRYPTION_NONE)
5007+
goto out_acct;
5008+
if (data->args.compression >= BTRFS_ENCODED_IO_COMPRESSION_TYPES ||
5009+
data->args.encryption >= BTRFS_ENCODED_IO_ENCRYPTION_TYPES)
5010+
goto out_acct;
5011+
if (data->args.unencoded_offset > data->args.unencoded_len)
5012+
goto out_acct;
5013+
if (data->args.len > data->args.unencoded_len - data->args.unencoded_offset)
5014+
goto out_acct;
5015+
5016+
data->iov = data->iovstack;
5017+
ret = import_iovec(ITER_SOURCE, data->args.iov, data->args.iovcnt,
5018+
ARRAY_SIZE(data->iovstack), &data->iov,
5019+
&data->iter);
5020+
if (ret < 0)
5021+
goto out_acct;
5022+
5023+
if (iov_iter_count(&data->iter) == 0) {
5024+
ret = 0;
5025+
goto out_iov;
5026+
}
5027+
}
5028+
5029+
if (issue_flags & IO_URING_F_NONBLOCK) {
5030+
ret = -EAGAIN;
5031+
goto out_acct;
5032+
}
5033+
5034+
pos = data->args.offset;
5035+
ret = rw_verify_area(WRITE, file, &pos, data->args.len);
5036+
if (ret < 0)
5037+
goto out_iov;
5038+
5039+
init_sync_kiocb(&kiocb, file);
5040+
ret = kiocb_set_rw_flags(&kiocb, 0, WRITE);
5041+
if (ret)
5042+
goto out_iov;
5043+
kiocb.ki_pos = pos;
5044+
5045+
file_start_write(file);
5046+
5047+
ret = btrfs_do_write_iter(&kiocb, &data->iter, &data->args);
5048+
if (ret > 0)
5049+
fsnotify_modify(file);
5050+
5051+
file_end_write(file);
5052+
out_iov:
5053+
kfree(data->iov);
5054+
out_acct:
5055+
if (ret > 0)
5056+
add_wchar(current, ret);
5057+
inc_syscw(current);
5058+
return ret;
5059+
}
5060+
49395061
int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
49405062
{
49415063
switch (cmd->cmd_op) {
@@ -4944,6 +5066,12 @@ int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
49445066
case BTRFS_IOC_ENCODED_READ_32:
49455067
#endif
49465068
return btrfs_uring_encoded_read(cmd, issue_flags);
5069+
5070+
case BTRFS_IOC_ENCODED_WRITE:
5071+
#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
5072+
case BTRFS_IOC_ENCODED_WRITE_32:
5073+
#endif
5074+
return btrfs_uring_encoded_write(cmd, issue_flags);
49475075
}
49485076

49495077
return -EINVAL;

0 commit comments

Comments
 (0)