Merge tag 'fuse-update-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Improve performance of the io-uring transport by introducing buffer
   pools and zero-copy (Joanne)

 - Fix lots of bugs (Baokun Li)

 - Fix io-uring initialization issues (Joanne, Bernd)

 - More prep work for large folios (Joanne)

 - Don't limit buffered read to 128k (Jim Harris)

 - Fix zeroing of page end (dirtied with mmap) on file size extension
   (Jimmy Zuber)

 - Improve performance in certain cases with wake_up_sync() when queuing
   request (Xuewen Yan)

 - Misc fixes and cleanups (Xuewen Yan)

* tag 'fuse-update-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (35 commits)
  fuse: zero the partial EOF page when extending a file
  io_uring: Add missing include for ITER_SOURCE and ITER_DEST
  fuse: Fix the condition to enable over-io-uring
  fuse: invalidate the correct range after O_APPEND direct write
  selftests/fuse: test post-EOF page zeroing when a file is extended
  fuse: wake one waiter per freed slot when raising max_background
  fuse: use min_not_zero() in fuse_init_server_timeout()
  fuse: copy request headers via a stack buffer for io-uring
  fuse: give wakeup hints to the scheduler for synchronous requests
  fuse: check for NULL root inode in fuse_fill_super_submount
  fuse: reject a duplicate fd= mount option
  cuse: wait for pending RCU callbacks on module exit
  fuse: fix invalidate lock leak on open O_TRUNC DAX failure
  fuse: fix invalidate lock leak on setattr writeback failure
  fuse: wait for FR_FINISHED on abort_on_kill to prevent use-after-free
  fuse: make dentry_tree_work static
  docs: fuse: document io-uring buffer pool and zero-copy uapi
  fuse: add zero-copy over io-uring
  fuse: support registered buffer pools in io-uring
  fuse: add io-uring buffer pools
  ...
