Skip to content

Redfs ubuntu resolute 7.0.0 14.14 - #206

Open
hbirth wants to merge 37 commits into
DDNStorage:redfs-ubuntu-resolute-7.0.0-14.14from
hbirth:redfs-ubuntu-resolute-7.0.0-14.14
Open

Redfs ubuntu resolute 7.0.0 14.14#206
hbirth wants to merge 37 commits into
DDNStorage:redfs-ubuntu-resolute-7.0.0-14.14from
hbirth:redfs-ubuntu-resolute-7.0.0-14.14

Conversation

@hbirth

@hbirth hbirth commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

bsbernd and others added 30 commits August 28, 2026 14:52
This is especially needed for better ftrace analysis,
for example to build histograms. So far the request unique
was missing, because it was added after the first trace message.

IDs/req-unique now might not come up perfectly sequentially
anymore, but especially  with cloned device or io-uring this
did not work perfectly anyway.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>

(imported from commit 4415892)

(cherry picked from commit 02f0a37)

[hbi: 7.0 assigns the unique in exported send helpers that also trace;
      keep them, assigning only when fuse_args_to_req() has not]
fuse_uring_send_next_to_ring() can just call into fuse_uring_send
and avoid code dup.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>

(imported from commit 9efaa8d)

(cherry picked from commit 67ef129)
Sometimes the file offset alignment needs to be opt-in to achieve the
optimum performance at the backend store.

For example when ErasureCode [1] is used at the backend store, the
optimum write performance is achieved when the WRITE request is aligned
with the stripe size of ErasureCode.  Otherwise a non-aligned WRITE
request needs to be split at the stripe size boundary.  It is quite
costly to handle these split partial requests, as firstly the whole
stripe to which the split partial request belongs needs to be read out,
then overwrite the read stripe buffer with the request, and finally write
the whole stripe back to the persistent storage.

Thus the backend store can suffer severe performance degradation when
WRITE requests can not fit into one stripe exactly.  The write performance
can be 10x slower when the request is 256KB in size given 4MB stripe size.
Also there can be 50% performance degradation in theory if the request
is not stripe boundary aligned.

Besides, the conveyed test indicates that, the non-alignment issue
becomes more severe when decreasing fuse's max_ratio, maybe partly
because the background writeback now is more likely to run parallelly
with the dirtier.

fuse's max_ratio	ratio of aligned WRITE requests
----------------	-------------------------------
70			99.9%
40			74%
20			45%
10			20%

With the patched version, which makes the alignment constraint opt-in
when constructing WRITE requests, the ratio of aligned WRITE requests
increases to 98% (previously 20%) when fuse's max_ratio is 10.

fuse: fix alignment to work with redfs ubuntu

- small fix to make the fuse alignment patch work with redfs ubuntu 6.8.x
- add writeback_control to fuse_writepage_need_send() to make
more accurate decisions about when to skip sending data
- fix shift number for FUSE_ALIGN_PG_ORDER
- remove test code

[1] https://lore.kernel.org/linux-fsdevel/20240124070512.52207-1-jefflexu@linux.alibaba.com/T/#m9bce469998ea6e4f911555c6f7be1e077ce3d8b4
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>

(imported from commit 5e590a6)

(cherry picked from commit 1ee8c80)

[hbi: 7.0 shares fuse_folios_need_send() with the read path, so the
      alignment check goes in fuse_iomap_writeback_range()]
generic_file_direct_write() also does this and has a large
comment about.

Reproducer here is xfstest's generic/209, which is exactly to
have competing DIO write and cached IO read.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>

(imported from commit 9e04c8a)

(cherry picked from commit 56b0509)
Simplify fuse_compound_req to hold only the pointers
to the added fuse args and the request housekeeping.

Simplify open+getattr call by using helper functions
to fill out the fuse request parameters

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>

(imported from commit 1607a03)
(imported from commit 9df5e4c)
(imported from commit 9921bcd)
(imported from commit 09d6f59)

