| Age | Commit message (Collapse) | Author | Files | Lines |
|
[WARNING]
When running test cases with injected errors or shutdown, e.g.
generic/388 or generic/475, there is a chance that the following kernel
warning is triggered:
BTRFS info (device dm-2): first mount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff
BTRFS info (device dm-2): using crc32c checksum algorithm
BTRFS info (device dm-2): checking UUID tree
BTRFS info (device dm-2): turning on async discard
BTRFS info (device dm-2): enabling free space tree
BTRFS critical (device dm-2 state E): emergency shutdown
------------[ cut here ]------------
WARNING: extent_io.c:1742 at extent_writepage_io+0x437/0x520 [btrfs], CPU#2: kworker/u43:2/651591
CPU: 2 UID: 0 PID: 651591 Comm: kworker/u43:2 Tainted: G W OE 7.0.0-rc6-custom+ #365 PREEMPT(full) 5804053f02137e627472d94b5128cc9fcb110e88
RIP: 0010:extent_writepage_io+0x437/0x520 [btrfs]
Call Trace:
<TASK>
extent_write_cache_pages+0x2a5/0x820 [btrfs 70299925d0856939e93b17d480651713b3cbba58]
btrfs_writepages+0x74/0x130 [btrfs 70299925d0856939e93b17d480651713b3cbba58]
do_writepages+0xd0/0x160
__writeback_single_inode+0x42/0x340
writeback_sb_inodes+0x22d/0x580
wb_writeback+0xc6/0x360
wb_workfn+0xbd/0x470
process_one_work+0x198/0x3b0
worker_thread+0x1c8/0x330
kthread+0xee/0x120
ret_from_fork+0x2a6/0x330
ret_from_fork_asm+0x11/0x20
</TASK>
---[ end trace 0000000000000000 ]---
BTRFS error (device dm-2 state E): root 5 ino 259 folio 1323008 is marked dirty without notifying the fs
BTRFS error (device dm-2 state E): failed to submit blocks, root=5 inode=259 folio=1323008 submit_bitmap=0: -117
BTRFS info (device dm-2 state E): last unmount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff
[CAUSE]
Inside btrfs we have the following pattern in several locations, for
example inside btrfs_dirty_folio():
btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block,
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
cached);
ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
extra_bits, cached);
if (ret)
return ret;
However btrfs_set_extent_delalloc() can return IO errors other than -ENOMEM
through the following callchain:
btrfs_set_extent_delalloc()
\- btrfs_find_new_delalloc_bytes()
\- btrfs_get_extent()
\- btrfs_lookup_file_extent()
\- btrfs_search_slot()
When such IO error happened, the previous btrfs_clear_extent_bit() has
cleared the EXTENT_DELALLOC for the range, and we're expecting
btrfs_set_extent_delalloc() to re-set EXTENT_DELALLOC.
But since btrfs_set_extent_delalloc() failed before
btrfs_set_extent_bit(), EXTENT_DELALLOC flag is no longer present.
And if the folio range is dirty before entering
btrfs_set_extent_delalloc(), we got a dirty folio but no EXTENT_DELALLOC
flag now.
Then we hit the folio writeback:
extent_writepage()
|- writepage_delalloc()
| No ordered extent is created, as there is no EXTENT_DELALLOC set
| for the folio range.
| This also means the folio has no ordered flag set.
|
|- extent_writepage_io()
\- if (unlikely(!folio_test_ordered(folio))
Now we hit the warning.
[FIX]
Introduce a new helper, btrfs_reset_extent_delalloc() to replace the
currently open-coded btrfs_clear_extent_bit() +
btrfs_set_extent_delalloc() combination.
Instead of calling btrfs_clear_extent_bit() first, update
EXTENT_DELALLOC_NEW first, as that part can fail due to metadata IO,
meanwhile btrfs_clear_extent_bit() and btrfs_set_extent_bit() won't
return any error but retry memory allocation until succeeded.
This allows us to fail early without clearing EXTENT_DELALLOC bit, so
even if that new btrfs_reset_extent_delalloc() failed before touching
EXTENT_DELALLOC, the existing dirty range will still have their old
EXTENT_DELALLOC flag present, thus avoid the warning.
CC: stable@vger.kernel.org # 6.1+
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
There is no need to pass the free space control structure as an argument
because we can grab it from the given block group.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We can get the free space control structure from the given block group,
so there is no need to pass it as an argument.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
It's not necessary since we can get the block group from the given
free space control structure.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
The op field always points to the same use_bitmap function, the only
exception is during self tests where we make it temporarily point to a
different function. So just because of this op pointer field we are
increasing the structure size by 8 bytes.
Instead of storing a pointer to a use_bitmap function in struct
btrfs_free_space_ctl, move the pointer to struct btrfs_info, make
insert_into_bitmap() use that pointer if we are running the self tests
and initialize that pointer to the current, default use_bitmap function
(now exported for the tests as btrfs_use_bitmap). This way we reduce
the size of struct btrfs_free_space_ctl from 136 to 128 bytes and can
now fit 32 structures in a 4K page instead of 30. This also avoids the
cost of the indirection of a function pointer call when we are not
running the self tests.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We have a 4 bytes hole in the structure, reorder some fields so that we
eliminate the hole and reduce the structure size from 144 bytes down to
136 bytes. This way on a 4K page system, we can fit 30 structures per
page instead of 28.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
The unit field always has a value matching the sector size, and since we
have a block group pointer in the structure, we can access the block group
and then its fs_info field to get to the sector size. So remove the field,
which will allow us later to shrink the structure size.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
There's no need for the start field, we can take it from the block group.
This reduces the structure size from 152 bytes down to 144 bytes, so on
a 4K page system we can now fit 28 structures instead of 26.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We are currently allocating the free space control structures for block
groups using the generic slabs, and given that the size of the
btrfs_free_space_ctl structure is 152 bytes (on a release kernel), we end
up using the kmalloc-192 slab and therefore waste quite some memory since
on a 4K page system we can only fit 21 free space control structures per
page. These structures are allocated and delallocated every time we create
and remove block groups.
So use a kmem_cache for free space control structures, this way on a 4K
page system we can fit 26 structures instead of 21.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We currently have several holes in the structure:
struct btrfs_block_group {
struct btrfs_fs_info * fs_info; /* 0 8 */
struct btrfs_inode * inode; /* 8 8 */
spinlock_t lock __attribute__((__aligned__(4))); /* 16 4 */
/* XXX 4 bytes hole, try to pack */
u64 start; /* 24 8 */
u64 length; /* 32 8 */
u64 pinned; /* 40 8 */
u64 reserved; /* 48 8 */
u64 used; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
u64 delalloc_bytes; /* 64 8 */
u64 bytes_super; /* 72 8 */
u64 flags; /* 80 8 */
u64 cache_generation; /* 88 8 */
u64 global_root_id; /* 96 8 */
u64 remap_bytes; /* 104 8 */
u32 identity_remap_count; /* 112 4 */
/* XXX 4 bytes hole, try to pack */
u64 last_used; /* 120 8 */
/* --- cacheline 2 boundary (128 bytes) --- */
u64 last_remap_bytes; /* 128 8 */
u32 last_identity_remap_count; /* 136 4 */
/* XXX 4 bytes hole, try to pack */
u64 last_flags; /* 144 8 */
u32 bitmap_high_thresh; /* 152 4 */
u32 bitmap_low_thresh; /* 156 4 */
struct rw_semaphore data_rwsem __attribute__((__aligned__(8))); /* 160 40 */
/* --- cacheline 3 boundary (192 bytes) was 8 bytes ago --- */
long unsigned int full_stripe_len; /* 200 8 */
long unsigned int runtime_flags; /* 208 8 */
unsigned int ro; /* 216 4 */
int disk_cache_state; /* 220 4 */
int cached; /* 224 4 */
/* XXX 4 bytes hole, try to pack */
struct btrfs_caching_control * caching_ctl; /* 232 8 */
struct btrfs_space_info * space_info; /* 240 8 */
struct btrfs_free_space_ctl * free_space_ctl; /* 248 8 */
/* --- cacheline 4 boundary (256 bytes) --- */
struct rb_node cache_node __attribute__((__aligned__(8))); /* 256 24 */
struct list_head list; /* 280 16 */
refcount_t refs __attribute__((__aligned__(4))); /* 296 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head cluster_list; /* 304 16 */
/* --- cacheline 5 boundary (320 bytes) --- */
struct list_head bg_list; /* 320 16 */
struct list_head ro_list; /* 336 16 */
atomic_t frozen __attribute__((__aligned__(4))); /* 352 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head discard_list; /* 360 16 */
int discard_index; /* 376 4 */
/* XXX 4 bytes hole, try to pack */
/* --- cacheline 6 boundary (384 bytes) --- */
u64 discard_eligible_time; /* 384 8 */
u64 discard_cursor; /* 392 8 */
enum btrfs_discard_state discard_state; /* 400 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head dirty_list; /* 408 16 */
struct list_head io_list; /* 424 16 */
struct btrfs_io_ctl io_ctl; /* 440 72 */
/* --- cacheline 8 boundary (512 bytes) --- */
atomic_t reservations __attribute__((__aligned__(4))); /* 512 4 */
atomic_t nocow_writers __attribute__((__aligned__(4))); /* 516 4 */
struct mutex free_space_lock __attribute__((__aligned__(8))); /* 520 32 */
bool using_free_space_bitmaps; /* 552 1 */
bool using_free_space_bitmaps_cached; /* 553 1 */
/* XXX 2 bytes hole, try to pack */
int swap_extents; /* 556 4 */
u64 alloc_offset; /* 560 8 */
u64 zone_unusable; /* 568 8 */
/* --- cacheline 9 boundary (576 bytes) --- */
u64 zone_capacity; /* 576 8 */
u64 meta_write_pointer; /* 584 8 */
struct btrfs_chunk_map * physical_map; /* 592 8 */
struct list_head active_bg_list; /* 600 16 */
struct work_struct zone_finish_work; /* 616 32 */
/* --- cacheline 10 boundary (640 bytes) was 8 bytes ago --- */
struct extent_buffer * last_eb; /* 648 8 */
enum btrfs_block_group_size_class size_class; /* 656 4 */
/* XXX 4 bytes hole, try to pack */
u64 reclaim_mark; /* 664 8 */
/* size: 672, cachelines: 11, members: 61 */
/* sum members: 634, holes: 10, sum holes: 38 */
/* forced alignments: 8 */
/* last cacheline: 32 bytes */
} __attribute__((__aligned__(8)));
Reorder some fields to eliminate the holes while keeping closely related
or frequently accessed fields together. After the reordering the size of
the structure is reduced down to 632 bytes and the number of cache lines
decreases from 11 to 10. We can still only pack 6 block groups per 4K page
but on a 64K page system we will now be able to pack 103 block groups
instead of 97. The new structure layout, on a release kernel, is the
following:
struct btrfs_block_group {
struct btrfs_fs_info * fs_info; /* 0 8 */
struct btrfs_inode * inode; /* 8 8 */
spinlock_t lock __attribute__((__aligned__(4))); /* 16 4 */
unsigned int ro; /* 20 4 */
u64 start; /* 24 8 */
u64 length; /* 32 8 */
u64 pinned; /* 40 8 */
u64 reserved; /* 48 8 */
u64 used; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
u64 delalloc_bytes; /* 64 8 */
u64 bytes_super; /* 72 8 */
u64 flags; /* 80 8 */
u64 cache_generation; /* 88 8 */
u64 global_root_id; /* 96 8 */
u64 remap_bytes; /* 104 8 */
u32 identity_remap_count; /* 112 4 */
u32 last_identity_remap_count; /* 116 4 */
u64 last_used; /* 120 8 */
/* --- cacheline 2 boundary (128 bytes) --- */
u64 last_remap_bytes; /* 128 8 */
u64 last_flags; /* 136 8 */
u32 bitmap_high_thresh; /* 144 4 */
u32 bitmap_low_thresh; /* 148 4 */
struct rw_semaphore data_rwsem __attribute__((__aligned__(8))); /* 152 40 */
/* --- cacheline 3 boundary (192 bytes) --- */
long unsigned int full_stripe_len; /* 192 8 */
long unsigned int runtime_flags; /* 200 8 */
int disk_cache_state; /* 208 4 */
int cached; /* 212 4 */
struct btrfs_caching_control * caching_ctl; /* 216 8 */
struct btrfs_space_info * space_info; /* 224 8 */
struct btrfs_free_space_ctl * free_space_ctl; /* 232 8 */
struct rb_node cache_node __attribute__((__aligned__(8))); /* 240 24 */
/* --- cacheline 4 boundary (256 bytes) was 8 bytes ago --- */
struct list_head list; /* 264 16 */
refcount_t refs __attribute__((__aligned__(4))); /* 280 4 */
atomic_t frozen __attribute__((__aligned__(4))); /* 284 4 */
struct list_head cluster_list; /* 288 16 */
struct list_head bg_list; /* 304 16 */
/* --- cacheline 5 boundary (320 bytes) --- */
struct list_head ro_list; /* 320 16 */
struct list_head discard_list; /* 336 16 */
int discard_index; /* 352 4 */
enum btrfs_discard_state discard_state; /* 356 4 */
u64 discard_eligible_time; /* 360 8 */
u64 discard_cursor; /* 368 8 */
struct list_head dirty_list; /* 376 16 */
/* --- cacheline 6 boundary (384 bytes) was 8 bytes ago --- */
struct list_head io_list; /* 392 16 */
struct btrfs_io_ctl io_ctl; /* 408 72 */
/* --- cacheline 7 boundary (448 bytes) was 32 bytes ago --- */
atomic_t reservations __attribute__((__aligned__(4))); /* 480 4 */
atomic_t nocow_writers __attribute__((__aligned__(4))); /* 484 4 */
struct mutex free_space_lock __attribute__((__aligned__(8))); /* 488 32 */
/* --- cacheline 8 boundary (512 bytes) was 8 bytes ago --- */
bool using_free_space_bitmaps; /* 520 1 */
bool using_free_space_bitmaps_cached; /* 521 1 */
/* XXX 2 bytes hole, try to pack */
/* Bitfield combined with previous fields */
static enum btrfs_block_group_size_class size_class; /* 0: 0 0 */
int swap_extents; /* 524 4 */
u64 alloc_offset; /* 528 8 */
u64 zone_unusable; /* 536 8 */
u64 zone_capacity; /* 544 8 */
u64 meta_write_pointer; /* 552 8 */
struct btrfs_chunk_map * physical_map; /* 560 8 */
struct list_head active_bg_list; /* 568 16 */
/* --- cacheline 9 boundary (576 bytes) was 8 bytes ago --- */
struct work_struct zone_finish_work; /* 584 32 */
struct extent_buffer * last_eb; /* 616 8 */
u64 reclaim_mark; /* 624 8 */
/* size: 632, cachelines: 10, members: 60, static members: 1 */
/* sum members: 630, holes: 1, sum holes: 2 */
/* sum bitfield members: 8 bits (1 bytes) */
/* forced alignments: 8 */
/* last cacheline: 56 bytes */
} __attribute__((__aligned__(8)));
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We are currently allocating block groups using the generic slabs, and
given that the size of btrfs_block_group structure is 672 bytes (on a
release kernel), we end up using the kmalloc-1024 slab and therefore
waste quite some memory since on a 4K page system we can only fit 4
block groups per page. The block groups are also allocated and
delallocated with some frequency, specially if we have auto reclaim
enabled.
So use a kmem_cache for block groups, this way on a 4K page system we
can fit 6 block groups per page instead of 4.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
We have support for optional string to be printed in ASSERT() (added in
19468a623a9109 ("btrfs: enhance ASSERT() to take optional format
string")), it's not yet everywhere it could be so add a few more files.
Try to finish what was left after 1c094e6ccead7a ("btrfs: make a few
more ASSERTs verbose").
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Many ioctl handlers are suitable for the AUTO_KFREE conversions as the
data are temporary and short lived. The conversions are trivial or the
collateral changes are straightforward.
A kfree() preceding mnt_drop_write_file() is slightly more efficient but
in the reverse order (i.e. the automatic kfree) does not cause any
significant change as the write drop does only a few simple operations.
Note: __free() handles also error pointers, so this is safe for the
memdup_user() errors too.
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
There's one use of kmalloc_array() that can be transformed to
kmalloc_objs() in the same way as suggested in commit 69050f8d6d075d
("treewide: Replace kmalloc with kmalloc_obj for non-scalar types"),
swap the arguments and drop GFP flags. All the other cases of
kmalloc_array() do not use a simple type so this is the only one.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Do a few more (trivial) conversions that started in commit 69050f8d6d075d
("treewide: Replace kmalloc with kmalloc_obj for non-scalar types").
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
There are only two possible types of the delayed ref action, this can be
verified at the beginning for the whole function and not just one block.
Replace the assertion with a debugging warning just in case.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
For a simple if + WARN_ON we should use the condition directly in the
macro.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
The folio checked flag is only utilized by the COW fixup mechanism
inside btrfs.
Since the COW fixup is already removed from non-experimental builds,
there is no need to keep the checked subpage bitmap.
This will saves us some space for large folios, for example for a single
256K sized large folio on 4K page sized systems:
Old bitmap size = 6 * (256K / 4K / 8) = 48 bytes
New bitmap size = 5 * (256K / 4K / 8) = 40 bytes
This will be more obvious when we're going to support huge folios (order
= 9).
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
[BACKGROUND]
Btrfs has a special mechanism called COW fixup, which detects dirty
pages without an ordered extent (folio ordered flag).
Normally a dirty folio must go through delayed allocation (delalloc)
before it can be submitted, and delalloc will create an ordered extent
for it and mark the range with ordered flag.
However in older kernels, there are bugs related to get_user_pages()
which can lead to some page marked dirty but without notifying the fs to
properly prepare them for writeback.
In that case without an ordered extent btrfs is unable to properly
submit such dirty folios, thus the COW fixup mechanism is introduced,
which do the extra space reservation so that they can be written back
properly.
[MODERN SOLUTIONS]
The MM layer has solved it properly now with the introduction of
pin_user_pages*(), so we're handling cases that are no longer valid.
So commit 7ca3e84980ef ("btrfs: reject out-of-band dirty folios during
writeback") is introduced to change the behavior from going through
COW fixup to rejecting them directly for experimental builds.
So far it works fine, but when errors are injected into the IO path, we
have random failures triggering the new warnings.
It looks like we have error path that cleared the ordered flag but
leaves the folio dirty flag, which later triggers the warning.
[REMOVAL OF COW FIXUP]
Although I hope to fix all those known warnings cases, I just can not
figure out the root cause yet.
But on the other hand, if we remove the ordered and checked flags in the
future, and purely rely on the dirty flags and ordered extent search, we
can get a much cleaner handling.
Considering it's no longer hitting the COW fixup for normal IO paths, I
think it's finally the time to remove the COW fixup completely.
Furthermore, the function name "btrfs_writepage_cow_fixup()" is no
longer meaningful, and since it's pretty small, only a folio flag check
with error message, there is no need to put it as a dedicated helper,
just open code it inside extent_writepage_io().
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Commit 6e181cfe2409 ("btrfs: revalidate cached tree blocks on the
uptodate path") introduced the @check parameter for
btrfs_buffer_uptodate() to allow re-validation of a cached extent
buffer.
But there are still call sites that don't utilize this parameter, which
exposes them to possible corrupted tree blocks, e.g. an empty child leaf
of a parent node, which should be rejected by btrfs_verify_level_key()
but if @check is NULL such check will be skipped and cause problems.
Thankfully for a lot of cases there is already an existing @check
structure around and we can pass it directly to btrfs_buffer_uptodate().
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
|
|
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner:
- Fix error handling in ovl_cache_get()
- Tighten access checks for exited tasks in pidfd_getfd()
- Fix selftests leak in __wait_for_test()
- Limit FUSE_NOTIFY_RETRIEVE to uptodate folios
- Reject fuse_notify() pagecache ops on directories
- Clear JOBCTL_PENDING_MASK for caller in zap_other_threads()
- Fix failure to unlock in nfsd4_create_file()
- Fix pointer arithmetic in qnx6 directory iteration
- Fix UAF due to unlocked ->mnt_ns read in may_decode_fh()
- Avoid potential null folio->mapping deref during iomap error
reporting
* tag 'vfs-7.1-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
iomap: avoid potential null folio->mapping deref during error reporting
fhandle: fix UAF due to unlocked ->mnt_ns read in may_decode_fh()
fs/qnx6: fix pointer arithmetic in directory iteration
VFS: fix possible failure to unlock in nfsd4_create_file()
signal: clear JOBCTL_PENDING_MASK for caller in zap_other_threads()
fuse: reject fuse_notify() pagecache ops on directories
fuse: limit FUSE_NOTIFY_RETRIEVE to uptodate folios
selftests: harness: fix pidfd leak in __wait_for_test
pidfd: refuse access to tasks that have started exiting harder
ovl: keep err zero after successful ovl_cache_get()
|
|
Add a sleepable BPF kfunc that resolves the real inode backing a dentry
via d_real_inode(). On overlay/union filesystems the inode attached to
the dentry is the overlay inode which does not carry the underlying
device information. d_real_inode() resolves through the overlay and
returns the inode from the lower, real filesystem.
This is used in the RestrictFilesytemAccess bpf program that has been
merged into systemd a little while ago.
Link: https://github.com/systemd/systemd/pull/41340 [1]
Link: https://patch.msgid.link/20260526-work-bpf-verity-v2-1-cd0b1850d31b@kernel.org
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Add support for extended attributes on bpffs inodes so that user space
and BPF LSM programs can attach metadata, for example, a content hash
or a security label - to a pinned object or directory. BPF LSM or user
space tooling can then uniformly look at this (e.g. security.bpf.*) in
similar way to other fs'es. The store is in-memory and non-persistent:
it lives only for the lifetime of the mount, like everything else in
bpffs. The modelling is similar to tmpfs.
bpffs serves the trusted.* and security.* namespaces; user.* is left
unsupported. As bpffs is FS_USERNS_MOUNT, security.* is reachable by
the unprivileged mounter in a user namespace, and thus we are using
the simple_xattr_set_limited infra there (trusted.* needs global
CAP_SYS_ADMIN).
bpf_fill_super() is open-coded instead of using simple_fill_super(),
because the root inode must now be allocated through bpf_fs_alloc_inode()
i.e. carry the bpf_fs_inode wrapper and come from the right cache -
which requires s_op (and s_xattr) to be installed before the first
inode is created. While at it, also harden s_iflags with SB_I_NOEXEC
and SB_I_NODEV.
bpf_fs_listxattr() is only reachable through the filesystem via
i_op->listxattr, so the BPF token inode is left untouched. Name-based
fsetxattr()/fgetxattr() on a token fd still work since the get/set
handlers are installed at the superblock.
For security.* namespace, we use simple_xattr_set_limited() but
there was no simple_xattr_add_limited() API yet which was needed
in bpf_fs_initxattrs() to avoid underflows in the accounting. The
symlink target is freed in bpf_free_inode() rather than in
bpf_destroy_inode() so that it is released only after an RCU grace
period, as an RCU path walk following the symlink may still
dereference inode->i_link in security_inode_follow_link(). Lastly,
the bpf_symlink() allocated the symlink target is switched to
GFP_KERNEL_ACCOUNT, so the string is charged to the caller's memcg.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://patch.msgid.link/20260602074012.416289-1-daniel@iogearbox.net
Cc: Christian Brauner <brauner@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
After commit 12e9e3cd03b5 ("simpe_xattr: use per-sb cache"),
kernfs_xattr_set() and kernfs_xattr_get() compute the cache via
kernfs_root(kn) before any other check. kernfs_root(kn) walks
kn->__parent first and falls back to kn->dir.root, both of which are
NULL on a freshly kmem_cache_zalloc()'d kn. kn->__parent was being set
in kernfs_new_node() after __kernfs_new_node() returned, and kn->dir.root
is set even later by kernfs_create_dir_ns() / kernfs_create_empty_dir().
The LSM kernfs_init_security hook is invoked from inside
__kernfs_new_node(), before either field has been initialized.
selinux_kernfs_init_security() ends with kernfs_xattr_set(kn,
XATTR_NAME_SELINUX, ...). kernfs_root(kn) then returns NULL, and
&((struct kernfs_root *)NULL)->xa_cache evaluates to
offsetof(struct kernfs_root, xa_cache) which faults:
BUG: kernel NULL pointer dereference, address: 00000000000000e0
RIP: 0010:simple_xattr_set+0x27/0x8b0
Call Trace:
kernfs_xattr_set+0x63/0xb0
selinux_kernfs_init_security+0x13b/0x270
security_kernfs_init_security+0x36/0xc0
__kernfs_new_node+0x182/0x290
kernfs_new_node+0x80/0xc0
kernfs_create_dir_ns+0x2b/0xa0
cgroup_create+0x116/0x380
cgroup_mkdir+0x7c/0x1a0
Reproduces deterministically at PID 1 (systemd) on an SELinux-enabled
distro. The first cgroup mkdir under /sys/fs/cgroup with a labelled
parent panics the kernel.
The LSM hook's contract is that the kn_dir argument is the parent of
the new kn, so kn->__parent should already point at kn_dir when the
hook runs. Move kernfs_get(parent) and rcu_assign_pointer of
kn->__parent from kernfs_new_node() into __kernfs_new_node() right
before the security hook, and unwind the parent reference on the
err_out4 path. kernfs_root(kn) then takes its parent branch during
the hook and returns parent->dir.root, which is the correct root.
This also closes the same-shape latent bug in kernfs_xattr_get() (which
today is hidden only by kernfs_iattrs_noalloc() returning NULL on a
fresh kn).
Fixes: 12e9e3cd03b5 ("simpe_xattr: use per-sb cache")
Reported-by: Calum Mackay <calum.mackay@oracle.com>
Closes: https://lore.kernel.org/all/5386153f-9112-4971-98fc-de90d7aae2c6@oracle.com/
Link: https://patch.msgid.link/20260526-ablief-demut-wehen-aef8446ef5c9@brauner
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Move the hash table to the super block to remove excessive overhead in case
of small number of xattrs per inode.
Add linked list to the inode, used for listxattr and eviction. Listxattr
uses rcu protection to iterate the list of xattrs.
Before being made per-sb, lazy allocation was protected by inode lock. Now
inode lock no longer provides sufficient exclusion, so use cmpxchg() to
ensure atomicity.
Though I haven't found a description of this pattern, after some research
it seems that cmpxchg_release() and READ_ONCE() should provide the
necessary memory barriers.
Use simple_xattr_free_rcu() in simple_xattrs_free(). This is needed because
the hash table is now shared between inodes and lookup on a different inode
might be running the compare function on the just freed element within the
RCU grace period.
Following stats are based on slabinfo diff, after creating 100k empty
files, then adding a "user.test=foo" xattr to each:
v7.0 (no rhashtable):
File creation: 993.40 bytes/file
Xattr addition: 79.99 bytes/file
v7.1-rc2 (per-inode rhashtable):
File creation: 939.73 bytes/file
Xattr addition: 1296.08 bytes/file
v7.1-rc2 + this patch (per-sb rhashtable)
File creation: 946.84 bytes/file
Xattr addition: 111.86 bytes/file
The overhead of a single xattr is reduced to nearly v7.0 levels. The per
xattr overhead is slightly larger due to the addition of three pointers to
struct simple_xattr.
Fixes: b32c4a213698 ("xattr: add rhashtable-based simple_xattr infrastructure")
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://patch.msgid.link/20260605135322.2632068-5-mszeredi@redhat.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Change the simple_xattr API to accept pointer-to-pointer (struct
simple_xattrs **) instead of pointer. This allows the functions to handle
lazy allocation internally without requiring callers to use
simple_xattrs_lazy_alloc().
The simple_xattr_set(), simple_xattr_set_limited() and simple_xattr_add()
functions now handle allocation when xattrs is NULL. simple_xattrs_free()
now also frees the xattrs structure itself and sets the pointer to NULL.
This simplifies callers and removes the need for most callers to explicitly
manage xattrs allocation and lifetime.
In shmem_initxattrs(), the total required space for all initial xattrs
(ispace) is pre-calculated and deducted from sbinfo->free_ispace.
Since this patch modifies the function to add new xattrs directly to the
inode's &info->xattrs list rather than using a local temporary variable, a
failure means that the partially populated info->xattrs list remains
attached to the inode.
When the VFS caller handles the -ENOMEM error, it drops the newly created
inode via iput(), shmem_free_inode() adds freed to sbinfo->free_ispace a
second time, permanently inflating the tmpfs free space quota.
Fix by substracting already added xattrs from ispace.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://patch.msgid.link/20260605135322.2632068-4-mszeredi@redhat.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Multiple superblocks with different namespaces can share the same
kernfs_node when kernfs_test_super() finds a matching root but
different namespace. This means multiple inodes from different
superblocks can reference the same kernfs_node->iattr->xattrs
structure.
The VFS layer only holds per-inode locks during xattr operations,
which is insufficient to serialize concurrent xattr modifications on
the shared kernfs_node. This can lead to race conditions in
simple_xattr_set() where the lookup->replace/remove sequence is not
atomic with respect to operations from other superblocks.
Fix this by protecting xattr operations with the existing hashed
kernfs_locks->open_file_mutex[] array, which is already used to
protect per-node open file data. The hashed mutex array provides
scalable per-node serialization (scaled by CPU count, up to 1024 locks
on 32+ CPU systems) with zero memory overhead.
Changes:
- Rename open_file_mutex[] to node_mutex[] to reflect dual purpose
- Add kernfs_node_lock_ptr() and kernfs_node_lock() helpers
- Protect simple_xattr_set() calls in kernfs_xattr_set() and
kernfs_vfs_user_xattr_set() with the hashed mutex
- Update file.c to use new helpers via compatibility wrappers
- Update documentation to explain the extended lock usage
Fixes: b32c4a213698 ("xattr: add rhashtable-based simple_xattr infrastructure")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260601162454.2116375-1-mszeredi%40redhat.com
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://patch.msgid.link/20260605135322.2632068-2-mszeredi@redhat.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Pull NFS client fix from Trond Myklebust:
- Fix a use after free in nfs_write_completion
* tag 'nfs-for-7.1-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS: write_completion: dereference loop-local req, not hdr->req
|
|
Pull xfs fixes from Carlos Maiolino:
"A collection of fixes mostly for the RT device, including a small
refactor that has no functional change"
* tag 'xfs-fixes-7.1-rc7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
xfs: Remove mention of PageWriteback
xfs: abort mount if xfs_fs_reserve_ag_blocks fails
xfs: factor rtgroup geom write pointer reporting into a helper
xfs: drop the RTG reference later in xfs_ioc_rtgroup_geometry
xfs: fix rtgroup cleanup in CoW fork repair
xfs: fix error returns in CoW fork repair
xfs: fix overlapping extents returned for pNFS LAYOUTGET
xfs: fix use of uninitialized imap in xfs_fs_map_blocks error path
xfs: handle racing deletions in xfs_zone_gc_iter_irec
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs fixes from Gao Xiang:
- Fix a UAF of sbi->sync_decompress when compressed I/Os
race with unmount
- Fix a regression introduced this development cycle that
incorrectly rejects multiple-algorithm images
* tag 'erofs-for-7.1-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
erofs: fix EFSCORRUPTED on multi-algorithm images in z_erofs_map_sanity_check()
erofs: fix use-after-free on sbi->sync_decompress
|
|
The shared lookup-time attribute validator now has a safe caller path for
$VOLUME_NAME corruption: ntfs_write_volume_label() no longer treats
lookup errors as an absent label, and the mount path reinitializes its
search context before continuing to $VOLUME_INFORMATION.
Add $VOLUME_NAME-specific resident value validation. A volume name is
stored as a UTF-16LE string, so reject odd byte lengths, and reject
values longer than the NTFS volume label limit. Empty labels remain
valid.
Also reject non-resident $VOLUME_NAME records. $VOLUME_NAME is required
to be resident, like $FILE_NAME; a crafted non-resident record would
otherwise pass lookup and ntfs_write_volume_label() would remove it as if
it were a normal resident attribute.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
On mount the volume inode is searched for $VOLUME_NAME and then, reusing
the same search context, for $VOLUME_INFORMATION. The $VOLUME_NAME lookup
is optional and its result is otherwise ignored.
Once lookup-time validation can reject a corrupt $VOLUME_NAME with -EIO,
the search context is left in an undefined state: ntfs_attr_find()
documents that on an actual error @ctx->attr is undefined. Continuing the
$VOLUME_INFORMATION search from that context is not contractually valid.
Reinitialize the search context before the $VOLUME_INFORMATION lookup so
it always starts from a well-defined state regardless of the
$VOLUME_NAME lookup outcome.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_write_volume_label() removes an existing $VOLUME_NAME attribute and
then adds the replacement. The old code only distinguished lookup success
from all other results, so any lookup error was treated like an absent
label and the add path still ran.
That is unsafe once lookup-time validation rejects corrupt $VOLUME_NAME
records with -EIO: the corrupt record would remain in place and a second
$VOLUME_NAME record could be appended next to it.
Only add the replacement after the old label was removed successfully or
after lookup returned -ENOENT. Propagate all other lookup errors, and
also stop if removing the old attribute fails.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_attr_find() and ntfs_external_attr_find() check that generic
resident attribute values fit in their attribute records and that
fixed-size resident values are large enough. For variable-length resident
formats, however, the fixed part is not enough: embedded length fields
can still point callers past the resident value.
A crafted image can set a small resident $FILE_NAME value_length while
leaving file_name_length large. Callers then trust file_name_length and
read past the resident value when converting or comparing the name. This
was reproduced with a crafted image under KASAN as a slab-out-of-bounds
read from the kmalloc-1k MFT record copy. The stack included
ntfs_lookup(), ntfs_iget(), ntfs_read_locked_inode(), ntfs_attr_name_get(),
ntfs_ucstonls(), and utf16s_to_utf8s().
Add a shared attribute value validator and use it before a lookup path
can return an attribute, including the AT_UNUSED enumeration case where
callers inspect returned attributes directly. The helper validates
resident value bounds, minimum resident value sizes, variable-length
$FILE_NAME fields, and non-resident mapping-pairs metadata that was
previously checked separately in both lookup paths.
This also preserves the intended resident @val matching semantics in the
external attribute lookup path. The old duplicated validation block
overwrote the actual resident value length with the type-specific minimum
length before comparing @val, so variable-length resident values could
fail to match even when the bytes were identical. Keep the comparison on
the actual value length, and make ntfs_attrlist_entry_add() compare
resident attributes with lowest_vcn zero instead of reading the
non-resident union member after a successful resident match.
Reject non-resident $FILE_NAME records too: the format requires
$FILE_NAME to be resident and callers treat returned records as resident.
Cc: stable@vger.kernel.org # v7.1
Fixes: 6ceb4cc81ef3 ("ntfs: add bound checking to ntfs_attr_find")
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The NTFS mapping-pairs parser accumulates relative LCN deltas in a
signed integer. A corrupted attribute can drive that addition past
the representable range.
One corrupt runlist shape sets the accumulated LCN to S64_MAX and
then adds a delta of 1 in the next mapping-pairs entry.
Signed overflow is undefined and can turn an invalid runlist into a
different set of physical clusters.
Check the LCN addition for overflow before storing the next run.
Cc: stable@vger.kernel.org # v7.1
Assisted-by: Codex:gpt-5.5-cyber-preview
Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
This continues the effort to refactor workqueue APIs, which began with
the introduction of new workqueues and a new alloc_workqueue flag in:
commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")
commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
The refactoring is going to alter the default behavior of
alloc_workqueue() to be unbound by default.
With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND),
any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND
must now use WQ_PERCPU. For more details see the Link tag below.
In order to keep alloc_workqueue() behavior identical, explicitly request
WQ_PERCPU.
Cc: stable@vger.kernel.org # v7.1
Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/
Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Protect vol->volume_label with a mutex and snaphost the label before
copy_to_user. This prevent a use-after-free when FS_IOC_SETFSLABEL
replaces the vol->volume_label and FS_IOC_GETTSLABEL reads it
concurrently.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
In ntfs_mapping_pairs_decompress(), attr_end points one byte past the
end of the attribute record:
attr_end = (u8 *)attr + le32_to_cpu(attr->length);
The two bounds checks validating that mapping pair data bytes fit within
the attribute use strict greater-than (>), which allows a one-byte
out-of-bounds read when the data extends exactly to attr_end:
b = *buf & 0xf;
if (b) {
if (unlikely(buf + b > attr_end)) // off-by-one
goto io_error;
for (deltaxcn = (s8)buf[b--]; b; b--)
deltaxcn = (deltaxcn << 8) + buf[b];
}
When buf + b == attr_end, the check evaluates to false and buf[b] reads
one byte past the valid attribute boundary. The same pattern appears in
the LCN delta bytes check.
Fix both checks to use >= so that buf[b] at exactly attr_end is
correctly rejected as out of bounds.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Ron de Bruijn <rmbruijn@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
When ntfs_resident_attr_resize() cannot grow a resident attribute in
place, it retries after converting other resident attributes to
non-resident to free space in the MFT recrord.
Do not select zero-length resident $DATA attributes for this conversion.
fsck treats 0-byte non-resident $DATA attribute as corruptions.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
There is a spelling mistake in a ntfs_error message. Fix it.
Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_link() converts the new link name with ntfs_nlstoucs() using
NTFS_MAX_NAME_LEN. In this case ntfs_nlstoucs() allocates the result
from ntfs_name_cache, and its contract requires callers to release the
buffer with kmem_cache_free(ntfs_name_cache, ...).
All other ntfs_nlstoucs() callers in namei.c do that, but ntfs_link()
uses kfree(), which mismatches the allocator for successfully converted
names.
The conversion failure path reaches the common out label with uname ==
NULL. That was harmless for kfree(), but kmem_cache_free() does not
provide the same NULL contract. Return directly on conversion failure
and free successful conversions with ntfs_name_cache.
Fixes: af0db57d4293 ("ntfs: update inode operations")
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
NULL check before kfree() is unnecessary and triggers coccinelle warnings.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Coccinelle warned about unnecessary patterns when
assigning to bool variables.
Simply assign the condition directly.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The ntfs driver does not implement quota accounting. It creates
new inodes with the NTFS 1.2 $STANDARD_INFORMATION layout and does
not maintain the NTFS 3.x owner_id/quota_charged fields or the
$Quota usage records that Windows would need for meaningful quota
accounting.
The only runtime quota path left in the driver is the remount-rw
code that tries to mark $Quota/$Q out of date, plus the mount-time
code that loads $Quota and its $Q index solely to support that
marker.
Since the driver does not maintain the per-file quota metadata,
setting QUOTA_FLAG_OUT_OF_DATE does not make the quota state
meaningful, and failures in this unsupported path can unnecessarily
block remount-rw or force a mount read-only.
Remove the quota marker, the $Quota/$Q loading state, and the
unused quota volume flag. Keep the on-disk quota layout definitions
in layout.h so the documented NTFS structures remain available.
Suggested-by: Hyunchul Lee <hyc.lee@gmail.com>
Link: https://lore.kernel.org/all/CANFS6bYTzioqZjYt=51Kb9RdR3MKXaez_fh_WCLoym093VxFmg@mail.gmail.com/
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Replace the manual ternary "s" pluralization with str_plural() to
simplify the code.
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
in ntfs_ea_lookup and ntfs_listxattr, this verifies that there is enough
space in the EA entry before accessing the next_entry_offset field of
the EA entry.
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Validate index entries immediately after reading an index root or index
block from disk. This eliminates repeated checks in lookup and readdir,
and reduce the risk of missing checks in those paths.
Cc: stable@vger.kernel.org # v7.1
Tested-by: woot000 <woot000@woot000.com>
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|