This commit is contained in:
Linus Torvalds
2026-08-25 07:59:44 -07:00
27 changed files with 1474 additions and 236 deletions
+1 -1
View File
@@ -3236,7 +3236,7 @@ static int __init io_uring_init(void)
io_uring_optable_init();
/* imu->dir is u8 */
BUILD_BUG_ON((IO_IMU_DEST | IO_IMU_SOURCE) > U8_MAX);
BUILD_BUG_ON((IO_BUF_DEST | IO_BUF_SOURCE) > U8_MAX);
/*
* Allow user copy in the per-command field, which starts after the
+92 -39
View File
@@ -912,7 +912,7 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
imu->release = io_release_ubuf;
imu->priv = imu;
imu->flags = 0;
imu->dir = IO_IMU_DEST | IO_IMU_SOURCE;
imu->dir = IO_BUF_DEST | IO_BUF_SOURCE;
if (coalesced)
imu->folio_shift = data.folio_shift;
refcount_set(&imu->refs, 1);
@@ -1015,71 +1015,124 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
return ret;
}
int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
void (*release)(void *), unsigned int index,
unsigned int issue_flags)
static struct io_mapped_ubuf *io_kernel_buffer_init(struct io_ring_ctx *ctx,
unsigned int nr_bvecs,
unsigned int total_bytes,
u8 dir,
void (*release)(void *),
void *priv,
unsigned int index)
{
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
struct io_rsrc_data *data = &ctx->buf_table;
struct req_iterator rq_iter;
struct io_mapped_ubuf *imu;
struct io_rsrc_node *node;
struct bio_vec bv;
unsigned int nr_bvecs = 0;
int ret = 0;
io_ring_submit_lock(ctx, issue_flags);
if (index >= data->nr) {
ret = -EINVAL;
goto unlock;
}
if (index >= data->nr)
return ERR_PTR(-EINVAL);
index = array_index_nospec(index, data->nr);
if (data->nodes[index]) {
ret = -EBUSY;
goto unlock;
}
if (data->nodes[index])
return ERR_PTR(-EBUSY);
node = io_rsrc_node_alloc(ctx, IORING_RSRC_BUFFER);
if (!node) {
ret = -ENOMEM;
goto unlock;
if (!node)
return ERR_PTR(-ENOMEM);
imu = io_alloc_imu(ctx, nr_bvecs);
if (!imu) {
io_cache_free(&ctx->node_cache, node);
return ERR_PTR(-ENOMEM);
}
imu->ubuf = 0;
imu->len = total_bytes;
imu->folio_shift = PAGE_SHIFT;
imu->nr_bvecs = nr_bvecs;
refcount_set(&imu->refs, 1);
imu->release = release;
imu->priv = priv;
imu->dir = dir;
imu->flags = IO_REGBUF_F_KBUF;
node->buf = imu;
data->nodes[index] = node;
return imu;
}
int io_buffer_register_request(struct io_uring_cmd *cmd, struct request *rq,
void (*release)(void *), unsigned int index,
unsigned int issue_flags)
{
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
struct req_iterator rq_iter;
struct io_mapped_ubuf *imu;
struct bio_vec bv;
/*
* blk_rq_nr_phys_segments() may overestimate the number of bvecs
* but avoids needing to iterate over the bvecs
*/
imu = io_alloc_imu(ctx, blk_rq_nr_phys_segments(rq));
if (!imu) {
io_cache_free(&ctx->node_cache, node);
ret = -ENOMEM;
unsigned int nr_bvecs = blk_rq_nr_phys_segments(rq);
unsigned int total_bytes = blk_rq_bytes(rq);
int ret = 0;
io_ring_submit_lock(ctx, issue_flags);
imu = io_kernel_buffer_init(ctx, nr_bvecs, total_bytes,
1 << rq_data_dir(rq), release, rq, index);
if (IS_ERR(imu)) {
ret = PTR_ERR(imu);
goto unlock;
}
imu->ubuf = 0;
imu->len = blk_rq_bytes(rq);
imu->folio_shift = PAGE_SHIFT;
refcount_set(&imu->refs, 1);
imu->release = release;
imu->priv = rq;
imu->flags = IO_REGBUF_F_KBUF;
imu->dir = 1 << rq_data_dir(rq);
nr_bvecs = 0;
rq_for_each_bvec(bv, rq, rq_iter)
imu->bvec[nr_bvecs++] = bv;
imu->nr_bvecs = nr_bvecs;
node->buf = imu;
data->nodes[index] = node;
unlock:
io_ring_submit_unlock(ctx, issue_flags);
return ret;
}
EXPORT_SYMBOL_GPL(io_buffer_register_request);
/*
* bvs is copied internally. caller may free it on return.
*/
int io_buffer_register_bvec(struct io_uring_cmd *cmd, const struct bio_vec *bvs,
unsigned int nr_bvecs, void (*release)(void *),
void *priv, u8 dir, unsigned int index,
unsigned int issue_flags)
{
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
struct io_mapped_ubuf *imu;
struct bio_vec *bvec;
unsigned int i, total_bytes = 0;
int ret = 0;
for (i = 0; i < nr_bvecs; i++)
total_bytes += bvs[i].bv_len;
io_ring_submit_lock(ctx, issue_flags);
imu = io_kernel_buffer_init(ctx, nr_bvecs, total_bytes, dir, release,
priv, index);
if (IS_ERR(imu)) {
ret = PTR_ERR(imu);
goto unlock;
}
bvec = imu->bvec;
for (i = 0; i < nr_bvecs; i++)
bvec[i] = bvs[i];
unlock:
io_ring_submit_unlock(ctx, issue_flags);
return ret;
}
EXPORT_SYMBOL_GPL(io_buffer_register_bvec);
int io_buffer_unregister_bvec(struct io_uring_cmd *cmd, unsigned int index,
unsigned int issue_flags)
int io_buffer_unregister(struct io_uring_cmd *cmd, unsigned int index,
unsigned int issue_flags)
{
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
struct io_rsrc_data *data = &ctx->buf_table;
@@ -1109,7 +1162,7 @@ unlock:
io_ring_submit_unlock(ctx, issue_flags);
return ret;
}
EXPORT_SYMBOL_GPL(io_buffer_unregister_bvec);
EXPORT_SYMBOL_GPL(io_buffer_unregister);
static int validate_fixed_range(u64 buf_addr, size_t len,
const struct io_mapped_ubuf *imu)
-5
View File
@@ -25,11 +25,6 @@ struct io_rsrc_node {
};
};
enum {
IO_IMU_DEST = 1 << ITER_DEST,
IO_IMU_SOURCE = 1 << ITER_SOURCE,
};
enum {
IO_REGBUF_F_KBUF = 1,
};