Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bbeb7f5
fuse: retry the read in fuse_write_begin() on DLM contention
hbirth Aug 13, 2026
5890520
fuse: use -EDEADLK for DLM lock error instead of -EAGAIN
bsbernd Aug 13, 2026
affca44
fuse: drop BDI_CAP_STRICTLIMIT from fuse bdi setup
hbirth Jun 22, 2026
00d60f0
fuse: switch to direct IO on an inode-invalidation notify storm
hbirth Aug 13, 2026
d33312f
fuse: use default writeback accounting
joannekoong Aug 13, 2026
fcacbc8
fuse: allow parallel direct writes past EOF
bsbernd Aug 13, 2026
0f696e4
fuse: balance uncached_io accounting under forced-DIO latch
hbirth Jul 16, 2026
3488a13
fuse: don't hold i_rwsem exclusively when doing buffered write
hbirth Aug 13, 2026
385d3ee
fuse: acquire dlm lock for the normal buffer read
hazhou-ddn Aug 13, 2026
4225b31
fuse: fence cached reads against NOTIFY invalidate with a percpu gate
hbirth Aug 13, 2026
7896594
fuse: satisfy DLM read lock requests from a held write lock
hbirth Jul 17, 2026
f2ba2c6
fuse: zero-fill writes past the server EOF instead of sending READs
hbirth Aug 13, 2026
5ce4f97
fuse: only refresh size on cached write when opened with O_APPEND
hazhou-ddn Jul 29, 2026
0f7f419
fuse: seed DLM grant merging with an interval-tree lookup
hbirth Jul 25, 2026
c48c1d1
fuse: re-validate the DLM grant after waiting on the coherency gate
hbirth Aug 13, 2026
42a13e9
fuse: fix the DLM revoke range of an inode invalidate
hbirth Aug 13, 2026
953ed78
fuse: fence mmapped invalidates and local truncates with the coherenc…
hbirth Jul 28, 2026
669269e
fuse: order grant recording against concurrent revokes
hbirth Jul 28, 2026
205e1d7
fuse: complete pinned-header sends in ring task context
hbirth Jul 30, 2026
19c898c
fuse: retry grant recording until it wins against revokes
hbirth Aug 12, 2026
3aa1aad
fuse: gate the notify-driven direct-IO latch behind a module parameter
hbirth Aug 12, 2026
0a69923
fuse: re-decide the write lock mode after the DLM probe
Aug 13, 2026
b510e66
fuse: mark writeback-initiated SETATTR with FATTR_WRITEBACK
hbirth Aug 5, 2026
eb0d730
fuse: disable local attribute cache override under DLM
hazhou-ddn Aug 12, 2026
9e9a8e7
fuse: don't launder from a NOTIFY invalidate while writepages are frozen
hbirth Aug 14, 2026
5157748
fuse: do not kill suid from inside the coherency gate
hbirth Aug 14, 2026
3fc92d6
fuse: keep cached size and times under a DLM write grant
hbirth Aug 14, 2026
db0bd6b
fuse: take i_rwsem exclusive when a write drops suid/sgid
hbirth Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion fs/fuse/dev_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,26 @@ static void fuse_uring_send_in_task(struct io_uring_cmd *cmd,
fuse_uring_send(ent, cmd, err, issue_flags);
}

/*
* The request was already copied to the ring buffer in the submitter's
* context, only the io_uring cmd completion is left to do.
* io_uring_cmd_done() must not run in the submitter's context as it would
* have to take ctx->uring_lock (io_uring_cmd_del_cancelable()) - a mutex
* the ring task holds across its whole submission path and frequently gets
* preempted under while the just-woken submitter runs.
*/
static void fuse_uring_send_prepared_in_task(struct io_uring_cmd *cmd,
unsigned int issue_flags)
{
struct fuse_ring_ent *ent = uring_cmd_to_ring_ent(cmd);
int err = 0;

if (unlikely(issue_flags & IO_URING_F_TASK_DEAD))
err = -ECANCELED;

fuse_uring_send(ent, cmd, err, issue_flags);
}

