| Age | Commit message (Collapse) | Author |
|
Because the iomap infrastructure does not always create an ifs to
manage sub-folio state when folio size is larger than blocksize,
invalidating a partial dirty folio during punch hole may fail to
clear the dirty state of the affected range. As a result, writeback
of that folio may observe a hole. At writeback submit time,
ext4_map_blocks() already handles this case and will not allocate
blocks. However, when punch hole races with writeback, the
following scenario can cause I/O completion to encounter a hole.
punch hole writeback
---------- ---------
ext4_punch_hole()
ext4_truncate_page_cache_block_range()
iomap_invalidate_folio() [partial folio]
iomap_clear_range_dirty()
-- no ifs, sub-block dirty bits NOT cleared
ext4_iomap_writepages()
iomap_writepages()
ext4_iomap_writeback_submit()
ext4_iomap_map_writeback_range()
ext4_map_blocks(IO_SUBMIT)
-> extent exists, not a hole
submit_io() -> bio in flight
down_write(&i_data_sem)
ext4_es_remove_extent()
ext4_ext_remove_space()
-> extent removed, hole inserted
up_write(&i_data_sem)
[ transaction commits, freed blocks released to buddy ]
[ allocator reuses freed blocks for another inode ]
[bio completes]
ext4_iomap_finish_ioend()
ext4_convert_unwritten_extents()
ext4_map_blocks(IO_CONVERT_EXT)
-> returns 0 (hole found)
[bio writes to reallocated blocks ]
-> silent data corruption
If the bio completes after the freed blocks have been reallocated to
another inode, it silently overwrites them and causes data corruption.
Therefore, on the iomap path, drain writeback in ext4_punch_hole() after
partial zeroing and before starting the freeing transaction, so any bio
in flight on a partial folio completes against blocks still owned by
this inode before extent removal. Once extent removal begins, the ES
hole insert and the existing IO_SUBMIT short-circuit prevent further bio
submission.
This is a workaround. The proper fix is for the iomap infrastructure to
always maintain an ifs when folio size is larger than blocksize, so that
partial invalidate reliably clears sub-block dirty bits and no draining
is needed.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-19-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Introduce a new iomap_ops instance, ext4_iomap_zero_ops, along with
ext4_block_iomap_zero_range() to implement block zeroing via the iomap
infrastructure for ext4.
ext4_block_iomap_zero_range() calls iomap_zero_range() with
ext4_iomap_zero_begin() as the callback. The callback locates the
range and populates the iomap mapping. If the range is mapped,
iomap_zero_iter() in the iomap core zeros the partial block
directly. If the range is an unwritten extent within EOF, the
callback collects a dirty folio batch via iomap_fill_dirty_folios()
so that iomap_zero_iter() can zero those folios directly, bypassing
a separate slow flush operation that would otherwise be needed to
convert the unwritten extent.
Note that ext4_iomap_zero_begin() can race with concurrent writeback:
after it queries an unwritten extent, writeback may convert it to
written and complete on the folio before iomap_fill_dirty_folios() scans
the range. The empty batch then makes iomap_zero_iter() skip zeroing,
leaving stale on-disk data.
zero_range writeback
---------------------- ----------------------
ext4_block_zero_range()
iomap_zero_range()
iomap_iter()
ext4_iomap_zero_begin()
ext4_iomap_map_blocks()
-> extent is UNWRITTEN
ext4_convert_unwritten_extents_endio()
-> extent is converted to WRITTEN
-> folio is clean
iomap_fill_dirty_folios()
filemap_get_folios_dirty()
-> folio is clean, not added to batch
ext4_set_iomap() -> IOMAP_UNWRITTEN
iomap_zero_iter()
__iomap_get_folio() -> NULL (empty batch)
iomap_iter_advance_full() <-- zeroing skipped
[later read returns stale on-disk data] <-- CORRUPTION
Therefore, we retry the extent lookup when iomap_fill_dirty_folios()
adds nothing and the i_es_seq cookie captured at the first lookup has
advanced, indicating the race actually occurred.
Other important constraints:
Zeroing out under an active journal handle can cause deadlock, as the
lock/handle ordering is inconsistent with the iomap writeback path.
Therefore, ext4_block_iomap_zero_range() must not be called under an
active handle. In addition, for post-EOF zeroing, the caller cannot
rely on data=ordered mode to persist the zeroed data before
i_disksize is updated.
Subsequent patches will address this by deferring i_disksize update
to i_size until after the zeroed data has been written back.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-18-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Introduce ext4_iomap_page_mkwrite() to implement the mmap iomap path
for ext4. The heavy lifting is delegated to iomap_page_mkwrite(), which
only requires ext4_iomap_buffered_write_ops and
ext4_iomap_buffered_da_write_ops to allocate and map blocks.
Note that the lock ordering between folio lock and transaction start in
this path is reversed compared to the buffer_head buffered write path.
The lock ordering documentation in super.c has been updated accordingly.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-17-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Add the iomap writeback path for ext4 buffered I/O. This introduces:
- ext4_iomap_writepages(): the main writeback entry point.
- ext4_writeback_ops: a new iomap_writeback_ops instance to handle
block mapping and I/O submission.
- A new end I/O work handler ext4_iomap_finish_ioend() is added for
converting unwritten extents, updating file size, and handling
DATA_ERR_ABORT after I/O completion.
Core implementation details:
- ->writeback_range() callback
Calls ext4_iomap_map_writeback_range() to map and allocate blocks
using the enhanced ext4_map_blocks(). ext4_map_blocks() now starts
its own transaction internally when it needs to allocate blocks.
For performance, when a block range is not yet allocated, it
allocates based on the writeback length and delalloc extent length
(ext4_map_blocks() will trim the allocated length), rather than
allocating a single folio at a time. The folio is then added to
an iomap_ioend instance.
- ->writeback_submit() callback
Registers ext4_iomap_end_bio() as the end bio callback. This callback
schedules a worker to handle:
- Unwritten extent conversion.
- i_disksize update after data is written back.
- Journal abort on writeback I/O failure.
- The new end I/O work handler ext4_iomap_finish_ioend()
This reuses i_rsv_conversion_work and i_rsv_conversion_list, which
are now used in the buffer_head writeback path for memory saving,
because an inode can never go through both buffer_head and iomap
paths. Those are not initialized in this patch but will be when the
iomap path is formally enabled later.
Key changes and considerations:
- Append write and unwritten extents
Since data=ordered mode is not used to prevent stale data exposure
during append writebacks, new blocks are always allocated as
unwritten extents (i.e. always enable dioread_nolock), and i_disksize
update is postponed until I/O completion. Additionally, the deadlock
that the reserve handle was expected to resolve does not occur
anymore. Therefore, the end I/O worker can start a normal journal
handle instead of a reserve handle when converting unwritten extents.
- Lock ordering
The ->writeback_range() callback runs under the folio lock, requiring
the journal handle to be started under that same lock. This reverses
the order compared to the buffer_head writeback path. The lock
ordering documentation in super.c has been updated accordingly.
- Don't cache writes
The iomap infrastructure sets the BIO_COMPLETE_IN_TASK flag when
submitting I/O, so the ioend will be processed in task context.
However, if a private defer worker is to be started, this flag must
be cleared explicitly to avoid double deferral. In the future, all
private defer work should be moved to the generic bio complete in
task framework.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-16-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
While converting the buffered I/O path to iomap, we noticed that the
writeback completion can hand over an ioend which was merged across an
arbitrary number of extents because iomap_ioend_try_merge() doesn't
limit the length of the merged ioends, while
ext4_convert_unwritten_extents() converts all of them with the handle
provided by the caller, and callers calculate the credits of that handle
without knowing the exact number of extents. Converting more extents
than that within one transaction can exhaust its credits.
Prepare for the iomap path nevertheless by making the conversion loop
check the remaining credits before each extent with
ext4_journal_ensure_credits(), so that the transaction is extended, or
restarted once it is full, as needed. Also estimate the credits with
ext4_meta_trans_blocks(..., alloc_extents = 0), since no data blocks are
allocated here, and manage an internally started transaction as a whole
instead of starting and stopping one for each extent.
The buffer_head writeback path is safe, as it passes a handle whose
credits are reserved by ext4_meta_trans_blocks(inode, bpf, bpf, 0),
which is enough to convert one extent per block of a folio, so the
reservation is sufficient and the handle is never restarted there.
This also helps the fallocate path, where ext4_alloc_file_blocks() sizes
the handle for the conversion with ext4_chunk_trans_blocks() as well,
i.e. for a single extent only, while a concurrent modification of the
extent tree can make the conversion cover more extents than the handle
has credits for.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-15-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Introduce two new iomap_ops instances for ext4 buffered writes:
- ext4_iomap_buffered_da_write_ops: for delayed allocation mode, using
ext4_da_map_blocks() to map delalloc extents.
- ext4_iomap_buffered_write_ops: for non-delayed allocation mode, using
ext4_map_blocks() to directly allocate blocks.
Also add ext4_iomap_valid() for the iomap infrastructure to check extent
validity. This is useful for the iomap buffered write path because it
does not hold the folio lock between mapping the inode extent and
copying data. So it can race with writeback, which may modify or stale
the extent type.
Key changes and considerations:
- Unwritten extents for new blocks (dioread_nolock always on)
Since data=ordered mode is not used to prevent stale data exposure in
the non-delayed allocation path, new blocks are always allocated as
unwritten extents.
- Short write and write failure handling
a. Delalloc path: On short write or failure, the stale delalloc range
must be dropped and its space reservation released. Otherwise, a
clean folio may cover leftover delalloc extents, causing
inaccurate space reservation accounting.
b. Non-delalloc path: No cleanup of allocated blocks is needed on
short write since leaving the preallocated blocks behind doesn't
cause any real issue. These blocks are visible to users and are
not permanently leaked.
- Adjust the call frequency of ext4_nonda_switch() so that it is no
longer called once per folio in the buffer_head path, but instead
once per write. For code simplicity, ext4_iomap_buffered_da_write_ops
will be shared with the later page-fault path. Since
ext4_nonda_switch() -> try_to_writeback_inodes_sb() synchronously
waits for writeback, which could lead to deadlock under the same
folio lock acquired by iomap_page_mkwrite(), we can no longer call
ext4_nonda_switch() inside ext4_iomap_buffered_da_write_ops. This may
increase the probability of a writeback-time allocation failure, but
the expected real-world impact is small, so it can be implemented
this way for now.
- Lock ordering reversal
The folio lock and transaction start ordering is reversed compared to
the buffer_head buffered write path. To handle this, the journal
handle must be stopped in iomap_begin() callbacks. The lock ordering
documentation in super.c has been updated accordingly.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-14-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
The data=ordered mode introduces two fundamental conflicts with the
iomap buffered write path, leading to potential deadlocks.
1) Lock ordering conflict
In the iomap writeback path, each folio is processed sequentially:
the folio lock is acquired first, followed by starting a transaction
to create block mappings.
In data=ordered mode, writeback triggered by the journal commit
process may attempt to acquire a folio lock that is already held by
iomap background writeback process. Meanwhile, iomap, under that same
folio lock, may start a new transaction to map other blocks on this
folio and wait for the currently committing transaction to finish,
resulting in a deadlock.
Trans N commit background writeback(via iomap)
journal_submit_data_buffers()
ext4_journal_submit_inode_data_buffers()
iomap_writepages()
iomap_writepages()
folio_lock()
folio_lock() -- wait
iomap_writeback_folio()
iomap_writeback_range()
ext4_journal_start()
start new transaction
-- wait for trans N commit,
DEADLOCK
ext4_map_blocks()
Currently, in the buffer_head writeback path, this is handled by
starting the transaction before taking any folio locks for writeback.
2) Partial folio submission not supported
When block size < folio size, a folio may contain both mapped and
unmapped blocks. In data=ordered mode, a deadlock can occur if the
journal waits (pure JI_WAIT_DATA) for such a folio to be written back
while background writeback has already started on it (with the
writeback flag set). The problem is that mapping the remaining
delalloc blocks can deadlock because the writeback flag is not
cleared until the entire folio is processed and committed.
T0: Assume we have a folio contains four blocks, from front to back,
they are A, B, C, D. The block B and C are holes, and the last
block D is written in delalloc mode (the block is not allocated
yet).
T1: The background writeback process starts to write back data, set
writeback flag on the folio, allocates block D, and adds it to
transaction N's order list of jbd2 in pure JI_WAIT_DATA mode.
T2: This folio completes the writeback and clears the writeback flag.
T3: Before transaction N commit, we buffered write block A to C.
T4: Transaction N commit and folio writeback are running
concurrently.
Trans N commit background writeback(via iomap)
iomap_writeback_folio()
folio_start_writeback()
-- set writeback flag
jbd2_journal_finish_inode_data_buffers()
__filemap_fdatawait_range()
-- wait writeback flag to clear
iomap_writeback_range()
ext4_journal_start()
start new transaction
-- wait for trans N commit,
DEADLOCK
ext4_map_block() (B, C)
Currently, in the buffer_head writeback path, this is handled by:
1. Partial folio submission — already-allocated buffers can be
submitted first. The writeback flag is cleared after I/O
completes, preventing block allocation while the writeback flag is
set.
2. Allocation order — the transaction is started first, then blocks
are allocated, the writeback flag is set, and finally the
allocated buffers submission begins.
To support data=ordered mode, the iomap core would need two invasive
changes:
- Acquire the transaction handle before locking any folio for
writeback.
- Support partial folio submission.
Both changes are complicated and risk performance regressions.
Therefore, we must avoid using data=ordered mode when converting to the
iomap path.
Currently, data=ordered mode is used in three scenarios:
- Append write
- Post-EOF partial block truncate-up followed by append write
- Online defragmentation
We can address the first two without data=ordered mode:
- For append write: always allocate unwritten blocks (i.e. always
enable dioread_nolock), preserving the behavior of current
extent-type inodes.
- For post-EOF truncate-up + append write: postpone updating i_disksize
until after the zeroed partial block has been written back.
Online defragmentation does not yet support iomap; this can be resolved
separately in the future.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-13-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
The iomap buffered write path does not hold the folio lock between
mapping the inode extent and copying data. Therefore, it can race
with writeback that modifies the extent type (e.g., from unwritten to
written). This can lead to data corruption on partial writes, as
iomap_block_needs_zeroing() may return a false positive based on a
stale extent. The iomap infrastructure uses the sequence counter
stored in the inode to detect such stale mappings.
Commit 07c440e8da8f ("ext4: pass out extent seq counter when mapping
blocks") added the m_seq field to ext4_map_blocks to pass out extent
sequence numbers, but it missed two callsites within
ext4_da_map_blocks(). These callsites are on the delayed allocation
path, which is needed in the iomap buffered write path. Pass out the
sequence counter to ensure stale mappings can be detected.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-12-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Implement the iomap read path for ext4 by introducing a new
ext4_iomap_buffered_read_ops instance. This provides the read_folio()
and readahead() callbacks for ext4_iomap_aops. The implementation
introduces:
- ext4_iomap_map_blocks(): Helper function to query extent mappings for
a given read range using ext4_map_blocks() and convert the mapping
information to iomap type
- ext4_iomap_buffered_read_begin(): The iomap_begin callbacks that maps
blocks, validates filesystem state, and populates the iomap. It
returns -ERANGE for inline data which is not yet supported.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-11-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Introduce initial support for iomap in the buffered I/O path for regular
files on ext4.
- Add a new inode state flag EXT4_STATE_BUFFERED_IOMAP to indicate the
inode uses iomap instead of buffer_head for buffered I/O
- Add helper ext4_inode_buffered_iomap() to check the flag
- Add new address space operations ext4_iomap_aops with callbacks that
will use generic iomap implementations
- Add ext4_iomap_aops to ext4_set_aops() when the flag is set
The following callbacks(read_folio(), readahead(), writepages()) are
provided as placeholders and will be implemented in later patches.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-10-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
When ext4_map_blocks() is called from the data submission path and I/O
end extent conversion path (EXT4_GET_BLOCKS_IO_SUBMIT), it should not
allocate blocks if the lookup returns a hole.
The writeback path can legitimately encounter dirty ranges that map to
holes. For example, when a folio straddles i_size and the tail beyond
i_size is dirtied via a mmap write. Allocating blocks for such ranges is
wrong because there is no data to write back, the dirty bits should
simply be discarded without submitting I/O.
This prepares for the buffered iomap writeback conversion, mirrors the
existing buffer_head writeback path, where mpage_add_bh_to_extent() skip
unmapped buffers and ext4_bio_write_folio() clears their dirty bits.
Since ext4_map_blocks() can now return zero for a hole,
mpage_map_one_extent() must handle it as well. However, because those
holes are already filtered out by mpage_add_bh_to_extent(), it only maps
buffers that are delayed or unwritten, so a hole can never occur in
normal operation. Add a WARN_ON_ONCE() and bail out with -EINVAL rather
than proceeding with an invalid physical block number of zero.
In the ioend extent conversion path, holes are also not expected because
we should wait for folio writeback before punching hole. If one is
encountered, it likely indicates a failure in the concurrency
protection, so ext4_map_blocks() returns zero, and we keep warning and
bail out with -EINVAL to surface the failure rather than continuing
conversion on torn data. Atomic writes in
ext4_convert_unwritten_extents_atomic() already bail out similarly.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-9-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
When ext4_map_blocks() finds an unwritten extent in the extent cache and
the caller is willing to accept unwritten extents without conversion,
there is no need to start a journal transaction since no metadata update
is required. This avoids unnecessary transaction overhead in the
upcoming iomap writeback path when overwriting already-allocated
unwritten extents.
One thing to be careful about, as the comment in ext4_map_blocks()
states, if the flags contain EXT4_GET_BLOCKS_CREATE, the function will
mark @map as mapped.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-8-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Make ext4_map_blocks() start its own transaction handle when the caller
does not provide one. The handle is started after the lookup path
confirms that allocation is actually needed, and is stopped at the
unified out exit path. This avoids unnecessarily starting a handle for
pure mapping queries. This prepares for the buffered iomap writeback
conversion, which improves performance for fragile overwrite cases.
Suggested-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/linux-ext4/i536qqwj5eyulec3r2ki2ycnelqdd4bkpat2drn7t72t6p622k@ktueynysgo3j/
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-7-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Save orig_mlen after clamping map->m_len to INT_MAX. Otherwise, the
unclamped value may be passed below, bypassing its overflow protection.
Fixes: 5bb12b1837c0 ("ext4: Add support for EXT4_GET_BLOCKS_QUERY_LEAF_BLOCKS")
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-6-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
After acquiring i_data_sem in write mode, recheck that the mapping
found via the extent status tree or disk query has not changed. A
racing truncate may have trimmed the extent between the earlier lookup
and the write lock acquisition, since writeback does not hold i_rwsem
or the folio locks covering the full extent. This could cause
ext4_map_create_blocks() to allocate blocks beyond the truncated range,
potentially leading to quota leaks in the upcomming iomap buffered
writeback path, because the iomap writeback infrastructure caches
extents beyond the folio range.
Therefore, if we find a valid extent and the sequence number has
changed, retry the entire lookup to obtain the correct trimmed mapping.
Note that a retry only happens when i_es_seq has actually changed, which
requires another thread to hold i_data_sem in write mode, so each retry
implies real lock contention, and the writer yields on the rwsem
slowpath rather than spinning. Moreover, the read-write lock also tries
its best to guarantee fairness, so even though no retry limit is added
here, livelock should not occur in theory. Also, the retry here mirrors
the existing write_ops->iomap_valid() + IOMAP_F_STALE mechanism in
iomap, which also rechecks the sequence number and retries without any
upper bound, and has not shown livelock problems in practice.
In addition, if ext4_map_query_blocks() fails, return the error
immediately. Otherwise the following sequence number comparison would
use a map->m_seq that may not have been updated, and silently
continuing on an error is not advisable.
Suggested-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/linux-ext4/b0781809-4759-4e12-be17-71555b764f48@gmail.com/
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-5-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Set EXT4_MAP_NEW in ext4_da_map_blocks() to properly indicate that a
new delayed allocation block has been inserted, allowing callers to
distinguish newly created delayed extents from existing ones.
Currently, the buffer_head caller, ext4_da_get_block_prep(), does not
consume this flag. It intercepts EXT4_MAP_DELAYED and returns early, and
unconditionally calls set_buffer_new(bh) so EXT4_MAP_NEW is not used.
The flag is prepared for the iomap buffered I/O path added later.
Reported-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://lore.kernel.org/linux-ext4/cc05c17d-163e-4251-b2c9-aa3a6f9555d7@huaweicloud.com/
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-4-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Refactor ext4_setattr() by introducing two helper functions,
ext4_truncate_up() and ext4_truncate_down(), to handle size changes. The
current ATTR_SIZE processing consolidates checks for both shrinking and
non-shrinking cases, leading to cluttered code. Separating the
truncation paths improves readability.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-3-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
The logic for updating the file size in ext4_setattr() is currently
somewhat messy. By directly entering the error-handling path after
failing to add an orphan inode, the unnecessary recovery process
involving old_disksize and the file size can be avoided.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-2-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel into soc/dt
Renesas DTS updates for v7.4 (take two)
- Add PCIe support for the RZ/G3L SoC,
- Add ADC DMA support for the RZ/T2H and RZ/N2H SoCs,
- Add initial support for the RZ/G2M v3.0 SoC and the HopeRun HiHope
RZ/G2M v3.0 board stack,
- Add USB support for the RZ/G3E SoC and the RZ/G3E SMARC EVK board,
- Add SPI (MSIOF) and I2C support for the R-Car X5H SoC,
- Add support for various SolidRun boards based on RZ/G2L, RZ/G2LC,
RZ/V2L, and RZ/G2UL,
- Miscellaneous fixes and improvements.
* tag 'renesas-dts-for-v7.4-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel: (34 commits)
arm64: dts: renesas: Add support for solidrun rzg2ul som on hb-ripple
arm64: dts: renesas: Add support for solidrun hb-ripple with rzg2lc som
arm64: dts: renesas: Add support for solidrun hb-ripple with rzv2l som
arm64: dts: renesas: Add support for solidrun hb-ripple with rzg2l som
arm64: dts: renesas: rzg2l(c)/rzv2l hb-iiot: Add dsi panel dt overlay
arm64: dts: renesas: Add support for solidrun rzg2lc som and hb-iiot evb
arm64: dts: renesas: Add support for solidrun rzv2l som and hb-iiot evb
arm64: dts: renesas: Add support for solidrun rzg2l som and hb-iiot evb
dt-bindings: soc: renesas: Add various SolidRun RZ/G2 based boards
arm64: dts: renesas: r8a779h0: Add PCIe Application/Local register reset
arm64: dts: renesas: r8a779g0: Add PCIe Application/Local register reset
arm64: dts: renesas: r8a779f0: Add PCIe Application/Local register reset
arm64: dts: renesas: r8a78000: Add I2C nodes
arm64: dts: renesas: r8a78000: Add MSIOF nodes
dt-bindings: clock: renesas,r8a78000-cpg: Add MSIOF clocks
arm64: dts: renesas: r9a09g047e57-smarc: Enable USB2.0 support
arm64: dts: renesas: r9a09g047: Add USB2.0 support
arm64: dts: renesas: r9a08g046: Add USB2.0 placeholder nodes
arm64: dts: renesas: Add HiHope RZ/G2M v3.0 SoC sub board support
arm64: dts: renesas: Add HiHope RZ/G2M v3.0 SoC main board support
...
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
|
Four of the MT6397 RTC's alarm registers use only their low bits; the
high byte of each is storage the clock and the alarm don't touch.
MediaTek's documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and
assigns the first to a fuel gauge, which is what a battery driver reads
at boot so that the reported capacity does not jump across a reboot.
They sit in the RTC's always-on domain, so the driver can offer them as
a battery-backed nvmem provider. Allow a board to lay cells out over
them.
Assisted-by: LLM
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://patch.msgid.link/20260917-rbrue-suez-upstreaming-mt6397-rtc-nvmem-v1-1-558b8f95cfbc@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>
|
|
thermal/fan quirk tables"
This reverts commit bb0f3a5d6b9844b70ad696b9470762028f6d86ec.
Lenovo's firmware team has verified that the X9-14 Gen 1 uses EC
register offsets that are unique to this platform, rather than the
shared non-standard ECFW layout of the models already covered by the
quirk tables. Applying the generic quirk would make the driver read
the wrong registers and report bogus temperatures. Lenovo is working
on the correct solution based on an updated EC register specification.
Link: https://lore.kernel.org/all/000acb24-7aef-4718-89ea-0dffd1ab34d9@app.fastmail.com/
Signed-off-by: Huang Wei <huangwei@kylinos.cn>
Link: https://patch.msgid.link/20261013070740.789934-1-huangwei@kylinos.cn
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
Merge series from Vijendar Mukunda <Vijendar.Mukunda@amd.com>:
A couple of additional fixups for the earlier series adding ACP7.B
support and ASP carveout firmware loading.
|
|
Add EC firmware version 1571EMS1.106 (MSI Creator Z16 A11UE) to the
list of firmwares handled by CONF14. The EC register layout matches
CONF14 field for field (verified against the out-of-tree msi-ec
configuration for this firmware, where it is part of CONF_G2_10).
Tested on a Creator Z16 A11UE with this driver built against
7.2.9: the module loads, charge_control_start_threshold and
charge_control_end_threshold read the values set by the EC, and
writing charge_control_end_threshold is applied and reads back.
Assisted-by: LLM
Signed-off-by: Alexey Subbota <subbota-job@yandex.ru>
Link: https://patch.msgid.link/20261013212228.17349-1-subbota-job@yandex.ru
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
BO_MMAP_OFFSET ioctl
This commit removes the call to drm_gem_create_mmap_offset() from
the BO_MMAP_OFFSET ioctl handler. The call was redundant and didn't
have any effect as file offset range is allocated unconditionally
at the BO creation time.
v2:
- New patch
Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Akash Goel <akash.goel@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Link: https://patch.msgid.link/20261013125433.26432-2-akash.goel@arm.com
|
|
The BOs created with DRM_PANTHOR_BO_NO_MMAP flag are not supposed to be
mmappable by the Userspace. But after the rework to support shrinker,
it became possible to mmap NO_MMAP BOs. Userspace could second guess
the file offset range, allocated unconditionally at the BO creation
time, and create a CPU mapping. There may not be any adverse effect of
such a CPU mapping though.
This commit adds a check in the mmap callback of Panthor driver to
fail the mmap() attempts on BOs created with NO_MMAP flag. The check
covers private BOs as well as the prime exported BOs that are mmapped
using prime fd.
v2:
- Fix breakage of mmap() on exported BOs that didn't have
BO_MMAP_OFFSET ioctl invoked for them.
Fixes: 68cbf96b1e9b ("drm/panthor: Part ways with drm_gem_shmem_object")
Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Akash Goel <akash.goel@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Link: https://patch.msgid.link/20261013125433.26432-1-akash.goel@arm.com
|
|
This turns down to cause up to 15% performance regressions on standard
large transfer workloads. Revert it and hope the IOVA allocator can
eventually be fixed to remove the need for the original workaround.
This reverts commit 3710e2b056cb92ad816e4d79fa54a6a5b6ad8cbd.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Joe Damato says:
====================
bnxt_en: Fix SW USO padding
As a followup to Eric's fix a51d233ccd48 ("bnxt_en: fix DMA mapping length
for padded small packets") which fixes padding for normal TX, this series
fixes padding for SW USO.
There are two cases I try to address:
1. The last segment could be shorter than BNXT_MIN_PKT_SIZE. So, add an
extra BD if needed to pad to that minimum.
2. The gso_size is so small that every segment would be shorter than
BNXT_MIN_PKT_SIZE (under 10 bytes with IPv4). This seems exceedingly
unlikely, but just in case, it is handled by clearing the GSO features
for these skbs so the stack segments them.
Patch 1 is a small refactor to move code into a helper that patch 2 uses to
avoid duplicating code.
I ran v1 on a bnxt machine and re-ran the uso.py test and it passed, but
the existing uso.py test doesn't test this specific case, so running the
test was more of a regression test. There were no functional changes to
v2.
Note that I did not see this issue in production and it should not be
possible for QUIC to hit this case on either ipv4 or ipv6 because QUIC
packets are at least 21 bytes. AFAIU, only ipv4 segments with less than 10
bytes of UDP payload can trigger this. As such, I was asked to send this
to net-next.
v1: https://lore.kernel.org/netdev/20261008191114.3736826-1-joe@dama.to/
====================
Link: https://patch.msgid.link/20261009215426.2377946-1-joe@dama.to
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
|
Each SW USO segment is hdr_len + seg_payload bytes. With IPv4, hdr_len
is 42 bytes, so a segment carrying less than 10 bytes of UDP payload is
sent shorter than BNXT_MIN_PKT_SIZE. This happens with a short last
segment (e.g. gso_size 1400 and 1405 bytes of payload) or with a
gso_size below 10 bytes.
Fix the short last segment in bnxt_sw_udp_gso_xmit(): zero the pad
bytes after the header in the segment's inline header slot and add a
pad BD pointing at them after the payload BDs. Only the last segment
can need padding, and its pad BD fits within the existing bound in
bds_needed and BNXT_SW_USO_MAX_DESCS, since payload BDs are at most
num_segs + nr_frags.
If gso_size itself is too small, every segment would need a pad BD,
exceeding the descriptor bound. This case is unlikely, so
bnxt_features_check() clears GSO features for these skbs and the stack
segments them instead; bnxt_start_xmit() then pads each segment.
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20261009215426.2377946-3-joe@dama.to
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
|
Move the code that fills a payload BD and its software ring entry in
bnxt_sw_udp_gso_xmit() into a helper, bnxt_sw_gso_data_bd().
No functional change. A following patch uses the helper to add a pad BD
to short SW USO segments.
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20261009215426.2377946-2-joe@dama.to
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
|
npcm_fiu_uma_read() and npcm_fiu_uma_write() use a 16-byte on-stack
staging buffer (u32 data_reg[4]) and move data_size bytes to or from
it. data_size comes straight from op->data.nbytes, which is supplied
by the SPI MEM operation and is not bounded by the driver:
npcm_fiu_exec_op() only validates op->addr.nbytes, and no
adjust_op_size callback truncates the transfer to the controller FIFO
size.
A SPI MEM operation with addr.nbytes == 0 and data.nbytes > 16
therefore overflows data_reg[] on the kernel stack (write path) or
reads past it (read path), corrupting the stack.
Reject data_size larger than the staging buffer in both UMA helpers
by returning -EOPNOTSUPP, so spi_mem falls back to the generic SPI
message path. The chunked path in npcm_fiu_manualwrite() always passes
at most CHUNK_SIZE bytes, so it is unaffected.
Fixes: ace55c411b11 ("spi: npcm-fiu: add NPCM FIU controller driver")
Cc: stable@vger.kernel.org # 5.4+
Reviewed-by: Guanglei Zhu <zhugl3@xiaopeng.com>
Signed-off-by: Weibin Liu <liuwb@xiaopeng.com>
Link: https://patch.msgid.link/20261015-npcm-fiu-uma-datasize-v1-1-7dee91cadee6@xiaopeng.com
Signed-off-by: Mark Brown <broonie@kernel.org>
|
|
wr_opcode_mask() indexes the global rxe_wr_opcode_info[] array with
a caller-supplied opcode and no bounds check. For a user QP the WQE
comes from an mmap'd SQ ring, so wqe->wr.opcode is an
attacker-controlled __u32 read back by the requester
(req_next_wqe() -> rxe_requester()); rxe_post_send() takes the
qp->is_user branch and never runs validate_send_wr(), whose only
opcode check is itself !wr_opcode_mask() (it indexes before it
checks). rxe_wr_opcode_info[] has entries only up to IB_WR_REG_MR,
so an out-of-range opcode reads out of bounds and the result is used
as a mask and dereferenced; observed as a KASAN global-out-of-bounds
"Read of size 4" and a wild-pointer oops.
Return a zero mask for an out-of-range opcode, matching how
validate_send_wr() already treats a zero mask (an invalid WR), so no
path indexes the array out of bounds.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Youngsung Ahn <ays511.kr@gmail.com>
Link: https://patch.msgid.link/20261002164552.294749-1-ays511.kr@gmail.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
2GiB size
When RDMA READ request for 2GiB in single WR, res->read.resid is u32
0x80000000, which is INT_MIN (-2147483648).
payload = min_t(int, res->read.resid, mtu);
The `min_t` function will return -2147483648 for payload. The wrong
size is propagated through call chain, `read_reply` -> `prepare_ack_packet`
-> `rxe_init_packet` -> `alloc_skb` . `alloc_skb` failed because of
invalid size. The passive side failed to emit response packet for RDMA
READ request.
After fixed it, the active side of RDMA READ failed with error code
"IB_WC_LOC_PROT_ERR". When RDMA_READ_RESPONSE_FIRST packet recived by
the active side, `do_read` call `copy_data`. dma->resid is u32 0x80000000.
int resid = dma->resid;
This conversion set resid to -2147483648. `copy_data` abort as length
greater than resid.
RDMA SEND and WRITE 2GiB message works too, after fixed these two bugs.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Honggang LI <honggangli@163.com>
Link: https://patch.msgid.link/20261002142250.657151-1-honggangli@163.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
inline_data[]
For a user QP, rxe_post_send() takes the qp->is_user branch and
never runs init_send_wqe(), so
dma.length/resid/num_sge/cur_sge/sge_offset all come straight from
the mmap'd SQ ring. In the inline send path finish_packet() uses
sge_offset directly as an index:
u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset];
memcpy(payload_addr(pkt), tmp, payload);
inline_data is a flex array whose capacity is qp->sq.max_inline, but
sge_offset is a u32 from user space, so the source pointer is
displaced arbitrarily past the WQE and the memcpy reads out of
bounds.
commit 126c757e4cd4 ("RDMA/rxe: Validate num_sge/cur_sge before indexing wqe->dma.sge[]")
added num_sge/cur_sge checks on the send path but not sge_offset, the
third attacker-controlled index in the same struct.
Read sge_offset once with READ_ONCE() and bound it (and the payload
that follows it) by qp->sq.max_inline before indexing, so the value
that is validated is the value that is used.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Youngsung Ahn <ays511.kr@gmail.com>
Link: https://patch.msgid.link/20261001152433.3259573-1-ays511.kr@gmail.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
An ODP MR has a page array, map.pfn_list[]. Its size is computed from
the umem start address. But rxe_check_pagefault() builds the index into
that array from an iova that is relative to the same start, while the
access itself was range-checked against the MR's iova (ibmr.iova).
Those two bases do not have to match. reg_mr only requires that start
and hca_va have the same page offset, so a user can register an MR with
hca_va = start + N*PAGE. The difference then becomes an index skew of
(hca_va - start) >> PAGE_SHIFT. Nothing compares the result with the
size of pfn_list[], so the read goes past the end of the array.
An unprivileged local user can reach this with a single RDMA operation
on a self-connected rxe QP. KASAN reports a slab-out-of-bounds read. If
the out-of-bounds qword happens to look like a writable HMM pfn, rxe
then copies the payload into a page the user never registered.
Reject an index that falls outside the umem and take the fault path
instead. That path rejects the out-of-range access in
ib_umem_odp_map_dma_and_lock(), which does check the umem range. The
other users of pfn_list[], __rxe_odp_mr_copy() and the atomic helpers,
run only after a successful map, so this single check covers them too.
Fixes: 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP")
Signed-off-by: Youngsung Ahn <ays511.kr@gmail.com>
Link: https://patch.msgid.link/20261004153246.2951263-1-ays511.kr@gmail.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
IB_WR_REG_MR is documented as kernel-only ("can not be issued by
userspace"), but nothing enforces it.
rxe_wr_opcode_info[IB_WR_REG_MR] sets WR_LOCAL_OP_MASK for IB_QPT_RC,
a QP type userspace can create, so a user QP that writes
opcode = IB_WR_REG_MR into its mmap'd SQ ring reaches
rxe_do_local_ops() -> rxe_reg_fast_mr(). That function then trusts
the ring-supplied fields:
struct rxe_mr *mr = to_rmr(wqe->wr.wr.reg.mr);
...
if (unlikely(mr->state != RXE_MR_STATE_FREE)) /* deref */
...
mr->access = access; /* write */
For a user QP wqe->wr.wr.reg.mr is a fully attacker-chosen pointer,
so this is an arbitrary-kernel-address dereference (arbitrary read
confirmed, oops). No existing check distinguishes a user QP on this
path.
Reject IB_WR_REG_MR for user QPs before dereferencing the supplied
pointer.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Youngsung Ahn <ays511.kr@gmail.com>
Link: https://patch.msgid.link/20261001152426.3259522-1-ays511.kr@gmail.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
Add a schema for hisilicon,hisi-localbus which is already in use for a
long time.
Link: https://patch.msgid.link/20261005205310.2079198-1-robh@kernel.org
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
|
|
Binding a type 2 memory window takes a reference on the QP:
rxe_do_bind_mw() does rxe_get(qp) and stores it in mw->qp. That
reference is released only when the window is invalidated
(rxe_do_invalidate_mw() on IB_WR_LOCAL_INV) or the window itself is
destroyed (rxe_mw_cleanup()).
rxe_qp_chk_destroy() does not account for those references -- it only
refuses when qp->mcg_num is non-zero. So an unprivileged user can bind
a type 2 MW to a QP and then destroy the QP while the binding is still
live. __rxe_cleanup() cannot drop the QP refcount to zero (the MW still
holds a reference), hits its -ETIMEDOUT path, and frees the QP anyway;
mw->qp is left dangling. When the MW is later invalidated or
deallocated, rxe_mw_cleanup()/rxe_do_invalidate_mw() do rxe_put(mw->qp)
on the freed struct rxe_qp -- a use-after-free write (refcount_dec, and
complete()/list work if it reaches zero) reachable from userspace.
IB_WR_BIND_MW is a local operation, so no peer is required.
Track the number of type 2 MWs bound to a QP and refuse to destroy the
QP while that count is non-zero, returning -EBUSY exactly as the
existing multicast-attachment check does. The window must be
invalidated or deallocated, which drops the reference and the count,
before the QP can be destroyed.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Youngsung Ahn <ays511.kr@gmail.com>
Link: https://patch.msgid.link/20260930182223.2511145-1-ays511.kr@gmail.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
|
|
Add compatible strings for the IMG GPUs in SpacemiT K1 and K3 SoCs:
- K1: IMG BXE-2-32 (adds a dedicated entry for a single core
clock and power domain).
- K3: IMG BXM-4-64 (shares the same configuration and entry as
the T-Head TH1520).
Signed-off-by: Baihui Liang <liangbaihui@linux.spacemit.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Link: https://patch.msgid.link/20261015-spacemit-gpu-binding-v1-1-a7a23c7e7788@linux.spacemit.com
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
|
|
The comment explaining the error policy of tpmi_create_devices() sits
inside the loop, between the call and the check it describes. Move it
above the function, where it describes the policy as a whole.
Also split the check into its two cases, skipping unsupported features
and failing on any other error, so that each reads on its own.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-21-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
Declare the loop counters in the for statements that use them, so that
they are scoped to their loops.
In tpmi_create_device() this also replaces the tmp cursor, which moved
in step with the counter, with res[i].
While at it, use post-increment in all of them, as the other loops in
the file already do.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-20-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
tpmi_create_device() fills in each feature resource field by field,
deriving the end from the start and setting IORESOURCE_MEM by hand.
That is what DEFINE_RES_MEM() exists for, so use it.
The resources come from kzalloc_flex(), so the fields the macro sets
that the open coded version left alone, name and desc, were already
zero.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-19-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
The kernel has both snprintf() and scnprintf() for formatting into a
fixed size buffer. The preference is to settle on scnprintf() and stop
adding snprintf() users, so that only one of the two remains in use.
Convert the two callers in tpmi_dbgfs_register(). Neither of them looks
at the return value, so the difference in what the two functions return
does not matter here.
No functional change intended.
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-18-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
The mem_write debugfs file open handler and file_operations are written
out by hand, which is what DEFINE_SHOW_STORE_ATTRIBUTE() exists for. Use
it, and rename the write callback to mem_write_write() to match the name
the macro derives.
The other two files in this driver already come from
DEFINE_SHOW_ATTRIBUTE(), so this also gives mem_write the
.owner = THIS_MODULE that the open coded file_operations was missing.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-17-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
Both mailbox words in tpmi_read_feature_status() are assembled as an
assignment followed by an or-assign of a second field, even though
neither value is used in between. Build each of them in a single
expression, so that a word and the fields it is made of read as one
thing.
The two comments on the command word described one value between them, so
fold them together as well.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-16-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
tpmi_mem_dump_show() frees its dump buffer and drops tpmi_dev_lock by
hand at the end of the function, so the ioremap() failure in the middle
of the loop cannot just return. It breaks out with an error stashed in
ret, which is the only reason ret exists.
Attach the buffer to __free(kfree) at its allocation and take the mutex
with guard(), then return the error directly from the loop. mem_write()
in this file already does both, so this makes the two debugfs paths
consistent.
No functional change intended.
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-15-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
tpmi_read_feature_status() takes tpmi_dev_lock explicitly and unwinds
through an err_unlock label, which is what forced the two error paths
before the mailbox command is issued to be gotos rather than returns.
Take the mutex with guard() and return directly from those two paths.
The done_proc label stays, because the paths that reach it have already
handed the mailbox to the hardware and still owe it the CPL write before
dropping the lock. That is unchanged: the two early failures never wrote
CPL before either.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-14-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
The macro computing a feature instance size has a few problems. Its
comment says the hardware reports the size in u32 units, but the
conversion to bytes is spelled as a shift by 2, so the comment and the
code have to be read together to see that they agree. Its body is a
single conditional expression wrapped in a statement expression that it
never needed. And it evaluates its argument twice.
Make it a plain static function, tpmi_get_single_entry_size(), which
fixes all three: the conversion becomes a multiply by sizeof(u32), there
is nothing left to wrap, and the argument is evaluated once and type
checked.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-13-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
tpmi_common.c uses a number of interfaces whose headers it never includes
directly and only gets by chance through other headers:
BIT_ULL(), GENMASK_ULL() bits.h
__packed compiler_attributes.h
EXPORT_SYMBOL_NS_GPL() export.h
DEFINE_IDA() idr.h
IORESOURCE_MEM ioport.h
DEFINE_MUTEX(), mutex_lock() mutex.h
seq_printf(), seq_hex_dump() seq_file.h
kmalloc(), kzalloc_flex() slab.h
USEC_PER_MSEC, USEC_PER_SEC time64.h
uXX types.h
Include them, so that the file does not break when an unrelated header
stops pulling them in.
Drop io.h while at it, as iopoll.h already includes it, and sort the
block alphabetically: debugfs.h and cleanup.h were the wrong way round.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-12-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
Everything the TPMI driver does once the PFS table has been located is
independent of how the TPMI MMIO region was discovered, from walking the
PFS to creating the per feature devices. Only the entry point is VSEC
specific and it is now reduced to filling in the arguments of
intel_tpmi_init().
Move the enumeration independent code to a new intel-tpmi_common module
and leave the auxiliary driver binding to the "intel_vsec.tpmi" device
created by the Intel VSEC driver in vsec_tpmi.c. The code is moved as
is, apart from a stray blank line and a typo in a comment that are fixed
in passing.
tpmi_common.h exposes what an enumeration method needs, which is
intel_tpmi_init(), intel_tpmi_deinit() and struct intel_tpmi_info. The
structure is a complete type because the enumeration method allocates it
and is expected to extend it with its own data. The PFS, TPMI_INFO and
feature state layouts stay private to tpmi_common.c, only the hardware
parsing touches them.
CONFIG_INTEL_TPMI_COMMON is a hidden symbol selected by the enumeration
method, in the same way as CONFIG_INTEL_TPMI_POWER_DOMAINS. The TPMI
client API is now exported by intel-tpmi_common, so the client drivers
depend on that module instead of intel-vsec_tpmi. That is what allows a
second, non PCI enumeration method to be added later without the client
drivers knowing which one is loaded.
No functional change.
Co-developed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-11-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
|
Once the two devices and the MMIO resources are known, the rest of what
the init path does is independent of how the TPMI instance was found.
Turn that part into intel_tpmi_init(), taking them as arguments, and add
intel_tpmi_deinit() for what removal has to undo. The auxiliary bus and
intel_vsec_device handling stays in tpmi_probe() and tpmi_remove().
intel_tpmi_info is allocated by the caller instead of by
intel_tpmi_init(), so that an enumeration method can embed it in its own
state and get back to that with container_of().
The TPMI_CORE_INIT and TPMI_CORE_EXIT notifications now pass the struct
device of the TPMI instance instead of its auxiliary device, so that the
generic code does not have to know about the auxiliary bus. No in tree
notifier callback looks at that argument and one that needs the
auxiliary device can use to_auxiliary_dev().
The driver data is set with dev_set_drvdata() on the same device that
auxiliary_set_drvdata() used, so tpmi_remove() still finds it.
No functional change.
Co-developed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://patch.msgid.link/20261013192935.2243291-10-sathyanarayanan.kuppuswamy@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|