(cherry picked from commit 41b40bd)
In preparation for allowing partial attribute updates via statx
(where only a subset of STATX_BASIC_STATS may be requested and
returned), modify fuse_change_attributes_common() to be more
selective about what it updates.

Currently, fuse_change_attributes_common() unconditionally:
1. Clears ALL of STATX_BASIC_STATS from inval_mask
2. Updates fi->i_time (extending the attribute timeout)

For some fuse-servers it might be benefitial to reduce the number
of queries attributes and and attribute mask is one of the
features of statx. With the all or nothing handling
of fuse_change_attributes_common() that statx feature is
impossible to be used.

This commit adds the logic to:
1. Track which attributes were actually returned (via sx->mask for
   statx, or assume all STATX_BASIC_STATS for getattr)
2. Only clear those specific attributes from inval_mask
3. Only update fi->i_time when it's safe: when cache_mask is empty
   OR when all cache_mask attributes were included in the response

The condition in fuse_do_statx() still requires ALL STATX_BASIC_STATS,
so this commit has no functional change. A follow up commit will relax
that condition to enable partial updates.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
(cherry picked from commit 8034f26)
(cherry picked from commit bf71659)
…attributes

For permission checks via inode_permission(), we only need mode, uid, and
gid attributes. Previously, we requested all STATX_BASIC_STATS, which was
inefficient.

This commit enables the optimization by:
1. Requesting only STATX_MODE | STATX_UID | STATX_GID for permission checks
2. Relaxing the condition in fuse_do_statx() from requiring all basic stats
   to accepting any subset of basic stats
3. Adding validation that the server returns at least what was requested

The preparation commit ensures partial updates work correctly by only
updating returned attributes and managing timeouts appropriately.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
(cherry picked from commit 09ed47b)
(cherry picked from commit 7a08fe8)
This is an extended version of lookup that supports additional flags
and returns attributes with valid masks via fuse_reply_lookupx.

(cherry picked from commit 1bcbb38)
(cherry picked from commit 20916ea)
fuse_perm_getattr() requests only STATX_MODE | STATX_UID | STATX_GID.
fi->i_time is only advanced when the response covers STATX_BASIC_STATS in
full, so a perm-only refresh clears the perm bits from inval_mask but
leaves i_time at its old (expired) value.

Add fi->i_perm_time, updated whenever a refresh covers MODE|UID|GID
(always for the non-statx getattr path; conditionally on returned_attrs
for the statx path), and gate fuse_permission()'s sync decision on it
instead of i_time. fuse_update_get_attr() continues to use i_time so a
full stat() still re-queries the server when size/mtime/etc. expire.

Fixes: 09ed47b ("fuse: Optimize statx for permission checks by requesting only needed attributes")
Signed-off-by: Horst Birthelmer <horst@birthelmer.de>
(cherry picked from commit a2d3971)
(cherry picked from commit fa98cf9)
…ing dentry

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit ec5c66b)
(cherry picked from commit 2e85651)
Don't assume that the name is null terminated in fuse_do_lookupx()
That holds when name is taken from a dentry's d_name
(dcache invariant), but the 6.14 d_revalidate signature change
(commit 5be1fa8) makes the callback receive the
walker's qstr, whose backing buffer is the pathname being resolved.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit e3501c1)
On the pinned-header send path fuse_uring_dispatch_ent() calls
io_uring_cmd_done() directly from the request submitter's context with
IO_URING_F_UNLOCKED. Every fuse-uring command is marked cancelable, so
io_uring_cmd_del_cancelable() has to take ctx->uring_lock from that
foreign task on every request.

The ring task holds this mutex for the whole ->uring_cmd() issue path
(io_uring_enter() submission), where it also wakes the submitter of the
request it just committed - before releasing the lock. The freshly
woken submitter usually preempts the ring task on the same CPU, and its
next dispatch then blocks on the very mutex its victim still holds. The
preempted owner is merely runnable and gets no wakeup boost, so under
CPU pressure this convoy costs milliseconds per request while the
daemon's actual work is a few microseconds.