static struct fuse_ring_queue *fuse_uring_select_queue(struct fuse_ring *ring,
bool background)
{
Expand Down Expand Up @@ -1560,7 +1580,9 @@ static void fuse_uring_dispatch_ent(struct fuse_ring_ent *ent, bool bg)
IO_URING_F_UNLOCKED);
return;
}
fuse_uring_send(ent, cmd, 0, IO_URING_F_UNLOCKED);
uring_cmd_set_ring_ent(cmd, ent);
io_uring_cmd_complete_in_task(cmd,
fuse_uring_send_prepared_in_task);
}
}

Expand Down
45 changes: 45 additions & 0 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,12 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
inarg.valid |= FATTR_FH;
inarg.fh = ff->fh;
}
/*
* This is ->write_inode() flushing times the kernel owns locally, not
* a userspace utimes(); let the server tell the two apart.
*/
if (fm->fc->setattr_writeback)
inarg.valid |= FATTR_WRITEBACK;
fuse_setattr_fill(fm->fc, &args, inode, &inarg, &outarg);

return fuse_simple_request(fm, &args);
Expand Down Expand Up @@ -2076,15 +2082,35 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
WARN_ON(!(attr->ia_valid & ATTR_SIZE));
WARN_ON(attr->ia_size != 0);
if (fc->atomic_o_trunc) {
struct percpu_rw_semaphore *wb_sem = fi->wb_inval_rwsem;

/*
* No need to send request to userspace, since actual
* truncation has already been done by OPEN. But still
* need to truncate page cache.
*
* Revoke and drop under the coherency gate write side,
* like the NOTIFY invalidate path: a gate reader that
* already re-validated its grant must not have the
* lock tree and the cache yanked mid-hold, or it
* would repopulate the truncated range trusting a
* grant that no longer exists. Waiting for gate
* readers here is safe: we hold i_rwsem exclusive, so
* no gate holder can be waiting on it (the write path
* takes i_rwsem before the gate, the read path never
* takes it).
*/
if (wb_sem)
percpu_down_write(wb_sem);
if (fc->dlm && fc->writeback_cache)
fuse_dlm_cache_release_locks(fi);
spin_lock(&fi->lock);
fi->server_size = 0;
i_size_write(inode, 0);
spin_unlock(&fi->lock);
truncate_pagecache(inode, 0);
if (wb_sem)
percpu_up_write(wb_sem);
goto out;
}
file = NULL;
Expand Down Expand Up @@ -2175,6 +2201,13 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
/* see the comment in fuse_change_attributes() */
if (!is_wb || is_truncate)
i_size_write(inode, outarg.attr.size);
/*
* A truncate settles the size on the server; only shrink the
* server-materialized bound: growing just exposes zeros, which the
* bound need not cover (see fuse_write_begin()).
*/
if (is_truncate && (loff_t) outarg.attr.size < fi->server_size)
fi->server_size = outarg.attr.size;

if (is_truncate) {
/* NOTE: this may release/reacquire fi->lock */
Expand All @@ -2188,11 +2221,23 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
*/
if ((is_truncate || !is_wb) &&
S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
struct percpu_rw_semaphore *wb_sem = fi->wb_inval_rwsem;

/*
* Revoke and drop under the coherency gate write side; see
* the atomic-O_TRUNC branch above. i_rwsem is held
* exclusive here as well (setattr), so waiting out gate
* readers cannot deadlock.
*/
if (wb_sem)
percpu_down_write(wb_sem);
if (fc->dlm && fc->writeback_cache)
fuse_dlm_unlock_range(fi, outarg.attr.size & PAGE_MASK, -1);

truncate_pagecache(inode, outarg.attr.size);
invalidate_inode_pages2(mapping);
if (wb_sem)
percpu_up_write(wb_sem);
}

clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
Expand Down
Loading
Loading