Keep the copies into the pinned pages in the submitter's context - that
is the point of the pinning - but defer the command completion to ring
task task-work, like the non-pinned path already does. There
io_uring_cmd_del_cancelable() runs under the task-work batch's already
held uring_lock, and the submitter no longer touches ctx->uring_lock at
all on the fast path (only the rare copy-failure fallback still can).

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit 6470c72)

[hbi: 7.0 task work takes io_req_tw_func_t; use tw.cancel in place of
      IO_URING_F_TASK_DEAD]
fuse_uring_commit_fetch() runs from the ->uring_cmd() issue path with
ctx->uring_lock held by io_uring_enter(). Ending the committed request
there means wake_up(&req->waitq) runs while the ring task still holds
the mutex, and the freshly woken submitter typically preempts the ring
task on the same CPU right away - leaving the lock held by a merely
runnable task for however long the runqueue is backed up.

wake_up_sync() would not help here: WF_SYNC only biases task placement
in select_task_rq_fair(), check_preempt_wakeup_fair() never looks at
it, so it cannot stop the wakee from preempting the waker.

Instead defer fuse_request_end() to task work on the ring task. It runs
after the submission path has dropped uring_lock - at latest on return
to userspace, typically at io_cqring_wait() entry via
io_run_task_work() - so the ring task finishes its critical section and
the entry recycling in fuse_uring_next_fuse_req() before the submitter
gets the CPU. This also moves the request ->end() callbacks off the
locked section, shortening the uring_lock hold time.

Fall back to completing in place when the command was issued from an
unlocked context (io-wq punt) or task_work_add() fails because the task
is exiting.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit b6ec467)
The append grant is taken at a sampled i_size, but the exclusive inode
lock does not pin it: attribute replies move i_size under fi->lock
alone.  generic_write_checks() then rewrites ki_pos to the fresher
i_size and the write lands past the granted range, dirtying the cache
without DLM coverage.  The in-gate re-validation checks the stale range
and cannot catch it.

Request the lock again for the final ki_pos when it moved, and let
dlm_pos track it so the in-gate re-validation guards the range the
write really lands in.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit c93c346)
Read-modify-writes of blocks past the server EOF go back to reading:
the zero-fill needed fi->server_size verified against every recorded
write grant, and the verification GETATTRs are server traffic and
complexity the saved READs are not worth.  Partial pages of expanding
writes will be sent as separate FUSE_WRITE requests instead, which
needs no read-modify-write at all.

Remove the fi->server_size bound with its grow and shrink sites, the
grant verification debt, and the zero-fill in
fuse_iomap_read_folio_range().

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit ea43157)
With the expansion zero-fill gone, every unaligned buffered write under
DLM pays a read-modify-write READ per partial page, and past the server
EOF that READ returns zero bytes: a wasted round trip for data that
cannot exist.  The write path cannot tell the wasted READ from a needed
one without trusting a bound the grant may predate.

Do not complete partial pages at all.  Split the buffered write
(fuse_dlm_buffered_write()): cache only the page-aligned interior,
whole pages need no read-modify-write, and send the unaligned head and
tail through the existing writethrough path (fuse_perform_write()).  A
partial page is written byte-exact and left non-uptodate, so nothing is
read and neighbouring writers sharing a boundary page accumulate their
bytes on the server.  A sub-page write with no aligned interior goes
fully through.

The DLM write lock is taken over the whole range before i_rwsem, so all
chunks are covered, and the pre-claimed i_size extension with its
reconciliation keeps working on the chunk total.  The read-modify-write
path stays functional for the rare unaligned restart of the interior
after a faulted user copy.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit ae035fb)
Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit 41b92e4)
fuse_dlm_buffered_write() sends the unaligned edges of a write to the
server itself so no partly written block is dirtied, and cuts at
PAGE_SIZE.  Nothing checked that a block is a page: a fuseblk mount
keeps whatever blksize= asked for.  iomap then goes back for the
remainder of an edge block and dirties what the write already sent.

Refuse the connection at FUSE_INIT when a writeback cache is negotiated
on a block that is not a page.  st_blksize still reports what the server
named.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit 7499e44)
[hbi: 7.0 dropped fc->blkbits and never sets inode->i_blkbits from the
      server, so check sb->s_blocksize_bits and drop the per-inode pin]
Readahead fills the page cache past the range fuse_cache_read_iter()
locked, so those folios get no revoke when a remote node writes them.
Request a read grant over the whole window in fuse_readahead() before
any folio is consumed, and skip the window when the request fails.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
(cherry picked from commit 8c2ff0e)

[hbi: 7.0 reads ahead through iomap_readahead(); take the grant
      before it]
The record was an interval tree of ranges carrying a lock mode and a
revoke generation, walked under one lock per inode.  Splitting and
merging ranges on every grant made it the contended structure on a file
several threads write.

Record coverage as two bitmaps per aligned file region instead, a bit
per page for granted and for granted-for-write.  A region is a fixed
span, so recording a grant neither allocates nor rearranges anything,
and the regions live in an xarray, so threads writing far apart never
touch the same one.  A grant still on the wire stays out of the bitmaps
and waits on a pending list where a revoke marks it, which keeps a reply
that crosses a revoke from recording coverage the server took back.

Adapt the paths to it: reads and readahead take a read grant, a cached
write takes the write grant for the range it dirties and sends its
unaligned edges straight through, writeback confirms the grant for every
run it sends, and a NOTIFY invalidate drops the record for the range it
revokes before it drops the page cache.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_writeback_write_iter() published its AOP_TRUNCATED_PAGE retry state
in a connection-wide xarray keyed by task pointer, and erased it again,
once per buffered write.  A task pointer is a high index, so every write
built and tore down the whole node chain down to it under one lock
shared by every writer of the mount, and its GFP_KERNEL allocation ran
with i_rwsem held.

iomap already carries a private pointer through to
fuse_iomap_read_folio_range(), where fuse put the struct file.  Put the
file and the flag in one struct on the stack and pass that instead.

The store could fail and take the write down with it, and the load could
come back empty and drop a needed retry.  Neither is reachable now.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
A server answers a contended range with -EDEADLK, which
fuse_do_readfolio() turns into AOP_TRUNCATED_PAGE so the read is retried.
__fuse_get_dlm_lock() returned it instead, and its writeback caller has
no way to hold on to a folio it reports an error for: iomap takes the
dirty flag off before offering the folio and clears its dirty ranges
whatever the callback returns, so the bytes are dropped without ever
reaching the server.  A NOTIFY invalidate then drops the now clean folio
and the next read gets the pre-write content.

Ask again on -EDEADLK and -EAGAIN, on the retry budget the killed-in-
flight grant already uses.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
iomap clears the dirty flag before it offers a folio to
->writeback_range and clears its dirty ranges whatever the callback
returns, and nothing puts either back.  A run that reports an error has
therefore dropped its bytes: the folio stays in the page cache, clean and
uptodate, holding data the server never received, until an invalidate
drops it and the next read returns what the server has.

The comment claimed the opposite.  Redirty the folio instead, for the
grant and the allocation, while there is still a connection to send it
on.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
The DLM buffered write holds i_rwsem shared and claims its i_size
extension before it dirties anything.  fuse_attr_cache_mask() decides
whether the server's size wins from an i_size it reads before that claim,
and sleeps in the lock tree query before fuse_change_attributes_i()
applies the answer under fi->lock.  A GETATTR that left while i_size
still matched the server's is therefore applied over every claim made
since, and i_size drops by exactly the writes in flight.
truncate_pagecache() then zeroes the tail of the page holding the new
size and drops what is above, which writeback sends as zeros.

Move attr_version on the claim so those replies are dropped, the same
reason fuse_write_update_attr() moves it, and count the writers whose
claim is not yet dirty for a reply that leaves after one.
FUSE_I_SIZE_UNSTABLE cannot serve as the count: it is a single bit and
every writer clears it.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_reverse_inval_inode() drives this inode's page cache, before the
revoke to flush it and after the revoke to drop it, on the thread that
wrote the NOTIFY into /dev/fuse.  Both reach fuse_iomap_writeback_range(),
which holds the folio locked and under writeback while
fuse_dlm_regrant_range() sends FUSE_DLM_WB_LOCK and waits.  The range is
the one being revoked, so the server cannot answer until the revoke
completes, and the revoke cannot complete until the handler returns.  A
folio dirtied under a grant a NOTIFY took away is reached this way, which
fuse_cache_write_iter() says is allowed to happen.

Mark the task across that work and report the run as a hole when the
grant is not already held: the folio goes back on the dirty list and an
ordinary writeback sends it with a grant of its own.  Reporting a hole
means the run needs the type reset that had no user before.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_iomap_writeback_range() runs with the folio locked and, since
iomap_writeback_folio() starts the writeback before the run loop, under
writeback as well.  Asking the server for a grant there is the ordering
Documentation/filesystems/fuse/fuse-AOP_TRUNCATED_PAGE-reason.txt exists
to forbid: no cluster lock may be taken while a page lock is held.  The
read path has AOP_TRUNCATED_PAGE to unlock and retry with, and
->writeback_range has nothing of the sort, so the violation sits where
the remedy does not reach.

Skip a run whose grant has gone: report it as a hole, put the folio back
on the dirty list and remember the range.  fuse_iomap_writeback_submit()
takes it back once the pass has let go of every folio, and the pass that
follows sends it.

Not from fuse_launder_folio(), which arrives with the folio locked by
folio_unmap_invalidate(), nor from a revoke handler, which would ask for
the range it is revoking.  There the skip stands.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_dlm_request_begin() publishes the range asked for, and
fuse_dlm_kill_pending() can only test that one, but the commit records
what the server granted, which may reach FUSE_DLM_MAX_EXTRA_GRANT either
side of it.  A revoke processed while the request was on the wire and
landing in that excess marks nothing: the request does not overlap it, and
the shards hold no bit for it yet because the grant is not recorded.  The
excess is then recorded over the revoked range and no later NOTIFY takes
it back, which is the case the pending list exists to catch.

Publish the widest bounds the commit could record as well, and separate
the two outcomes.  A revoke over the range asked for still kills the
grant.  One over the excess alone leaves the range asked for recorded and
drops the excess, which only costs a re-request.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
The comment claimed the round trip happens before any folio of the window
is locked.  ->readahead is entered with all of them locked and
readahead_folio() is what unlocks them, so it happens under them.

Say so, and say why it does not close a cycle: the lock in the way belongs
to the node the revoke is sent to, not to this one.  Name the case that
does not follow, a window this already holds part of.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_iomap_writeback_range() unions every run it had to skip, and
fuse_iomap_writeback_submit() asks for the lot in one grant.  A pass
sweeping a large file skips runs gigabytes apart, so the union grows to
the whole sweep and the request covers a range nothing wanted.

Stop extending at one shard.  The runs left out stay dirty and a later
pass asks for them.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_writeback_redirty() dirtied the folio from inside ->writeback_range,
and iomap_writeback_folio() runs iomap_clear_range_dirty() over the whole
folio once that returns.  For a folio one block wide there is no
iomap_folio_state and the call does nothing, so it worked.  A large folio
has one, and the folio is left with the dirty flag and no dirty block
under it: the next pass finds nothing to write and the folio goes clean
with its bytes never sent.

Hold the folio instead and dirty it once iomap has released it, on the
next call or in the submit.

fuse_writepage_need_send() also reached wbc->range_end with no wbc, which
only a folio of a single run kept out of reach; guard it.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_fill_write_pages() carried the offset of the next copy across
iterations as a within page residue and turned it into a folio offset by
adding the page delta.  A write that starts inside a folio it does not
begin covers the rest of that folio, and the residue left from it is then
added to the next folio's own delta: the copy lands past the end of the
folio, copy_folio_from_iter_atomic() warns and returns nothing, and the
fault in loop retries it for good.  A folio one page wide cannot start
before the write does, which is what kept it out of reach.  Take the
offset from @pos, which is always current, and read the loop's carry on
test off the folio it just filled.

fuse_page_mkwrite() locked the page that faulted.  The whole folio is
dirtied on the way out, in fault_dirty_shared_page(), so the DLM lock has
to cover the folio.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
Two ways a cached write reached the write check as a hole.

fuse_iomap_writeback_range() returns -EIO when the inode has no file open
for writing, and dropped the folio doing so.  fuse_open() invalidates the
whole mapping unless the server sets FOPEN_KEEP_CACHE, and reaches
fuse_launder_folio() that way; by the time a reader opens the file the
last writer has closed, so fuse_write_file_get() finds nothing, warns, and
the bytes go.  They are still the newest there are, so keep them.

And a run whose grant had gone is skipped, its range taken back in the
submit, and the folio left dirty for a later pass.  A data integrity
writeback has no later pass, so fsync() and close() reported bytes written
that were still only in the page cache.  Go round again while anything is
left deferred.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
A writer confirms its grant and then copies and dirties, and a revoke
landing in between is answered while those bytes are in no page cache
and on no wire.  The flush the revoke runs cannot find them, so they go
out later under a fresh grant, after the server has handed the lock to
another node.

Add a pin: the range a writer is about to dirty, on a list a revoke
walks before it removes anything.  A revoke publishes the range it takes
away on a second list and waits for the pins overlapping it, and a pin
overlapping a published range is refused.  Refusal and wait test the
same overlap, so the wait converges, and ranges that do not overlap
never meet: a notify leaves the rest of the file writable and a write
outside the notified range does not hold it up.

Both nodes are caller storage, so nothing is allocated to take a pin and
the writeback path can take one with a folio held.  A pin is found again
by owner, since iomap hands ->put_folio the inode and nothing of the
iteration.

Confirm the grant under the pin, never before, in the three places bytes
become the server's: the iomap interior through new ->get_folio and
->put_folio hooks, the writethrough edges around their FUSE_WRITE, and
the writeback run until the folio is under writeback.  A grant that has
gone is asked for again with the pin dropped, since that request is
answered by the server the revoke came from.

With the writers fenced, the flush a revoke runs needs a single pass:
nothing can turn up dirty behind it.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
A folio wider than a block carries per-block dirty state, and
iomap_writeback_folio() clears all of it after ->writeback_range.  A run
fuse defers and puts back with folio_mark_dirty() comes back dirty over
the whole folio, since iomap_dirty_folio() sets the whole range, so the
next pass sends blocks this client never wrote: data read from the
server, or zeros laid down above the size the file had at the time.

Order-0 folios carry no per-block state, so a dirty folio is one this
client wrote whole and the widening cannot happen.  The parameter stays
writable for anyone opting back in.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
The !CONFIG_FUSE_IO_URING branch carries a second stub for it, declared
bool and returning nothing, so fs/fuse does not build without io-uring.
It came in with the fuse_uring_flush_bg() stub, which is the one that
hunk was meant to add.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse: fine-grained request ftraces split the one tracepoint in two:
trace_fuse_request_enqueue() where a request is queued, and
trace_fuse_request_send() where it reaches the server, so the time in
each is separable.  7.0 moved its own trace_fuse_request_send() out of
fuse_send_one() into fuse_request_assign_unique{,_locked}(), which the
split did not reach, so every request is traced sent twice: once at queue
time and once for real.

Drop the send from the assign helpers.  It stays in fuse_dev_do_read()
and fuse_uring_send(), and virtiofs is left with the enqueue trace its
send_req already stands for.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
fuse_uring_args_to_ring() finished the copy state twice: the 7.0 line
after fuse_copy_args() and the copy_finish label that already covers both
exits.  fuse_uring_create() kept a kcalloc() while every allocation
around it moved to kzalloc_objs(), and lost its continuation indent doing
so.  io_pages_free() and the queue map destructors were hoisted above
their neighbours for no reason.

No functional change; the remaining delta to the 6.17 branch is now the
7.0 API differences alone.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
@hbirth
hbirth force-pushed the redfs-ubuntu-resolute-7.0.0-14.14 branch from bde846e to 0b2ea3e Compare September 1, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants