5.15.87-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 140/290 ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit eee22187b53611e173161e38f61de1c7ecbeb876 upstream.
In do_writepages, if the value returned by ext4_writepages is "-ENOMEM" and "wbc->sync_mode == WB_SYNC_ALL", retry until the condition is not met.
In __ext4_get_inode_loc, if the bh returned by sb_getblk is NULL, the function returns -ENOMEM.
In __getblk_slow, if the return value of grow_buffers is less than 0, the function returns NULL.
When the three processes are connected in series like the following stack, an infinite loop may occur:
do_writepages <--- keep retrying
ext4_writepages
mpage_map_and_submit_extent
mpage_map_one_extent
ext4_map_blocks
ext4_ext_map_blocks
ext4_ext_handle_unwritten_extents
ext4_ext_convert_to_initialized
ext4_split_extent
ext4_split_extent_at
__ext4_ext_dirty
__ext4_mark_inode_dirty
ext4_reserve_inode_write
ext4_get_inode_loc
__ext4_get_inode_loc <--- return -ENOMEM
sb_getblk
__getblk_gfp
__getblk_slow <--- return NULL
grow_buffers
grow_dev_page <--- return -ENXIO
ret = (block < end_block) ? 1 : -ENXIO;In this issue, bg_inode_table_hi is overwritten as an incorrect value. As a result, block < end_block cannot be met in grow_dev_page. Therefore, __ext4_get_inode_loc always returns '-ENOMEM' and do_writepages keeps retrying. As a result, the writeback process is in the D state due to an infinite loop.
Add a check on inode table block in the __ext4_get_inode_loc function by referring to ext4_read_inode_bitmap to avoid this infinite loop.
--- fs/ext4/inode.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
fs/ext4/inode.c +9 -1
@@ -4299,9 +4299,17 @@ static int __ext4_get_inode_loc(struct s inodes_per_block =EXT4_SB (sb)->s_inodes_per_block; inode_offset = ((ino -1 ) %EXT4_INODES_PER_GROUP (sb)); - block =ext4_inode_table (sb, gdp) + (inode_offset / inodes_per_block); iloc->offset = (inode_offset % inodes_per_block) *EXT4_INODE_SIZE (sb); + block =ext4_inode_table (sb, gdp); +if ((block <=le32_to_cpu (EXT4_SB (sb)->s_es->s_first_data_block)) || + (block >=ext4_blocks_count (EXT4_SB (sb)->s_es))) { +ext4_error (sb,"Invalid inode table block %llu in " +"block_group %u" , block, iloc->block_group); +return -EFSCORRUPTED ; + } + block += (inode_offset / inodes_per_block); + bh =sb_getblk (sb, block);if (unlikely (!bh))return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 141/290 ext4: remove trailing newline from ext4_msg() message
In reply to Greg Kroah-HartmanFrom: Luís Henriques <[email protected]>
commit 78742d4d056df7d2fad241c90185d281bf924844 upstream.
The ext4_msg() function adds a new line to the message. Remove extra '\n' from call to ext4_msg() in ext4_orphan_cleanup().
--- fs/ext4/orphan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/orphan.c +1 -1
@@ -412,7 +412,7 @@ void ext4_orphan_cleanup(struct super_bl/* don't clear list on RO mount w/ errors */ if (es->s_last_orphan && !(s_flags &SB_RDONLY )) {ext4_msg (sb,KERN_INFO ,"Errors on filesystem, " -"clearing orphan list.\n" ); +"clearing orphan list." ); es->s_last_orphan =0 ; }jbd_debug (1 ,"Skipping orphan recovery on fs with errors.\n" );
Greg Kroah-Hartman
maintainerPATCH 142/290 fs: ext4: initialize fsdata in pagecache_write()
In reply to Greg Kroah-HartmanFrom: Alexander Potapenko <[email protected]>
commit 956510c0c7439e90b8103aaeaf4da92878c622f0 upstream.
When aops->write_begin() does not initialize fsdata, KMSAN reports an error passing the latter to aops->write_end().
Fix this by unconditionally initializing fsdata.
--- fs/ext4/verity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/verity.c +1 -1
@@ -76,7 +76,7 @@ static int pagecache_write(struct inodesize_t n =min_t (size_t, count,PAGE_SIZE -offset_in_page (pos));struct page *page; -void *fsdata; +void *fsdata =NULL ;int res; res = pagecache_write_begin(NULL, inode->i_mapping, pos, n, 0,
Greg Kroah-Hartman
maintainerPATCH 143/290 ext4: fix use-after-free in ext4_orphan_cleanup
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit a71248b1accb2b42e4980afef4fa4a27fa0e36f5 upstream.
I caught a issue as follows:
==================================================================
BUG: KASAN: use-after-free in __list_add_valid+0x28/0x1a0 Read of size 8 at addr ffff88814b13f378 by task mount/710 CPU: 1 PID: 710 Comm: mount Not tainted 6.1.0-rc3-next #370 Call Trace: <TASK> dump_stack_lvl+0x73/0x9f print_report+0x25d/0x759 kasan_report+0xc0/0x120 __asan_load8+0x99/0x140 __list_add_valid+0x28/0x1a0 ext4_orphan_cleanup+0x564/0x9d0 [ext4] __ext4_fill_super+0x48e2/0x5300 [ext4] ext4_fill_super+0x19f/0x3a0 [ext4] get_tree_bdev+0x27b/0x450 ext4_get_tree+0x19/0x30 [ext4] vfs_get_tree+0x49/0x150 path_mount+0xaae/0x1350 do_mount+0xe2/0x110 __x64_sys_mount+0xf0/0x190 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x63/0xcd </TASK> [...] ==================================================================
Above issue may happen as follows:
-------------------------------------ext4_fill_super
ext4_orphan_cleanup
--- loop1: assume last_orphan is 12 ---
list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan)
ext4_truncate --> return 0
ext4_inode_attach_jinode --> return -ENOMEM
iput(inode) --> free inode<12>
--- loop2: last_orphan is still 12 ---
list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
// use inode<12> and trigger UAFTo solve this issue, we need to propagate the return value of ext4_inode_attach_jinode() appropriately.
--- fs/ext4/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/inode.c +2 -1
@@ -4198,7 +4198,8 @@ int ext4_truncate(struct inode *inode)/* If we zero-out tail of the page, we have to create jinode for jbd2 */ if (inode->i_size & (inode->i_sb->s_blocksize -1 )) { -if (ext4_inode_attach_jinode (inode) <0 ) + err =ext4_inode_attach_jinode (inode); +if (err) goto out_trace; }
Greg Kroah-Hartman
maintainerPATCH 144/290 ext4: fix undefined behavior in bit shift for ext4_check_flag_values
In reply to Greg Kroah-HartmanFrom: Gaosheng Cui <[email protected]>
commit 3bf678a0f9c017c9ba7c581541dbc8453452a7ae upstream.
Shifting signed 32-bit value by 31 bits is undefined, so changing significant bit to unsigned. The UBSAN warning calltrace like below:
UBSAN: shift-out-of-bounds in fs/ext4/ext4.h:591:2 left shift of 1 by 31 places cannot be represented in type 'int' Call Trace: <TASK> dump_stack_lvl+0x7d/0xa5 dump_stack+0x15/0x1b ubsan_epilogue+0xe/0x4e __ubsan_handle_shift_out_of_bounds+0x1e7/0x20c ext4_init_fs+0x5a/0x277 do_one_initcall+0x76/0x430 kernel_init_freeable+0x3b3/0x422 kernel_init+0x24/0x1e0 ret_from_fork+0x1f/0x30 </TASK>
--- fs/ext4/ext4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/ext4.h +1 -1
@@ -559,7 +559,7 @@ enum {* * It's not paranoia if the Murphy's Law really *is* out to get you. :-) */ -#define TEST_FLAG_VALUE (FLAG ) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG)) +#define TEST_FLAG_VALUE (FLAG ) (EXT4_##FLAG##_FL == (1U << EXT4_INODE_##FLAG))#define CHECK_FLAG_VALUE (FLAG ) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG))static inline void ext4_check_flag_values (void )
Greg Kroah-Hartman
maintainerPATCH 145/290 ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit 63b1e9bccb71fe7d7e3ddc9877dbdc85e5d2d023 upstream.
There are many places that will get unhappy (and crash) when ext4_iget() returns a bad inode. However, if iget the boot loader inode, allows a bad inode to be returned, because the inode may not be initialized. This mechanism can be used to bypass some checks and cause panic. To solve this problem, we add a special iget flag EXT4_IGET_BAD. Only with this flag we'd be returning bad inode from ext4_iget(), otherwise we always return the error code if the inode is bad inode.(suggested by Jan Kara)
--- fs/ext4/ext4.h | 3 ++- fs/ext4/inode.c | 8 +++++++- fs/ext4/ioctl.c | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-)
fs/ext4/ext4.h +2 -1
@@ -2996,7 +2996,8 @@ int do_journal_get_write_access(handle_ttypedef enum {EXT4_IGET_NORMAL =0 ,EXT4_IGET_SPECIAL =0x0001 ,/* OK to iget a system inode */ -EXT4_IGET_HANDLE =0x0002 /* Inode # is from a handle */ +EXT4_IGET_HANDLE =0x0002 ,/* Inode # is from a handle */ +EXT4_IGET_BAD =0x0004 /* Allow to iget a bad inode */ }ext4_iget_flags ; extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
fs/ext4/inode.c +7 -1
@@ -4885,8 +4885,14 @@ struct inode *__ext4_iget(struct super_bif (IS_CASEFOLDED (inode) && !ext4_has_feature_casefold (inode->i_sb))ext4_error_inode (inode, function, line,0 ,"casefold flag without casefold feature" ); -brelse (iloc.bh); +if (is_bad_inode (inode) && !(flags &EXT4_IGET_BAD )) { +ext4_error_inode (inode, function, line,0 , +"bad inode without EXT4_IGET_BAD flag" ); + ret = -EUCLEAN ; + goto bad_inode; + } +brelse (iloc.bh);unlock_new_inode (inode);return inode;
fs/ext4/ioctl.c +2 -1
@@ -124,7 +124,8 @@ static long swap_inode_boot_loader(strucblkcnt_t blocks;unsigned short bytes; - inode_bl =ext4_iget (sb,EXT4_BOOT_LOADER_INO ,EXT4_IGET_SPECIAL ); + inode_bl =ext4_iget (sb,EXT4_BOOT_LOADER_INO , +EXT4_IGET_SPECIAL |EXT4_IGET_BAD );if (IS_ERR (inode_bl))return PTR_ERR (inode_bl); ei_bl =EXT4_I (inode_bl);
Greg Kroah-Hartman
maintainerPATCH 146/290 ext4: add helper to check quota inums
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit 07342ec259df2a35d6a34aebce010567a80a0e15 upstream.
Before quota is enabled, a check on the preset quota inums in ext4_super_block is added to prevent wrong quota inodes from being loaded. In addition, when the quota fails to be enabled, the quota type and quota inum are printed to facilitate fault locating.
--- fs/ext4/super.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-)
fs/ext4/super.c +25 -3
@@ -6309,6 +6309,20 @@ static int ext4_quota_on(struct super_blreturn err; } +static inline bool ext4_check_quota_inum (int type,unsigned long qf_inum) +{ +switch (type) { +case USRQUOTA : +return qf_inum ==EXT4_USR_QUOTA_INO ; +case GRPQUOTA : +return qf_inum ==EXT4_GRP_QUOTA_INO ; +case PRJQUOTA : +return qf_inum >=EXT4_GOOD_OLD_FIRST_INO ; +default : +BUG (); + } +} +static int ext4_quota_enable (struct super_block *sb,int type,int format_id,unsigned int flags) {
@@ -6325,9 +6339,16 @@ static int ext4_quota_enable(struct supeif (!qf_inums[type])return -EPERM ; +if (!ext4_check_quota_inum (type, qf_inums[type])) { +ext4_error (sb,"Bad quota inum: %lu, type: %d" , + qf_inums[type], type); +return -EUCLEAN ; + } + qf_inode =ext4_iget (sb, qf_inums[type],EXT4_IGET_SPECIAL );if (IS_ERR (qf_inode)) { -ext4_error (sb,"Bad quota inode # %lu" , qf_inums[type]); +ext4_error (sb,"Bad quota inode: %lu, type: %d" , + qf_inums[type], type);return PTR_ERR (qf_inode); }
@@ -6366,8 +6387,9 @@ int ext4_enable_quotas(struct super_blocif (err) {ext4_warning (sb,"Failed to enable quota tracking " -"(type=%d, err=%d). Please run " -"e2fsck to fix." , type, err); +"(type=%d, err=%d, ino=%lu). " +"Please run e2fsck to fix." , type, + err, qf_inums[type]);for (type--; type >=0 ; type--) {struct inode *inode;
Greg Kroah-Hartman
maintainerPATCH 147/290 ext4: fix bug_on in __es_tree_search caused by bad quota inode
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit d323877484765aaacbb2769b06e355c2041ed115 upstream.
We got a issue as fllows:
==================================================================
kernel BUG at fs/ext4/extents_status.c:202!
invalid opcode: 0000 [#1] PREEMPT SMP
CPU: 1 PID: 810 Comm: mount Not tainted 6.1.0-rc1-next-g9631525255e3 #352 RIP: 0010:__es_tree_search.isra.0+0xb8/0xe0 RSP: 0018:ffffc90001227900 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 0000000077512a0f RCX: 0000000000000000 RDX: 0000000000000002 RSI: 0000000000002a10 RDI: ffff8881004cd0c8 RBP: ffff888177512ac8 R08: 47ffffffffffffff R09: 0000000000000001 R10: 0000000000000001 R11: 00000000000679af R12: 0000000000002a10 R13: ffff888177512d88 R14: 0000000077512a10 R15: 0000000000000000 FS: 00007f4bd76dbc40(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005653bf993cf8 CR3: 000000017bfdf000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> ext4_es_cache_extent+0xe2/0x210 ext4_cache_extents+0xd2/0x110 ext4_find_extent+0x5d5/0x8c0 ext4_ext_map_blocks+0x9c/0x1d30 ext4_map_blocks+0x431/0xa50 ext4_getblk+0x82/0x340 ext4_bread+0x14/0x110 ext4_quota_read+0xf0/0x180 v2_read_header+0x24/0x90 v2_check_quota_file+0x2f/0xa0 dquot_load_quota_sb+0x26c/0x760 dquot_load_quota_inode+0xa5/0x190 ext4_enable_quotas+0x14c/0x300 __ext4_fill_super+0x31cc/0x32c0 ext4_fill_super+0x115/0x2d0 get_tree_bdev+0x1d2/0x360 ext4_get_tree+0x19/0x30 vfs_get_tree+0x26/0xe0 path_mount+0x81d/0xfc0 do_mount+0x8d/0xc0 __x64_sys_mount+0xc0/0x160 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x63/0xcd </TASK> ==================================================================
Above issue may happen as follows:
-------------------------------------ext4_fill_super
ext4_orphan_cleanup
ext4_enable_quotas
ext4_quota_enable
ext4_iget --> get error inode <5>
ext4_ext_check_inode --> Wrong imode makes it escape inspection
make_bad_inode(inode) --> EXT4_BOOT_LOADER_INO set imode
dquot_load_quota_inode
vfs_setup_quota_inode --> check pass
dquot_load_quota_sb
v2_check_quota_file
v2_read_header
ext4_quota_read
ext4_bread
ext4_getblk
ext4_map_blocks
ext4_ext_map_blocks
ext4_find_extent
ext4_cache_extents
ext4_es_cache_extent
__es_tree_search.isra.0
ext4_es_end --> Wrong extents trigger BUG_ONIn the above issue, s_usr_quota_inum is set to 5, but inode<5> contains incorrect imode and disordered extents. Because 5 is EXT4_BOOT_LOADER_INO, the ext4_ext_check_inode check in the ext4_iget function can be bypassed, finally, the extents that are not checked trigger the BUG_ON in the __es_tree_search function. To solve this issue, check whether the inode is bad_inode in vfs_setup_quota_inode().
--- fs/quota/dquot.c | 2 ++ 1 file changed, 2 insertions(+)
fs/quota/dquot.c +2 -0
@@ -2317,6 +2317,8 @@ static int vfs_setup_quota_inode(structstruct super_block *sb = inode->i_sb;struct quota_info *dqopt =sb_dqopt (sb); +if (is_bad_inode (inode)) +return -EUCLEAN ;if (!S_ISREG (inode->i_mode))return -EACCES ;if (IS_RDONLY (inode))
Greg Kroah-Hartman
maintainerPATCH 148/290 ext4: fix reserved cluster accounting in __es_remove_extent()
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 1da18e38cb97e9521e93d63034521a9649524f64 upstream.
When bigalloc is enabled, reserved cluster accounting for delayed allocation is handled in extent_status.c. With a corrupted file system, it's possible for this accounting to be incorrect, dsicovered by Syzbot:
EXT4-fs error (device loop0): ext4_validate_block_bitmap:398: comm rep:
bg 0: block 5: invalid block bitmap
EXT4-fs (loop0): Delayed block allocation failed for inode 18 at logical
offset 0 with max blocks 32 with error 28
EXT4-fs (loop0): This should not happen!! Data will be lost
EXT4-fs (loop0): Total free blocks count 0
EXT4-fs (loop0): Free/Dirty block details
EXT4-fs (loop0): free_blocks=0
EXT4-fs (loop0): dirty_blocks=32
EXT4-fs (loop0): Block reservation details
EXT4-fs (loop0): i_reserved_data_blocks=2
EXT4-fs (loop0): Inode 18 (00000000845cd634):
i_reserved_data_blocks (1) not cleared!
Above issue happens as follows:
Assume:sbi->s_cluster_ratio = 16
Step1:
Insert delay block [0, 31] -> ei->i_reserved_data_blocks=2 Step2:ext4_writepages
mpage_map_and_submit_extent -> return failed mpage_release_unused_pages -> to release [0, 30]
ext4_es_remove_extent -> remove lblk=0 end=30
__es_remove_extent -> len1=0 len2=31-30=1
__es_remove_extent:
...
if (len2 > 0) {
...
if (len1 > 0) {
...
} else {
es->es_lblk = end + 1;
es->es_len = len2;
...
}
if (count_reserved)
count_rsvd(inode, lblk, ...);
goto out; -> will return but didn't calculate 'reserved' ...
Step3:ext4_destroy_inode -> trigger "i_reserved_data_blocks (1) not cleared!"
To solve above issue if 'len2>0' call 'get_rsvd()' before goto out.
--- fs/ext4/extents_status.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/extents_status.c +2 -1
@@ -1372,7 +1372,7 @@ retry:if (count_reserved)count_rsvd (inode, lblk, orig_es.es_len - len1 - len2, &orig_es, &rc); - goto out; + goto out_get_reserved; }if (len1 >0 ) {
@@ -1414,6 +1414,7 @@ retry: } } +out_get_reserved:if (count_reserved) *reserved =get_rsvd (inode, end, es, &rc); out:
Greg Kroah-Hartman
maintainerPATCH 149/290 ext4: check and assert if marking an no_delete evicting inode dirty
In reply to Greg Kroah-HartmanFrom: Zhang Yi <[email protected]>
commit 318cdc822c63b6e2befcfdc2088378ae6fa18def upstream.
In ext4_evict_inode(), if we evicting an inode in the 'no_delete' path, it cannot be raced by another mark_inode_dirty(). If it happens, someone else may accidentally dirty it without holding inode refcount and probably cause use-after-free issues in the writeback procedure. It's indiscoverable and hard to debug, so add an WARN_ON_ONCE() to check and detect this issue in advance.
--- fs/ext4/inode.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/ext4/inode.c +6 -0
@@ -338,6 +338,12 @@ stop_handle:ext4_xattr_inode_array_free (ea_inode_array);return ; no_delete: +/* +* Check out some where else accidentally dirty the evicting inode, +* which may probably cause inode use-after-free issues later. +*/ +WARN_ON_ONCE (!list_empty_careful (&inode->i_io_list)); +if (!list_empty (&EXT4_I (inode)->i_fc_list))ext4_fc_mark_ineligible (inode->i_sb,EXT4_FC_REASON_NOMEM ,NULL );ext4_clear_inode (inode);/* We must guarantee clearing of inode... */
Greg Kroah-Hartman
maintainerPATCH 150/290 ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit 991ed014de0840c5dc405b679168924afb2952ac upstream.
We got a issue as fllows:
==================================================================
kernel BUG at fs/ext4/extents_status.c:203!
invalid opcode: 0000 [#1] PREEMPT SMP
CPU: 1 PID: 945 Comm: cat Not tainted 6.0.0-next-20221007-dirty #349 RIP: 0010:ext4_es_end.isra.0+0x34/0x42 RSP: 0018:ffffc9000143b768 EFLAGS: 00010203 RAX: 0000000000000000 RBX: ffff8881769cd0b8 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff8fc27cf7 RDI: 00000000ffffffff RBP: ffff8881769cd0bc R08: 0000000000000000 R09: ffffc9000143b5f8 R10: 0000000000000001 R11: 0000000000000001 R12: ffff8881769cd0a0 R13: ffff8881768e5668 R14: 00000000768e52f0 R15: 0000000000000000 FS: 00007f359f7f05c0(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f359f5a2000 CR3: 000000017130c000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> __es_tree_search.isra.0+0x6d/0xf5 ext4_es_cache_extent+0xfa/0x230 ext4_cache_extents+0xd2/0x110 ext4_find_extent+0x5d5/0x8c0 ext4_ext_map_blocks+0x9c/0x1d30 ext4_map_blocks+0x431/0xa50 ext4_mpage_readpages+0x48e/0xe40 ext4_readahead+0x47/0x50 read_pages+0x82/0x530 page_cache_ra_unbounded+0x199/0x2a0 do_page_cache_ra+0x47/0x70 page_cache_ra_order+0x242/0x400 ondemand_readahead+0x1e8/0x4b0 page_cache_sync_ra+0xf4/0x110 filemap_get_pages+0x131/0xb20 filemap_read+0xda/0x4b0 generic_file_read_iter+0x13a/0x250 ext4_file_read_iter+0x59/0x1d0 vfs_read+0x28f/0x460 ksys_read+0x73/0x160 __x64_sys_read+0x1e/0x30 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x63/0xcd </TASK> ==================================================================
In the above issue, ioctl invokes the swap_inode_boot_loader function to swap inode<5> and inode<12>. However, inode<5> contain incorrect imode and disordered extents, and i_nlink is set to 1. The extents check for inode in the ext4_iget function can be bypassed bacause 5 is EXT4_BOOT_LOADER_INO. While links_count is set to 1, the extents are not initialized in swap_inode_boot_loader. After the ioctl command is executed successfully, the extents are swapped to inode<12>, in this case, run the cat command to view inode<12>. And Bug_ON is triggered due to the incorrect extents.
When the boot loader inode is not initialized, its imode can be one of the following:
1) the imode is a bad type, which is marked as bad_inode in ext4_iget and set to S_IFREG.
2) the imode is good type but not S_IFREG.
3) the imode is S_IFREG.
The BUG_ON may be triggered by bypassing the check in cases 1 and 2. Therefore, when the boot loader inode is bad_inode or its imode is not S_IFREG, initialize the inode to avoid triggering the BUG.
--- fs/ext4/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/ioctl.c +1 -1
@@ -175,7 +175,7 @@ static long swap_inode_boot_loader(struc/* Protect extent tree against block allocations via delalloc */ ext4_double_down_write_data_sem (inode, inode_bl); -if (inode_bl->i_nlink ==0 ) { +if (is_bad_inode (inode_bl) || !S_ISREG (inode_bl->i_mode)) {/* this inode has never been used as a BOOT_LOADER */ set_nlink (inode_bl,1 );i_uid_write (inode_bl,0 );
Greg Kroah-Hartman
maintainerPATCH 151/290 ext4: fix leaking uninitialized memory in fast-commit journal
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit 594bc43b410316d70bb42aeff168837888d96810 upstream.
When space at the end of fast-commit journal blocks is unused, make sure to zero it out so that uninitialized memory is not leaked to disk.
--- fs/ext4/fast_commit.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/ext4/fast_commit.c +5 -0
@@ -657,6 +657,9 @@ static u8 *ext4_fc_reserve_space(struct *crc =ext4_chksum (sbi, *crc, tl,sizeof (*tl));if (pad_len >0 )ext4_fc_memzero (sb, tl +1 , pad_len, crc); +/* Don't leak uninitialized memory in the unused last byte. */ + *((u8 *)(tl +1 ) + pad_len) =0 ; +ext4_fc_submit_bh (sb, false); ret =jbd2_fc_get_buf (EXT4_SB (sb)->s_journal, &bh);
@@ -713,6 +716,8 @@ static int ext4_fc_write_tail(struct sup dst +=sizeof (tail.fc_tid); tail.fc_crc =cpu_to_le32 (crc);ext4_fc_memcpy (sb, dst, &tail.fc_crc,sizeof (tail.fc_crc),NULL ); + dst +=sizeof (tail.fc_crc); +memset (dst,0 , bsize - off);/* Don't leak uninitialized memory. */ ext4_fc_submit_bh (sb, true);
Greg Kroah-Hartman
maintainerPATCH 152/290 ext4: fix uninititialized value in ext4_evict_inode
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 7ea71af94eaaaf6d9aed24bc94a05b977a741cb9 upstream.
Syzbot found the following issue:
=====================================================
BUG: KMSAN: uninit-value in ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180 ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180 evict+0x365/0x9a0 fs/inode.c:664 iput_final fs/inode.c:1747 [inline] iput+0x985/0xdd0 fs/inode.c:1773 __ext4_new_inode+0xe54/0x7ec0 fs/ext4/ialloc.c:1361 ext4_mknod+0x376/0x840 fs/ext4/namei.c:2844 vfs_mknod+0x79d/0x830 fs/namei.c:3914 do_mknodat+0x47d/0xaa0 __do_sys_mknodat fs/namei.c:3992 [inline] __se_sys_mknodat fs/namei.c:3989 [inline] __ia32_sys_mknodat+0xeb/0x150 fs/namei.c:3989 do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline] __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178 do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203 do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246 entry_SYSENTER_compat_after_hwframe+0x70/0x82
Uninit was created at:
__alloc_pages+0x9f1/0xe80 mm/page_alloc.c:5578 alloc_pages+0xaae/0xd80 mm/mempolicy.c:2285 alloc_slab_page mm/slub.c:1794 [inline] allocate_slab+0x1b5/0x1010 mm/slub.c:1939 new_slab mm/slub.c:1992 [inline] ___slab_alloc+0x10c3/0x2d60 mm/slub.c:3180 __slab_alloc mm/slub.c:3279 [inline] slab_alloc_node mm/slub.c:3364 [inline] slab_alloc mm/slub.c:3406 [inline] __kmem_cache_alloc_lru mm/slub.c:3413 [inline] kmem_cache_alloc_lru+0x6f3/0xb30 mm/slub.c:3429 alloc_inode_sb include/linux/fs.h:3117 [inline] ext4_alloc_inode+0x5f/0x860 fs/ext4/super.c:1321 alloc_inode+0x83/0x440 fs/inode.c:259 new_inode_pseudo fs/inode.c:1018 [inline] new_inode+0x3b/0x430 fs/inode.c:1046 __ext4_new_inode+0x2a7/0x7ec0 fs/ext4/ialloc.c:959 ext4_mkdir+0x4d5/0x1560 fs/ext4/namei.c:2992 vfs_mkdir+0x62a/0x870 fs/namei.c:4035 do_mkdirat+0x466/0x7b0 fs/namei.c:4060 __do_sys_mkdirat fs/namei.c:4075 [inline] __se_sys_mkdirat fs/namei.c:4073 [inline] __ia32_sys_mkdirat+0xc4/0x120 fs/namei.c:4073 do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline] __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178 do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203 do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246 entry_SYSENTER_compat_after_hwframe+0x70/0x82 CPU: 1 PID: 4625 Comm: syz-executor.2 Not tainted 6.1.0-rc4-syzkaller-62821-gcb231e2f67ec #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 =====================================================
Now, 'ext4_alloc_inode()' didn't init 'ei->i_flags'. If new inode failed before set 'ei->i_flags' in '__ext4_new_inode()', then do 'iput()'. As after 6bc0d63dad7f commit will access 'ei->i_flags' in 'ext4_evict_inode()' which will lead to access uninit-value.
To solve above issue just init 'ei->i_flags' in 'ext4_alloc_inode()'.
--- fs/ext4/super.c | 1 + 1 file changed, 1 insertion(+)
fs/ext4/super.c +1 -0
@@ -1288,6 +1288,7 @@ static struct inode *ext4_alloc_inode(streturn NULL ;inode_set_iversion (&ei->vfs_inode,1 ); + ei->i_flags =0 ;spin_lock_init (&ei->i_raw_lock);INIT_LIST_HEAD (&ei->i_prealloc_list);atomic_set (&ei->i_prealloc_active,0 );
Greg Kroah-Hartman
maintainerPATCH 153/290 ext4: init quota for old.inode in ext4_rename
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit fae381a3d79bb94aa2eb752170d47458d778b797 upstream.
Syzbot found the following issue:ext4_parse_param: s_want_extra_isize=128ext4_inode_info_init: s_want_extra_isize=32ext4_rename: old.inode=ffff88823869a2c8 old.dir=ffff888238699828 new.inode=ffff88823869d7e8 new.dir=ffff888238699828 __ext4_mark_inode_dirty: inode=ffff888238699828 ea_isize=32 want_ea_size=128 __ext4_mark_inode_dirty: inode=ffff88823869a2c8 ea_isize=32 want_ea_size=128ext4_xattr_block_set: inode=ffff88823869a2c8
------------[ cut here ]------------ WARNING: CPU: 13 PID: 2234 at fs/ext4/xattr.c:2070 ext4_xattr_block_set.cold+0x22/0x980 Modules linked in: RIP: 0010:ext4_xattr_block_set.cold+0x22/0x980 RSP: 0018:ffff888227d3f3b0 EFLAGS: 00010202 RAX: 0000000000000001 RBX: ffff88823007a000 RCX: 0000000000000000 RDX: 0000000000000a03 RSI: 0000000000000040 RDI: ffff888230078178 RBP: 0000000000000000 R08: 000000000000002c R09: ffffed1075c7df8e R10: ffff8883ae3efc6b R11: ffffed1075c7df8d R12: 0000000000000000 R13: ffff88823869a2c8 R14: ffff8881012e0460 R15: dffffc0000000000 FS: 00007f350ac1f740(0000) GS:ffff8883ae200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f350a6ed6a0 CR3: 0000000237456000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> ? ext4_xattr_set_entry+0x3b7/0x2320 ? ext4_xattr_block_set+0x0/0x2020 ? ext4_xattr_set_entry+0x0/0x2320 ? ext4_xattr_check_entries+0x77/0x310 ? ext4_xattr_ibody_set+0x23b/0x340 ext4_xattr_move_to_block+0x594/0x720 ext4_expand_extra_isize_ea+0x59a/0x10f0 __ext4_expand_extra_isize+0x278/0x3f0 __ext4_mark_inode_dirty.cold+0x347/0x410 ext4_rename+0xed3/0x174f vfs_rename+0x13a7/0x2510 do_renameat2+0x55d/0x920 __x64_sys_rename+0x7d/0xb0 do_syscall_64+0x3b/0xa0 entry_SYSCALL_64_after_hwframe+0x72/0xdc
As 'ext4_rename' will modify 'old.inode' ctime and mark inode dirty, which may trigger expand 'extra_isize' and allocate block. If inode didn't init quota will lead to warning. To solve above issue, init 'old.inode' firstly in 'ext4_rename'.
--- fs/ext4/namei.c | 3 +++ 1 file changed, 3 insertions(+)
fs/ext4/namei.c +3 -0
@@ -3808,6 +3808,9 @@ static int ext4_rename(struct user_names retval =dquot_initialize (old.dir);if (retval)return retval; + retval =dquot_initialize (old.inode); +if (retval) +return retval; retval =dquot_initialize (new.dir);if (retval)return retval;
Greg Kroah-Hartman
maintainerPATCH 154/290 ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
In reply to Greg Kroah-HartmanFrom: Eric Whitney <[email protected]>
commit 131294c35ed6f777bd4e79d42af13b5c41bf2775 upstream.
When converting files with inline data to extents, delayed allocations made on a file system created with both the bigalloc and inline options can result in invalid extent status cache content, incorrect reserved cluster counts, kernel memory leaks, and potential kernel panics.
With bigalloc, the code that determines whether a block must be delayed allocated searches the extent tree to see if that block maps to a previously allocated cluster. If not, the block is delayed allocated, and otherwise, it isn't. However, if the inline option is also used, and if the file containing the block is marked as able to store data inline, there isn't a valid extent tree associated with the file. The current code in ext4_clu_mapped() calls ext4_find_extent() to search the non-existent tree for a previously allocated cluster anyway, which typically finds nothing, as desired. However, a side effect of the search can be to cache invalid content from the non-existent tree (garbage) in the extent status tree, including bogus entries in the pending reservation tree.
To fix this, avoid searching the extent tree when allocating blocks for bigalloc + inline files that are being converted from inline to extent mapped.
--- fs/ext4/extents.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ext4/extents.c +8 -0
@@ -5810,6 +5810,14 @@ int ext4_clu_mapped(struct inode *inode,struct ext4_extent *extent;ext4_lblk_t first_lblk, first_lclu, last_lclu; +/* +* if data can be stored inline, the logical cluster isn't +* mapped - no physical clusters have been allocated, and the +* file has no extents +*/ +if (ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA )) +return 0 ; +/* search for the extent closest to the first block in the cluster */ path =ext4_find_extent (inode,EXT4_C2B (sbi, lclu),NULL ,0 );if (IS_ERR (path)) {
Greg Kroah-Hartman
maintainerPATCH 155/290 ext4: fix corruption when online resizing a 1K bigalloc fs
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit 0aeaa2559d6d53358fca3e3fce73807367adca74 upstream.
When a backup superblock is updated in update_backups(), the primary superblock's offset in the group (that is, sbi->s_sbh->b_blocknr) is used as the backup superblock's offset in its group. However, when the block size is 1K and bigalloc is enabled, the two offsets are not equal. This causes the backup group descriptors to be overwritten by the superblock in update_backups(). Moreover, if meta_bg is enabled, the file system will be corrupted because this feature uses backup group descriptors.
To solve this issue, we use a more accurate ext4_group_first_block_no() as the offset of the backup superblock in its group.
--- fs/ext4/resize.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/ext4/resize.c +3 -3
@@ -1557,8 +1557,8 @@ exit_journal:int meta_bg =ext4_has_feature_meta_bg (sb);sector_t old_gdb =0 ; -update_backups (sb, sbi->s_sbh->b_blocknr, (char *)es, -sizeof (struct ext4_super_block ),0 ); +update_backups (sb,ext4_group_first_block_no (sb,0 ), + (char *)es,sizeof (struct ext4_super_block ),0 );for (; gdb_num <= gdb_num_end; gdb_num++) {struct buffer_head *gdb_bh;
@@ -1769,7 +1769,7 @@ errout:if (test_opt (sb,DEBUG ))printk (KERN_DEBUG "EXT4-fs: extended group to %llu " "blocks\n" ,ext4_blocks_count (es)); -update_backups (sb,EXT4_SB (sb)->s_sbh->b_blocknr, +update_backups (sb,ext4_group_first_block_no (sb,0 ), (char *)es,sizeof (struct ext4_super_block ),0 ); }return err;
Greg Kroah-Hartman
maintainerPATCH 156/290 ext4: fix error code return to user-space in ext4_get_branch()
In reply to Greg Kroah-HartmanFrom: Luís Henriques <[email protected]>
commit 26d75a16af285a70863ba6a81f85d81e7e65da50 upstream.
If a block is out of range in ext4_get_branch(), -ENOMEM will be returned to user-space. Obviously, this error code isn't really useful. This patch fixes it by making sure the right error code (-EFSCORRUPTED) is propagated to user-space. EUCLEAN is more informative than ENOMEM.
--- fs/ext4/indirect.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/ext4/indirect.c +8 -1
@@ -148,6 +148,7 @@ static Indirect *ext4_get_branch(structstruct super_block *sb = inode->i_sb;Indirect *p = chain;struct buffer_head *bh; +unsigned int key;int ret = -EIO ; *err =0 ;
@@ -156,7 +157,13 @@ static Indirect *ext4_get_branch(structif (!p->key) goto no_block;while (--depth) { - bh =sb_getblk (sb,le32_to_cpu (p->key)); + key =le32_to_cpu (p->key); +if (key >ext4_blocks_count (EXT4_SB (sb)->s_es)) { +/* the block was out of range */ + ret = -EFSCORRUPTED ; + goto failure; + } + bh =sb_getblk (sb, key);if (unlikely (!bh)) { ret = -ENOMEM ; goto failure;
Greg Kroah-Hartman
maintainerPATCH 157/290 ext4: avoid BUG_ON when creating xattrs
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit b40ebaf63851b3a401b0dc9263843538f64f5ce6 upstream.
Commit fb0a387dcdcd ("ext4: limit block allocations for indirect-block files to < 2^32") added code to try to allocate xattr block with 32-bit block number for indirect block based files on the grounds that these files cannot use larger block numbers. It also added BUG_ON when allocated block could not fit into 32 bits. This is however bogus reasoning because xattr block is stored in inode->i_file_acl and inode->i_file_acl_hi and as such even indirect block based files can happily use full 48 bits for xattr block number. The proper handling seems to be there basically since 64-bit block number support was added. So remove the bogus limitation and BUG_ON.
--- fs/ext4/xattr.c | 8 -------- 1 file changed, 8 deletions(-)
fs/ext4/xattr.c +0 -8
@@ -2070,19 +2070,11 @@ inserted: goal =ext4_group_first_block_no (sb,EXT4_I (inode)->i_block_group); - -/* non-extent files can't have physical blocks past 2^32 */ -if (!(ext4_test_inode_flag (inode,EXT4_INODE_EXTENTS ))) - goal = goal &EXT4_MAX_BLOCK_FILE_PHYS ; - block =ext4_new_meta_blocks (handle, inode, goal,0 ,NULL , &error);if (error) goto cleanup; -if (!(ext4_test_inode_flag (inode,EXT4_INODE_EXTENTS ))) -BUG_ON (block >EXT4_MAX_BLOCK_FILE_PHYS ); -ea_idebug (inode,"creating block %llu" , (unsigned long long )block);
Greg Kroah-Hartman
maintainerPATCH 158/290 ext4: fix kernel BUG in ext4_write_inline_data_end()
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 5c099c4fdc438014d5893629e70a8ba934433ee8 upstream.
Syzbot report follow issue:
------------[ cut here ]------------ kernel BUG at fs/ext4/inline.c:227! invalid opcode: 0000 [#1] PREEMPT SMP KASAN CPU: 1 PID: 3629 Comm: syz-executor212 Not tainted 6.1.0-rc5-syzkaller-00018-g59d0d52c30d4 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 RIP: 0010:ext4_write_inline_data+0x344/0x3e0 fs/ext4/inline.c:227 RSP: 0018:ffffc90003b3f368 EFLAGS: 00010293 RAX: 0000000000000000 RBX: ffff8880704e16c0 RCX: 0000000000000000 RDX: ffff888021763a80 RSI: ffffffff821e31a4 RDI: 0000000000000006 RBP: 000000000006818e R08: 0000000000000006 R09: 0000000000068199 R10: 0000000000000079 R11: 0000000000000000 R12: 000000000000000b R13: 0000000000068199 R14: ffffc90003b3f408 R15: ffff8880704e1c82 FS: 000055555723e3c0(0000) GS:ffff8880b9b00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fffe8ac9080 CR3: 0000000079f81000 CR4: 0000000000350ee0 Call Trace: <TASK> ext4_write_inline_data_end+0x2a3/0x12f0 fs/ext4/inline.c:768 ext4_write_end+0x242/0xdd0 fs/ext4/inode.c:1313 ext4_da_write_end+0x3ed/0xa30 fs/ext4/inode.c:3063 generic_perform_write+0x316/0x570 mm/filemap.c:3764 ext4_buffered_write_iter+0x15b/0x460 fs/ext4/file.c:285 ext4_file_write_iter+0x8bc/0x16e0 fs/ext4/file.c:700 call_write_iter include/linux/fs.h:2191 [inline] do_iter_readv_writev+0x20b/0x3b0 fs/read_write.c:735 do_iter_write+0x182/0x700 fs/read_write.c:861 vfs_iter_write+0x74/0xa0 fs/read_write.c:902 iter_file_splice_write+0x745/0xc90 fs/splice.c:686 do_splice_from fs/splice.c:764 [inline] direct_splice_actor+0x114/0x180 fs/splice.c:931 splice_direct_to_actor+0x335/0x8a0 fs/splice.c:886 do_splice_direct+0x1ab/0x280 fs/splice.c:974 do_sendfile+0xb19/0x1270 fs/read_write.c:1255 __do_sys_sendfile64 fs/read_write.c:1323 [inline] __se_sys_sendfile64 fs/read_write.c:1309 [inline] __x64_sys_sendfile64+0x1d0/0x210 fs/read_write.c:1309 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd ---[ end trace 0000000000000000 ]---
Above issue may happens as follows:ext4_da_write_begin
ext4_da_write_inline_data_begin
ext4_da_convert_inline_data_to_extent
ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);ext4_da_write_end
ext4_run_li_request
ext4_mb_prefetch
ext4_read_block_bitmap_nowait
ext4_validate_block_bitmap
ext4_mark_group_bitmap_corrupted(sb, block_group, EXT4_GROUP_INFO_BBITMAP_CORRUPT)
percpu_counter_sub(&sbi->s_freeclusters_counter,grp->bb_free);
-> sbi->s_freeclusters_counter become zero
ext4_da_write_begin
if (ext4_nonda_switch(inode->i_sb)) -> As freeclusters_counter is zero will return true
*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
ext4_write_begin
ext4_da_write_end
if (write_mode == FALL_BACK_TO_NONDELALLOC)
ext4_write_end
if (inline_data)
ext4_write_inline_data_end
ext4_write_inline_data
BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
-> As inode is already convert to extent, so 'pos + len' > inline_size
-> then trigger BUG.To solve this issue, instead of checking ext4_has_inline_data() which is only cleared after data has been written back, check the EXT4_STATE_MAY_INLINE_DATA flag in ext4_write_end().
--- fs/ext4/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/inode.c +2 -1
@@ -1304,7 +1304,8 @@ static int ext4_write_end(struct file *ftrace_ext4_write_end (inode, pos, len, copied); -if (ext4_has_inline_data (inode)) +if (ext4_has_inline_data (inode) && +ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA ))return ext4_write_inline_data_end (inode, pos, len, copied, page); copied =block_write_end (file, mapping, pos, len, copied, page, fsdata);
Greg Kroah-Hartman
maintainerPATCH 159/290 ext4: fix inode leak in ext4_xattr_inode_create() on an error path
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit e4db04f7d3dbbe16680e0ded27ea2a65b10f766a upstream.
There is issue as follows when do setxattr with inject fault:
[localhost]# fsck.ext4 -fn /dev/sda
e2fsck 1.46.6-rc1 (12-Sep-2022)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Unattached zero-length inode 15. Clear? no
Unattached inode 15
Connect to /lost+found? no
Pass 5: Checking group summary information
/dev/sda: ********** WARNING: Filesystem still has errors **********
/dev/sda: 15/655360 files (0.0% non-contiguous), 66755/2621440 blocks
This occurs in 'ext4_xattr_inode_create()'. If 'ext4_mark_inode_dirty()' fails, dropping i_nlink of the inode is needed. Or will lead to inode leak.
--- fs/ext4/xattr.c | 3 +++ 1 file changed, 3 insertions(+)
fs/ext4/xattr.c +3 -0
@@ -1441,6 +1441,9 @@ static struct inode *ext4_xattr_inode_crif (!err) err =ext4_inode_attach_jinode (ea_inode);if (err) { +if (ext4_xattr_inode_dec_ref (handle, ea_inode)) +ext4_warning_inode (ea_inode, +"cleanup dec ref error %d" , err);iput (ea_inode);return ERR_PTR (err); }
Greg Kroah-Hartman
maintainerPATCH 160/290 ext4: initialize quota before expanding inode in setproject ioctl
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 1485f726c6dec1a1f85438f2962feaa3d585526f upstream.
Make sure we initialize quotas before possibly expanding inode space (and thus maybe needing to allocate external xattr block) in ext4_ioctl_setproject(). This prevents not accounting the necessary block allocation.
--- fs/ext4/ioctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/ext4/ioctl.c +4 -4
@@ -492,6 +492,10 @@ static int ext4_ioctl_setproject(structif (ext4_is_quota_file (inode))return err; + err =dquot_initialize (inode); +if (err) +return err; + err =ext4_get_inode_loc (inode, &iloc);if (err)return err;
@@ -507,10 +511,6 @@ static int ext4_ioctl_setproject(structbrelse (iloc.bh); } - err =dquot_initialize (inode); -if (err) -return err; - handle =ext4_journal_start (inode,EXT4_HT_QUOTA ,EXT4_QUOTA_INIT_BLOCKS (sb) +EXT4_QUOTA_DEL_BLOCKS (sb) +3 );
Greg Kroah-Hartman
maintainerPATCH 161/290 ext4: avoid unaccounted block allocation when expanding inode
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 8994d11395f8165b3deca1971946f549f0822630 upstream.
When expanding inode space in ext4_expand_extra_isize_ea() we may need to allocate external xattr block. If quota is not initialized for the inode, the block allocation will not be accounted into quota usage. Make sure the quota is initialized before we try to expand inode space.
--- fs/ext4/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ext4/inode.c +8 -0
@@ -5813,6 +5813,14 @@ static int __ext4_expand_extra_isize(strreturn 0 ; } +/* +* We may need to allocate external xattr block so we need quotas +* initialized. Here we can be called with various locks held so we +* cannot affort to initialize quotas ourselves. So just bail. +*/ +if (dquot_initialize_needed (inode)) +return -EAGAIN ; +/* try to expand with EAs present */ error =ext4_expand_extra_isize_ea (inode, new_extra_isize, raw_inode, handle);
Greg Kroah-Hartman
maintainerPATCH 162/290 ext4: allocate extended attribute value in vmalloc area
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit cc12a6f25e07ed05d5825a1664b67a970842b2ca upstream.
Now, extended attribute value maximum length is 64K. The memory requested here does not need continuous physical addresses, so it is appropriate to use kvmalloc to request memory. At the same time, it can also cope with the situation that the extended attribute will become longer in the future.
--- fs/ext4/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/ext4/xattr.c +2 -2
@@ -2549,7 +2549,7 @@ static int ext4_xattr_move_to_block(hand is =kzalloc (sizeof (struct ext4_xattr_ibody_find ),GFP_NOFS ); bs =kzalloc (sizeof (struct ext4_xattr_block_find ),GFP_NOFS ); - buffer =kmalloc (value_size,GFP_NOFS ); + buffer =kvmalloc (value_size,GFP_NOFS ); b_entry_name =kmalloc (entry->e_name_len +1 ,GFP_NOFS );if (!is || !bs || !buffer || !b_entry_name) { error = -ENOMEM ;
@@ -2601,7 +2601,7 @@ static int ext4_xattr_move_to_block(hand error =0 ; out:kfree (b_entry_name); -kfree (buffer); +kvfree (buffer);if (is)brelse (is->iloc.bh);if (bs)
Greg Kroah-Hartman
maintainerPATCH 163/290 drm/amdgpu: handle polaris10/11 overlap asics (v2)
In reply to Greg Kroah-HartmanFrom: Alex Deucher <[email protected]>
commit 1d4624cd72b912b2680c08d0be48338a1629a858 upstream.
Some special polaris 10 chips overlap with the polaris11 DID range. Handle this properly in the driver.
v2: use local flags for other function calls.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +11 -2
@@ -2008,6 +2008,15 @@ static int amdgpu_pci_probe(struct pci_d "See modparam exp_hw_support\n");return -ENODEV ; } +/* differentiate between P10 and P11 asics with the same DID */ +if (pdev->device ==0x67FF && + (pdev->revision ==0xE3 || + pdev->revision ==0xE7 || + pdev->revision ==0xF3 || + pdev->revision ==0xF7 )) { + flags &= ~AMD_ASIC_MASK ; + flags |=CHIP_POLARIS10 ; + }/* Due to hardware bugs, S/G Display on raven requires a 1:1 IOMMU mapping, * however, SME requires an indirect IOMMU mapping because the encryption
@@ -2081,12 +2090,12 @@ static int amdgpu_pci_probe(struct pci_dpci_set_drvdata (pdev, ddev); - ret =amdgpu_driver_load_kms (adev, ent->driver_data); + ret =amdgpu_driver_load_kms (adev, flags);if (ret) goto err_pci; retry_init: - ret =drm_dev_register (ddev, ent->driver_data); + ret =drm_dev_register (ddev, flags);if (ret == -EAGAIN && ++retry <=3 ) {DRM_INFO ("retry init %d\n" , retry);/* Don't request EX mode too frequently which is attacking */
Greg Kroah-Hartman
maintainerPATCH 164/290 drm/amdgpu: make display pinning more flexible (v2)
In reply to Greg Kroah-HartmanFrom: Alex Deucher <[email protected]>
commit 81d0bcf9900932633d270d5bc4a54ff599c6ebdb upstream.
Only apply the static threshold for Stoney and Carrizo. This hardware has certain requirements that don't allow mixing of GTT and VRAM. Newer asics do not have these requirements so we should be able to be more flexible with where buffers end up.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +2 -1
@@ -1510,7 +1510,8 @@ u64 amdgpu_bo_gpu_offset_no_check(structuint32_t amdgpu_bo_get_preferred_domain (struct amdgpu_device *adev,uint32_t domain) { -if (domain == (AMDGPU_GEM_DOMAIN_VRAM |AMDGPU_GEM_DOMAIN_GTT )) { +if ((domain == (AMDGPU_GEM_DOMAIN_VRAM |AMDGPU_GEM_DOMAIN_GTT )) && + ((adev->asic_type ==CHIP_CARRIZO ) || (adev->asic_type ==CHIP_STONEY ))) { domain =AMDGPU_GEM_DOMAIN_VRAM ;if (adev->gmc.real_vram_size <=AMDGPU_SG_THRESHOLD ) domain =AMDGPU_GEM_DOMAIN_GTT ;
Greg Kroah-Hartman
maintainerPATCH 165/290 block: mq-deadline: Fix dd_finish_request() for zoned devices
In reply to Greg Kroah-HartmanFrom: Damien Le Moal <[email protected]>
commit 2820e5d0820ac4daedff1272616a53d9c7682fd2 upstream.
dd_finish_request() tests if the per prio fifo_list is not empty to determine if request dispatching must be restarted for handling blocked write requests to zoned devices with a call to blk_mq_sched_mark_restart_hctx(). While simple, this implementation has 2 problems:
1) Only the priority level of the completed request is considered. However, writes to a zone may be blocked due to other writes to the same zone using a different priority level. While this is unlikely to happen in practice, as writing a zone with different IO priorirites does not make sense, nothing in the code prevents this from happening.
2) The use of list_empty() is dangerous as dd_finish_request() does not take dd->lock and may run concurrently with the insert and dispatch code.
Fix these 2 problems by testing the write fifo list of all priority levels using the new helper dd_has_write_work(), and by testing each fifo list using list_empty_careful().
--- block/mq-deadline.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
block/mq-deadline.c +15 -3
@@ -791,6 +791,18 @@ static void dd_prepare_request(struct re rq->elv.priv[0 ] =NULL ; } +static bool dd_has_write_work (struct blk_mq_hw_ctx *hctx) +{ +struct deadline_data *dd = hctx->queue->elevator->elevator_data; +enum dd_prio p; + +for (p =0 ; p <=DD_PRIO_MAX ; p++) +if (!list_empty_careful (&dd->per_prio[p].fifo_list[DD_WRITE ])) +return true; + +return false; +} +/* * Callback from inside blk_mq_free_request(). *
@@ -813,7 +825,6 @@ static void dd_finish_request(struct reqstruct deadline_data *dd = q->elevator->elevator_data;const u8 ioprio_class =dd_rq_ioclass (rq);const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; -struct dd_per_prio *per_prio = &dd->per_prio[prio];/* * The block layer core may call dd_finish_request() without having
@@ -829,9 +840,10 @@ static void dd_finish_request(struct reqspin_lock_irqsave (&dd->zone_lock, flags);blk_req_zone_write_unlock (rq); -if (!list_empty (&per_prio->fifo_list[DD_WRITE ])) -blk_mq_sched_mark_restart_hctx (rq->mq_hctx);spin_unlock_irqrestore (&dd->zone_lock, flags); + +if (dd_has_write_work (rq->mq_hctx)) +blk_mq_sched_mark_restart_hctx (rq->mq_hctx); } }
Greg Kroah-Hartman
maintainerPATCH 166/290 tracing: Fix issue of missing one synthetic field
In reply to Greg Kroah-HartmanFrom: Zheng Yejian <[email protected]>
commit ff4837f7fe59ff018eca4705a70eca5e0b486b97 upstream.
The maximum number of synthetic fields supported is defined as SYNTH_FIELDS_MAX which value currently is 64, but it actually fails when try to generate a synthetic event with 64 fields by executing like:
# echo "my_synth_event int v1; int v2; int v3; int v4; int v5; int v6;\ int v7; int v8; int v9; int v10; int v11; int v12; int v13; int v14;\ int v15; int v16; int v17; int v18; int v19; int v20; int v21; int v22;\ int v23; int v24; int v25; int v26; int v27; int v28; int v29; int v30;\ int v31; int v32; int v33; int v34; int v35; int v36; int v37; int v38;\ int v39; int v40; int v41; int v42; int v43; int v44; int v45; int v46;\ int v47; int v48; int v49; int v50; int v51; int v52; int v53; int v54;\ int v55; int v56; int v57; int v58; int v59; int v60; int v61; int v62;\ int v63; int v64" >> /sys/kernel/tracing/synthetic_events
Correct the field counting to fix it.
--- kernel/trace/trace_events_synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_events_synth.c +1 -1
@@ -1275,12 +1275,12 @@ static int __create_synth_event(const ch goto err; } - fields[n_fields++] = field;if (n_fields ==SYNTH_FIELDS_MAX ) {synth_err (SYNTH_ERR_TOO_MANY_FIELDS ,0 ); ret = -EINVAL ; goto err; } + fields[n_fields++] = field; n_fields_this_loop++; }
Greg Kroah-Hartman
maintainerPATCH 167/290 ext4: remove unused enum EXT4_FC_COMMIT_FAILED
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Ritesh Harjani <[email protected]>
commit c864ccd182d6ff2730a0f5b636c6b7c48f6f4f7f upstream.
Below commit removed all references of EXT4_FC_COMMIT_FAILED. commit 0915e464cb274 ("ext4: simplify updating of fast commit stats")
Just remove it since it is not used anymore.
--- fs/ext4/fast_commit.h | 1 - 1 file changed, 1 deletion(-)
fs/ext4/fast_commit.h +0 -1
@@ -93,7 +93,6 @@ enum {EXT4_FC_REASON_RENAME_DIR ,EXT4_FC_REASON_FALLOC_RANGE ,EXT4_FC_REASON_INODE_JOURNAL_DATA , -EXT4_FC_COMMIT_FAILED , EXT4_FC_REASON_MAX };
Greg Kroah-Hartman
maintainerPATCH 168/290 ext4: use ext4_debug() instead of jbd_debug()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Jan Kara <[email protected]>
commit 4978c659e7b5c1926cdb4b556e4ca1fd2de8ad42 upstream.
We use jbd_debug() in some places in ext4. It seems a bit strange to use jbd2 debugging output function for ext4 code. Also these days ext4_debug() uses dynamic printk so each debug message can be enabled / disabled on its own so the time when it made some sense to have these combined (to allow easier common selecting of messages to report) has passed. Just convert all jbd_debug() uses in ext4 to ext4_debug().
--- fs/ext4/balloc.c | 2 +- fs/ext4/ext4_jbd2.c | 3 +-- fs/ext4/fast_commit.c | 44 ++++++++++++++++++++++---------------------- fs/ext4/indirect.c | 4 ++-- fs/ext4/inode.c | 2 +- fs/ext4/orphan.c | 24 ++++++++++++------------ fs/ext4/super.c | 2 +- 7 files changed, 40 insertions(+), 41 deletions(-)
fs/ext4/balloc.c +1 -1
@@ -665,7 +665,7 @@ int ext4_should_retry_alloc(struct super* it's possible we've just missed a transaction commit here, * so ignore the returned status */ -jbd_debug (1 ,"%s: retrying operation after ENOSPC\n" , sb->s_id); +ext4_debug ("%s: retrying operation after ENOSPC\n" , sb->s_id); (void )jbd2_journal_force_commit_nested (sbi->s_journal);return 1 ; }
fs/ext4/ext4_jbd2.c +1 -2
@@ -267,8 +267,7 @@ int __ext4_forget(const char *where, unstrace_ext4_forget (inode, is_metadata, blocknr);BUFFER_TRACE (bh,"enter" ); -jbd_debug (4 ,"forgetting bh %p: is_metadata = %d, mode %o, " -"data mode %x\n" , +ext4_debug ("forgetting bh %p: is_metadata=%d, mode %o, data mode %x\n" , bh, is_metadata, inode->i_mode,test_opt (inode->i_sb,DATA_FLAGS ));
fs/ext4/fast_commit.c +22 -22
170 lines not on this page · raw message
fs/ext4/indirect.c +2 -2
@@ -467,7 +467,7 @@ static int ext4_splice_branch(handle_t ** the new i_size. But that is not done here - it is done in * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. */ -jbd_debug (5 ,"splicing indirect only\n" ); +ext4_debug ("splicing indirect only\n" );BUFFER_TRACE (where->bh,"call ext4_handle_dirty_metadata" ); err =ext4_handle_dirty_metadata (handle, ar->inode, where->bh);if (err)
@@ -479,7 +479,7 @@ static int ext4_splice_branch(handle_t * err =ext4_mark_inode_dirty (handle, ar->inode);if (unlikely (err)) goto err_out; -jbd_debug (5 ,"splicing direct\n" ); +ext4_debug ("splicing direct\n" ); }return err;
fs/ext4/inode.c +1 -1
@@ -5220,7 +5220,7 @@ int ext4_write_inode(struct inode *inodeif (EXT4_SB (inode->i_sb)->s_journal) {if (ext4_journal_current_handle ()) { -jbd_debug (1 ,"called recursively, non-PF_MEMALLOC!\n" ); +ext4_debug ("called recursively, non-PF_MEMALLOC!\n" );dump_stack ();return -EIO ; }
fs/ext4/orphan.c +12 -12
@@ -181,8 +181,8 @@ int ext4_orphan_add(handle_t *handle, st }else brelse (iloc.bh); -jbd_debug (4 ,"superblock will point to %lu\n" , inode->i_ino); -jbd_debug (4 ,"orphan inode %lu will point to %d\n" , +ext4_debug ("superblock will point to %lu\n" , inode->i_ino); +ext4_debug ("orphan inode %lu will point to %d\n" , inode->i_ino,NEXT_ORPHAN (inode)); out:ext4_std_error (sb, err);
@@ -251,7 +251,7 @@ int ext4_orphan_del(handle_t *handle, st }mutex_lock (&sbi->s_orphan_lock); -jbd_debug (4 ,"remove inode %lu from orphan list\n" , inode->i_ino); +ext4_debug ("remove inode %lu from orphan list\n" , inode->i_ino); prev = ei->i_orphan.prev;list_del_init (&ei->i_orphan);
@@ -267,7 +267,7 @@ int ext4_orphan_del(handle_t *handle, st ino_next =NEXT_ORPHAN (inode);if (prev == &sbi->s_orphan) { -jbd_debug (4 ,"superblock will point to %u\n" , ino_next); +ext4_debug ("superblock will point to %u\n" , ino_next);BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); err =ext4_journal_get_write_access (handle, inode->i_sb, sbi->s_sbh,EXT4_JTR_NONE );
@@ -286,7 +286,7 @@ int ext4_orphan_del(handle_t *handle, ststruct inode *i_prev = &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode; -jbd_debug (4 ,"orphan inode %lu will point to %u\n" , +ext4_debug ("orphan inode %lu will point to %u\n" , i_prev->i_ino, ino_next); err =ext4_reserve_inode_write (handle, i_prev, &iloc2);if (err) {
@@ -332,8 +332,8 @@ static void ext4_process_orphan(struct iext4_msg (sb,KERN_DEBUG ,"%s: truncating inode %lu to %lld bytes" , __func__, inode->i_ino, inode->i_size); -jbd_debug (2 ,"truncating inode %lu to %lld bytes\n" , - inode->i_ino, inode->i_size); +ext4_debug ("truncating inode %lu to %lld bytes\n" , + inode->i_ino, inode->i_size);inode_lock (inode);truncate_inode_pages (inode->i_mapping, inode->i_size); ret =ext4_truncate (inode);
@@ -353,8 +353,8 @@ static void ext4_process_orphan(struct iext4_msg (sb,KERN_DEBUG ,"%s: deleting unreferenced inode %lu" , __func__, inode->i_ino); -jbd_debug (2 ,"deleting unreferenced inode %lu\n" , - inode->i_ino); +ext4_debug ("deleting unreferenced inode %lu\n" , + inode->i_ino); (*nr_orphans)++; }iput (inode);/* The delete magic happens here! */
@@ -391,7 +391,7 @@ void ext4_orphan_cleanup(struct super_blint inodes_per_ob =ext4_inodes_per_orphan_block (sb);if (!es->s_last_orphan && !oi->of_blocks) { -jbd_debug (4 ,"no orphan inodes to clean up\n" ); +ext4_debug ("no orphan inodes to clean up\n" );return ; }
@@ -415,7 +415,7 @@ void ext4_orphan_cleanup(struct super_bl "clearing orphan list."); es->s_last_orphan =0 ; } -jbd_debug (1 ,"Skipping orphan recovery on fs with errors.\n" ); +ext4_debug ("Skipping orphan recovery on fs with errors.\n" );return ; }
@@ -459,7 +459,7 @@ void ext4_orphan_cleanup(struct super_bl* so, skip the rest. */ if (EXT4_SB (sb)->s_mount_state &EXT4_ERROR_FS ) { -jbd_debug (1 ,"Skipping orphan recovery on fs with errors.\n" ); +ext4_debug ("Skipping orphan recovery on fs with errors.\n" ); es->s_last_orphan =0 ;break ; }
fs/ext4/super.c +1 -1
@@ -5154,7 +5154,7 @@ static struct inode *ext4_get_journal_inreturn NULL ; } -jbd_debug (2 ,"Journal inode found at %p: %lld bytes\n" , +ext4_debug ("Journal inode found at %p: %lld bytes\n" , journal_inode, journal_inode->i_size);if (!S_ISREG (journal_inode->i_mode)) {ext4_msg (sb,KERN_ERR ,"invalid journal inode" );
Greg Kroah-Hartman
maintainerPATCH 169/290 ext4: introduce EXT4_FC_TAG_BASE_LEN helper
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Ye Bin <[email protected]>
commit fdc2a3c75dd8345c5b48718af90bad1a7811bedb upstream.
Introduce EXT4_FC_TAG_BASE_LEN helper for calculate length of struct ext4_fc_tl.
--- fs/ext4/fast_commit.c | 54 +++++++++++++++++++++++++------------------------- fs/ext4/fast_commit.h | 3 ++ 2 files changed, 31 insertions(+), 26 deletions(-)
fs/ext4/fast_commit.c +28 -26
@@ -631,10 +631,10 @@ static u8 *ext4_fc_reserve_space(struct* After allocating len, we should have space at least for a 0 byte * padding. */ -if (len +sizeof (struct ext4_fc_tl ) > bsize) +if (len +EXT4_FC_TAG_BASE_LEN > bsize)return NULL ; -if (bsize - off -1 > len +sizeof (struct ext4_fc_tl )) { +if (bsize - off -1 > len +EXT4_FC_TAG_BASE_LEN ) {/* * Only allocate from current buffer if we have enough space for * this request AND we have space to add a zero byte padding.
@@ -651,10 +651,10 @@ static u8 *ext4_fc_reserve_space(struct/* Need to add PAD tag */ tl = (struct ext4_fc_tl *)(sbi->s_fc_bh->b_data + off); tl->fc_tag =cpu_to_le16 (EXT4_FC_TAG_PAD ); - pad_len = bsize - off -1 -sizeof (struct ext4_fc_tl ); + pad_len = bsize - off -1 -EXT4_FC_TAG_BASE_LEN ; tl->fc_len =cpu_to_le16 (pad_len);if (crc) - *crc =ext4_chksum (sbi, *crc, tl,sizeof (*tl)); + *crc =ext4_chksum (sbi, *crc, tl,EXT4_FC_TAG_BASE_LEN );if (pad_len >0 )ext4_fc_memzero (sb, tl +1 , pad_len, crc);/* Don't leak uninitialized memory in the unused last byte. */
@@ -699,7 +699,7 @@ static int ext4_fc_write_tail(struct sup* ext4_fc_reserve_space takes care of allocating an extra block if * there's no enough space on this block for accommodating this tail. */ - dst =ext4_fc_reserve_space (sb,sizeof (tl) +sizeof (tail), &crc); + dst =ext4_fc_reserve_space (sb,EXT4_FC_TAG_BASE_LEN +sizeof (tail), &crc);if (!dst)return -ENOSPC ;
@@ -709,8 +709,8 @@ static int ext4_fc_write_tail(struct sup tl.fc_len =cpu_to_le16 (bsize - off -1 +sizeof (struct ext4_fc_tail )); sbi->s_fc_bytes =round_up (sbi->s_fc_bytes, bsize); -ext4_fc_memcpy (sb, dst, &tl,sizeof (tl), &crc); - dst +=sizeof (tl); +ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , &crc); + dst +=EXT4_FC_TAG_BASE_LEN ; tail.fc_tid =cpu_to_le32 (sbi->s_journal->j_running_transaction->t_tid);ext4_fc_memcpy (sb, dst, &tail.fc_tid,sizeof (tail.fc_tid), &crc); dst +=sizeof (tail.fc_tid);
@@ -734,15 +734,15 @@ static bool ext4_fc_add_tlv(struct superstruct ext4_fc_tl tl;u8 *dst; - dst =ext4_fc_reserve_space (sb,sizeof (tl) + len, crc); + dst =ext4_fc_reserve_space (sb,EXT4_FC_TAG_BASE_LEN + len, crc);if (!dst)return false; tl.fc_tag =cpu_to_le16 (tag); tl.fc_len =cpu_to_le16 (len); -ext4_fc_memcpy (sb, dst, &tl,sizeof (tl), crc); -ext4_fc_memcpy (sb, dst +sizeof (tl), val, len, crc); +ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , crc); +ext4_fc_memcpy (sb, dst +EXT4_FC_TAG_BASE_LEN , val, len, crc);return true; }
@@ -754,8 +754,8 @@ static bool ext4_fc_add_dentry_tlv(strucstruct ext4_fc_dentry_info fcd;struct ext4_fc_tl tl;int dlen = fc_dentry->fcd_name.len; -u8 *dst =ext4_fc_reserve_space (sb,sizeof (tl) +sizeof (fcd) + dlen, - crc); +u8 *dst =ext4_fc_reserve_space (sb, +EXT4_FC_TAG_BASE_LEN +sizeof (fcd) + dlen, crc);if (!dst)return false;
@@ -764,8 +764,8 @@ static bool ext4_fc_add_dentry_tlv(struc fcd.fc_ino =cpu_to_le32 (fc_dentry->fcd_ino); tl.fc_tag =cpu_to_le16 (fc_dentry->fcd_op); tl.fc_len =cpu_to_le16 (sizeof (fcd) + dlen); -ext4_fc_memcpy (sb, dst, &tl,sizeof (tl), crc); - dst +=sizeof (tl); +ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , crc); + dst +=EXT4_FC_TAG_BASE_LEN ;ext4_fc_memcpy (sb, dst, &fcd,sizeof (fcd), crc); dst +=sizeof (fcd);ext4_fc_memcpy (sb, dst, fc_dentry->fcd_name.name, dlen, crc);
@@ -801,13 +801,13 @@ static int ext4_fc_write_inode(struct in ret = -ECANCELED ; dst =ext4_fc_reserve_space (inode->i_sb, -sizeof (tl) + inode_len +sizeof (fc_inode.fc_ino), crc); +EXT4_FC_TAG_BASE_LEN + inode_len +sizeof (fc_inode.fc_ino), crc);if (!dst) goto err; -if (!ext4_fc_memcpy (inode->i_sb, dst, &tl,sizeof (tl), crc)) +if (!ext4_fc_memcpy (inode->i_sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , crc)) goto err; - dst +=sizeof (tl); + dst +=EXT4_FC_TAG_BASE_LEN ;if (!ext4_fc_memcpy (inode->i_sb, dst, &fc_inode,sizeof (fc_inode), crc)) goto err; dst +=sizeof (fc_inode);
@@ -1957,9 +1957,10 @@ static int ext4_fc_replay_scan(journal_t } state->fc_replay_expected_off++; -for (cur = start; cur < end; cur = cur +sizeof (tl) +le16_to_cpu (tl.fc_len)) { -memcpy (&tl, cur,sizeof (tl)); - val = cur +sizeof (tl); +for (cur = start; cur < end; + cur = cur +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)) { +memcpy (&tl, cur,EXT4_FC_TAG_BASE_LEN ); + val = cur +EXT4_FC_TAG_BASE_LEN ;ext4_debug ("Scan phase, tag:%s, blk %lld\n" ,tag2str (le16_to_cpu (tl.fc_tag)), bh->b_blocknr);switch (le16_to_cpu (tl.fc_tag)) {
@@ -1982,13 +1983,13 @@ static int ext4_fc_replay_scan(journal_tcase EXT4_FC_TAG_PAD : state->fc_cur_tag++; state->fc_crc =ext4_chksum (sbi, state->fc_crc, cur, -sizeof (tl) +le16_to_cpu (tl.fc_len)); +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len));break ;case EXT4_FC_TAG_TAIL : state->fc_cur_tag++;memcpy (&tail, val,sizeof (tail)); state->fc_crc =ext4_chksum (sbi, state->fc_crc, cur, -sizeof (tl) + +EXT4_FC_TAG_BASE_LEN + offsetof(struct ext4_fc_tail , fc_crc)); if (le32_to_cpu(tail.fc_tid) == expected_tid &&
@@ -2015,7 +2016,7 @@ static int ext4_fc_replay_scan(journal_t } state->fc_cur_tag++; state->fc_crc =ext4_chksum (sbi, state->fc_crc, cur, -sizeof (tl) +le16_to_cpu (tl.fc_len)); +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len));break ;default : ret = state->fc_replay_num_tags ?
@@ -2070,9 +2071,10 @@ static int ext4_fc_replay(journal_t *jou start = (u8 *)bh->b_data; end = (__u8 *)bh->b_data + journal->j_blocksize -1 ; -for (cur = start; cur < end; cur = cur +sizeof (tl) +le16_to_cpu (tl.fc_len)) { -memcpy (&tl, cur,sizeof (tl)); - val = cur +sizeof (tl); +for (cur = start; cur < end; + cur = cur +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)) { +memcpy (&tl, cur,EXT4_FC_TAG_BASE_LEN ); + val = cur +EXT4_FC_TAG_BASE_LEN ;if (state->fc_replay_num_tags ==0 ) { ret =JBD2_FC_REPLAY_STOP ;
fs/ext4/fast_commit.h +3 -0
@@ -70,6 +70,9 @@ struct ext4_fc_tail {__le32 fc_crc; }; +/* Tag base length */ +#define EXT4_FC_TAG_BASE_LEN (sizeof(struct ext4_fc_tl)) +/* * Fast commit status codes */
Greg Kroah-Hartman
maintainerPATCH 170/290 ext4: factor out ext4_fc_get_tl()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Ye Bin <[email protected]>
commit dcc5827484d6e53ccda12334f8bbfafcc593ceda upstream.
Factor out ext4_fc_get_tl() to fill 'tl' with host byte order.
--- fs/ext4/fast_commit.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-)
fs/ext4/fast_commit.c +25 -21
@@ -1271,7 +1271,7 @@ struct dentry_info_args { };static inline void tl_to_darg (struct dentry_info_args *darg, -struct ext4_fc_tl *tl,u8 *val) +struct ext4_fc_tl *tl,u8 *val) {struct ext4_fc_dentry_info fcd;
@@ -1280,8 +1280,14 @@ static inline void tl_to_darg(struct den darg->parent_ino =le32_to_cpu (fcd.fc_parent_ino); darg->ino =le32_to_cpu (fcd.fc_ino); darg->dname = val + offsetof(struct ext4_fc_dentry_info , fc_dname); - darg->dname_len =le16_to_cpu (tl->fc_len) - -sizeof (struct ext4_fc_dentry_info ); + darg->dname_len = tl->fc_len -sizeof (struct ext4_fc_dentry_info ); +} + +static inline void ext4_fc_get_tl (struct ext4_fc_tl *tl,u8 *val) +{ +memcpy (tl, val,EXT4_FC_TAG_BASE_LEN ); + tl->fc_len =le16_to_cpu (tl->fc_len); + tl->fc_tag =le16_to_cpu (tl->fc_tag); }/* Unlink replay function */
@@ -1446,7 +1452,7 @@ static int ext4_fc_replay_inode(struct sstruct ext4_inode *raw_fc_inode;struct inode *inode =NULL ;struct ext4_iloc iloc; -int inode_len, ino, ret, tag =le16_to_cpu (tl->fc_tag); +int inode_len, ino, ret, tag = tl->fc_tag;struct ext4_extent_header *eh;memcpy (&fc_inode, val,sizeof (fc_inode));
@@ -1471,7 +1477,7 @@ static int ext4_fc_replay_inode(struct sif (ret) goto out; - inode_len =le16_to_cpu (tl->fc_len) -sizeof (struct ext4_fc_inode ); + inode_len = tl->fc_len -sizeof (struct ext4_fc_inode ); raw_inode =ext4_raw_inode (&iloc);memcpy (raw_inode, raw_fc_inode, offsetof(struct ext4_inode , i_block));
@@ -1958,12 +1964,12 @@ static int ext4_fc_replay_scan(journal_t state->fc_replay_expected_off++;for (cur = start; cur < end; - cur = cur +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)) { -memcpy (&tl, cur,EXT4_FC_TAG_BASE_LEN ); + cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) { +ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ;ext4_debug ("Scan phase, tag:%s, blk %lld\n" , -tag2str (le16_to_cpu (tl.fc_tag)), bh->b_blocknr); -switch (le16_to_cpu (tl.fc_tag)) { +tag2str (tl.fc_tag), bh->b_blocknr); +switch (tl.fc_tag) {case EXT4_FC_TAG_ADD_RANGE :memcpy (&ext, val,sizeof (ext)); ex = (struct ext4_extent *)&ext.fc_ex;
@@ -1983,7 +1989,7 @@ static int ext4_fc_replay_scan(journal_tcase EXT4_FC_TAG_PAD : state->fc_cur_tag++; state->fc_crc =ext4_chksum (sbi, state->fc_crc, cur, -EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)); +EXT4_FC_TAG_BASE_LEN + tl.fc_len);break ;case EXT4_FC_TAG_TAIL : state->fc_cur_tag++;
@@ -2016,7 +2022,7 @@ static int ext4_fc_replay_scan(journal_t } state->fc_cur_tag++; state->fc_crc =ext4_chksum (sbi, state->fc_crc, cur, -EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)); +EXT4_FC_TAG_BASE_LEN + tl.fc_len);break ;default : ret = state->fc_replay_num_tags ?
@@ -2072,8 +2078,8 @@ static int ext4_fc_replay(journal_t *jou end = (__u8 *)bh->b_data + journal->j_blocksize -1 ;for (cur = start; cur < end; - cur = cur +EXT4_FC_TAG_BASE_LEN +le16_to_cpu (tl.fc_len)) { -memcpy (&tl, cur,EXT4_FC_TAG_BASE_LEN ); + cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) { +ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ;if (state->fc_replay_num_tags ==0 ) {
@@ -2081,10 +2087,9 @@ static int ext4_fc_replay(journal_t *jouext4_fc_set_bitmaps_and_counters (sb);break ; } -ext4_debug ("Replay phase, tag:%s\n" , -tag2str (le16_to_cpu (tl.fc_tag))); +ext4_debug ("Replay phase, tag:%s\n" ,tag2str (tl.fc_tag)); state->fc_replay_num_tags--; -switch (le16_to_cpu (tl.fc_tag)) { +switch (tl.fc_tag) {case EXT4_FC_TAG_LINK : ret =ext4_fc_replay_link (sb, &tl, val);break ;
@@ -2105,19 +2110,18 @@ static int ext4_fc_replay(journal_t *joubreak ;case EXT4_FC_TAG_PAD :trace_ext4_fc_replay (sb,EXT4_FC_TAG_PAD ,0 , -le16_to_cpu (tl.fc_len),0 ); + tl.fc_len,0 );break ;case EXT4_FC_TAG_TAIL : -trace_ext4_fc_replay (sb,EXT4_FC_TAG_TAIL ,0 , -le16_to_cpu (tl.fc_len),0 ); +trace_ext4_fc_replay (sb,EXT4_FC_TAG_TAIL , +0 , tl.fc_len,0 );memcpy (&tail, val,sizeof (tail));WARN_ON (le32_to_cpu (tail.fc_tid) != expected_tid);break ;case EXT4_FC_TAG_HEAD :break ;default : -trace_ext4_fc_replay (sb,le16_to_cpu (tl.fc_tag),0 , -le16_to_cpu (tl.fc_len),0 ); +trace_ext4_fc_replay (sb, tl.fc_tag,0 , tl.fc_len,0 ); ret = -ECANCELED ;break ; }
Greg Kroah-Hartman
maintainerPATCH 171/290 ext4: fix potential out of bound read in ext4_fc_replay_scan()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Ye Bin <[email protected]>
commit 1b45cc5c7b920fd8bf72e5a888ec7abeadf41e09 upstream.
For scan loop must ensure that at least EXT4_FC_TAG_BASE_LEN space. If remain space less than EXT4_FC_TAG_BASE_LEN which will lead to out of bound read when mounting corrupt file system image.
ADD_RANGE/HEAD/TAIL is needed to add extra check when do journal scan, as this three tags will read data during scan, tag length couldn't less than data length which will read.
--- fs/ext4/fast_commit.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
fs/ext4/fast_commit.c +36 -2
@@ -1907,6 +1907,34 @@ void ext4_fc_replay_cleanup(struct superkfree (sbi->s_fc_replay_state.fc_modified_inodes); } +static inline bool ext4_fc_tag_len_isvalid (struct ext4_fc_tl *tl, +u8 *val,u8 *end) +{ +if (val + tl->fc_len > end) +return false; + +/* Here only check ADD_RANGE/TAIL/HEAD which will read data when do +* journal rescan before do CRC check. Other tags length check will +* rely on CRC check. +*/ +switch (tl->fc_tag) { +case EXT4_FC_TAG_ADD_RANGE : +return (sizeof (struct ext4_fc_add_range ) == tl->fc_len); +case EXT4_FC_TAG_TAIL : +return (sizeof (struct ext4_fc_tail ) <= tl->fc_len); +case EXT4_FC_TAG_HEAD : +return (sizeof (struct ext4_fc_head ) == tl->fc_len); +case EXT4_FC_TAG_DEL_RANGE : +case EXT4_FC_TAG_LINK : +case EXT4_FC_TAG_UNLINK : +case EXT4_FC_TAG_CREAT : +case EXT4_FC_TAG_INODE : +case EXT4_FC_TAG_PAD : +default : +return true; + } +} +/* * Recovery Scan phase handler *
@@ -1963,10 +1991,15 @@ static int ext4_fc_replay_scan(journal_t } state->fc_replay_expected_off++; -for (cur = start; cur < end; +for (cur = start; cur < end -EXT4_FC_TAG_BASE_LEN ; cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) {ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ; +if (!ext4_fc_tag_len_isvalid (&tl, val, end)) { + ret = state->fc_replay_num_tags ? +JBD2_FC_REPLAY_STOP : -ECANCELED ; + goto out_err; + }ext4_debug ("Scan phase, tag:%s, blk %lld\n" ,tag2str (tl.fc_tag), bh->b_blocknr);switch (tl.fc_tag) {
@@ -2077,7 +2110,7 @@ static int ext4_fc_replay(journal_t *jou start = (u8 *)bh->b_data; end = (__u8 *)bh->b_data + journal->j_blocksize -1 ; -for (cur = start; cur < end; +for (cur = start; cur < end -EXT4_FC_TAG_BASE_LEN ; cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) {ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ;
@@ -2087,6 +2120,7 @@ static int ext4_fc_replay(journal_t *jouext4_fc_set_bitmaps_and_counters (sb);break ; } +ext4_debug ("Replay phase, tag:%s\n" ,tag2str (tl.fc_tag)); state->fc_replay_num_tags--;switch (tl.fc_tag) {
Greg Kroah-Hartman
maintainerPATCH 172/290 ext4: disable fast-commit of encrypted dir operations
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Eric Biggers <[email protected]>
commit 0fbcb5251fc81b58969b272c4fb7374a7b922e3e upstream.
fast-commit of create, link, and unlink operations in encrypted directories is completely broken because the unencrypted filenames are being written to the fast-commit journal instead of the encrypted filenames. These operations can't be replayed, as encryption keys aren't present at journal replay time. It is also an information leak.
Until if/when we can get this working properly, make encrypted directory operations ineligible for fast-commit.
Note that fast-commit operations on encrypted regular files continue to be allowed, as they seem to work.
--- fs/ext4/fast_commit.c | 41 +++++++++++++++++++++++++---------------- fs/ext4/fast_commit.h | 1 + include/trace/events/ext4.h | 7 +++++-- 3 files changed, 31 insertions(+), 18 deletions(-)
fs/ext4/fast_commit.c +25 -16
@@ -399,25 +399,34 @@ static int __track_dentry_update(structstruct __track_dentry_update_args *dentry_update = (struct __track_dentry_update_args *)arg;struct dentry *dentry = dentry_update->dentry; -struct ext4_sb_info *sbi =EXT4_SB (inode->i_sb); +struct inode *dir = dentry->d_parent->d_inode; +struct super_block *sb = inode->i_sb; +struct ext4_sb_info *sbi =EXT4_SB (sb);mutex_unlock (&ei->i_fc_lock); + +if (IS_ENCRYPTED (dir)) { +ext4_fc_mark_ineligible (sb,EXT4_FC_REASON_ENCRYPTED_FILENAME , +NULL ); +mutex_lock (&ei->i_fc_lock); +return -EOPNOTSUPP ; + } + node =kmem_cache_alloc (ext4_fc_dentry_cachep,GFP_NOFS );if (!node) { -ext4_fc_mark_ineligible (inode->i_sb,EXT4_FC_REASON_NOMEM ,NULL ); +ext4_fc_mark_ineligible (sb,EXT4_FC_REASON_NOMEM ,NULL );mutex_lock (&ei->i_fc_lock);return -ENOMEM ; } node->fcd_op = dentry_update->op; - node->fcd_parent = dentry->d_parent->d_inode->i_ino; + node->fcd_parent = dir->i_ino; node->fcd_ino = inode->i_ino;if (dentry->d_name.len >DNAME_INLINE_LEN ) { node->fcd_name.name =kmalloc (dentry->d_name.len,GFP_NOFS );if (!node->fcd_name.name) {kmem_cache_free (ext4_fc_dentry_cachep, node); -ext4_fc_mark_ineligible (inode->i_sb, -EXT4_FC_REASON_NOMEM ,NULL ); +ext4_fc_mark_ineligible (sb,EXT4_FC_REASON_NOMEM ,NULL );mutex_lock (&ei->i_fc_lock);return -ENOMEM ; }
@@ -2179,17 +2188,17 @@ void ext4_fc_init(struct super_block *sb journal->j_fc_cleanup_callback = ext4_fc_cleanup; } -static const char *fc_ineligible_reasons[] = { -"Extended attributes changed" , -"Cross rename" , -"Journal flag changed" , -"Insufficient memory" , -"Swap boot" , -"Resize" , -"Dir renamed" , -"Falloc range op" , -"Data journalling" , -"FC Commit Failed" +static const char *const fc_ineligible_reasons[] = { + [EXT4_FC_REASON_XATTR ] ="Extended attributes changed" , + [EXT4_FC_REASON_CROSS_RENAME ] ="Cross rename" , + [EXT4_FC_REASON_JOURNAL_FLAG_CHANGE ] ="Journal flag changed" , + [EXT4_FC_REASON_NOMEM ] ="Insufficient memory" , + [EXT4_FC_REASON_SWAP_BOOT ] ="Swap boot" , + [EXT4_FC_REASON_RESIZE ] ="Resize" , + [EXT4_FC_REASON_RENAME_DIR ] ="Dir renamed" , + [EXT4_FC_REASON_FALLOC_RANGE ] ="Falloc range op" , + [EXT4_FC_REASON_INODE_JOURNAL_DATA ] ="Data journalling" , + [EXT4_FC_REASON_ENCRYPTED_FILENAME ] ="Encrypted filename" , };int ext4_fc_info_show (struct seq_file *seq,void *v)
fs/ext4/fast_commit.h +1 -0
@@ -96,6 +96,7 @@ enum {EXT4_FC_REASON_RENAME_DIR ,EXT4_FC_REASON_FALLOC_RANGE ,EXT4_FC_REASON_INODE_JOURNAL_DATA , +EXT4_FC_REASON_ENCRYPTED_FILENAME , EXT4_FC_REASON_MAX };
include/trace/events/ext4.h +5 -2
@@ -104,6 +104,7 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_RESIZE)TRACE_DEFINE_ENUM (EXT4_FC_REASON_RENAME_DIR );TRACE_DEFINE_ENUM (EXT4_FC_REASON_FALLOC_RANGE );TRACE_DEFINE_ENUM (EXT4_FC_REASON_INODE_JOURNAL_DATA ); +TRACE_DEFINE_ENUM (EXT4_FC_REASON_ENCRYPTED_FILENAME );TRACE_DEFINE_ENUM (EXT4_FC_REASON_MAX );#define show_fc_reason (reason) \
@@ -116,7 +117,8 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX); { EXT4_FC_REASON_RESIZE, "RESIZE"}, \ { EXT4_FC_REASON_RENAME_DIR, "RENAME_DIR"}, \ { EXT4_FC_REASON_FALLOC_RANGE, "FALLOC_RANGE"}, \ - { EXT4_FC_REASON_INODE_JOURNAL_DATA, "INODE_JOURNAL_DATA"}) + { EXT4_FC_REASON_INODE_JOURNAL_DATA, "INODE_JOURNAL_DATA"}, \ + { EXT4_FC_REASON_ENCRYPTED_FILENAME, "ENCRYPTED_FILENAME"}) TRACE_EVENT(ext4_other_inode_update_time, TP_PROTO(struct inode *inode, ino_t orig_ino),
@@ -2764,7 +2766,7 @@ TRACE_EVENT(ext4_fc_stats, ), TP_printk("dev %d,%d fc ineligible reasons:\n" - "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u " + "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u" "num_commits:%lu, ineligible: %lu, numblks: %lu", MAJOR(__entry->dev), MINOR(__entry->dev), FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR),
@@ -2776,6 +2778,7 @@ TRACE_EVENT(ext4_fc_stats,FC_REASON_NAME_STAT (EXT4_FC_REASON_RENAME_DIR ),FC_REASON_NAME_STAT (EXT4_FC_REASON_FALLOC_RANGE ),FC_REASON_NAME_STAT (EXT4_FC_REASON_INODE_JOURNAL_DATA ), +FC_REASON_NAME_STAT (EXT4_FC_REASON_ENCRYPTED_FILENAME ), __entry->fc_commits, __entry->fc_ineligible_commits, __entry->fc_numblks) );
Greg Kroah-Hartman
maintainerPATCH 173/290 ext4: dont set up encryption key during jbd2 transaction
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Eric Biggers <[email protected]>
commit 4c0d5778385cb3618ff26a561ce41de2b7d9de70 upstream.
Commit a80f7fcf1867 ("ext4: fixup ext4_fc_track_* functions' signature") extended the scope of the transaction in ext4_unlink() too far, making it include the call to ext4_find_entry(). However, ext4_find_entry() can deadlock when called from within a transaction because it may need to set up the directory's encryption key.
Fix this by restoring the transaction to its original scope.
--- fs/ext4/ext4.h | 4 ++-- fs/ext4/fast_commit.c | 2 +- fs/ext4/namei.c | 44 ++++++++++++++++++++++++-------------------- 3 files changed, 27 insertions(+), 23 deletions(-)
fs/ext4/ext4.h +2 -2
@@ -3647,8 +3647,8 @@ extern void ext4_initialize_dirent_tail( unsigned int blocksize);extern int ext4_handle_dirty_dirblock (handle_t *handle,struct inode *inode,struct buffer_head *bh); -extern int __ext4_unlink (handle_t *handle,struct inode *dir,const struct qstr *d_name, -struct inode *inode); +extern int __ext4_unlink (struct inode *dir,const struct qstr *d_name, +struct inode *inode,struct dentry *dentry);extern int __ext4_link (struct inode *dir,struct inode *inode,struct dentry *dentry);
fs/ext4/fast_commit.c +1 -1
@@ -1330,7 +1330,7 @@ static int ext4_fc_replay_unlink(structreturn 0 ; } - ret =__ext4_unlink (NULL , old_parent, &entry, inode); + ret =__ext4_unlink (old_parent, &entry, inode,NULL );/* -ENOENT ok coz it might not exist anymore. */ if (ret == -ENOENT ) ret =0 ;
fs/ext4/namei.c +24 -20
96 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 174/290 ext4: add missing validation of fast-commit record lengths
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Eric Biggers <[email protected]>
commit 64b4a25c3de81a69724e888ec2db3533b43816e2 upstream.
Validate the inode and filename lengths in fast-commit journal records so that a malicious fast-commit journal cannot cause a crash by having invalid values for these. Also validate EXT4_FC_TAG_DEL_RANGE.
--- fs/ext4/fast_commit.c | 38 +++++++++++++++++++------------------- fs/ext4/fast_commit.h | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-)
fs/ext4/fast_commit.c +19 -19
@@ -1916,32 +1916,31 @@ void ext4_fc_replay_cleanup(struct superkfree (sbi->s_fc_replay_state.fc_modified_inodes); } -static inline bool ext4_fc_tag_len_isvalid (struct ext4_fc_tl *tl, -u8 *val,u8 *end) +static bool ext4_fc_value_len_isvalid (struct ext4_sb_info *sbi, +int tag,int len) { -if (val + tl->fc_len > end) -return false; - -/* Here only check ADD_RANGE/TAIL/HEAD which will read data when do -* journal rescan before do CRC check. Other tags length check will -* rely on CRC check. -*/ -switch (tl->fc_tag) { +switch (tag) {case EXT4_FC_TAG_ADD_RANGE : -return (sizeof (struct ext4_fc_add_range ) == tl->fc_len); -case EXT4_FC_TAG_TAIL : -return (sizeof (struct ext4_fc_tail ) <= tl->fc_len); -case EXT4_FC_TAG_HEAD : -return (sizeof (struct ext4_fc_head ) == tl->fc_len); +return len ==sizeof (struct ext4_fc_add_range );case EXT4_FC_TAG_DEL_RANGE : +return len ==sizeof (struct ext4_fc_del_range ); +case EXT4_FC_TAG_CREAT :case EXT4_FC_TAG_LINK :case EXT4_FC_TAG_UNLINK : -case EXT4_FC_TAG_CREAT : + len -=sizeof (struct ext4_fc_dentry_info ); +return len >=1 && len <=EXT4_NAME_LEN ;case EXT4_FC_TAG_INODE : + len -=sizeof (struct ext4_fc_inode ); +return len >=EXT4_GOOD_OLD_INODE_SIZE && + len <= sbi->s_inode_size;case EXT4_FC_TAG_PAD : -default : -return true; +return true;/* padding can have any length */ +case EXT4_FC_TAG_TAIL : +return len >=sizeof (struct ext4_fc_tail ); +case EXT4_FC_TAG_HEAD : +return len ==sizeof (struct ext4_fc_head ); } +return false; }/*
@@ -2004,7 +2003,8 @@ static int ext4_fc_replay_scan(journal_t cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ; -if (!ext4_fc_tag_len_isvalid (&tl, val, end)) { +if (tl.fc_len > end - val || + !ext4_fc_value_len_isvalid (sbi, tl.fc_tag, tl.fc_len)) { ret = state->fc_replay_num_tags ?JBD2_FC_REPLAY_STOP : -ECANCELED ; goto out_err;
fs/ext4/fast_commit.h +1 -1
@@ -58,7 +58,7 @@ struct ext4_fc_dentry_info {__u8 fc_dname[0 ]; }; -/* Value structure for EXT4_FC_TAG_INODE and EXT4_FC_TAG_INODE_PARTIAL. */ +/* Value structure for EXT4_FC_TAG_INODE. */ struct ext4_fc_inode {__le32 fc_ino;__u8 fc_raw_inode[0 ];
Greg Kroah-Hartman
maintainerPATCH 175/290 ext4: fix unaligned memory access in ext4_fc_reserve_space()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Eric Biggers <[email protected]>
commit 8415ce07ecf0cc25efdd5db264a7133716e503cf upstream.
As is done elsewhere in the file, build the struct ext4_fc_tl on the stack and memcpy() it into the buffer, rather than directly writing it to a potentially-unaligned location in the buffer.
--- fs/ext4/fast_commit.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-)
fs/ext4/fast_commit.c +21 -18
@@ -604,6 +604,15 @@ static void ext4_fc_submit_bh(struct sup/* Ext4 commit path routines */ +/* memcpy to fc reserved space and update CRC */ +static void *ext4_fc_memcpy (struct super_block *sb,void *dst,const void *src, +int len,u32 *crc) +{ +if (crc) + *crc =ext4_chksum (EXT4_SB (sb), *crc, src, len); +return memcpy (dst, src, len); +} +/* memzero and update CRC */ static void *ext4_fc_memzero (struct super_block *sb,void *dst,int len,u32 *crc)
@@ -629,12 +638,13 @@ static void *ext4_fc_memzero(struct supe*/ static u8 *ext4_fc_reserve_space (struct super_block *sb,int len,u32 *crc) { -struct ext4_fc_tl *tl; +struct ext4_fc_tl tl;struct ext4_sb_info *sbi =EXT4_SB (sb);struct buffer_head *bh;int bsize = sbi->s_journal->j_blocksize;int ret, off = sbi->s_fc_bytes % bsize;int pad_len; +u8 *dst;/* * After allocating len, we should have space at least for a 0 byte
@@ -658,16 +668,18 @@ static u8 *ext4_fc_reserve_space(structreturn sbi->s_fc_bh->b_data + off; }/* Need to add PAD tag */ - tl = (struct ext4_fc_tl *)(sbi->s_fc_bh->b_data + off); - tl->fc_tag =cpu_to_le16 (EXT4_FC_TAG_PAD ); + dst = sbi->s_fc_bh->b_data + off; + tl.fc_tag =cpu_to_le16 (EXT4_FC_TAG_PAD ); pad_len = bsize - off -1 -EXT4_FC_TAG_BASE_LEN ; - tl->fc_len =cpu_to_le16 (pad_len); -if (crc) - *crc =ext4_chksum (sbi, *crc, tl,EXT4_FC_TAG_BASE_LEN ); -if (pad_len >0 ) -ext4_fc_memzero (sb, tl +1 , pad_len, crc); + tl.fc_len =cpu_to_le16 (pad_len); +ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , crc); + dst +=EXT4_FC_TAG_BASE_LEN ; +if (pad_len >0 ) { +ext4_fc_memzero (sb, dst, pad_len, crc); + dst += pad_len; + }/* Don't leak uninitialized memory in the unused last byte. */ - *((u8 *)(tl +1 ) + pad_len) =0 ; + *dst =0 ;ext4_fc_submit_bh (sb, false);
@@ -679,15 +691,6 @@ static u8 *ext4_fc_reserve_space(structreturn sbi->s_fc_bh->b_data; } -/* memcpy to fc reserved space and update CRC */ -static void *ext4_fc_memcpy (struct super_block *sb,void *dst,const void *src, -int len,u32 *crc) -{ -if (crc) - *crc =ext4_chksum (EXT4_SB (sb), *crc, src, len); -return memcpy (dst, src, len); -} -/* * Complete a fast commit by writing tail tag. *
Greg Kroah-Hartman
maintainerPATCH 176/290 ext4: fix off-by-one errors in fast-commit block filling
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
From: Eric Biggers <[email protected]>
commit 48a6a66db82b8043d298a630f22c62d43550cae5 upstream.
Due to several different off-by-one errors, or perhaps due to a late change in design that wasn't fully reflected in the code that was actually merged, there are several very strange constraints on how fast-commit blocks are filled with tlv entries:
- tlvs must start at least 10 bytes before the end of the block, even though the minimum tlv length is 8. Otherwise, the replay code will ignore them. (BUG: ext4_fc_reserve_space() could violate this requirement if called with a len of blocksize - 9 or blocksize - 8. Fortunately, this doesn't seem to happen currently.)
- tlvs must end at least 1 byte before the end of the block. Otherwise the replay code will consider them to be invalid. This quirk contributed to a bug (fixed by an earlier commit) where uninitialized memory was being leaked to disk in the last byte of blocks.
Also, strangely these constraints don't apply to the replay code in e2fsprogs, which will accept any tlvs in the blocks (with no bounds checks at all, but that is a separate issue...).
Given that this all seems to be a bug, let's fix it by just filling blocks with tlv entries in the natural way.
Note that old kernels will be unable to replay fast-commit journals created by kernels that have this commit.
--- fs/ext4/fast_commit.c | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-)
fs/ext4/fast_commit.c +33 -33
@@ -643,43 +643,43 @@ static u8 *ext4_fc_reserve_space(structstruct buffer_head *bh;int bsize = sbi->s_journal->j_blocksize;int ret, off = sbi->s_fc_bytes % bsize; -int pad_len; +int remaining;u8 *dst;/* -* After allocating len, we should have space at least for a 0 byte -* padding. +* If 'len' is too long to fit in any block alongside a PAD tlv, then we +* cannot fulfill the request. */ -if (len +EXT4_FC_TAG_BASE_LEN > bsize) +if (len > bsize -EXT4_FC_TAG_BASE_LEN )return NULL ; -if (bsize - off -1 > len +EXT4_FC_TAG_BASE_LEN ) { -/* -* Only allocate from current buffer if we have enough space for -* this request AND we have space to add a zero byte padding. -*/ -if (!sbi->s_fc_bh) { - ret =jbd2_fc_get_buf (EXT4_SB (sb)->s_journal, &bh); -if (ret) -return NULL ; - sbi->s_fc_bh = bh; - } - sbi->s_fc_bytes += len; -return sbi->s_fc_bh->b_data + off; +if (!sbi->s_fc_bh) { + ret =jbd2_fc_get_buf (EXT4_SB (sb)->s_journal, &bh); +if (ret) +return NULL ; + sbi->s_fc_bh = bh; } -/* Need to add PAD tag */ dst = sbi->s_fc_bh->b_data + off; + +/* +* Allocate the bytes in the current block if we can do so while still +* leaving enough space for a PAD tlv. +*/ + remaining = bsize -EXT4_FC_TAG_BASE_LEN - off; +if (len <= remaining) { + sbi->s_fc_bytes += len; +return dst; + } + +/* +* Else, terminate the current block with a PAD tlv, then allocate a new +* block and allocate the bytes at the start of that new block. +*/ + tl.fc_tag =cpu_to_le16 (EXT4_FC_TAG_PAD ); - pad_len = bsize - off -1 -EXT4_FC_TAG_BASE_LEN ; - tl.fc_len =cpu_to_le16 (pad_len); + tl.fc_len =cpu_to_le16 (remaining);ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , crc); - dst +=EXT4_FC_TAG_BASE_LEN ; -if (pad_len >0 ) { -ext4_fc_memzero (sb, dst, pad_len, crc); - dst += pad_len; - } -/* Don't leak uninitialized memory in the unused last byte. */ - *dst =0 ; +ext4_fc_memzero (sb, dst +EXT4_FC_TAG_BASE_LEN , remaining, crc);ext4_fc_submit_bh (sb, false);
@@ -687,7 +687,7 @@ static u8 *ext4_fc_reserve_space(structif (ret)return NULL ; sbi->s_fc_bh = bh; - sbi->s_fc_bytes = (sbi->s_fc_bytes / bsize +1 ) * bsize + len; + sbi->s_fc_bytes += bsize - off + len;return sbi->s_fc_bh->b_data; }
@@ -718,7 +718,7 @@ static int ext4_fc_write_tail(struct sup off = sbi->s_fc_bytes % bsize; tl.fc_tag =cpu_to_le16 (EXT4_FC_TAG_TAIL ); - tl.fc_len =cpu_to_le16 (bsize - off -1 +sizeof (struct ext4_fc_tail )); + tl.fc_len =cpu_to_le16 (bsize - off +sizeof (struct ext4_fc_tail )); sbi->s_fc_bytes =round_up (sbi->s_fc_bytes, bsize);ext4_fc_memcpy (sb, dst, &tl,EXT4_FC_TAG_BASE_LEN , &crc);
@@ -1981,7 +1981,7 @@ static int ext4_fc_replay_scan(journal_t state = &sbi->s_fc_replay_state; start = (u8 *)bh->b_data; - end = (__u8 *)bh->b_data + journal->j_blocksize -1 ; + end = start + journal->j_blocksize;if (state->fc_replay_expected_off ==0 ) { state->fc_cur_tag =0 ;
@@ -2002,7 +2002,7 @@ static int ext4_fc_replay_scan(journal_t } state->fc_replay_expected_off++; -for (cur = start; cur < end -EXT4_FC_TAG_BASE_LEN ; +for (cur = start; cur <= end -EXT4_FC_TAG_BASE_LEN ; cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) {ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ;
@@ -2120,9 +2120,9 @@ static int ext4_fc_replay(journal_t *jou#endif start = (u8 *)bh->b_data; - end = (__u8 *)bh->b_data + journal->j_blocksize -1 ; + end = start + journal->j_blocksize; -for (cur = start; cur < end -EXT4_FC_TAG_BASE_LEN ; +for (cur = start; cur <= end -EXT4_FC_TAG_BASE_LEN ; cur = cur +EXT4_FC_TAG_BASE_LEN + tl.fc_len) {ext4_fc_get_tl (&tl, cur); val = cur +EXT4_FC_TAG_BASE_LEN ;
Greg Kroah-Hartman
maintainerPATCH 177/290 ARM: renumber bits related to _TIF_WORK_MASK
In reply to Greg Kroah-HartmanFrom: Jens Axboe <[email protected]>
commit 191f8453fc99a537ea78b727acea739782378b0d upstream.
We want to ensure that the mask related to calling do_work_pending() is within the first 16 bits. Move bits unrelated to that outside of that range, to avoid spuriously calling do_work_pending() when we don't need to.
--- arch/arm/include/asm/thread_info.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
arch/arm/include/asm/thread_info.h +7 -6
@@ -129,15 +129,16 @@ extern int vfp_restore_user_hwstate(stru#define TIF_NEED_RESCHED 1/* rescheduling necessary */ #define TIF_NOTIFY_RESUME 2/* callback before returning to user */ #define TIF_UPROBE 3/* breakpointed or singlestepping */ -#define TIF_SYSCALL_TRACE 4/* syscall trace active */ -#define TIF_SYSCALL_AUDIT 5/* syscall auditing active */ -#define TIF_SYSCALL_TRACEPOINT 6/* syscall tracepoint instrumentation */ -#define TIF_SECCOMP 7/* seccomp syscall filtering active */ -#define TIF_NOTIFY_SIGNAL 8/* signal notifications exist */ +#define TIF_NOTIFY_SIGNAL 4/* signal notifications exist */ #define TIF_USING_IWMMXT 17#define TIF_MEMDIE 18/* is terminating due to OOM killer */ -#define TIF_RESTORE_SIGMASK 20 +#define TIF_RESTORE_SIGMASK 19 +#define TIF_SYSCALL_TRACE 20/* syscall trace active */ +#define TIF_SYSCALL_AUDIT 21/* syscall auditing active */ +#define TIF_SYSCALL_TRACEPOINT 22/* syscall tracepoint instrumentation */ +#define TIF_SECCOMP 23/* seccomp syscall filtering active */ +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
Greg Kroah-Hartman
maintainerPATCH 178/290 phy: qcom-qmp-combo: fix out-of-bounds clock access
In reply to Greg Kroah-Hartman[ Upstream commit d8a5b59c5fc75c99ba17e3eb1a8f580d8d172b28 ]
The SM8250 only uses three clocks but the DP configuration erroneously described four clocks.
In case the DP part of the PHY is initialised before the USB part, this would lead to uninitialised memory beyond the bulk-clocks array to be treated as a clock pointer as the clocks are requested based on the USB configuration.
--- drivers/phy/qualcomm/phy-qcom-qmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp.c +2 -2
@@ -3805,8 +3805,8 @@ static const struct qmp_phy_cfg sm8250_dpphy_cfg = { .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .clk_list = qmp_v4_sm8250_usbphy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 179/290 btrfs: replace strncpy() with strscpy()
In reply to Greg Kroah-Hartman[ Upstream commit 63d5429f68a3d4c4aa27e65a05196c17f86c41d6 ]
Using strncpy() on NUL-terminated strings are deprecated. To avoid possible forming of non-terminated string strscpy() should be used.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- fs/btrfs/ioctl.c | 9 +++------ fs/btrfs/rcu-string.h | 6 +++++- 2 files changed, 8 insertions(+), 7 deletions(-)
fs/btrfs/ioctl.c +3 -6
@@ -3415,13 +3415,10 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info, di_args->bytes_used =btrfs_device_get_bytes_used (dev); di_args->total_bytes =btrfs_device_get_total_bytes (dev);memcpy (di_args->uuid, dev->uuid,sizeof (di_args->uuid)); -if (dev->name) { -strncpy (di_args->path,rcu_str_deref (dev->name), -sizeof (di_args->path) -1 ); - di_args->path[sizeof (di_args->path) -1 ] =0 ; - }else { +if (dev->name) +strscpy (di_args->path,rcu_str_deref (dev->name),sizeof (di_args->path)); +else di_args->path[0 ] ='\0' ; - } out:rcu_read_unlock ();
fs/btrfs/rcu-string.h +5 -1
@@ -18,7 +18,11 @@ static inline struct rcu_string *rcu_string_strdup(const char *src, gfp_t mask) (len * sizeof(char)), mask);if (!ret)return ret; -strncpy (ret->str, src, len); +/* Warn if the source got unexpectedly truncated. */ +if (WARN_ON (strscpy (ret->str, src, len) <0 )) { +kfree (ret); +return NULL ; + }return ret; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 180/290 btrfs: move missing device handling in a dedicate function
In reply to Greg Kroah-HartmanFrom: Nikolay Borisov <[email protected]>
[ Upstream commit ff37c89f94be14b0e22a532d1e6d57187bfd5bb8 ]
This simplifies the code flow in read_one_chunk and makes error handling when handling missing devices a bit simpler by reducing it to a single check if something went wrong. No functional changes.
Stable-dep-of: 1742e1c90c3d ("btrfs: fix extent map use-after-free when handling missing device in read_one_chunk")
--- fs/btrfs/volumes.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
fs/btrfs/volumes.c +24 -14
@@ -7043,6 +7043,27 @@ static void warn_32bit_meta_chunk(struct btrfs_fs_info *fs_info, }#endif +static struct btrfs_device *handle_missing_device (struct btrfs_fs_info *fs_info, +u64 devid,u8 *uuid) +{ +struct btrfs_device *dev; + +if (!btrfs_test_opt (fs_info,DEGRADED )) { +btrfs_report_missing_device (fs_info, devid, uuid, true); +return ERR_PTR (-ENOENT ); + } + + dev =add_missing_dev (fs_info->fs_devices, devid, uuid); +if (IS_ERR (dev)) { +btrfs_err (fs_info,"failed to init missing device %llu: %ld" , + devid,PTR_ERR (dev)); +return dev; + } +btrfs_report_missing_device (fs_info, devid, uuid, false); + +return dev; +} +static int read_one_chunk (struct btrfs_key *key,struct extent_buffer *leaf,struct btrfs_chunk *chunk) {
@@ -7130,28 +7151,17 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, BTRFS_UUID_SIZE); args.uuid = uuid; map->stripes[i].dev =btrfs_find_device (fs_info->fs_devices, &args); -if (!map->stripes[i].dev && - !btrfs_test_opt (fs_info,DEGRADED )) { -free_extent_map (em); -btrfs_report_missing_device (fs_info, devid, uuid, true); -return -ENOENT ; - }if (!map->stripes[i].dev) { - map->stripes[i].dev = -add_missing_dev (fs_info->fs_devices, devid, - uuid); + map->stripes[i].dev =handle_missing_device (fs_info, + devid, uuid);if (IS_ERR (map->stripes[i].dev)) {free_extent_map (em); -btrfs_err (fs_info, -"failed to init missing dev %llu: %ld" , - devid,PTR_ERR (map->stripes[i].dev));return PTR_ERR (map->stripes[i].dev); } -btrfs_report_missing_device (fs_info, devid, uuid, false); } +set_bit (BTRFS_DEV_STATE_IN_FS_METADATA , &(map->stripes[i].dev->dev_state)); - }write_lock (&map_tree->lock);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 181/290 btrfs: fix extent map use-after-free when handling missing device in read_one_chunk
In reply to Greg Kroah-HartmanFrom: void0red <[email protected]>
[ Upstream commit 1742e1c90c3da344f3bb9b1f1309b3f47482756a ]
Store the error code before freeing the extent_map. Though it's reference counted structure, in that function it's the first and last allocation so this would lead to a potential use-after-free.
The error can happen eg. when chunk is stored on a missing device and the degraded mount option is missing.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=216721
--- fs/btrfs/volumes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/btrfs/volumes.c +2 -1
@@ -7155,8 +7155,9 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, map->stripes[i].dev =handle_missing_device (fs_info, devid, uuid);if (IS_ERR (map->stripes[i].dev)) { + ret =PTR_ERR (map->stripes[i].dev);free_extent_map (em); -return PTR_ERR (map->stripes[i].dev); +return ret; } }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 182/290 x86/mce: Get rid of msr_ops
In reply to Greg Kroah-HartmanFrom: Borislav Petkov <[email protected]>
[ Upstream commit 8121b8f947be0033f567619be204639a50cad298 ]
Avoid having indirect calls and use a normal function which returns the proper MSR address based on ->smca setting.
No functional changes.
Stable-dep-of: bc1b705b0eee ("x86/MCE/AMD: Clear DFR errors found in THR handler")
--- arch/x86/kernel/cpu/mce/amd.c | 10 ++-- arch/x86/kernel/cpu/mce/core.c | 95 ++++++++++-------------------- arch/x86/kernel/cpu/mce/internal.h | 12 ++-- 3 files changed, 42 insertions(+), 75 deletions(-)
arch/x86/kernel/cpu/mce/amd.c +5 -5
@@ -526,7 +526,7 @@ static u32 get_block_address(u32 current_addr, u32 low, u32 high,/* Fall back to method we used for older processors: */ switch (block) {case 0 : - addr = msr_ops.misc (bank); + addr =mca_msr_reg (bank,MCA_MISC );break ;case 1 : offset = ((low &MASK_BLKPTR_LO ) >>21 );
@@ -978,8 +978,8 @@ static void log_error_deferred(unsigned int bank) {bool defrd; - defrd =_log_error_bank (bank, msr_ops.status (bank), - msr_ops.addr (bank),0 ); + defrd =_log_error_bank (bank,mca_msr_reg (bank,MCA_STATUS ), +mca_msr_reg (bank,MCA_ADDR ),0 );if (!mce_flags.smca)return ;
@@ -1009,7 +1009,7 @@ static void amd_deferred_error_interrupt(void)static void log_error_thresholding (unsigned int bank,u64 misc) { -_log_error_bank (bank, msr_ops.status (bank), msr_ops.addr (bank), misc); +_log_error_bank (bank,mca_msr_reg (bank,MCA_STATUS ),mca_msr_reg (bank,MCA_ADDR ), misc); }static void log_and_reset_block (struct threshold_block *block)
@@ -1397,7 +1397,7 @@ static int threshold_create_bank(struct threshold_bank **bp, unsigned int cpu, } } - err =allocate_threshold_blocks (cpu, b, bank,0 , msr_ops.misc (bank)); + err =allocate_threshold_blocks (cpu, b, bank,0 ,mca_msr_reg (bank,MCA_MISC ));if (err) goto out_kobj;
arch/x86/kernel/cpu/mce/core.c +31 -64
182 lines not on this page · raw message
arch/x86/kernel/cpu/mce/internal.h +6 -6
@@ -168,14 +168,14 @@ struct mce_vendor_flags {extern struct mce_vendor_flags mce_flags; -struct mca_msr_regs { -u32 (*ctl) (int bank); -u32 (*status) (int bank); -u32 (*addr) (int bank); -u32 (*misc) (int bank); +enum mca_msr { +MCA_CTL , +MCA_STATUS , +MCA_ADDR , +MCA_MISC , }; -extern struct mca_msr_regs msr_ops; +u32 mca_msr_reg (int bank,enum mca_msr reg);/* Decide whether to add MCE record to MCE event pool or filter it out. */ extern bool filter_mce (struct mce *m);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 183/290 x86/MCE/AMD: Clear DFR errors found in THR handler
In reply to Greg Kroah-HartmanFrom: Yazen Ghannam <[email protected]>
[ Upstream commit bc1b705b0eee4c645ad8b3bbff3c8a66e9688362 ]
AMD's MCA Thresholding feature counts errors of all severity levels, not just correctable errors. If a deferred error causes the threshold limit to be reached (it was the error that caused the overflow), then both a deferred error interrupt and a thresholding interrupt will be triggered.
The order of the interrupts is not guaranteed. If the threshold interrupt handler is executed first, then it will clear MCA_STATUS for the error. It will not check or clear MCA_DESTAT which also holds a copy of the deferred error. When the deferred error interrupt handler runs it will not find an error in MCA_STATUS, but it will find the error in MCA_DESTAT. This will cause two errors to be logged.
Check for deferred errors when handling a threshold interrupt. If a bank contains a deferred error, then clear the bank's MCA_DESTAT register.
Define a new helper function to do the deferred error check and clearing of MCA_DESTAT.
[ bp: Simplify, convert comment to passive voice. ]
--- arch/x86/kernel/cpu/mce/amd.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/mce/amd.c +20 -13
@@ -965,6 +965,24 @@ _log_error_bank(unsigned int bank, u32 msr_stat, u32 msr_addr, u64 misc)return status &MCI_STATUS_DEFERRED ; } +static bool _log_error_deferred (unsigned int bank,u32 misc) +{ +if (!_log_error_bank (bank,mca_msr_reg (bank,MCA_STATUS ), +mca_msr_reg (bank,MCA_ADDR ), misc)) +return false; + +/* +* Non-SMCA systems don't have MCA_DESTAT/MCA_DEADDR registers. +* Return true here to avoid accessing these registers. +*/ +if (!mce_flags.smca) +return true; + +/* Clear MCA_DESTAT if the deferred error was logged from MCA_STATUS. */ +wrmsrl (MSR_AMD64_SMCA_MCx_DESTAT (bank),0 ); +return true; +} +/* * We have three scenarios for checking for Deferred errors: *
@@ -976,19 +994,8 @@ _log_error_bank(unsigned int bank, u32 msr_stat, u32 msr_addr, u64 misc)*/ static void log_error_deferred (unsigned int bank) { -bool defrd; - - defrd =_log_error_bank (bank,mca_msr_reg (bank,MCA_STATUS ), -mca_msr_reg (bank,MCA_ADDR ),0 ); - -if (!mce_flags.smca) -return ; - -/* Clear MCA_DESTAT if we logged the deferred error from MCA_STATUS. */ -if (defrd) { -wrmsrl (MSR_AMD64_SMCA_MCx_DESTAT (bank),0 ); +if (_log_error_deferred (bank,0 ))return ; - }/* * Only deferred errors are logged in MCA_DE{STAT,ADDR} so just check
@@ -1009,7 +1016,7 @@ static void amd_deferred_error_interrupt(void)static void log_error_thresholding (unsigned int bank,u64 misc) { -_log_error_bank (bank,mca_msr_reg (bank,MCA_STATUS ),mca_msr_reg (bank,MCA_ADDR ), misc); +_log_error_deferred (bank, misc); }static void log_and_reset_block (struct threshold_block *block)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 184/290 media: s5p-mfc: Fix to handle reference queue during finishing
In reply to Greg Kroah-HartmanFrom: Smitha T Murthy <[email protected]>
[ Upstream commit d8a46bc4e1e0446459daa77c4ce14218d32dacf9 ]
On receiving last buffer driver puts MFC to MFCINST_FINISHING state which in turn skips transferring of frame from SRC to REF queue. This causes driver to stop MFC encoding and last frame is lost.
This patch guarantees safe handling of frames during MFCINST_FINISHING and correct clearing of workbit to avoid early stopping of encoding.
--- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +10 -2
@@ -1218,6 +1218,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)unsigned long mb_y_addr, mb_c_addr;int slice_type;unsigned int strm_size; +bool src_ready; slice_type =s5p_mfc_hw_call (dev->mfc_ops, get_enc_slice_type, dev); strm_size =s5p_mfc_hw_call (dev->mfc_ops, get_enc_strm_size, dev);
@@ -1257,7 +1258,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) } } } -if ((ctx->src_queue_cnt >0 ) && (ctx->state ==MFCINST_RUNNING )) { +if (ctx->src_queue_cnt >0 && (ctx->state ==MFCINST_RUNNING || + ctx->state ==MFCINST_FINISHING )) { mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);if (mb_entry->flags &MFC_BUF_FLAG_USED ) {
@@ -1288,7 +1290,13 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)vb2_set_plane_payload (&mb_entry->b->vb2_buf,0 , strm_size);vb2_buffer_done (&mb_entry->b->vb2_buf,VB2_BUF_STATE_DONE ); } -if ((ctx->src_queue_cnt ==0 ) || (ctx->dst_queue_cnt ==0 )) + + src_ready = true; +if (ctx->state ==MFCINST_RUNNING && ctx->src_queue_cnt ==0 ) + src_ready = false; +if (ctx->state ==MFCINST_FINISHING && ctx->ref_queue_cnt ==0 ) + src_ready = false; +if (!src_ready || ctx->dst_queue_cnt ==0 )clear_work_bit (ctx);return 0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 185/290 media: s5p-mfc: Clear workbit to handle error condition
In reply to Greg Kroah-HartmanFrom: Smitha T Murthy <[email protected]>
[ Upstream commit d3f3c2fe54e30b0636496d842ffbb5ad3a547f9b ]
During error on CLOSE_INSTANCE command, ctx_work_bits was not getting cleared. During consequent mfc execution NULL pointer dereferencing of this context led to kernel panic. This patch fixes this issue by making sure to clear ctx_work_bits always.
--- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +3 -1
@@ -468,8 +468,10 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)s5p_mfc_hw_call (dev->mfc_ops, try_run, dev);/* Wait until instance is returned or timeout occurred */ if (s5p_mfc_wait_for_done_ctx (ctx, -S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET ,0 )) +S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET ,0 )){ +clear_work_bit_irqsave (ctx);mfc_err ("Err returning instance\n" ); + }/* Free resources */ s5p_mfc_hw_call (dev->mfc_ops, release_codec_buffers, ctx);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 186/290 media: s5p-mfc: Fix in register read and write for H264
In reply to Greg Kroah-HartmanFrom: Smitha T Murthy <[email protected]>
[ Upstream commit 06710cd5d2436135046898d7e4b9408c8bb99446 ]
Few of the H264 encoder registers written were not getting reflected since the read values were not stored and getting overwritten.
--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +7 -7
@@ -1060,7 +1060,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) }/* aspect ratio VUI */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<5 ); reg |= ((p_h264->vui_sar &0x1 ) <<5 );writel (reg, mfc_regs->e_h264_options);
@@ -1083,7 +1083,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)/* intra picture period for H.264 open GOP */ /* control */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<4 ); reg |= ((p_h264->open_gop &0x1 ) <<4 );writel (reg, mfc_regs->e_h264_options);
@@ -1097,23 +1097,23 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) }/* 'WEIGHTED_BI_PREDICTION' for B is disable */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x3 <<9 );writel (reg, mfc_regs->e_h264_options);/* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<14 );writel (reg, mfc_regs->e_h264_options);/* ASO */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<6 ); reg |= ((p_h264->aso &0x1 ) <<6 );writel (reg, mfc_regs->e_h264_options);/* hier qp enable */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<8 ); reg |= ((p_h264->open_gop &0x1 ) <<8 );writel (reg, mfc_regs->e_h264_options);
@@ -1134,7 +1134,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)writel (reg, mfc_regs->e_h264_num_t_layer);/* frame packing SEI generation */ -readl (mfc_regs->e_h264_options); + reg =readl (mfc_regs->e_h264_options); reg &= ~(0x1 <<25 ); reg |= ((p_h264->sei_frame_packing &0x1 ) <<25 );writel (reg, mfc_regs->e_h264_options);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 187/290 perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
In reply to Greg Kroah-HartmanFrom: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit f828929ab7f0dc3353e4a617f94f297fa8f3dec3 ]
Use dwarf_attr_integrate() instead of dwarf_attr() for generic attribute acccessor functions, so that it can find the specified attribute from abstact origin DIE etc.
Stable-dep-of: a9dfc46c67b5 ("perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data")
--- tools/perf/util/dwarf-aux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/dwarf-aux.c +2 -2
@@ -308,7 +308,7 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, {Dwarf_Attribute attr; -if (dwarf_attr (tp_die, attr_name, &attr) ==NULL || +if (dwarf_attr_integrate (tp_die, attr_name, &attr) ==NULL ||dwarf_formudata (&attr, result) !=0 )return -ENOENT ;
@@ -321,7 +321,7 @@ static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, {Dwarf_Attribute attr; -if (dwarf_attr (tp_die, attr_name, &attr) ==NULL || +if (dwarf_attr_integrate (tp_die, attr_name, &attr) ==NULL ||dwarf_formsdata (&attr, result) !=0 )return -ENOENT ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 188/290 perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data
In reply to Greg Kroah-HartmanFrom: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit a9dfc46c67b52ad43b8e335e28f4cf8002c67793 ]
DWARF version 5 standard Sec 2.14 says that
Any debugging information entry representing the declaration of an object, module, subprogram or type may have DW_AT_decl_file, DW_AT_decl_line and DW_AT_decl_column attributes, each of whose value is an unsigned integer constant.
So it should be an unsigned integer data. Also, even though the standard doesn't clearly say the DW_AT_call_file is signed or unsigned, the elfutils (eu-readelf) interprets it as unsigned integer data and it is natural to handle it as unsigned integer data as same as DW_AT_decl_file. This changes the DW_AT_call_file as unsigned integer data too.
--- tools/perf/util/dwarf-aux.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-)
tools/perf/util/dwarf-aux.c +4 -17
@@ -315,19 +315,6 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,return 0 ; } -/* Get attribute and translate it as a sdata */ -static int die_get_attr_sdata (Dwarf_Die *tp_die,unsigned int attr_name, -Dwarf_Sword *result) -{ -Dwarf_Attribute attr; - -if (dwarf_attr_integrate (tp_die, attr_name, &attr) ==NULL || -dwarf_formsdata (&attr, result) !=0 ) -return -ENOENT ; - -return 0 ; -} -/** * die_is_signed_type - Check whether a type DIE is signed or not * @tp_die: a DIE of a type
@@ -467,9 +454,9 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)/* Get the call file index number in CU DIE */ static int die_get_call_fileno (Dwarf_Die *in_die) { -Dwarf_Sword idx; +Dwarf_Word idx; -if (die_get_attr_sdata (in_die, DW_AT_call_file, &idx) ==0 ) +if (die_get_attr_udata (in_die, DW_AT_call_file, &idx) ==0 )return (int )idx;else return -ENOENT ;
@@ -478,9 +465,9 @@ static int die_get_call_fileno(Dwarf_Die *in_die)/* Get the declared file index number in CU DIE */ static int die_get_decl_fileno (Dwarf_Die *pdie) { -Dwarf_Sword idx; +Dwarf_Word idx; -if (die_get_attr_sdata (pdie, DW_AT_decl_file, &idx) ==0 ) +if (die_get_attr_udata (pdie, DW_AT_decl_file, &idx) ==0 )return (int )idx;else return -ENOENT ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 189/290 ravb: Fix "failed to switch device to config mode" message during unbind
In reply to Greg Kroah-HartmanFrom: Biju Das <[email protected]>
[ Upstream commit c72a7e42592b2e18d862cf120876070947000d7a ]
This patch fixes the error "ravb 11c20000.ethernet eth0: failed to switch device to config mode" during unbind.
We are doing register access after pm_runtime_put_sync().
We usually do cleanup in reverse order of init. Currently in remove(), the "pm_runtime_put_sync" is not in reverse order.
Probe
reset_control_deassert(rstc); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
remove
pm_runtime_put_sync(&pdev->dev); unregister_netdev(ndev); .. ravb_mdio_release(priv); pm_runtime_disable(&pdev->dev);
Consider the call to unregister_netdev() unregister_netdev->unregister_netdevice_queue->rollback_registered_many that calls the below functions which access the registers after pm_runtime_put_sync()
1) ravb_get_stats
2) ravb_close
--- drivers/net/ethernet/renesas/ravb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/renesas/ravb_main.c +1 -1
@@ -2378,11 +2378,11 @@ static int ravb_remove(struct platform_device *pdev) priv->desc_bat_dma);/* Set reset mode */ ravb_write (ndev,CCC_OPC_RESET ,CCC ); -pm_runtime_put_sync (&pdev->dev);unregister_netdev (ndev);netif_napi_del (&priv->napi[RAVB_NC ]);netif_napi_del (&priv->napi[RAVB_BE ]);ravb_mdio_release (priv); +pm_runtime_put_sync (&pdev->dev);pm_runtime_disable (&pdev->dev);reset_control_assert (priv->rstc);free_netdev (ndev);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 190/290 ext4: goto right label failed_mount3a
In reply to Greg Kroah-HartmanFrom: Jason Yan <[email protected]>
[ Upstream commit 43bd6f1b49b61f43de4d4e33661b8dbe8c911f14 ]
Before these two branches neither loaded the journal nor created the xattr cache. So the right label to goto is 'failed_mount3a'. Although this did not cause any issues because the error handler validated if the pointer is null. However this still made me confused when reading the code. So it's still worth to modify to goto the right label.
Stable-dep-of: 89481b5fa8c0 ("ext4: correct inconsistent error msg in nojournal mode")
--- fs/ext4/super.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/ext4/super.c +5 -5
@@ -4664,30 +4664,30 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_has_feature_journal_needs_recovery(sb)) { ext4_msg(sb, KERN_ERR, "required journal recovery " "suppressed and not mounted read-only"); - goto failed_mount_wq; + goto failed_mount3a; } else {/* Nojournal mode, all journal mount options are illegal */ if (test_opt2 (sb,EXPLICIT_JOURNAL_CHECKSUM )) {ext4_msg (sb,KERN_ERR ,"can't mount with " "journal_checksum, fs mounted w/o journal" ); - goto failed_mount_wq; + goto failed_mount3a; }if (test_opt (sb,JOURNAL_ASYNC_COMMIT )) {ext4_msg (sb,KERN_ERR ,"can't mount with " "journal_async_commit, fs mounted w/o journal" ); - goto failed_mount_wq; + goto failed_mount3a; }if (sbi->s_commit_interval !=JBD2_DEFAULT_MAX_COMMIT_AGE *HZ ) {ext4_msg (sb,KERN_ERR ,"can't mount with " "commit=%lu, fs mounted w/o journal" , sbi->s_commit_interval /HZ ); - goto failed_mount_wq; + goto failed_mount3a; }if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {ext4_msg (sb,KERN_ERR ,"can't mount with " "data=, fs mounted w/o journal" ); - goto failed_mount_wq; + goto failed_mount3a; } sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM ;clear_opt (sb,JOURNAL_CHECKSUM );
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 191/290 ext4: correct inconsistent error msg in nojournal mode
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
[ Upstream commit 89481b5fa8c0640e62ba84c6020cee895f7ac643 ]
When we used the journal_async_commit mounting option in nojournal mode, the kernel told me that "can't mount with journal_checksum", was very confusing. I find that when we mount with journal_async_commit, both the JOURNAL_ASYNC_COMMIT and EXPLICIT_JOURNAL_CHECKSUM flags are set. However, in the error branch, CHECKSUM is checked before ASYNC_COMMIT. As a result, the above inconsistency occurs, and the ASYNC_COMMIT branch becomes dead code that cannot be executed. Therefore, we exchange the positions of the two judgments to make the error msg more accurate.
--- fs/ext4/super.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
fs/ext4/super.c +5 -4
@@ -4667,14 +4667,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount3a; }else {/* Nojournal mode, all journal mount options are illegal */ -if (test_opt2 (sb,EXPLICIT_JOURNAL_CHECKSUM )) { +if (test_opt (sb,JOURNAL_ASYNC_COMMIT )) {ext4_msg (sb,KERN_ERR ,"can't mount with " -"journal_checksum, fs mounted w/o journal" ); +"journal_async_commit, fs mounted w/o journal" ); goto failed_mount3a; } -if (test_opt (sb,JOURNAL_ASYNC_COMMIT )) { + +if (test_opt2 (sb,EXPLICIT_JOURNAL_CHECKSUM )) {ext4_msg (sb,KERN_ERR ,"can't mount with " -"journal_async_commit, fs mounted w/o journal" ); +"journal_checksum, fs mounted w/o journal" ); goto failed_mount3a; }if (sbi->s_commit_interval !=JBD2_DEFAULT_MAX_COMMIT_AGE *HZ ) {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 192/290 mbcache: automatically delete entries from cache on freeing
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
[ Upstream commit 307af6c879377c1c63e71cbdd978201f9c7ee8df ]
Use the fact that entries with elevated refcount are not removed from the hash and just move removal of the entry from the hash to the entry freeing time. When doing this we also change the generic code to hold one reference to the cache entry, not two of them, which makes code somewhat more obvious.
Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
--- fs/mbcache.c | 108 +++++++++++++++------------------------- include/linux/mbcache.h | 24 ++++++--- 2 files changed, 55 insertions(+), 77 deletions(-)
fs/mbcache.c +39 -69
@@ -90,7 +90,7 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,return -ENOMEM ;INIT_LIST_HEAD (&entry->e_list); -/* One ref for hash, one ref returned */ +/* Initial hash reference */ atomic_set (&entry->e_refcnt,1 ); entry->e_key = key; entry->e_value = value;
@@ -106,21 +106,28 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, } }hlist_bl_add_head (&entry->e_hash_list, head); -hlist_bl_unlock (head); - +/* +* Add entry to LRU list before it can be found by +* mb_cache_entry_delete() to avoid races +*/ spin_lock (&cache->c_list_lock);list_add_tail (&entry->e_list, &cache->c_list); -/* Grab ref for LRU list */ -atomic_inc (&entry->e_refcnt); cache->c_entry_count++;spin_unlock (&cache->c_list_lock); +hlist_bl_unlock (head);return 0 ; }EXPORT_SYMBOL (mb_cache_entry_create); -void __mb_cache_entry_free (struct mb_cache_entry *entry) +void __mb_cache_entry_free (struct mb_cache *cache,struct mb_cache_entry *entry) { +struct hlist_bl_head *head; + + head =mb_cache_entry_head (cache, entry->e_key); +hlist_bl_lock (head); +hlist_bl_del (&entry->e_hash_list); +hlist_bl_unlock (head);kmem_cache_free (mb_entry_cache, entry); }EXPORT_SYMBOL (__mb_cache_entry_free);
@@ -134,7 +141,7 @@ EXPORT_SYMBOL(__mb_cache_entry_free);*/ void mb_cache_entry_wait_unused (struct mb_cache_entry *entry) { -wait_var_event (&entry->e_refcnt,atomic_read (&entry->e_refcnt) <=3 ); +wait_var_event (&entry->e_refcnt,atomic_read (&entry->e_refcnt) <=2 ); }EXPORT_SYMBOL (mb_cache_entry_wait_unused);
@@ -155,10 +162,9 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,while (node) { entry = hlist_bl_entry(node, struct mb_cache_entry, e_hash_list); -if (entry->e_key == key && entry->e_reusable) { -atomic_inc (&entry->e_refcnt); +if (entry->e_key == key && entry->e_reusable && +atomic_inc_not_zero (&entry->e_refcnt)) goto out; - } node = node->next; } entry =NULL ;
@@ -218,10 +224,9 @@ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, head =mb_cache_entry_head (cache, key);hlist_bl_lock (head);hlist_bl_for_each_entry (entry, node, head, e_hash_list) { -if (entry->e_key == key && entry->e_value == value) { -atomic_inc (&entry->e_refcnt); +if (entry->e_key == key && entry->e_value == value && +atomic_inc_not_zero (&entry->e_refcnt)) goto out; - } } entry =NULL ; out:
@@ -281,37 +286,25 @@ EXPORT_SYMBOL(mb_cache_entry_delete);struct mb_cache_entry *mb_cache_entry_delete_or_get (struct mb_cache *cache,u32 key,u64 value) { -struct hlist_bl_node *node; -struct hlist_bl_head *head;struct mb_cache_entry *entry; - head =mb_cache_entry_head (cache, key); -hlist_bl_lock (head); -hlist_bl_for_each_entry (entry, node, head, e_hash_list) { -if (entry->e_key == key && entry->e_value == value) { -if (atomic_read (&entry->e_refcnt) >2 ) { -atomic_inc (&entry->e_refcnt); -hlist_bl_unlock (head); -return entry; - } -/* We keep hash list reference to keep entry alive */ -hlist_bl_del_init (&entry->e_hash_list); -hlist_bl_unlock (head); -spin_lock (&cache->c_list_lock); -if (!list_empty (&entry->e_list)) { -list_del_init (&entry->e_list); -if (!WARN_ONCE (cache->c_entry_count ==0 , -"mbcache: attempt to decrement c_entry_count past zero" )) - cache->c_entry_count--; -atomic_dec (&entry->e_refcnt); - } -spin_unlock (&cache->c_list_lock); -mb_cache_entry_put (cache, entry); -return NULL ; - } - } -hlist_bl_unlock (head); + entry =mb_cache_entry_get (cache, key, value); +if (!entry) +return NULL ; +/* +* Drop the ref we got from mb_cache_entry_get() and the initial hash +* ref if we are the last user +*/ +if (atomic_cmpxchg (&entry->e_refcnt,2 ,0 ) !=2 ) +return entry; + +spin_lock (&cache->c_list_lock); +if (!list_empty (&entry->e_list)) +list_del_init (&entry->e_list); + cache->c_entry_count--; +spin_unlock (&cache->c_list_lock); +__mb_cache_entry_free (cache, entry);return NULL ; }EXPORT_SYMBOL (mb_cache_entry_delete_or_get);
@@ -343,42 +336,24 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, unsigned long nr_to_scan) {struct mb_cache_entry *entry; -struct hlist_bl_head *head;unsigned long shrunk =0 ;spin_lock (&cache->c_list_lock);while (nr_to_scan-- && !list_empty (&cache->c_list)) { entry =list_first_entry (&cache->c_list, struct mb_cache_entry, e_list); -if (entry->e_referenced ||atomic_read (&entry->e_refcnt) >2 ) { +/* Drop initial hash reference if there is no user */ +if (entry->e_referenced || +atomic_cmpxchg (&entry->e_refcnt,1 ,0 ) !=1 ) { entry->e_referenced =0 ;list_move_tail (&entry->e_list, &cache->c_list);continue ; }list_del_init (&entry->e_list); cache->c_entry_count--; -/* -* We keep LRU list reference so that entry doesn't go away -* from under us. -*/ spin_unlock (&cache->c_list_lock); - head =mb_cache_entry_head (cache, entry->e_key); -hlist_bl_lock (head); -/* Now a reliable check if the entry didn't get used... */ -if (atomic_read (&entry->e_refcnt) >2 ) { -hlist_bl_unlock (head); -spin_lock (&cache->c_list_lock); -list_add_tail (&entry->e_list, &cache->c_list); - cache->c_entry_count++; -continue ; - } -if (!hlist_bl_unhashed (&entry->e_hash_list)) { -hlist_bl_del_init (&entry->e_hash_list); -atomic_dec (&entry->e_refcnt); - } -hlist_bl_unlock (head); -if (mb_cache_entry_put (cache, entry)) - shrunk++; +__mb_cache_entry_free (cache, entry); + shrunk++;cond_resched ();spin_lock (&cache->c_list_lock); }
@@ -470,11 +445,6 @@ void mb_cache_destroy(struct mb_cache *cache)* point. */ list_for_each_entry_safe (entry, next, &cache->c_list, e_list) { -if (!hlist_bl_unhashed (&entry->e_hash_list)) { -hlist_bl_del_init (&entry->e_hash_list); -atomic_dec (&entry->e_refcnt); - }else -WARN_ON (1 );list_del (&entry->e_list);WARN_ON (atomic_read (&entry->e_refcnt) !=1 );mb_cache_entry_put (cache, entry);
include/linux/mbcache.h +16 -8
@@ -13,8 +13,16 @@ struct mb_cache;struct mb_cache_entry {/* List of entries in cache - protected by cache->c_list_lock */ struct list_head e_list; -/* Hash table list - protected by hash chain bitlock */ +/* +* Hash table list - protected by hash chain bitlock. The entry is +* guaranteed to be hashed while e_refcnt > 0. +*/ struct hlist_bl_node e_hash_list; +/* +* Entry refcount. Once it reaches zero, entry is unhashed and freed. +* While refcount > 0, the entry is guaranteed to stay in the hash and +* e.g. mb_cache_entry_try_delete() will fail. +*/ atomic_t e_refcnt;/* Key in hash - stable during lifetime of the entry */ u32 e_key;
@@ -29,20 +37,20 @@ void mb_cache_destroy(struct mb_cache *cache);int mb_cache_entry_create (struct mb_cache *cache,gfp_t mask,u32 key,u64 value,bool reusable); -void __mb_cache_entry_free (struct mb_cache_entry *entry); +void __mb_cache_entry_free (struct mb_cache *cache, +struct mb_cache_entry *entry);void mb_cache_entry_wait_unused (struct mb_cache_entry *entry); -static inline int mb_cache_entry_put (struct mb_cache *cache, -struct mb_cache_entry *entry) +static inline void mb_cache_entry_put (struct mb_cache *cache, +struct mb_cache_entry *entry) {unsigned int cnt =atomic_dec_return (&entry->e_refcnt);if (cnt >0 ) { -if (cnt <=3 ) +if (cnt <=2 )wake_up_var (&entry->e_refcnt); -return 0 ; +return ; } -__mb_cache_entry_free (entry); -return 1 ; +__mb_cache_entry_free (cache, entry); } struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 193/290 ext4: fix deadlock due to mbcache entry corruption
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
[ Upstream commit a44e84a9b7764c72896f7241a0ec9ac7e7ef38dd ]
When manipulating xattr blocks, we can deadlock infinitely looping inside ext4_xattr_block_set() where we constantly keep finding xattr block for reuse in mbcache but we are unable to reuse it because its reference count is too big. This happens because cache entry for the xattr block is marked as reusable (e_reusable set) although its reference count is too big. When this inconsistency happens, this inconsistent state is kept indefinitely and so ext4_xattr_block_set() keeps retrying indefinitely.
The inconsistent state is caused by non-atomic update of e_reusable bit. e_reusable is part of a bitfield and e_reusable update can race with update of e_referenced bit in the same bitfield resulting in loss of one of the updates. Fix the problem by using atomic bitops instead.
This bug has been around for many years, but it became *much* easier to hit after commit 65f8b80053a1 ("ext4: fix race when reusing xattr blocks").
--- fs/ext4/xattr.c | 4 ++-- fs/mbcache.c | 14 ++++++++------ include/linux/mbcache.h | 9 +++++++-- 3 files changed, 17 insertions(+), 10 deletions(-)
fs/ext4/xattr.c +2 -2
@@ -1281,7 +1281,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, ce =mb_cache_entry_get (ea_block_cache, hash, bh->b_blocknr);if (ce) { - ce->e_reusable =1 ; +set_bit (MBE_REUSABLE_B , &ce->e_flags);mb_cache_entry_put (ea_block_cache, ce); } }
@@ -2045,7 +2045,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, }BHDR (new_bh)->h_refcount =cpu_to_le32 (ref);if (ref ==EXT4_XATTR_REFCOUNT_MAX ) - ce->e_reusable =0 ; +clear_bit (MBE_REUSABLE_B , &ce->e_flags);ea_bdebug (new_bh,"reusing; refcount now=%d" , ref);ext4_xattr_block_csum_set (inode, new_bh);
fs/mbcache.c +8 -6
@@ -94,8 +94,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,atomic_set (&entry->e_refcnt,1 ); entry->e_key = key; entry->e_value = value; - entry->e_reusable = reusable; - entry->e_referenced =0 ; + entry->e_flags =0 ; +if (reusable) +set_bit (MBE_REUSABLE_B , &entry->e_flags); head =mb_cache_entry_head (cache, key);hlist_bl_lock (head);hlist_bl_for_each_entry (dup, dup_node, head, e_hash_list) {
@@ -162,7 +163,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,while (node) { entry = hlist_bl_entry(node, struct mb_cache_entry, e_hash_list); -if (entry->e_key == key && entry->e_reusable && +if (entry->e_key == key && +test_bit (MBE_REUSABLE_B , &entry->e_flags) &&atomic_inc_not_zero (&entry->e_refcnt)) goto out; node = node->next;
@@ -318,7 +320,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get);void mb_cache_entry_touch (struct mb_cache *cache,struct mb_cache_entry *entry) { - entry->e_referenced =1 ; +set_bit (MBE_REFERENCED_B , &entry->e_flags); }EXPORT_SYMBOL (mb_cache_entry_touch);
@@ -343,9 +345,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, entry =list_first_entry (&cache->c_list, struct mb_cache_entry, e_list);/* Drop initial hash reference if there is no user */ -if (entry->e_referenced || +if (test_bit (MBE_REFERENCED_B , &entry->e_flags) ||atomic_cmpxchg (&entry->e_refcnt,1 ,0 ) !=1 ) { - entry->e_referenced =0 ; +clear_bit (MBE_REFERENCED_B , &entry->e_flags);list_move_tail (&entry->e_list, &cache->c_list);continue ; }
include/linux/mbcache.h +7 -2
@@ -10,6 +10,12 @@struct mb_cache ; +/* Cache entry flags */ +enum { +MBE_REFERENCED_B =0 , +MBE_REUSABLE_B +}; +struct mb_cache_entry {/* List of entries in cache - protected by cache->c_list_lock */ struct list_head e_list;
@@ -26,8 +32,7 @@ struct mb_cache_entry {atomic_t e_refcnt;/* Key in hash - stable during lifetime of the entry */ u32 e_key; - u32 e_referenced:1; - u32 e_reusable:1; +unsigned long e_flags;/* User provided value - stable during lifetime of the entry */ u64 e_value; };
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 194/290 drm/i915/migrate: dont check the scratch page
In reply to Greg Kroah-HartmanFrom: Matthew Auld <[email protected]>
[ Upstream commit 8eb7fcce34d16f77ac8efa80e8dfecec2503e8c5 ]
The scratch page might not be allocated in LMEM(like on DG2), so instead of using that as the deciding factor for where the paging structures live, let's just query the pt before mapping it.
--- drivers/gpu/drm/i915/gt/intel_migrate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/gpu/drm/i915/gt/intel_migrate.c +1 -3
@@ -13,7 +13,6 @@struct insert_pte_data {u64 offset; -bool is_lmem; };#define CHUNK_SZ SZ_8M/* ~1ms at 8GiB/s preemption delay */
@@ -40,7 +39,7 @@ static void insert_pte(struct i915_address_space *vm,struct insert_pte_data *d = data; vm->insert_page (vm,px_dma (pt), d->offset,I915_CACHE_NONE , - d->is_lmem ?PTE_LM :0 ); +i915_gem_object_is_lmem (pt->base) ?PTE_LM :0 ); d->offset +=PAGE_SIZE ; }
@@ -134,7 +133,6 @@ static struct i915_address_space *migrate_vm(struct intel_gt *gt) goto err_vm;/* Now allow the GPU to rewrite the PTE via its own ppGTT */ - d.is_lmem =i915_gem_object_is_lmem (vm->vm.scratch[0 ]); vm->vm.foreach (&vm->vm, base, base + sz, insert_pte, &d); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 195/290 drm/i915/migrate: fix offset calculation
In reply to Greg Kroah-HartmanFrom: Matthew Auld <[email protected]>
[ Upstream commit 08c7c122ad90799cc3ae674e7f29f236f91063ce ]
Ensure we add the engine base only after we calculate the qword offset into the PTE window.
--- drivers/gpu/drm/i915/gt/intel_migrate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_migrate.c +1 -1
@@ -279,10 +279,10 @@ static int emit_pte(struct i915_request *rq,GEM_BUG_ON (GRAPHICS_VER (rq->engine->i915) <8 );/* Compute the page directory offset for the target address range */ - offset += (u64 )rq->engine->instance <<32 ; offset >>=12 ; offset *=sizeof (u64); offset +=2 *CHUNK_SZ ; + offset += (u64 )rq->engine->instance <<32 ; cs =intel_ring_begin (rq,6 );if (IS_ERR (cs))
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 196/290 drm/i915/migrate: fix length calculation
In reply to Greg Kroah-HartmanFrom: Matthew Auld <[email protected]>
[ Upstream commit 31d70749bfe110593fbe8bf45e7c7788c7d85035 ]
No need to insert PTEs for the PTE window itself, also foreach expects a length not an end offset, which could be gigantic here with a second engine.
--- drivers/gpu/drm/i915/gt/intel_migrate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_migrate.c +1 -1
@@ -133,7 +133,7 @@ static struct i915_address_space *migrate_vm(struct intel_gt *gt) goto err_vm;/* Now allow the GPU to rewrite the PTE via its own ppGTT */ - vm->vm.foreach (&vm->vm, base, base + sz, insert_pte, &d); + vm->vm.foreach (&vm->vm, base, d.offset - base, insert_pte, &d); }return &vm->vm;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 197/290 SUNRPC: ensure the matching upcall is in-flight upon downcall
In reply to Greg Kroah-HartmanFrom: minoura makoto <[email protected]>
[ Upstream commit b18cba09e374637a0a3759d856a6bca94c133952 ]
Commit 9130b8dbc6ac ("SUNRPC: allow for upcalls for the same uid but different gss service") introduced auth argument to __gss_find_upcall(), but in gss_pipe_downcall() it was left as NULL since it (and auth->service) was not (yet) determined.
When multiple upcalls with the same uid and different service are ongoing, it could happen that __gss_find_upcall(), which returns the first match found in the pipe->in_downcall list, could not find the correct gss_msg corresponding to the downcall we are looking for. Moreover, it might return a msg which is not sent to rpc.gssd yet.
We could see mount.nfs process hung in D state with multiple mount.nfs are executed in parallel. The call trace below is of CentOS 7.9 kernel-3.10.0-1160.24.1.el7.x86_64 but we observed the same hang w/ elrepo kernel-ml-6.0.7-1.el7.
PID: 71258 TASK: ffff91ebd4be0000 CPU: 36 COMMAND: "mount.nfs"
#0 [ffff9203ca3234f8] __schedule at ffffffffa3b8899f
#1 [ffff9203ca323580] schedule at ffffffffa3b88eb9
#2 [ffff9203ca323590] gss_cred_init at ffffffffc0355818 [auth_rpcgss] #3 [ffff9203ca323658] rpcauth_lookup_credcache at ffffffffc0421ebc
[sunrpc]
#4 [ffff9203ca3236d8] gss_lookup_cred at ffffffffc0353633 [auth_rpcgss] #5 [ffff9203ca3236e8] rpcauth_lookupcred at ffffffffc0421581 [sunrpc] #6 [ffff9203ca323740] rpcauth_refreshcred at ffffffffc04223d3 [sunrpc] #7 [ffff9203ca3237a0] call_refresh at ffffffffc04103dc [sunrpc] #8 [ffff9203ca3237b8] __rpc_execute at ffffffffc041e1c9 [sunrpc] #9 [ffff9203ca323820] rpc_execute at ffffffffc0420a48 [sunrpc]
The scenario is like this. Let's say there are two upcalls for services A and B, A -> B in pipe->in_downcall, B -> A in pipe->pipe.
When rpc.gssd reads pipe to get the upcall msg corresponding to service B from pipe->pipe and then writes the response, in gss_pipe_downcall the msg corresponding to service A will be picked because only uid is used to find the msg and it is before the one for B in pipe->in_downcall. And the process waiting for the msg corresponding to service A will be woken up.
Actual scheduing of that process might be after rpc.gssd processes the next msg. In rpc_pipe_generic_upcall it clears msg->errno (for A). The process is scheduled to see gss_msg->ctx == NULL and gss_msg->msg.errno == 0, therefore it cannot break the loop in gss_create_upcall and is never woken up after that.
This patch adds a simple check to ensure that a msg which is not sent to rpc.gssd yet is not chosen as the matching upcall upon receiving a downcall.
--- include/linux/sunrpc/rpc_pipe_fs.h | 5 +++++ net/sunrpc/auth_gss/auth_gss.c | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-)
include/linux/sunrpc/rpc_pipe_fs.h +5 -0
@@ -92,6 +92,11 @@ extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, char __user *, size_t);extern int rpc_queue_upcall (struct rpc_pipe *,struct rpc_pipe_msg *); +/* returns true if the msg is in-flight, i.e., already eaten by the peer */ +static inline bool rpc_msg_is_inflight (const struct rpc_pipe_msg *msg) { +return (msg->copied !=0 &&list_empty (&msg->list)); +} +struct rpc_clnt ;extern struct dentry *rpc_create_client_dir (struct dentry *,const char *,struct rpc_clnt *);extern int rpc_remove_client_dir (struct rpc_clnt *);
net/sunrpc/auth_gss/auth_gss.c +17 -2
@@ -301,7 +301,7 @@ __gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *authlist_for_each_entry (pos, &pipe->in_downcall, list) {if (!uid_eq (pos->uid, uid))continue ; -if (auth && pos->auth->service != auth->service) +if (pos->auth->service != auth->service)continue ;refcount_inc (&pos->count);return pos;
@@ -685,6 +685,21 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)return err; } +static struct gss_upcall_msg * +gss_find_downcall (struct rpc_pipe *pipe,kuid_t uid) +{ +struct gss_upcall_msg *pos; +list_for_each_entry (pos, &pipe->in_downcall, list) { +if (!uid_eq (pos->uid, uid)) +continue ; +if (!rpc_msg_is_inflight (&pos->msg)) +continue ; +refcount_inc (&pos->count); +return pos; + } +return NULL ; +} +#define MSG_BUF_MAXSIZE 1024 static ssize_t
@@ -731,7 +746,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = -ENOENT ;/* Find a matching upcall */ spin_lock (&pipe->lock); - gss_msg =__gss_find_upcall (pipe, uid,NULL ); + gss_msg =gss_find_downcall (pipe, uid);if (gss_msg ==NULL ) {spin_unlock (&pipe->lock); goto err_put_ctx;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 198/290 btrfs: fix an error handling path in btrfs_defrag_leaves()
In reply to Greg Kroah-Hartman[ Upstream commit db0a4a7b8e95f9312a59a67cbd5bc589f090e13d ]
All error handling paths end to 'out', except this memory allocation failure.
This is spurious. So branch to the error handling path also in this case. It will add a call to:
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
--- fs/btrfs/tree-defrag.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/btrfs/tree-defrag.c +4 -2
@@ -39,8 +39,10 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, goto out; path =btrfs_alloc_path (); -if (!path) -return -ENOMEM ; +if (!path) { + ret = -ENOMEM ; + goto out; + } level =btrfs_header_level (root->node);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 199/290 bpf: pull before calling skb_postpull_rcsum()
In reply to Greg Kroah-HartmanFrom: Jakub Kicinski <[email protected]>
[ Upstream commit 54c3f1a81421f85e60ae2eaae7be3727a09916ee ]
Anand hit a BUG() when pulling off headers on egress to a SW tunnel. We get to skb_checksum_help() with an invalid checksum offset (commit d7ea0d9df2a6 ("net: remove two BUG() from skb_checksum_help()") converted those BUGs to WARN_ONs()).
He points out oddness in how skb_postpull_rcsum() gets used. Indeed looks like we should pull before "postpull", otherwise the CHECKSUM_PARTIAL fixup from skb_postpull_rcsum() will not be able to do its job:
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_start_offset(skb) < 0) skb->ip_summed = CHECKSUM_NONE;
--- net/core/filter.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/core/filter.c +5 -2
@@ -3182,15 +3182,18 @@ static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)static int bpf_skb_generic_pop (struct sk_buff *skb,u32 off,u32 len) { +void *old_data; +/* skb_ensure_writable() is not needed here, as we're * already working on an uncloned skb. */ if (unlikely (!pskb_may_pull (skb, off + len)))return -ENOMEM ; -skb_postpull_rcsum (skb, skb->data + off, len); -memmove (skb->data + len, skb->data, off); + old_data = skb->data;__skb_pull (skb, len); +skb_postpull_rcsum (skb, old_data + off, len); +memmove (skb->data, old_data, off);return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 200/290 drm/panfrost: Fix GEM handle creation ref-counting
In reply to Greg Kroah-HartmanFrom: Steven Price <[email protected]>
[ Upstream commit 4217c6ac817451d5116687f3cc6286220dc43d49 ]
panfrost_gem_create_with_handle() previously returned a BO but with the only reference being from the handle, which user space could in theory guess and release, causing a use-after-free. Additionally if the call to panfrost_gem_mapping_get() in panfrost_ioctl_create_bo() failed then a(nother) reference on the BO was dropped.
The _create_with_handle() is a problematic pattern, so ditch it and instead create the handle in panfrost_ioctl_create_bo(). If the call to panfrost_gem_mapping_get() fails then this means that user space has indeed gone behind our back and freed the handle. In which case just return an error code.
--- drivers/gpu/drm/panfrost/panfrost_drv.c | 27 ++++++++++++++++--------- drivers/gpu/drm/panfrost/panfrost_gem.c | 16 +-------------- drivers/gpu/drm/panfrost/panfrost_gem.h | 5 +---- 3 files changed, 20 insertions(+), 28 deletions(-)
drivers/gpu/drm/panfrost/panfrost_drv.c +18 -9
@@ -82,6 +82,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,struct panfrost_gem_object *bo;struct drm_panfrost_create_bo *args = data;struct panfrost_gem_mapping *mapping; +int ret;if (!args->size || args->pad || (args->flags & ~(PANFROST_BO_NOEXEC |PANFROST_BO_HEAP )))
@@ -92,21 +93,29 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, !(args->flags & PANFROST_BO_NOEXEC))return -EINVAL ; - bo =panfrost_gem_create_with_handle (file, dev, args->size, args->flags, - &args->handle); + bo =panfrost_gem_create (dev, args->size, args->flags);if (IS_ERR (bo))return PTR_ERR (bo); + ret =drm_gem_handle_create (file, &bo->base.base, &args->handle); +if (ret) + goto out; + mapping =panfrost_gem_mapping_get (bo, priv); -if (!mapping) { -drm_gem_object_put (&bo->base.base); -return -EINVAL ; +if (mapping) { + args->offset = mapping->mmnode.start <<PAGE_SHIFT ; +panfrost_gem_mapping_put (mapping); + }else { +/* This can only happen if the handle from +* drm_gem_handle_create() has already been guessed and freed +* by user space +*/ + ret = -EINVAL ; } - args->offset = mapping->mmnode.start <<PAGE_SHIFT ; -panfrost_gem_mapping_put (mapping); - -return 0 ; +out: +drm_gem_object_put (&bo->base.base); +return ret; }/**
drivers/gpu/drm/panfrost/panfrost_gem.c +1 -15
@@ -234,12 +234,8 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t }struct panfrost_gem_object * -panfrost_gem_create_with_handle (struct drm_file *file_priv, -struct drm_device *dev,size_t size, -u32 flags, -uint32_t *handle) +panfrost_gem_create (struct drm_device *dev,size_t size,u32 flags) { -int ret;struct drm_gem_shmem_object *shmem;struct panfrost_gem_object *bo;
@@ -255,16 +251,6 @@ panfrost_gem_create_with_handle(struct drm_file *file_priv, bo->noexec = !!(flags &PANFROST_BO_NOEXEC ); bo->is_heap = !!(flags &PANFROST_BO_HEAP ); -/* -* Allocate an id of idr table where the obj is registered -* and handle has the id what user can see. -*/ - ret =drm_gem_handle_create (file_priv, &shmem->base, handle); -/* drop reference from allocate - handle holds it now. */ -drm_gem_object_put (&shmem->base); -if (ret) -return ERR_PTR (ret); -return bo; }
drivers/gpu/drm/panfrost/panfrost_gem.h +1 -4
@@ -69,10 +69,7 @@ panfrost_gem_prime_import_sg_table(struct drm_device *dev, struct sg_table *sgt);struct panfrost_gem_object * -panfrost_gem_create_with_handle (struct drm_file *file_priv, -struct drm_device *dev,size_t size, -u32 flags, -uint32_t *handle); +panfrost_gem_create (struct drm_device *dev,size_t size,u32 flags);int panfrost_gem_open (struct drm_gem_object *obj,struct drm_file *file_priv); void panfrost_gem_close(struct drm_gem_object *obj,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 201/290 netfilter: nf_tables: consolidate set description
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit bed4a63ea4ae77cfe5aae004ef87379f0655260a ]
Add the following fields to the set description:
- key type
- data type
- object type
- policy
- gc_int: garbage collection interval)
- timeout: element timeout
This prepares for stricter set type checks on updates in a follow up patch.
Stable-dep-of: f6594c372afd ("netfilter: nf_tables: perform type checking for existing sets")
--- include/net/netfilter/nf_tables.h | 12 +++++++ net/netfilter/nf_tables_api.c | 58 +++++++++++++++---------------- 2 files changed, 40 insertions(+), 30 deletions(-)
include/net/netfilter/nf_tables.h +12 -0
@@ -283,17 +283,29 @@ struct nft_set_iter {/** * struct nft_set_desc - description of set elements * +* @ktype: key type * @klen: key length +* @dtype: data type * @dlen: data length +* @objtype: object type +* @flags: flags * @size: number of set elements +* @policy: set policy +* @gc_int: garbage collector interval * @field_len: length of each field in concatenation, bytes * @field_count: number of concatenated fields in element * @expr: set must support for expressions */ struct nft_set_desc { +u32 ktype;unsigned int klen; +u32 dtype;unsigned int dlen; +u32 objtype;unsigned int size; +u32 policy; +u32 gc_int; +u64 timeout;u8 field_len[NFT_REG32_COUNT ];u8 field_count;bool expr;
net/netfilter/nf_tables_api.c +28 -30
146 lines not on this page · raw message
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 202/290 netfilter: nf_tables: add function to create set stateful expressions
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit a8fe4154fa5a1bae590b243ed60f871e5a5e1378 ]
Add a helper function to allocate and initialize the stateful expressions that are defined in a set.
This patch allows to reuse this code from the set update path, to check that type of the update matches the existing set in the kernel.
Stable-dep-of: f6594c372afd ("netfilter: nf_tables: perform type checking for existing sets")
--- net/netfilter/nf_tables_api.c | 106 ++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 38 deletions(-)
net/netfilter/nf_tables_api.c +68 -38
@@ -4243,6 +4243,59 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc,return err; } +static int nft_set_expr_alloc (struct nft_ctx *ctx,struct nft_set *set, +const struct nlattr *const *nla, +struct nft_expr **exprs,int *num_exprs, +u32 flags) +{ +struct nft_expr *expr; +int err, i; + +if (nla[NFTA_SET_EXPR ]) { + expr =nft_set_elem_expr_alloc (ctx, set, nla[NFTA_SET_EXPR ]); +if (IS_ERR (expr)) { + err =PTR_ERR (expr); + goto err_set_expr_alloc; + } + exprs[0 ] = expr; + (*num_exprs)++; + }else if (nla[NFTA_SET_EXPRESSIONS ]) { +struct nlattr *tmp; +int left; + +if (!(flags &NFT_SET_EXPR )) { + err = -EINVAL ; + goto err_set_expr_alloc; + } + i =0 ; +nla_for_each_nested (tmp, nla[NFTA_SET_EXPRESSIONS ], left) { +if (i ==NFT_SET_EXPR_MAX ) { + err = -E2BIG ; + goto err_set_expr_alloc; + } +if (nla_type (tmp) !=NFTA_LIST_ELEM ) { + err = -EINVAL ; + goto err_set_expr_alloc; + } + expr =nft_set_elem_expr_alloc (ctx, set, tmp); +if (IS_ERR (expr)) { + err =PTR_ERR (expr); + goto err_set_expr_alloc; + } + exprs[i++] = expr; + (*num_exprs)++; + } + } + +return 0 ; + +err_set_expr_alloc: +for (i =0 ; i < *num_exprs; i++) +nft_expr_destroy (ctx, exprs[i]); + +return err; +} +static int nf_tables_newset (struct sk_buff *skb,const struct nfnl_info *info,const struct nlattr *const nla[]) {
@@ -4250,7 +4303,6 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,u8 genmask =nft_genmask_next (info->net);u8 family = info->nfmsg->nfgen_family;const struct nft_set_ops *ops; -struct nft_expr *expr =NULL ;struct net *net = info->net;struct nft_set_desc desc;struct nft_table *table;
@@ -4258,6 +4310,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,struct nft_set *set;struct nft_ctx ctx;size_t alloc_size; +int num_exprs =0 ;char *name;int err, i;u16 udlen;
@@ -4384,6 +4437,8 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,return PTR_ERR (set); } }else { +struct nft_expr *exprs[NFT_SET_EXPR_MAX ] = {}; +if (info->nlh->nlmsg_flags &NLM_F_EXCL ) {NL_SET_BAD_ATTR (extack, nla[NFTA_SET_NAME ]);return -EEXIST ;
@@ -4391,6 +4446,13 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,if (info->nlh->nlmsg_flags &NLM_F_REPLACE )return -EOPNOTSUPP ; + err =nft_set_expr_alloc (&ctx, set, nla, exprs, &num_exprs, flags); +if (err <0 ) +return err; + +for (i =0 ; i < num_exprs; i++) +nft_expr_destroy (&ctx, exprs[i]); +return 0 ; }
@@ -4458,43 +4520,11 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,if (err <0 ) goto err_set_init; -if (nla[NFTA_SET_EXPR ]) { - expr =nft_set_elem_expr_alloc (&ctx, set, nla[NFTA_SET_EXPR ]); -if (IS_ERR (expr)) { - err =PTR_ERR (expr); - goto err_set_expr_alloc; - } - set->exprs[0 ] = expr; - set->num_exprs++; - }else if (nla[NFTA_SET_EXPRESSIONS ]) { -struct nft_expr *expr; -struct nlattr *tmp; -int left; - -if (!(flags &NFT_SET_EXPR )) { - err = -EINVAL ; - goto err_set_expr_alloc; - } - i =0 ; -nla_for_each_nested (tmp, nla[NFTA_SET_EXPRESSIONS ], left) { -if (i ==NFT_SET_EXPR_MAX ) { - err = -E2BIG ; - goto err_set_expr_alloc; - } -if (nla_type (tmp) !=NFTA_LIST_ELEM ) { - err = -EINVAL ; - goto err_set_expr_alloc; - } - expr =nft_set_elem_expr_alloc (&ctx, set, tmp); -if (IS_ERR (expr)) { - err =PTR_ERR (expr); - goto err_set_expr_alloc; - } - set->exprs[i++] = expr; - set->num_exprs++; - } - } + err =nft_set_expr_alloc (&ctx, set, nla, set->exprs, &num_exprs, flags); +if (err <0 ) + goto err_set_destroy; + set->num_exprs = num_exprs; set->handle =nf_tables_alloc_handle (table); err =nft_trans_set_add (&ctx,NFT_MSG_NEWSET , set);
@@ -4508,7 +4538,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, err_set_expr_alloc:for (i =0 ; i < set->num_exprs; i++)nft_expr_destroy (&ctx, set->exprs[i]); - +err_set_destroy: ops->destroy (set); err_set_init:kfree (set->name);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 203/290 netfilter: nf_tables: perform type checking for existing sets
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit f6594c372afd5cec8b1e9ee9ea8f8819d59c6fb1 ]
If a ruleset declares a set name that matches an existing set in the kernel, then validate that this declaration really refers to the same set, otherwise bail out with EEXIST.
Currently, the kernel reports success when adding a set that already exists in the kernel. This usually results in EINVAL errors at a later stage, when the user adds elements to the set, if the set declaration mismatches the existing set representation in the kernel.
Add a new function to check that the set declaration really refers to the same existing set in the kernel.
--- net/netfilter/nf_tables_api.c | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
net/netfilter/nf_tables_api.c +35 -1
@@ -4296,6 +4296,34 @@ static int nft_set_expr_alloc(struct nft_ctx *ctx, struct nft_set *set,return err; } +static bool nft_set_is_same (const struct nft_set *set, +const struct nft_set_desc *desc, +struct nft_expr *exprs[],u32 num_exprs,u32 flags) +{ +int i; + +if (set->ktype != desc->ktype || + set->dtype != desc->dtype || + set->flags != flags || + set->klen != desc->klen || + set->dlen != desc->dlen || + set->field_count != desc->field_count || + set->num_exprs != num_exprs) +return false; + +for (i =0 ; i < desc->field_count; i++) { +if (set->field_len[i] != desc->field_len[i]) +return false; + } + +for (i =0 ; i < num_exprs; i++) { +if (set->exprs[i]->ops != exprs[i]->ops) +return false; + } + +return true; +} +static int nf_tables_newset (struct sk_buff *skb,const struct nfnl_info *info,const struct nlattr *const nla[]) {
@@ -4450,10 +4478,16 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,if (err <0 )return err; + err =0 ; +if (!nft_set_is_same (set, &desc, exprs, num_exprs, flags)) { +NL_SET_BAD_ATTR (extack, nla[NFTA_SET_NAME ]); + err = -EEXIST ; + } +for (i =0 ; i < num_exprs; i++)nft_expr_destroy (&ctx, exprs[i]); -return 0 ; +return err; }if (!(info->nlh->nlmsg_flags &NLM_F_CREATE ))
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 204/290 vmxnet3: correctly report csum_level for encapsulated packet
In reply to Greg Kroah-HartmanFrom: Ronak Doshi <[email protected]>
[ Upstream commit 3d8f2c4269d08f8793e946279dbdf5e972cc4911 ]
Commit dacce2be3312 ("vmxnet3: add geneve and vxlan tunnel offload support") added support for encapsulation offload. However, the pathc did not report correctly the csum_level for encapsulated packet.
This patch fixes this issue by reporting correct csum level for the encapsulated packet.
--- drivers/net/vmxnet3/vmxnet3_drv.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/vmxnet3/vmxnet3_drv.c +8 -0
@@ -1242,6 +1242,10 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, (le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) { skb->ip_summed =CHECKSUM_UNNECESSARY ; +if ((le32_to_cpu (gdesc->dword[0 ]) & + (1UL <<VMXNET3_RCD_HDR_INNER_SHIFT ))) { + skb->csum_level =1 ; + }WARN_ON_ONCE (!(gdesc->rcd.tcp || gdesc->rcd.udp) && !(le32_to_cpu (gdesc->dword[0 ]) & (1UL <<VMXNET3_RCD_HDR_INNER_SHIFT )));
@@ -1251,6 +1255,10 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, }else if (gdesc->rcd.v6 && (le32_to_cpu (gdesc->dword[3 ]) & (1 <<VMXNET3_RCD_TUC_SHIFT ))) { skb->ip_summed =CHECKSUM_UNNECESSARY ; +if ((le32_to_cpu (gdesc->dword[0 ]) & + (1UL <<VMXNET3_RCD_HDR_INNER_SHIFT ))) { + skb->csum_level =1 ; + }WARN_ON_ONCE (!(gdesc->rcd.tcp || gdesc->rcd.udp) && !(le32_to_cpu (gdesc->dword[0 ]) & (1UL <<VMXNET3_RCD_HDR_INNER_SHIFT )));
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 205/290 netfilter: nf_tables: honor set timeout and garbage collection updates
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 123b99619cca94bdca0bf7bde9abe28f0a0dfe06 ]
Set timeout and garbage collection interval updates are ignored on updates. Add transaction to update global set element timeout and garbage collection interval.
--- include/net/netfilter/nf_tables.h | 13 ++++++- net/netfilter/nf_tables_api.c | 63 ++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 19 deletions(-)
include/net/netfilter/nf_tables.h +12 -1
@@ -562,7 +562,9 @@ void *nft_set_catchall_gc(const struct nft_set *set);static inline unsigned long nft_set_gc_interval (const struct nft_set *set) { -return set->gc_int ?msecs_to_jiffies (set->gc_int) :HZ ; +u32 gc_int =READ_ONCE (set->gc_int); + +return gc_int ?msecs_to_jiffies (gc_int) :HZ ; }/**
@@ -1511,6 +1513,9 @@ struct nft_trans_rule {struct nft_trans_set {struct nft_set *set;u32 set_id; +u32 gc_int; +u64 timeout; +bool update;bool bound; };
@@ -1520,6 +1525,12 @@ struct nft_trans_set { (((struct nft_trans_set *)trans->data)->set_id)#define nft_trans_set_bound (trans) \ (((struct nft_trans_set *)trans->data)->bound) +#define nft_trans_set_update (trans) \ + (((struct nft_trans_set *)trans->data)->update) +#define nft_trans_set_timeout (trans) \ + (((struct nft_trans_set *)trans->data)->timeout) +#define nft_trans_set_gc_int (trans) \ + (((struct nft_trans_set *)trans->data)->gc_int)struct nft_trans_chain {bool update;
net/netfilter/nf_tables_api.c +45 -18
132 lines not on this page · raw message
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 206/290 veth: Fix race with AF_XDP exposing old or uninitialized descriptors
In reply to Greg Kroah-HartmanFrom: Shawn Bohrer <[email protected]>
[ Upstream commit fa349e396e4886d742fd6501c599ec627ef1353b ]
When AF_XDP is used on on a veth interface the RX ring is updated in two steps. veth_xdp_rcv() removes packet descriptors from the FILL ring fills them and places them in the RX ring updating the cached_prod pointer. Later xdp_do_flush() syncs the RX ring prod pointer with the cached_prod pointer allowing user-space to see the recently filled in descriptors. The rings are intended to be SPSC, however the existing order in veth_poll allows the xdp_do_flush() to run concurrently with another CPU creating a race condition that allows user-space to see old or uninitialized descriptors in the RX ring. This bug has been observed in production systems.
To summarize, we are expecting this ordering:
CPU 0 __xsk_rcv_zc()
CPU 0 __xsk_map_flush()
CPU 2 __xsk_rcv_zc()
CPU 2 __xsk_map_flush()
But we are seeing this order:
CPU 0 __xsk_rcv_zc()
CPU 2 __xsk_rcv_zc()
CPU 0 __xsk_map_flush()
CPU 2 __xsk_map_flush()
This occurs because we rely on NAPI to ensure that only one napi_poll handler is running at a time for the given veth receive queue. napi_schedule_prep() will prevent multiple instances from getting scheduled. However calling napi_complete_done() signals that this napi_poll is complete and allows subsequent calls to napi_schedule_prep() and __napi_schedule() to succeed in scheduling a concurrent napi_poll before the xdp_do_flush() has been called. For the veth driver a concurrent call to napi_schedule_prep() and __napi_schedule() can occur on a different CPU because the veth xmit path can additionally schedule a napi_poll creating the race.
The fix as suggested by Magnus Karlsson, is to simply move the xdp_do_flush() call before napi_complete_done(). This syncs the producer ring pointers before another instance of napi_poll can be scheduled on another CPU. It will also slightly improve performance by moving the flush closer to when the descriptors were placed in the RX ring.
--- drivers/net/veth.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/veth.c +3 -2
@@ -916,6 +916,9 @@ static int veth_poll(struct napi_struct *napi, int budget)xdp_set_return_frame_no_direct (); done =veth_xdp_rcv (rq, budget, &bq, &stats); +if (stats.xdp_redirect >0 ) +xdp_do_flush (); +if (done < budget &&napi_complete_done (napi, done)) {/* Write rx_notify_masked before reading ptr_ring */ smp_store_mb (rq->rx_notify_masked, false);
@@ -929,8 +932,6 @@ static int veth_poll(struct napi_struct *napi, int budget)if (stats.xdp_tx >0 )veth_xdp_flush (rq, &bq); -if (stats.xdp_redirect >0 ) -xdp_do_flush ();xdp_clear_return_frame_no_direct ();return done;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 207/290 nfsd: shut down the NFSv4 state objects before the filecache
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
[ Upstream commit 789e1e10f214c00ca18fc6610824c5b9876ba5f2 ]
Currently, we shut down the filecache before trying to clean up the stateids that depend on it. This leads to the kernel trying to free an nfsd_file twice, and a refcount overput on the nf_mark.
Change the shutdown procedure to tear down all of the stateids prior to shutting down the filecache.
--- fs/nfsd/nfssvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfssvc.c +1 -1
@@ -425,8 +425,8 @@ static void nfsd_shutdown_net(struct net *net) {struct nfsd_net *nn =net_generic (net, nfsd_net_id); -nfsd_file_cache_shutdown_net (net);nfs4_state_shutdown_net (net); +nfsd_file_cache_shutdown_net (net);if (nn->lockd_up) {lockd_down (net); nn->lockd_up = false;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 208/290 net: hns3: add interrupts re-initialization while doing VF FLR
In reply to Greg Kroah-HartmanFrom: Jie Wang <[email protected]>
[ Upstream commit 09e6b30eeb254f1818a008cace3547159e908dfd ]
Currently keep alive message between PF and VF may be lost and the VF is unalive in PF. So the VF will not do reset during PF FLR reset process. This would make the allocated interrupt resources of VF invalid and VF would't receive or respond to PF any more.
So this patch adds VF interrupts re-initialization during VF FLR for VF recovery in above cases.
--- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +2 -1
@@ -3258,7 +3258,8 @@ static int hclgevf_pci_reset(struct hclgevf_dev *hdev)struct pci_dev *pdev = hdev->pdev;int ret =0 ; -if (hdev->reset_type ==HNAE3_VF_FULL_RESET && +if ((hdev->reset_type ==HNAE3_VF_FULL_RESET || + hdev->reset_type ==HNAE3_FLR_RESET ) &&test_bit (HCLGEVF_STATE_IRQ_INITED , &hdev->state)) {hclgevf_misc_irq_uninit (hdev);hclgevf_uninit_msi (hdev);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 209/290 net: hns3: refactor hns3_nic_reuse_page()
In reply to Greg Kroah-HartmanFrom: Hao Chen <[email protected]>
[ Upstream commit e74a726da2c4dcedb8b0631f423d0044c7901a20 ]
Split rx copybreak handle into a separate function from function hns3_nic_reuse_page() to improve code simplicity.
Stable-dep-of: 7d89b53cea1a ("net: hns3: fix miss L3E checking for rx packet")
--- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +35 -20
@@ -3561,6 +3561,38 @@ static bool hns3_can_reuse_page(struct hns3_desc_cb *cb)return page_count (cb->priv) == cb->pagecnt_bias; } +static int hns3_handle_rx_copybreak (struct sk_buff *skb,int i, +struct hns3_enet_ring *ring, +int pull_len, +struct hns3_desc_cb *desc_cb) +{ +struct hns3_desc *desc = &ring->desc[ring->next_to_clean]; +u32 frag_offset = desc_cb->page_offset + pull_len; +int size =le16_to_cpu (desc->rx.size); +u32 frag_size = size - pull_len; +void *frag =napi_alloc_frag (frag_size); + +if (unlikely (!frag)) { +u64_stats_update_begin (&ring->syncp); + ring->stats.frag_alloc_err++; +u64_stats_update_end (&ring->syncp); + +hns3_rl_err (ring_to_netdev (ring), +"failed to allocate rx frag\n" ); +return -ENOMEM ; + } + + desc_cb->reuse_flag =1 ; +memcpy (frag, desc_cb->buf + frag_offset, frag_size); +skb_add_rx_frag (skb, i,virt_to_page (frag), +offset_in_page (frag), frag_size, frag_size); + +u64_stats_update_begin (&ring->syncp); + ring->stats.frag_alloc++; +u64_stats_update_end (&ring->syncp); +return 0 ; +} +static void hns3_nic_reuse_page (struct sk_buff *skb,int i,struct hns3_enet_ring *ring,int pull_len,struct hns3_desc_cb *desc_cb)
@@ -3570,6 +3602,7 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,int size =le16_to_cpu (desc->rx.size);u32 truesize =hns3_buf_size (ring);u32 frag_size = size - pull_len; +int ret =0 ;bool reused;if (ring->page_pool) {
@@ -3604,27 +3637,9 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i, desc_cb->page_offset =0 ; desc_cb->reuse_flag =1 ; }else if (frag_size <= ring->rx_copybreak) { -void *frag =napi_alloc_frag (frag_size); - -if (unlikely (!frag)) { -u64_stats_update_begin (&ring->syncp); - ring->stats.frag_alloc_err++; -u64_stats_update_end (&ring->syncp); - -hns3_rl_err (ring_to_netdev (ring), -"failed to allocate rx frag\n" ); + ret =hns3_handle_rx_copybreak (skb, i, ring, pull_len, desc_cb); +if (ret) goto out; - } - - desc_cb->reuse_flag =1 ; -memcpy (frag, desc_cb->buf + frag_offset, frag_size); -skb_add_rx_frag (skb, i,virt_to_page (frag), -offset_in_page (frag), frag_size, frag_size); - -u64_stats_update_begin (&ring->syncp); - ring->stats.frag_alloc++; -u64_stats_update_end (&ring->syncp); -return ; } out:
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 210/290 net: hns3: extract macro to simplify ring stats update code
In reply to Greg Kroah-HartmanFrom: Peng Li <[email protected]>
[ Upstream commit e6d72f6ac2ad4965491354d74b48e35a60abf298 ]
As the code to update ring stats is alike for different ring stats type, this patch extract macro to simplify ring stats update code.
Stable-dep-of: 7d89b53cea1a ("net: hns3: fix miss L3E checking for rx packet")
--- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 123 +++++------------- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 7 + 2 files changed, 38 insertions(+), 92 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +31 -92
@@ -1005,9 +1005,7 @@ static bool hns3_can_use_tx_bounce(struct hns3_enet_ring *ring,return false;if (ALIGN (len,dma_get_cache_alignment ()) > space) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_spare_full++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_spare_full);return false; }
@@ -1024,9 +1022,7 @@ static bool hns3_can_use_tx_sgl(struct hns3_enet_ring *ring,return false;if (space <HNS3_MAX_SGL_SIZE ) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_spare_full++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_spare_full);return false; }
@@ -1554,9 +1550,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, ret =hns3_handle_vtags (ring, skb);if (unlikely (ret <0 )) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_vlan_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_vlan_err);return ret; }else if (ret ==HNS3_INNER_VLAN_TAG ) { inner_vtag =skb_vlan_tag_get (skb);
@@ -1591,9 +1585,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, ret =hns3_get_l4_protocol (skb, &ol4_proto, &il4_proto);if (unlikely (ret <0 )) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_l4_proto_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_l4_proto_err);return ret; }
@@ -1601,18 +1593,14 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, &type_cs_vlan_tso, &ol_type_vlan_len_msec);if (unlikely (ret <0 )) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_l2l3l4_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_l2l3l4_err);return ret; } ret =hns3_set_tso (skb, &paylen_ol4cs, &mss_hw_csum, &type_cs_vlan_tso, &desc_cb->send_bytes);if (unlikely (ret <0 )) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_tso_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_tso_err);return ret; } }
@@ -1705,9 +1693,7 @@ static int hns3_map_and_fill_desc(struct hns3_enet_ring *ring, void *priv, }if (unlikely (dma_mapping_error (dev, dma))) { -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt);return -ENOMEM ; }
@@ -1853,9 +1839,7 @@ static int hns3_skb_linearize(struct hns3_enet_ring *ring,* recursion level of over HNS3_MAX_RECURSION_LEVEL. */ if (bd_num ==UINT_MAX ) { -u64_stats_update_begin (&ring->syncp); - ring->stats.over_max_recursion++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, over_max_recursion);return -ENOMEM ; }
@@ -1864,16 +1848,12 @@ static int hns3_skb_linearize(struct hns3_enet_ring *ring,*/ if (skb->len >HNS3_MAX_TSO_SIZE || (!skb_is_gso (skb) && skb->len >HNS3_MAX_NON_TSO_SIZE )) { -u64_stats_update_begin (&ring->syncp); - ring->stats.hw_limitation++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, hw_limitation);return -ENOMEM ; }if (__skb_linearize (skb)) { -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt);return -ENOMEM ; }
@@ -1903,9 +1883,7 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring, bd_num =hns3_tx_bd_count (skb->len); -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_copy++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_copy); } out:
@@ -1925,9 +1903,7 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,return bd_num; } -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_busy++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_busy);return -EBUSY ; }
@@ -2012,9 +1988,7 @@ static void hns3_tx_doorbell(struct hns3_enet_ring *ring, int num, ring->pending_buf += num;if (!doorbell) { -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_more++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_more);return ; }
@@ -2064,9 +2038,7 @@ static int hns3_handle_tx_bounce(struct hns3_enet_ring *ring, ret =skb_copy_bits (skb,0 , buf, size);if (unlikely (ret <0 )) {hns3_tx_spare_rollback (ring, cb_len); -u64_stats_update_begin (&ring->syncp); - ring->stats.copy_bits_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, copy_bits_err);return ret; }
@@ -2089,9 +2061,8 @@ static int hns3_handle_tx_bounce(struct hns3_enet_ring *ring,dma_sync_single_for_device (ring_to_dev (ring), dma, size,DMA_TO_DEVICE ); -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_bounce++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_bounce); +return bd_num; }
@@ -2121,9 +2092,7 @@ static int hns3_handle_tx_sgl(struct hns3_enet_ring *ring, nents =skb_to_sgvec (skb, sgt->sgl,0 , skb->len);if (unlikely (nents <0 )) {hns3_tx_spare_rollback (ring, cb_len); -u64_stats_update_begin (&ring->syncp); - ring->stats.skb2sgl_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, skb2sgl_err);return -ENOMEM ; }
@@ -2132,9 +2101,7 @@ static int hns3_handle_tx_sgl(struct hns3_enet_ring *ring, DMA_TO_DEVICE);if (unlikely (!sgt->nents)) {hns3_tx_spare_rollback (ring, cb_len); -u64_stats_update_begin (&ring->syncp); - ring->stats.map_sg_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, map_sg_err);return -ENOMEM ; }
@@ -2146,10 +2113,7 @@ static int hns3_handle_tx_sgl(struct hns3_enet_ring *ring,for (i =0 ; i < sgt->nents; i++) bd_num +=hns3_fill_desc (ring,sg_dma_address (sgt->sgl + i),sg_dma_len (sgt->sgl + i)); - -u64_stats_update_begin (&ring->syncp); - ring->stats.tx_sgl++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, tx_sgl);return bd_num; }
@@ -2188,9 +2152,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)if (skb_put_padto (skb,HNS3_MIN_TX_LEN )) {hns3_tx_doorbell (ring,0 , !netdev_xmit_more ()); -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt);return NETDEV_TX_OK ; }
@@ -3522,17 +3484,13 @@ static bool hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring,for (i =0 ; i < cleand_count; i++) { desc_cb = &ring->desc_cb[ring->next_to_use];if (desc_cb->reuse_flag) { -u64_stats_update_begin (&ring->syncp); - ring->stats.reuse_pg_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, reuse_pg_cnt);hns3_reuse_buffer (ring, ring->next_to_use); }else { ret =hns3_alloc_and_map_buffer (ring, &res_cbs);if (ret) { -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt); hns3_rl_err(ring_to_netdev(ring), "alloc rx buffer failed: %d\n",
@@ -3544,9 +3502,7 @@ static bool hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring, }hns3_replace_buffer (ring, ring->next_to_use, &res_cbs); -u64_stats_update_begin (&ring->syncp); - ring->stats.non_reuse_pg++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, non_reuse_pg); }ring_ptr_move_fw (ring, next_to_use);
@@ -3573,9 +3529,7 @@ static int hns3_handle_rx_copybreak(struct sk_buff *skb, int i,void *frag =napi_alloc_frag (frag_size);if (unlikely (!frag)) { -u64_stats_update_begin (&ring->syncp); - ring->stats.frag_alloc_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, frag_alloc_err);hns3_rl_err (ring_to_netdev (ring),"failed to allocate rx frag\n" );
@@ -3587,9 +3541,7 @@ static int hns3_handle_rx_copybreak(struct sk_buff *skb, int i,skb_add_rx_frag (skb, i,virt_to_page (frag),offset_in_page (frag), frag_size, frag_size); -u64_stats_update_begin (&ring->syncp); - ring->stats.frag_alloc++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, frag_alloc);return 0 ; }
@@ -3722,9 +3674,7 @@ static bool hns3_checksum_complete(struct hns3_enet_ring *ring, hns3_rx_ptype_tbl[ptype].ip_summed != CHECKSUM_COMPLETE)return false; -u64_stats_update_begin (&ring->syncp); - ring->stats.csum_complete++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, csum_complete); skb->ip_summed =CHECKSUM_COMPLETE ; skb->csum =csum_unfold ((__force __sum16 )csum);
@@ -3798,9 +3748,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,if (unlikely (l234info & (BIT (HNS3_RXD_L3E_B ) |BIT (HNS3_RXD_L4E_B ) |BIT (HNS3_RXD_OL3E_B ) |BIT (HNS3_RXD_OL4E_B )))) { -u64_stats_update_begin (&ring->syncp); - ring->stats.l3l4_csum_err++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, l3l4_csum_err);return ; }
@@ -3891,10 +3839,7 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, skb = ring->skb;if (unlikely (!skb)) {hns3_rl_err (netdev,"alloc rx skb fail\n" ); - -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt);return -ENOMEM ; }
@@ -3925,9 +3870,7 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length,if (ring->page_pool)skb_mark_for_recycle (skb); -u64_stats_update_begin (&ring->syncp); - ring->stats.seg_pkt_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, seg_pkt_cnt); ring->pull_len =eth_get_headlen (netdev, va,HNS3_RX_HEAD_SIZE );__skb_put (skb, ring->pull_len);
@@ -4119,9 +4062,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) ret =hns3_set_gro_and_checksum (ring, skb, l234info, bd_base_info, ol_info, csum);if (unlikely (ret)) { -u64_stats_update_begin (&ring->syncp); - ring->stats.rx_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, rx_err_cnt);return ret; }
@@ -5333,9 +5274,7 @@ static int hns3_clear_rx_ring(struct hns3_enet_ring *ring)if (!ring->desc_cb[ring->next_to_use].reuse_flag) { ret =hns3_alloc_and_map_buffer (ring, &res_cbs);if (ret) { -u64_stats_update_begin (&ring->syncp); - ring->stats.sw_err_cnt++; -u64_stats_update_end (&ring->syncp); +hns3_ring_stats_update (ring, sw_err_cnt);/* if alloc new buffer fail, exit directly * and reclear in up flow. */
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +7 -0
@@ -654,6 +654,13 @@ static inline bool hns3_nic_resetting(struct net_device *netdev)#define hns3_buf_size (_ring) ((_ring)->buf_size) +#define hns3_ring_stats_update (ring, cnt) do { \ + typeof(ring) (tmp) = (ring); \ + u64_stats_update_begin(&(tmp)->syncp); \ + ((tmp)->stats.cnt)++; \ + u64_stats_update_end(&(tmp)->syncp); \ +} while (0) \ +static inline unsigned int hns3_page_order (struct hns3_enet_ring *ring) {#if (PAGE_SIZE <8192 )
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 211/290 net: hns3: fix miss L3E checking for rx packet
In reply to Greg Kroah-HartmanFrom: Jian Shen <[email protected]>
[ Upstream commit 7d89b53cea1a702f97117fb4361523519bb1e52c ]
For device supports RXD advanced layout, the driver will return directly if the hardware finish the checksum calculate. It cause missing L3E checking for ip packets. Fixes it.
--- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +4 -6
@@ -3667,18 +3667,16 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)return 0 ; } -static bool hns3_checksum_complete (struct hns3_enet_ring *ring, +static void hns3_checksum_complete (struct hns3_enet_ring *ring,struct sk_buff *skb,u32 ptype,u16 csum) {if (ptype ==HNS3_INVALID_PTYPE || hns3_rx_ptype_tbl[ptype].ip_summed !=CHECKSUM_COMPLETE ) -return false; +return ;hns3_ring_stats_update (ring, csum_complete); skb->ip_summed =CHECKSUM_COMPLETE ; skb->csum =csum_unfold ((__force __sum16 )csum); - -return true; } static void hns3_rx_handle_csum(struct sk_buff *skb, u32 l234info,
@@ -3738,8 +3736,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, ptype =hnae3_get_field (ol_info,HNS3_RXD_PTYPE_M ,HNS3_RXD_PTYPE_S ); -if (hns3_checksum_complete (ring, skb, ptype, csum)) -return ; +hns3_checksum_complete (ring, skb, ptype, csum);/* check if hardware has done checksum */ if (!(bd_base_info &BIT (HNS3_RXD_L3L4P_B )))
@@ -3748,6 +3745,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,if (unlikely (l234info & (BIT (HNS3_RXD_L3E_B ) |BIT (HNS3_RXD_L4E_B ) |BIT (HNS3_RXD_OL3E_B ) |BIT (HNS3_RXD_OL4E_B )))) { + skb->ip_summed =CHECKSUM_NONE ;hns3_ring_stats_update (ring, l3l4_csum_err);return ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 212/290 net: hns3: fix VF promisc mode not update when mac table full
In reply to Greg Kroah-HartmanFrom: Jian Shen <[email protected]>
[ Upstream commit 8ee57c7b8406c7aa8ca31e014440c87c6383f429 ]
Currently, it missed set HCLGE_VPORT_STATE_PROMISC_CHANGE flag for VF when vport->overflow_promisc_flags changed. So the VF won't check whether to update promisc mode in this case. So add it.
--- .../hisilicon/hns3/hns3pf/hclge_main.c | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +43 -32
@@ -12825,60 +12825,71 @@ static int hclge_gro_en(struct hnae3_handle *handle, bool enable)return ret; } -static void hclge_sync_promisc_mode (struct hclge_dev *hdev) +static int hclge_sync_vport_promisc_mode (struct hclge_vport *vport) { -struct hclge_vport *vport = &hdev->vport[0 ];struct hnae3_handle *handle = &vport->nic; +struct hclge_dev *hdev = vport->back; +bool uc_en = false; +bool mc_en = false;u8 tmp_flags; +bool bc_en;int ret; -u16 i;if (vport->last_promisc_flags != vport->overflow_promisc_flags) {set_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , &vport->state); vport->last_promisc_flags = vport->overflow_promisc_flags; } -if (test_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , &vport->state)) { +if (!test_and_clear_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , + &vport->state)) +return 0 ; + +/* for PF */ +if (!vport->vport_id) { tmp_flags = handle->netdev_flags | vport->last_promisc_flags; ret =hclge_set_promisc_mode (handle, tmp_flags &HNAE3_UPE , tmp_flags &HNAE3_MPE ); -if (!ret) { -clear_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , - &vport->state); +if (!ret)set_bit (HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE , &vport->state); - } +else +set_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , + &vport->state); +return ret; } -for (i =1 ; i < hdev->num_alloc_vport; i++) { -bool uc_en = false; -bool mc_en = false; -bool bc_en; +/* for VF */ +if (vport->vf_info.trusted) { + uc_en = vport->vf_info.request_uc_en >0 || + vport->overflow_promisc_flags &HNAE3_OVERFLOW_UPE ; + mc_en = vport->vf_info.request_mc_en >0 || + vport->overflow_promisc_flags &HNAE3_OVERFLOW_MPE ; + } + bc_en = vport->vf_info.request_bc_en >0 ; - vport = &hdev->vport[i]; + ret =hclge_cmd_set_promisc_mode (hdev, vport->vport_id, uc_en, + mc_en, bc_en); +if (ret) { +set_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , &vport->state); +return ret; + } +hclge_set_vport_vlan_fltr_change (vport); -if (!test_and_clear_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , - &vport->state)) -continue ; +return 0 ; +} -if (vport->vf_info.trusted) { - uc_en = vport->vf_info.request_uc_en >0 || - vport->overflow_promisc_flags & -HNAE3_OVERFLOW_UPE ; - mc_en = vport->vf_info.request_mc_en >0 || - vport->overflow_promisc_flags & -HNAE3_OVERFLOW_MPE ; - } - bc_en = vport->vf_info.request_bc_en >0 ; +static void hclge_sync_promisc_mode (struct hclge_dev *hdev) +{ +struct hclge_vport *vport; +int ret; +u16 i; - ret =hclge_cmd_set_promisc_mode (hdev, vport->vport_id, uc_en, - mc_en, bc_en); -if (ret) { -set_bit (HCLGE_VPORT_STATE_PROMISC_CHANGE , - &vport->state); +for (i =0 ; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + + ret =hclge_sync_vport_promisc_mode (vport); +if (ret)return ; - } -hclge_set_vport_vlan_fltr_change (vport); } }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 213/290 net: sched: fix memory leak in tcindex_set_parms
In reply to Greg Kroah-HartmanFrom: Hawkins Jiawei <[email protected]>
[ Upstream commit 399ab7fe0fa0d846881685fd4e57e9a8ef7559f7 ]
Syzkaller reports a memory leak as follows:
====================================
BUG: memory leak
unreferenced object 0xffff88810c287f00 (size 256):
comm "syz-executor105", pid 3600, jiffies 4294943292 (age 12.990s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<ffffffff814cf9f0>] kmalloc_trace+0x20/0x90 mm/slab_common.c:1046
[<ffffffff839c9e07>] kmalloc include/linux/slab.h:576 [inline]
[<ffffffff839c9e07>] kmalloc_array include/linux/slab.h:627 [inline]
[<ffffffff839c9e07>] kcalloc include/linux/slab.h:659 [inline]
[<ffffffff839c9e07>] tcf_exts_init include/net/pkt_cls.h:250 [inline]
[<ffffffff839c9e07>] tcindex_set_parms+0xa7/0xbe0 net/sched/cls_tcindex.c:342
[<ffffffff839caa1f>] tcindex_change+0xdf/0x120 net/sched/cls_tcindex.c:553
[<ffffffff8394db62>] tc_new_tfilter+0x4f2/0x1100 net/sched/cls_api.c:2147
[<ffffffff8389e91c>] rtnetlink_rcv_msg+0x4dc/0x5d0 net/core/rtnetlink.c:6082
[<ffffffff839eba67>] netlink_rcv_skb+0x87/0x1d0 net/netlink/af_netlink.c:2540
[<ffffffff839eab87>] netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
[<ffffffff839eab87>] netlink_unicast+0x397/0x4c0 net/netlink/af_netlink.c:1345
[<ffffffff839eb046>] netlink_sendmsg+0x396/0x710 net/netlink/af_netlink.c:1921
[<ffffffff8383e796>] sock_sendmsg_nosec net/socket.c:714 [inline]
[<ffffffff8383e796>] sock_sendmsg+0x56/0x80 net/socket.c:734
[<ffffffff8383eb08>] ____sys_sendmsg+0x178/0x410 net/socket.c:2482
[<ffffffff83843678>] ___sys_sendmsg+0xa8/0x110 net/socket.c:2536
[<ffffffff838439c5>] __sys_sendmmsg+0x105/0x330 net/socket.c:2622
[<ffffffff83843c14>] __do_sys_sendmmsg net/socket.c:2651 [inline]
[<ffffffff83843c14>] __se_sys_sendmmsg net/socket.c:2648 [inline]
[<ffffffff83843c14>] __x64_sys_sendmmsg+0x24/0x30 net/socket.c:2648
[<ffffffff84605fd5>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
[<ffffffff84605fd5>] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
[<ffffffff84800087>] entry_SYSCALL_64_after_hwframe+0x63/0xcd
====================================Kernel uses tcindex_change() to change an existing filter properties.
Yet the problem is that, during the process of changing, if old_r is retrieved from p->perfect, then kernel uses tcindex_alloc_perfect_hash() to newly allocate filter results, uses tcindex_filter_result_init() to clear the old filter result, without destroying its tcf_exts structure, which triggers the above memory leak.
To be more specific, there are only two source for the old_r, according to the tcindex_lookup(). old_r is retrieved from p->perfect, or old_r is retrieved from p->h.
* If old_r is retrieved from p->perfect, kernel usestcindex_alloc_perfect_hash() to newly allocate the
filter results. Then r is assigned with cp->perfect + handle, which is newly allocated. So condition old_r && old_r != r is true in this situation, and kernel uses tcindex_filter_result_init() to clear the old filter result, without destroying
its tcf_exts structure
* If old_r is retrieved from p->h, then p->perfect is NULL
according to the tcindex_lookup(). Considering that cp->h is directly copied from p->h and p->perfect is NULL, r is assigned with tcindex_lookup(cp, handle), whose value should be the same as old_r, so condition old_r && old_r != r is false in this situation, kernel ignores using tcindex_filter_result_init() to clear the old filter result.
So only when old_r is retrieved from p->perfect does kernel use tcindex_filter_result_init() to clear the old filter result, which triggers the above memory leak.
Considering that there already exists a tc_filter_wq workqueue to destroy the old tcindex_data by tcindex_partial_destroy_work() at the end of tcindex_set_parms(), this patch solves this memory leak bug by removing this old filter result clearing part and delegating it to the tc_filter_wq workqueue.
Note that this patch doesn't introduce any other issues. If old_r is retrieved from p->perfect, this patch just delegates old filter result clearing part to the tc_filter_wq workqueue; If old_r is retrieved from p->h, kernel doesn't reach the old filter result clearing part, so removing this part has no effect.
[Thanks to the suggestion from Jakub Kicinski, Cong Wang, Paolo Abeni and Dmitry Vyukov]
--- net/sched/cls_tcindex.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-)
net/sched/cls_tcindex.c +2 -10
@@ -332,7 +332,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct tcindex_filter_result *r, struct nlattr **tb, struct nlattr *est, u32 flags, struct netlink_ext_ack *extack) { - struct tcindex_filter_result new_filter_result, *old_r = r; + struct tcindex_filter_result new_filter_result;struct tcindex_data *cp =NULL , *oldp;struct tcindex_filter *f =NULL ;/* make gcc behave */ struct tcf_result cr = {};
@@ -401,7 +401,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, err =tcindex_filter_result_init (&new_filter_result, cp, net);if (err <0 ) goto errout_alloc; -if (old_r) +if (r) cr = r->res; err = -EBUSY ;
@@ -478,14 +478,6 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,tcf_bind_filter (tp, &cr, base); } -if (old_r && old_r != r) { - err =tcindex_filter_result_init (old_r, cp, net); -if (err <0 ) { -kfree (f); - goto errout_alloc; - } - } - oldp = p; r->res = cr;tcf_exts_change (&r->exts, &e);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 214/290 qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
In reply to Greg Kroah-HartmanFrom: Daniil Tatianin <[email protected]>
[ Upstream commit 13a7c8964afcd8ca43c0b6001ebb0127baa95362 ]
adapter->dcb would get silently freed inside qlcnic_dcb_enable() in case qlcnic_dcb_attach() would return an error, which always happens under OOM conditions. This would lead to use-after-free because both of the existing callers invoke qlcnic_dcb_get_info() on the obtained pointer, which is potentially freed at that point.
Propagate errors from qlcnic_dcb_enable(), and instead free the dcb pointer at callsite using qlcnic_dcb_free(). This also removes the now unused qlcnic_clear_dcb_ops() helper, which was a simple wrapper around kfree() also causing memory leaks for partially initialized dcb.
Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool.
--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 8 +++++++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h | 10 ++-------- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 8 +++++++- 3 files changed, 16 insertions(+), 10 deletions(-)
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +7 -1
@@ -2505,7 +2505,13 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) goto disable_mbx_intr;qlcnic_83xx_clear_function_resources (adapter); -qlcnic_dcb_enable (adapter->dcb); + + err =qlcnic_dcb_enable (adapter->dcb); +if (err) { +qlcnic_dcb_free (adapter->dcb); + goto disable_mbx_intr; + } +qlcnic_83xx_initialize_nic (adapter,1 );qlcnic_dcb_get_info (adapter->dcb);
drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +2 -8
@@ -41,11 +41,6 @@ struct qlcnic_dcb {unsigned long state; }; -static inline void qlcnic_clear_dcb_ops (struct qlcnic_dcb *dcb) -{ -kfree (dcb); -} -static inline int qlcnic_dcb_get_hw_capability (struct qlcnic_dcb *dcb) {if (dcb && dcb->ops->get_hw_capability)
@@ -112,9 +107,8 @@ static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb) dcb->ops->init_dcbnl_ops(dcb); } -static inline void qlcnic_dcb_enable (struct qlcnic_dcb *dcb) +static inline int qlcnic_dcb_enable (struct qlcnic_dcb *dcb) { -if (dcb &&qlcnic_dcb_attach (dcb)) -qlcnic_clear_dcb_ops (dcb); +return dcb ?qlcnic_dcb_attach (dcb) :0 ; }#endif
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +7 -1
@@ -2616,7 +2616,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Device does not support MSI interrupts\n");if (qlcnic_82xx_check (adapter)) { -qlcnic_dcb_enable (adapter->dcb); + err =qlcnic_dcb_enable (adapter->dcb); +if (err) { +qlcnic_dcb_free (adapter->dcb); +dev_err (&pdev->dev,"Failed to enable DCB\n" ); + goto err_out_free_hw; + } +qlcnic_dcb_get_info (adapter->dcb); err =qlcnic_setup_intr (adapter);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 215/290 net: dsa: mv88e6xxx: depend on PTP conditionally
In reply to Greg Kroah-HartmanFrom: Johnny S. Lee <[email protected]>
[ Upstream commit 30e725537546248bddc12eaac2fe0a258917f190 ]
PTP hardware timestamping related objects are not linked when PTP support for MV88E6xxx (NET_DSA_MV88E6XXX_PTP) is disabled, therefore NET_DSA_MV88E6XXX should not depend on PTP_1588_CLOCK_OPTIONAL regardless of NET_DSA_MV88E6XXX_PTP.
Instead, condition more strictly on how NET_DSA_MV88E6XXX_PTP's dependencies are met, making sure that it cannot be enabled when NET_DSA_MV88E6XXX=y and PTP_1588_CLOCK=m.
In other words, this commit allows NET_DSA_MV88E6XXX to be built-in while PTP_1588_CLOCK is a module, as long as NET_DSA_MV88E6XXX_PTP is prevented from being enabled.
--- drivers/net/dsa/mv88e6xxx/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/dsa/mv88e6xxx/Kconfig +2 -2
@@ -2,7 +2,6 @@ config NET_DSA_MV88E6XXX tristate "Marvell 88E6xxx Ethernet switch fabric support" depends on NET_DSA - depends on PTP_1588_CLOCK_OPTIONAL select IRQ_DOMAIN select NET_DSA_TAG_EDSA select NET_DSA_TAG_DSA
@@ -13,7 +12,8 @@ config NET_DSA_MV88E6XXX config NET_DSA_MV88E6XXX_PTP bool "PTP support for Marvell 88E6xxx" default n - depends on NET_DSA_MV88E6XXX && PTP_1588_CLOCK + depends on (NET_DSA_MV88E6XXX = y && PTP_1588_CLOCK = y) || \ + (NET_DSA_MV88E6XXX = m && PTP_1588_CLOCK) help Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch chips that support it.
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 216/290 nfc: Fix potential resource leaks
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit df49908f3c52d211aea5e2a14a93bbe67a2cb3af ]
nfc_get_device() take reference for the device, add missing nfc_put_device() to release it when not need anymore. Also fix the style warnning by use error EOPNOTSUPP instead of ENOTSUPP.
--- net/nfc/netlink.c | 52 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-)
net/nfc/netlink.c +38 -14
@@ -1497,6 +1497,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)u32 dev_idx, se_idx;u8 *apdu;size_t apdu_len; +int rc; if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || !info->attrs[NFC_ATTR_SE_INDEX] ||
@@ -1510,25 +1511,37 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)if (!dev)return -ENODEV ; -if (!dev->ops || !dev->ops->se_io) -return -ENOTSUPP ; +if (!dev->ops || !dev->ops->se_io) { + rc = -EOPNOTSUPP ; + goto put_dev; + } apdu_len =nla_len (info->attrs[NFC_ATTR_SE_APDU ]); -if (apdu_len ==0 ) -return -EINVAL ; +if (apdu_len ==0 ) { + rc = -EINVAL ; + goto put_dev; + } apdu =nla_data (info->attrs[NFC_ATTR_SE_APDU ]); -if (!apdu) -return -EINVAL ; +if (!apdu) { + rc = -EINVAL ; + goto put_dev; + } ctx =kzalloc (sizeof (struct se_io_ctx ),GFP_KERNEL ); -if (!ctx) -return -ENOMEM ; +if (!ctx) { + rc = -ENOMEM ; + goto put_dev; + } ctx->dev_idx = dev_idx; ctx->se_idx = se_idx; -return nfc_se_io (dev, se_idx, apdu, apdu_len, se_io_cb, ctx); + rc =nfc_se_io (dev, se_idx, apdu, apdu_len, se_io_cb, ctx); + +put_dev: +nfc_put_device (dev); +return rc; } static int nfc_genl_vendor_cmd(struct sk_buff *skb,
@@ -1551,14 +1564,21 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb, subcmd =nla_get_u32 (info->attrs[NFC_ATTR_VENDOR_SUBCMD ]); dev =nfc_get_device (dev_idx); -if (!dev || !dev->vendor_cmds || !dev->n_vendor_cmds) +if (!dev)return -ENODEV ; +if (!dev->vendor_cmds || !dev->n_vendor_cmds) { + err = -ENODEV ; + goto put_dev; + } +if (info->attrs[NFC_ATTR_VENDOR_DATA ]) { data =nla_data (info->attrs[NFC_ATTR_VENDOR_DATA ]); data_len =nla_len (info->attrs[NFC_ATTR_VENDOR_DATA ]); -if (data_len ==0 ) -return -EINVAL ; +if (data_len ==0 ) { + err = -EINVAL ; + goto put_dev; + } }else { data =NULL ; data_len =0 ;
@@ -1573,10 +1593,14 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb, dev->cur_cmd_info = info; err = cmd->doit (dev, data, data_len); dev->cur_cmd_info =NULL ; -return err; + goto put_dev; } -return -EOPNOTSUPP ; + err = -EOPNOTSUPP ; + +put_dev: +nfc_put_device (dev); +return err; }/* message building helper */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 217/290 vdpa_sim: fix possible memory leak in vdpasim_net_init() and vdpasim_blk_init()
In reply to Greg Kroah-HartmanFrom: ruanjinjie <[email protected]>
[ Upstream commit aeca7ff254843d49a8739f07f7dab1341450111d ]
Inject fault while probing module, if device_register() fails in vdpasim_net_init() or vdpasim_blk_init(), but the refcount of kobject is not decreased to 0, the name allocated in dev_set_name() is leaked. Fix this by calling put_device(), so that name can be freed in callback function kobject_cleanup().
(vdpa_sim_net)
unreferenced object 0xffff88807eebc370 (size 16):
comm "modprobe", pid 3848, jiffies 4362982860 (age 18.153s) hex dump (first 16 bytes):
76 64 70 61 73 69 6d 5f 6e 65 74 00 6b 6b 6b a5 vdpasim_net.kkk.
backtrace:
[<ffffffff8174f19e>] __kmalloc_node_track_caller+0x4e/0x150
[<ffffffff81731d53>] kstrdup+0x33/0x60
[<ffffffff83a5d421>] kobject_set_name_vargs+0x41/0x110
[<ffffffff82d87aab>] dev_set_name+0xab/0xe0
[<ffffffff82d91a23>] device_add+0xe3/0x1a80
[<ffffffffa0270013>] 0xffffffffa0270013
[<ffffffff81001c27>] do_one_initcall+0x87/0x2e0
[<ffffffff813739cb>] do_init_module+0x1ab/0x640
[<ffffffff81379d20>] load_module+0x5d00/0x77f0
[<ffffffff8137bc40>] __do_sys_finit_module+0x110/0x1b0
[<ffffffff83c4d505>] do_syscall_64+0x35/0x80
[<ffffffff83e0006a>] entry_SYSCALL_64_after_hwframe+0x46/0xb0(vdpa_sim_blk)
unreferenced object 0xffff8881070c1250 (size 16):
comm "modprobe", pid 6844, jiffies 4364069319 (age 17.572s) hex dump (first 16 bytes):
76 64 70 61 73 69 6d 5f 62 6c 6b 00 6b 6b 6b a5 vdpasim_blk.kkk.
backtrace:
[<ffffffff8174f19e>] __kmalloc_node_track_caller+0x4e/0x150
[<ffffffff81731d53>] kstrdup+0x33/0x60
[<ffffffff83a5d421>] kobject_set_name_vargs+0x41/0x110
[<ffffffff82d87aab>] dev_set_name+0xab/0xe0
[<ffffffff82d91a23>] device_add+0xe3/0x1a80
[<ffffffffa0220013>] 0xffffffffa0220013
[<ffffffff81001c27>] do_one_initcall+0x87/0x2e0
[<ffffffff813739cb>] do_init_module+0x1ab/0x640
[<ffffffff81379d20>] load_module+0x5d00/0x77f0
[<ffffffff8137bc40>] __do_sys_finit_module+0x110/0x1b0
[<ffffffff83c4d505>] do_syscall_64+0x35/0x80
[<ffffffff83e0006a>] entry_SYSCALL_64_after_hwframe+0x46/0xb0Message-Id: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 4 +++- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-)
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +3 -1
@@ -308,8 +308,10 @@ static int __init vdpasim_blk_init(void)int ret; ret =device_register (&vdpasim_blk_mgmtdev); -if (ret) +if (ret) { +put_device (&vdpasim_blk_mgmtdev);return ret; + } ret =vdpa_mgmtdev_register (&mgmt_dev);if (ret)
drivers/vdpa/vdpa_sim/vdpa_sim_net.c +3 -1
@@ -194,8 +194,10 @@ static int __init vdpasim_net_init(void) } ret =device_register (&vdpasim_net_mgmtdev); -if (ret) +if (ret) { +put_device (&vdpasim_net_mgmtdev);return ret; + } ret =vdpa_mgmtdev_register (&mgmt_dev);if (ret)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 218/290 vhost/vsock: Fix error handling in vhost_vsock_init()
In reply to Greg Kroah-HartmanFrom: Yuan Can <[email protected]>
[ Upstream commit 7a4efe182ca61fb3e5307e69b261c57cbf434cd4 ]
A problem about modprobe vhost_vsock failed is triggered with the following log given:
modprobe: ERROR: could not insert 'vhost_vsock': Device or resource busy
The reason is that vhost_vsock_init() returns misc_register() directly without checking its return value, if misc_register() failed, it returns without calling vsock_core_unregister() on vhost_transport, resulting the vhost_vsock can never be installed later.
A simple call graph is shown as below:
vhost_vsock_init()
vsock_core_register() # register vhost_transport misc_register()
device_create_with_groups()
device_create_groups_vargs()
dev = kzalloc(...) # OOM happened
# return without unregister vhost_transport
Fix by calling vsock_core_unregister() when misc_register() returns error.
Message-Id: <[email protected]>
--- drivers/vhost/vsock.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/vhost/vsock.c +8 -1
@@ -968,7 +968,14 @@ static int __init vhost_vsock_init(void) VSOCK_TRANSPORT_F_H2G);if (ret <0 )return ret; -return misc_register (&vhost_vsock_misc); + + ret =misc_register (&vhost_vsock_misc); +if (ret) { +vsock_core_unregister (&vhost_transport.transport); +return ret; + } + +return 0 ; }; static void __exit vhost_vsock_exit(void)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 219/290 vringh: fix range used in iotlb_translate()
In reply to Greg Kroah-HartmanFrom: Stefano Garzarella <[email protected]>
[ Upstream commit f85efa9b0f5381874f727bd98f56787840313f0b ]
vhost_iotlb_itree_first() requires start and last parameters to search for a mapping that overlaps the range.
In iotlb_translate() we cyclically call vhost_iotlb_itree_first(), incrementing addr by the amount already translated, so rightly we move the start parameter passed to vhost_iotlb_itree_first(), but we should hold the last parameter constant.
Let's fix it by saving the last parameter value before incrementing addr in the loop.
Message-Id: <[email protected]>
--- drivers/vhost/vringh.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/vhost/vringh.c +2 -3
@@ -1101,7 +1101,7 @@ static int iotlb_translate(const struct vringh *vrh,struct vhost_iotlb_map *map;struct vhost_iotlb *iotlb = vrh->iotlb;int ret =0 ; -u64 s =0 ; +u64 s =0 , last = addr + len -1 ;spin_lock (vrh->iotlb_lock);
@@ -1113,8 +1113,7 @@ static int iotlb_translate(const struct vringh *vrh,break ; } - map =vhost_iotlb_itree_first (iotlb, addr, - addr + len -1 ); + map =vhost_iotlb_itree_first (iotlb, addr, last);if (!map || map->start > addr) { ret = -EINVAL ;break ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 220/290 vhost: fix range used in translate_desc()
In reply to Greg Kroah-HartmanFrom: Stefano Garzarella <[email protected]>
[ Upstream commit 98047313cdb46828093894d0ac8b1183b8b317f9 ]
vhost_iotlb_itree_first() requires start and last parameters to search for a mapping that overlaps the range.
In translate_desc() we cyclically call vhost_iotlb_itree_first(), incrementing addr by the amount already translated, so rightly we move the start parameter passed to vhost_iotlb_itree_first(), but we should hold the last parameter constant.
Let's fix it by saving the last parameter value before incrementing addr in the loop.
Message-Id: <[email protected]>
--- drivers/vhost/vhost.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/vhost/vhost.c +2 -2
@@ -2048,7 +2048,7 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,struct vhost_dev *dev = vq->dev;struct vhost_iotlb *umem = dev->iotlb ? dev->iotlb : dev->umem;struct iovec *_iov; -u64 s =0 ; +u64 s =0 , last = addr + len -1 ;int ret =0 ;while ((u64 )len > s) {
@@ -2058,7 +2058,7 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,break ; } - map =vhost_iotlb_itree_first (umem, addr, addr + len -1 ); + map =vhost_iotlb_itree_first (umem, addr, last);if (map ==NULL || map->start > addr) {if (umem != dev->iotlb) { ret = -EFAULT ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 221/290 vdpa_sim: fix vringh initialization in vdpasim_queue_ready()
In reply to Greg Kroah-HartmanFrom: Stefano Garzarella <[email protected]>
[ Upstream commit 794ec498c9fa79e6bfd71b931410d5897a9c00d4 ]
When we initialize vringh, we should pass the features and the number of elements in the virtqueue negotiated with the driver, otherwise operations with vringh may fail.
This was discovered in a case where the driver sets a number of elements in the virtqueue different from the value returned by .get_vq_num_max().
In vdpasim_vq_reset() is safe to initialize the vringh with default values, since the virtqueue will not be used until vdpasim_queue_ready() is called again.
Message-Id: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/vdpa/vdpa_sim/vdpa_sim.c +1 -2
@@ -66,8 +66,7 @@ static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) {struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; - vringh_init_iotlb(&vq->vring, vdpasim->dev_attr.supported_features, - VDPASIM_QUEUE_MAX, false, + vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, false, (struct vring_desc *)(uintptr_t)vq->desc_addr, (struct vring_avail *) (uintptr_t)vq->driver_addr,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 222/290 net/mlx5: E-Switch, properly handle ingress tagged packets on VST
In reply to Greg Kroah-HartmanFrom: Moshe Shemesh <[email protected]>
[ Upstream commit 1f0ae22ab470946143485a02cc1cd7e05c0f9120 ]
Fix SRIOV VST mode behavior to insert cvlan when a guest tag is already present in the frame. Previous VST mode behavior was to drop packets or override existing tag, depending on the device version.
In this patch we fix this behavior by correctly building the HW steering rule with a push vlan action, or for older devices we ask the FW to stack the vlan when a vlan is already present.
--- .../mellanox/mlx5/core/esw/acl/egress_lgcy.c | 7 +++- .../mellanox/mlx5/core/esw/acl/ingress_lgcy.c | 33 ++++++++++++++++--- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 30 ++++++++++++----- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 6 ++++ include/linux/mlx5/device.h | 5 +++ include/linux/mlx5/mlx5_ifc.h | 3 +- 6 files changed, 68 insertions(+), 16 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_lgcy.c +6 -1
@@ -67,6 +67,7 @@ static void esw_acl_egress_lgcy_groups_destroy(struct mlx5_vport *vport)int esw_acl_egress_lgcy_setup (struct mlx5_eswitch *esw,struct mlx5_vport *vport) { +bool vst_mode_steering =esw_vst_mode_is_steering (esw);struct mlx5_flow_destination drop_ctr_dst = {};struct mlx5_flow_destination *dst =NULL ;struct mlx5_fc *drop_counter =NULL ;
@@ -77,6 +78,7 @@ int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw,*/ int table_size =2 ;int dest_num =0 ; +int actions_flag;int err =0 ;if (vport->egress.legacy.drop_counter) {
@@ -119,8 +121,11 @@ int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, vport->vport, vport->info.vlan, vport->info.qos);/* Allowed vlan rule */ + actions_flag =MLX5_FLOW_CONTEXT_ACTION_ALLOW ; +if (vst_mode_steering) + actions_flag |=MLX5_FLOW_CONTEXT_ACTION_VLAN_POP ; err =esw_egress_acl_vlan_create (esw, vport,NULL , vport->info.vlan, -MLX5_FLOW_CONTEXT_ACTION_ALLOW ); + actions_flag);if (err) goto out;
drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ingress_lgcy.c +28 -5
@@ -139,11 +139,14 @@ static void esw_acl_ingress_lgcy_groups_destroy(struct mlx5_vport *vport)int esw_acl_ingress_lgcy_setup (struct mlx5_eswitch *esw,struct mlx5_vport *vport) { +bool vst_mode_steering =esw_vst_mode_is_steering (esw);struct mlx5_flow_destination drop_ctr_dst = {};struct mlx5_flow_destination *dst =NULL ;struct mlx5_flow_act flow_act = {};struct mlx5_flow_spec *spec =NULL ;struct mlx5_fc *counter =NULL ; +bool vst_check_cvlan = false; +bool vst_push_cvlan = false;/* The ingress acl table contains 4 groups * (2 active rules at the same time - * 1 allow rule from one of the first 3 groups.
@@ -203,7 +206,26 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, goto out; } -if (vport->info.vlan || vport->info.qos) +if ((vport->info.vlan || vport->info.qos)) { +if (vst_mode_steering) + vst_push_cvlan = true; +else if (!MLX5_CAP_ESW (esw->dev, vport_cvlan_insert_always)) + vst_check_cvlan = true; + } + +if (vst_check_cvlan || vport->info.spoofchk) + spec->match_criteria_enable =MLX5_MATCH_OUTER_HEADERS ; + +/* Create ingress allow rule */ + flow_act.action =MLX5_FLOW_CONTEXT_ACTION_ALLOW ; +if (vst_push_cvlan) { + flow_act.action |=MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH ; + flow_act.vlan[0 ].prio = vport->info.qos; + flow_act.vlan[0 ].vid = vport->info.vlan; + flow_act.vlan[0 ].ethtype =ETH_P_8021Q ; + } + +if (vst_check_cvlan)MLX5_SET_TO_ONES (fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
@@ -218,9 +240,6 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw,ether_addr_copy (smac_v, vport->info.mac); } -/* Create ingress allow rule */ - spec->match_criteria_enable =MLX5_MATCH_OUTER_HEADERS ; - flow_act.action =MLX5_FLOW_CONTEXT_ACTION_ALLOW ; vport->ingress.allow_rule =mlx5_add_flow_rules (vport->ingress.acl, spec, &flow_act,NULL ,0 );if (IS_ERR (vport->ingress.allow_rule)) {
@@ -232,6 +251,9 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, goto out; } +if (!vst_check_cvlan && !vport->info.spoofchk) + goto out; +memset (&flow_act,0 ,sizeof (flow_act)); flow_act.action =MLX5_FLOW_CONTEXT_ACTION_DROP ;/* Attach drop flow counter */
@@ -257,7 +279,8 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw,return 0 ; out: -esw_acl_ingress_lgcy_cleanup (esw, vport); +if (err) +esw_acl_ingress_lgcy_cleanup (esw, vport);kvfree (spec);return err; }
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +21 -9
@@ -160,10 +160,17 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, esw_vport_context.vport_cvlan_strip, 1);if (set_flags &SET_VLAN_INSERT ) { -/* insert only if no vlan in packet */ -MLX5_SET (modify_esw_vport_context_in, in, - esw_vport_context.vport_cvlan_insert,1 ); - +if (MLX5_CAP_ESW (dev, vport_cvlan_insert_always)) { +/* insert either if vlan exist in packet or not */ +MLX5_SET (modify_esw_vport_context_in, in, + esw_vport_context.vport_cvlan_insert, +MLX5_VPORT_CVLAN_INSERT_ALWAYS ); + }else { +/* insert only if no vlan in packet */ +MLX5_SET (modify_esw_vport_context_in, in, + esw_vport_context.vport_cvlan_insert, +MLX5_VPORT_CVLAN_INSERT_WHEN_NO_CVLAN ); + }MLX5_SET (modify_esw_vport_context_in, in, esw_vport_context.cvlan_pcp, qos); MLX5_SET(modify_esw_vport_context_in, in,
@@ -773,6 +780,7 @@ static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,static int esw_vport_setup (struct mlx5_eswitch *esw,struct mlx5_vport *vport) { +bool vst_mode_steering =esw_vst_mode_is_steering (esw);u16 vport_num = vport->vport;int flags;int err;
@@ -802,8 +810,9 @@ static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) flags = (vport->info.vlan || vport->info.qos) ?SET_VLAN_STRIP |SET_VLAN_INSERT :0 ; -modify_esw_vport_cvlan (esw->dev, vport_num, vport->info.vlan, - vport->info.qos, flags); +if (esw->mode ==MLX5_ESWITCH_OFFLOADS || !vst_mode_steering) +modify_esw_vport_cvlan (esw->dev, vport_num, vport->info.vlan, + vport->info.qos, flags);return 0 ; }
@@ -1846,6 +1855,7 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, u16 vport, u16 vlan, u8 qos, u8 set_flags) { struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport); +bool vst_mode_steering =esw_vst_mode_is_steering (esw);int err =0 ;if (IS_ERR (evport))
@@ -1853,9 +1863,11 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,if (vlan >4095 || qos >7 )return -EINVAL ; - err =modify_esw_vport_cvlan (esw->dev, vport, vlan, qos, set_flags); -if (err) -return err; +if (esw->mode ==MLX5_ESWITCH_OFFLOADS || !vst_mode_steering) { + err =modify_esw_vport_cvlan (esw->dev, vport, vlan, qos, set_flags); +if (err) +return err; + } evport->info.vlan = vlan; evport->info.qos = qos;
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +6 -0
@@ -505,6 +505,12 @@ static inline bool mlx5_esw_qos_enabled(struct mlx5_eswitch *esw)return esw->qos.enabled; } +static inline bool esw_vst_mode_is_steering (struct mlx5_eswitch *esw) +{ +return (MLX5_CAP_ESW_EGRESS_ACL (esw->dev, pop_vlan) && +MLX5_CAP_ESW_INGRESS_ACL (esw->dev, push_vlan)); +} +static inline bool mlx5_eswitch_vlan_actions_supported (struct mlx5_core_dev *dev,u8 vlan_depth) {
include/linux/mlx5/device.h +5 -0
@@ -1074,6 +1074,11 @@ enum { MLX5_VPORT_ADMIN_STATE_AUTO = 0x2, }; +enum { +MLX5_VPORT_CVLAN_INSERT_WHEN_NO_CVLAN =0x1 , +MLX5_VPORT_CVLAN_INSERT_ALWAYS =0x3 , +}; +enum {MLX5_L3_PROT_TYPE_IPV4 =0 ,MLX5_L3_PROT_TYPE_IPV6 =1 ,
include/linux/mlx5/mlx5_ifc.h +2 -1
@@ -822,7 +822,8 @@ struct mlx5_ifc_e_switch_cap_bits {u8 vport_svlan_insert[0x1 ];u8 vport_cvlan_insert_if_not_exist[0x1 ];u8 vport_cvlan_insert_overwrite[0x1 ]; -u8 reserved_at_5[0x2 ]; +u8 reserved_at_5[0x1 ]; +u8 vport_cvlan_insert_always[0x1 ];u8 esw_shared_ingress_acl[0x1 ];u8 esw_uplink_ingress_acl[0x1 ];u8 root_ft_on_other_esw[0x1 ];
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 223/290 net/mlx5: Add forgotten cleanup calls into mlx5_init_once() error path
In reply to Greg Kroah-HartmanFrom: Jiri Pirko <[email protected]>
[ Upstream commit 2a35b2c2e6a252eda2134aae6a756861d9299531 ]
There are two cleanup calls missing in mlx5_init_once() error path. Add them making the error path flow to be the same as mlx5_cleanup_once().
--- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/main.c +2 -0
@@ -928,6 +928,8 @@ static int mlx5_init_once(struct mlx5_core_dev *dev) err_tables_cleanup:mlx5_geneve_destroy (dev->geneve);mlx5_vxlan_destroy (dev->vxlan); +mlx5_cleanup_clock (dev); +mlx5_cleanup_reserved_gids (dev);mlx5_cq_debugfs_cleanup (dev);mlx5_fw_reset_cleanup (dev); err_events_cleanup:
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 224/290 net/mlx5: Avoid recovery in probe flows
In reply to Greg Kroah-HartmanFrom: Shay Drory <[email protected]>
[ Upstream commit 9078e843efec530f279a155f262793c58b0746bd ]
Currently, recovery is done without considering whether the device is still in probe flow.
This may lead to recovery before device have finished probed successfully. e.g.: while mlx5_init_one() is running. Recovery flow is using functionality that is loaded only by mlx5_init_one(), and there is no point in running recovery without mlx5_init_one() finished successfully.
Fix it by waiting for probe flow to finish and checking whether the device is probed before trying to perform recovery.
--- drivers/net/ethernet/mellanox/mlx5/core/health.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/health.c +6 -0
@@ -614,6 +614,12 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work) priv = container_of(health, struct mlx5_priv, health); dev = container_of(priv, struct mlx5_core_dev, priv); +mutex_lock (&dev->intf_state_mutex); +if (test_bit (MLX5_DROP_NEW_HEALTH_WORK , &health->flags)) { +mlx5_core_err (dev,"health works are not permitted at this stage\n" ); +return ; + } +mutex_unlock (&dev->intf_state_mutex);enter_error_state (dev, false);if (IS_ERR_OR_NULL (health->fw_fatal_reporter)) {if (mlx5_health_try_recover (dev))
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 225/290 net/mlx5e: IPoIB, Dont allow CQE compression to be turned on by default
In reply to Greg Kroah-HartmanFrom: Dragos Tatulea <[email protected]>
[ Upstream commit b12d581e83e3ae1080c32ab83f123005bd89a840 ]
mlx5e_build_nic_params will turn CQE compression on if the hardware capability is enabled and the slow_pci_heuristic condition is detected. As IPoIB doesn't support CQE compression, make sure to disable the feature in the IPoIB profile init.
Please note that the feature is not exposed to the user for IPoIB interfaces, so it can't be subsequently turned on.
--- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +4 -0
@@ -70,6 +70,10 @@ static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev, params->packet_merge.type =MLX5E_PACKET_MERGE_NONE ; params->hard_mtu =MLX5_IB_GRH_BYTES +MLX5_IPOIB_HARD_LEN ; params->tunneled_offload_en = false; + +/* CQE compression is not supported for IPoIB */ + params->rx_cqe_compress_def = false; +MLX5E_SET_PFLAG (params,MLX5E_PFLAG_RX_CQE_COMPRESS , params->rx_cqe_compress_def); }/* Called directly after IPoIB netdevice was created to initialize SW structs */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 226/290 net/mlx5e: TC, Refactor mlx5e_tc_add_flow_mod_hdr() to get flow attr
In reply to Greg Kroah-HartmanFrom: Roi Dayan <[email protected]>
[ Upstream commit ff99316700799b84e842f819a44db608557bae3e ]
In later commit we are going to instantiate multiple attr instances for flow instead of single attr.
Make sure mlx5e_tc_add_flow_mod_hdr() use the correct attr and not flow->attr.
Stable-dep-of: 2951b2e142ec ("net/mlx5e: Always clear dest encap in neigh-update-del")
--- .../ethernet/mellanox/mlx5/core/en/tc_tun_encap.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 12 ++++++------ drivers/net/ethernet/mellanox/mlx5/core/en_tc.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +1 -1
@@ -1342,7 +1342,7 @@ static void mlx5e_reoffload_encap(struct mlx5e_priv *priv,continue ; } - err =mlx5e_tc_add_flow_mod_hdr (priv, parse_attr, flow); + err =mlx5e_tc_add_flow_mod_hdr (priv, flow, attr);if (err) {mlx5_core_warn (priv->mdev,"Failed to update flow mod_hdr err=%d" , err);
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +6 -6
@@ -1342,10 +1342,10 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro }int mlx5e_tc_add_flow_mod_hdr (struct mlx5e_priv *priv, -struct mlx5e_tc_flow_parse_attr *parse_attr, -struct mlx5e_tc_flow *flow) +struct mlx5e_tc_flow *flow, +struct mlx5_flow_attr *attr) { -struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts = &parse_attr->mod_hdr_acts; +struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts = &attr->parse_attr->mod_hdr_acts;struct mlx5_modify_hdr *mod_hdr; mod_hdr = mlx5_modify_header_alloc(priv->mdev,
@@ -1355,8 +1355,8 @@ int mlx5e_tc_add_flow_mod_hdr(struct mlx5e_priv *priv,if (IS_ERR (mod_hdr))return PTR_ERR (mod_hdr); -WARN_ON (flow->attr->modify_hdr); - flow->attr->modify_hdr = mod_hdr; +WARN_ON (attr->modify_hdr); + attr->modify_hdr = mod_hdr;return 0 ; }
@@ -1457,7 +1457,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,if (attr->action &MLX5_FLOW_CONTEXT_ACTION_MOD_HDR && !(attr->ct_attr.ct_action &TCA_CT_ACT_CLEAR )) {if (vf_tun) { - err =mlx5e_tc_add_flow_mod_hdr (priv, parse_attr, flow); + err =mlx5e_tc_add_flow_mod_hdr (priv, flow, attr);if (err) goto err_out; }else {
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h +2 -2
@@ -241,8 +241,8 @@ int mlx5e_tc_match_to_reg_set_and_get_id(struct mlx5_core_dev *mdev, u32 data);int mlx5e_tc_add_flow_mod_hdr (struct mlx5e_priv *priv, -struct mlx5e_tc_flow_parse_attr *parse_attr, -struct mlx5e_tc_flow *flow); +struct mlx5e_tc_flow *flow, +struct mlx5_flow_attr *attr); int alloc_mod_hdr_actions(struct mlx5_core_dev *mdev, int namespace,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 227/290 net/mlx5e: Always clear dest encap in neigh-update-del
In reply to Greg Kroah-HartmanFrom: Chris Mi <[email protected]>
[ Upstream commit 2951b2e142ecf6e0115df785ba91e91b6da74602 ]
The cited commit introduced a bug for multiple encapsulations flow. If one dest encap becomes invalid, the flow is set slow path flag. But when other dests encap become invalid, they are not cleared due to slow path flag of the flow. When neigh-update-add is running, it will use invalid encap.
Fix it by checking slow path flag after clearing dest encap.
--- .../net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +8 -1
@@ -188,12 +188,19 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,int err;list_for_each_entry (flow, flow_list, tmp_list) { -if (!mlx5e_is_offloaded_flow (flow) ||flow_flag_test (flow,SLOW )) +if (!mlx5e_is_offloaded_flow (flow))continue ; attr = flow->attr; esw_attr = attr->esw_attr; spec = &attr->parse_attr->spec; +/* Clear pkt_reformat before checking slow path flag. Because +* in next iteration, the same flow is already set slow path +* flag, but still need to clear the pkt_reformat. +*/ +if (flow_flag_test (flow,SLOW )) +continue ; +/* update from encap rule to slow path rule */ rule =mlx5e_tc_offload_to_slow_path (esw, flow, spec);/* mark the flow's encap dest as non-valid */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 228/290 net/mlx5e: Fix hw mtu initializing at XDP SQ allocation
In reply to Greg Kroah-HartmanFrom: Adham Faris <[email protected]>
[ Upstream commit 1e267ab88dc44c48f556218f7b7f14c76f7aa066 ]
Current xdp xmit functions logic (mlx5e_xmit_xdp_frame_mpwqe or mlx5e_xmit_xdp_frame), validates xdp packet length by comparing it to hw mtu (configured at xdp sq allocation) before xmiting it. This check does not account for ethernet fcs length (calculated and filled by the nic). Hence, when we try sending packets with length > (hw-mtu - ethernet-fcs-size), the device port drops it and tx_errors_phy is incremented. Desired behavior is to catch these packets and drop them by the driver.
Fix this behavior in XDP SQ allocation function (mlx5e_alloc_xdpsq) by subtracting ethernet FCS header size (4 Bytes) from current hw mtu value, since ethernet FCS is calculated and written to ethernet frames by the nic.
--- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +1 -1
@@ -977,7 +977,7 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c, sq->channel = c; sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map; sq->min_inline_mode = params->tx_min_inline_mode; - sq->hw_mtu =MLX5E_SW2HW_MTU (params, params->sw_mtu); + sq->hw_mtu =MLX5E_SW2HW_MTU (params, params->sw_mtu) -ETH_FCS_LEN ; sq->xsk_pool = xsk_pool; sq->stats = sq->xsk_pool ?
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 229/290 net: amd-xgbe: add missed tasklet_kill
In reply to Greg Kroah-HartmanFrom: Jiguang Xiao <[email protected]>
[ Upstream commit d530ece70f16f912e1d1bfeea694246ab78b0a4b ]
The driver does not call tasklet_kill in several places. Add the calls to fix it.
--- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 +++ drivers/net/ethernet/amd/xgbe/xgbe-i2c.c | 4 +++- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-)
drivers/net/ethernet/amd/xgbe/xgbe-drv.c +3 -0
@@ -1064,6 +1064,9 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata)devm_free_irq (pdata->dev, pdata->dev_irq, pdata); +tasklet_kill (&pdata->tasklet_dev); +tasklet_kill (&pdata->tasklet_ecc); +if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq))devm_free_irq (pdata->dev, pdata->ecc_irq, pdata);
drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +3 -1
@@ -447,8 +447,10 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata)xgbe_i2c_disable (pdata);xgbe_i2c_clear_all_interrupts (pdata); -if (pdata->dev_irq != pdata->i2c_irq) +if (pdata->dev_irq != pdata->i2c_irq) {devm_free_irq (pdata->dev, pdata->i2c_irq, pdata); +tasklet_kill (&pdata->tasklet_i2c); + } }static int xgbe_i2c_start (struct xgbe_prv_data *pdata)
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +3 -1
@@ -1390,8 +1390,10 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)/* Disable auto-negotiation */ xgbe_an_disable_all (pdata); -if (pdata->dev_irq != pdata->an_irq) +if (pdata->dev_irq != pdata->an_irq) {devm_free_irq (pdata->dev, pdata->an_irq, pdata); +tasklet_kill (&pdata->tasklet_an); + } pdata->phy_if.phy_impl.stop (pdata);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 230/290 net: ena: Fix toeplitz initial hash value
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit 332b49ff637d6c1a75b971022a8b992cf3c57db1 ]
On driver initialization, RSS hash initial value is set to zero, instead of the default value. This happens because we pass NULL as the RSS key parameter, which caused us to never initialize the RSS hash value.
This patch fixes it by making sure the initial value is set, no matter what the value of the RSS key is.
--- drivers/net/ethernet/amazon/ena/ena_com.c | 29 +++++++---------------- 1 file changed, 9 insertions(+), 20 deletions(-)
drivers/net/ethernet/amazon/ena/ena_com.c +9 -20
@@ -2392,29 +2392,18 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,return -EOPNOTSUPP ; } -switch (func) { -case ENA_ADMIN_TOEPLITZ : -if (key) { -if (key_len !=sizeof (hash_key->key)) { -netdev_err (ena_dev->net_device, -"key len (%u) doesn't equal the supported size (%zu)\n" , - key_len,sizeof (hash_key->key)); -return -EINVAL ; - } -memcpy (hash_key->key, key, key_len); - rss->hash_init_val = init_val; - hash_key->key_parts = key_len /sizeof (hash_key->key[0 ]); +if ((func ==ENA_ADMIN_TOEPLITZ ) && key) { +if (key_len !=sizeof (hash_key->key)) { +netdev_err (ena_dev->net_device, +"key len (%u) doesn't equal the supported size (%zu)\n" , + key_len,sizeof (hash_key->key)); +return -EINVAL ; } -break ; -case ENA_ADMIN_CRC32 : - rss->hash_init_val = init_val; -break ; -default : -netdev_err (ena_dev->net_device,"Invalid hash function (%d)\n" , - func); -return -EINVAL ; +memcpy (hash_key->key, key, key_len); + hash_key->key_parts = key_len /sizeof (hash_key->key[0 ]); } + rss->hash_init_val = init_val; old_func = rss->hash_func; rss->hash_func = func; rc =ena_com_set_hash_function (ena_dev);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 231/290 net: ena: Dont register memory info on XDP exchange
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit 9c9e539956fa67efb8a65e32b72a853740b33445 ]
Since the queues aren't destroyed when we only exchange XDP programs, there's no need to re-register them again.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/amazon/ena/ena_netdev.c +5 -3
@@ -516,16 +516,18 @@ static void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,struct bpf_prog *prog, int first, int count) { + struct bpf_prog *old_bpf_prog;struct ena_ring *rx_ring;int i =0 ;for (i = first; i < count; i++) { rx_ring = &adapter->rx_ring[i]; -xchg (&rx_ring->xdp_bpf_prog, prog); -if (prog) { + old_bpf_prog =xchg (&rx_ring->xdp_bpf_prog, prog); + +if (!old_bpf_prog && prog) {ena_xdp_register_rxq_info (rx_ring); rx_ring->rx_headroom =XDP_PACKET_HEADROOM ; - }else { + }else if (old_bpf_prog && !prog) {ena_xdp_unregister_rxq_info (rx_ring); rx_ring->rx_headroom =NET_SKB_PAD ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 232/290 net: ena: Account for the number of processed bytes in XDP
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit c7f5e34d906320fdc996afa616676161c029cc02 ]
The size of packets that were forwarded or dropped by XDP wasn't added to the total processed bytes statistic.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/amazon/ena/ena_netdev.c +1 -0
@@ -1729,6 +1729,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, }if (xdp_verdict !=XDP_PASS ) { xdp_flags |= xdp_verdict; + total_len += ena_rx_ctx.ena_bufs[0 ].len; res_budget--;continue ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 233/290 net: ena: Use bitmask to indicate packet redirection
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit 59811faa2c54dbcf44d575b5a8f6e7077da88dc2 ]
Redirecting packets with XDP Redirect is done in two phases:
1. A packet is passed by the driver to the kernel using xdp_do_redirect().
2. After finishing polling for new packets the driver lets the kernel know that it can now process the redirected packet using xdp_do_flush_map().
The packets' redirection is handled in the napi context of the queue that called xdp_do_redirect()
To avoid calling xdp_do_flush_map() each time the driver first checks whether any packets were redirected, using
xdp_flags |= xdp_verdict; and if (xdp_flags & XDP_REDIRECT) xdp_do_flush_map()
essentially treating XDP instructions as a bitmask, which isn't the case:
enum xdp_action {
XDP_ABORTED = 0,
XDP_DROP,
XDP_PASS,
XDP_TX,
XDP_REDIRECT,
};Given the current possible values of xdp_action, the current design doesn't have a bug (since XDP_REDIRECT = 100b), but it is still flawed.
This patch makes the driver use a bitmask instead, to avoid future issues.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 26 ++++++++++++-------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 9 +++++++ 2 files changed, 25 insertions(+), 10 deletions(-)
drivers/net/ethernet/amazon/ena/ena_netdev.c +16 -10
@@ -378,9 +378,9 @@ static int ena_xdp_xmit(struct net_device *dev, int n,static int ena_xdp_execute (struct ena_ring *rx_ring,struct xdp_buff *xdp) { +u32 verdict =ENA_XDP_PASS ;struct bpf_prog *xdp_prog;struct ena_ring *xdp_ring; -u32 verdict =XDP_PASS ;struct xdp_frame *xdpf;u64 *xdp_stat;
@@ -397,7 +397,7 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)if (unlikely (!xdpf)) {trace_xdp_exception (rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; - verdict =XDP_ABORTED ; + verdict =ENA_XDP_DROP ;break ; }
@@ -413,29 +413,35 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)spin_unlock (&xdp_ring->xdp_tx_lock); xdp_stat = &rx_ring->rx_stats.xdp_tx; + verdict =ENA_XDP_TX ;break ;case XDP_REDIRECT :if (likely (!xdp_do_redirect (rx_ring->netdev, xdp, xdp_prog))) { xdp_stat = &rx_ring->rx_stats.xdp_redirect; + verdict =ENA_XDP_REDIRECT ;break ; }trace_xdp_exception (rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; - verdict =XDP_ABORTED ; + verdict =ENA_XDP_DROP ;break ;case XDP_ABORTED :trace_xdp_exception (rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; + verdict =ENA_XDP_DROP ;break ;case XDP_DROP : xdp_stat = &rx_ring->rx_stats.xdp_drop; + verdict =ENA_XDP_DROP ;break ;case XDP_PASS : xdp_stat = &rx_ring->rx_stats.xdp_pass; + verdict =ENA_XDP_PASS ;break ;default :bpf_warn_invalid_xdp_action (verdict); xdp_stat = &rx_ring->rx_stats.xdp_invalid; + verdict =ENA_XDP_DROP ; }ena_increase_stat (xdp_stat,1 , &rx_ring->syncp);
@@ -1631,12 +1637,12 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp)* we expect, then we simply drop it */ if (unlikely (rx_ring->ena_bufs[0 ].len >ENA_XDP_MAX_MTU )) -return XDP_DROP ; +return ENA_XDP_DROP ; ret =ena_xdp_execute (rx_ring, xdp);/* The xdp program might expand the headers */ -if (ret ==XDP_PASS ) { +if (ret ==ENA_XDP_PASS ) { rx_info->page_offset = xdp->data - xdp->data_hard_start; rx_ring->ena_bufs[0 ].len = xdp->data_end - xdp->data; }
@@ -1675,7 +1681,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,xdp_init_buff (&xdp,ENA_PAGE_SIZE , &rx_ring->xdp_rxq); do { - xdp_verdict = XDP_PASS; + xdp_verdict = ENA_XDP_PASS; skb = NULL; ena_rx_ctx.ena_bufs = rx_ring->ena_bufs; ena_rx_ctx.max_bufs = rx_ring->sgl_size;
@@ -1703,7 +1709,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, xdp_verdict =ena_xdp_handle_buff (rx_ring, &xdp);/* allocate skb and fill it */ -if (xdp_verdict ==XDP_PASS ) +if (xdp_verdict ==ENA_XDP_PASS ) skb = ena_rx_skb(rx_ring, rx_ring->ena_bufs, ena_rx_ctx.descs,
@@ -1721,13 +1727,13 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,/* Packets was passed for transmission, unmap it * from RX side. */ -if (xdp_verdict ==XDP_TX || xdp_verdict ==XDP_REDIRECT ) { +if (xdp_verdict &ENA_XDP_FORWARDED ) {ena_unmap_rx_buff (rx_ring, &rx_ring->rx_buffer_info[req_id]); rx_ring->rx_buffer_info[req_id].page =NULL ; } } -if (xdp_verdict !=XDP_PASS ) { +if (xdp_verdict !=ENA_XDP_PASS ) { xdp_flags |= xdp_verdict; total_len += ena_rx_ctx.ena_bufs[0 ].len; res_budget--;
@@ -1773,7 +1779,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,ena_refill_rx_bufs (rx_ring, refill_required); } -if (xdp_flags &XDP_REDIRECT ) +if (xdp_flags &ENA_XDP_REDIRECT )xdp_do_flush_map ();return work_done;
drivers/net/ethernet/amazon/ena/ena_netdev.h +9 -0
@@ -412,6 +412,15 @@ enum ena_xdp_errors_t { ENA_XDP_NO_ENOUGH_QUEUES, }; +enum ENA_XDP_ACTIONS { +ENA_XDP_PASS =0 , +ENA_XDP_TX =BIT (0 ), +ENA_XDP_REDIRECT =BIT (1 ), +ENA_XDP_DROP =BIT (2 ) +}; + +#define ENA_XDP_FORWARDED (ENA_XDP_TX | ENA_XDP_REDIRECT) +static inline bool ena_xdp_present (struct ena_adapter *adapter) {return !!adapter->xdp_bpf_prog;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 234/290 net: ena: Fix rx_copybreak value update
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit c7062aaee099f2f43d6f07a71744b44b94b94b34 ]
Make the upper bound on rx_copybreak tighter, by making sure it is smaller than the minimum of mtu and ENA_PAGE_SIZE. With the current upper bound of mtu, rx_copybreak can be larger than a page. Such large rx_copybreak will not bring any performance benefit to the user and therefore makes no sense.
In addition, the value update was only reflected in the adapter structure, but not applied for each ring, causing it to not take effect.
--- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 6 +----- drivers/net/ethernet/amazon/ena/ena_netdev.c | 18 ++++++++++++++++++ drivers/net/ethernet/amazon/ena/ena_netdev.h | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-)
drivers/net/ethernet/amazon/ena/ena_ethtool.c +1 -5
@@ -880,11 +880,7 @@ static int ena_set_tunable(struct net_device *netdev,switch (tuna->id) {case ETHTOOL_RX_COPYBREAK : len = *(u32 *)data; -if (len > adapter->netdev->mtu) { - ret = -EINVAL ; -break ; - } - adapter->rx_copybreak = len; + ret =ena_set_rx_copybreak (adapter, len);break ;default : ret = -EINVAL ;
drivers/net/ethernet/amazon/ena/ena_netdev.c +18 -0
@@ -2829,6 +2829,24 @@ int ena_update_queue_sizes(struct ena_adapter *adapter,return dev_was_up ?ena_up (adapter) :0 ; } +int ena_set_rx_copybreak (struct ena_adapter *adapter,u32 rx_copybreak) +{ +struct ena_ring *rx_ring; +int i; + +if (rx_copybreak >min_t (u16, adapter->netdev->mtu,ENA_PAGE_SIZE )) +return -EINVAL ; + + adapter->rx_copybreak = rx_copybreak; + +for (i =0 ; i < adapter->num_io_queues; i++) { + rx_ring = &adapter->rx_ring[i]; + rx_ring->rx_copybreak = rx_copybreak; + } + +return 0 ; +} +int ena_update_queue_count (struct ena_adapter *adapter,u32 new_channel_count) {struct ena_com_dev *ena_dev = adapter->ena_dev;
drivers/net/ethernet/amazon/ena/ena_netdev.h +2 -0
@@ -404,6 +404,8 @@ int ena_update_queue_sizes(struct ena_adapter *adapter,int ena_update_queue_count (struct ena_adapter *adapter,u32 new_channel_count); +int ena_set_rx_copybreak (struct ena_adapter *adapter,u32 rx_copybreak); +int ena_get_sset_count (struct net_device *netdev,int sset);enum ena_xdp_errors_t {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 235/290 net: ena: Set default value for RX interrupt moderation
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit e712f3e4920b3a1a5e6b536827d118e14862896c ]
RX ring can be NULL in XDP use cases where only TX queues are configured. In this scenario, the RX interrupt moderation value sent to the device remains in its default value of 0.
In this change, setting the default value of the RX interrupt moderation to be the same as of the TX.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/amazon/ena/ena_netdev.c +2 -1
@@ -1836,8 +1836,9 @@ static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)static void ena_unmask_interrupt (struct ena_ring *tx_ring,struct ena_ring *rx_ring) { +u32 rx_interval = tx_ring->smoothed_interval;struct ena_eth_io_intr_reg intr_reg; -u32 rx_interval =0 ; +/* Rx ring can be NULL when for XDP tx queues which don't have an * accompanying rx_ring pair. */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 236/290 net: ena: Update NUMA TPH hint register upon NUMA node update
In reply to Greg Kroah-HartmanFrom: David Arinzon <[email protected]>
[ Upstream commit a8ee104f986e720cea52133885cc822d459398c7 ]
The device supports a PCIe optimization hint, which indicates on which NUMA the queue is currently processed. This hint is utilized by PCIe in order to reduce its access time by accessing the correct NUMA resources and maintaining cache coherence.
The driver calls the register update for the hint (called TPH - TLP Processing Hint) during the NAPI loop.
Though the update is expected upon a NUMA change (when a queue is moved from one NUMA to the other), the current logic performs a register update when the queue is moved to a different CPU, but the CPU is not necessarily in a different NUMA.
The changes include:
1. Performing the TPH update only when the queue has switched a NUMA node.
2. Moving the TPH update call to be triggered only when NAPI was scheduled from interrupt context, as opposed to a busy-polling loop. This is due to the fact that during busy-polling, the frequency of CPU switches for a particular queue is significantly higher, thus, the likelihood to switch NUMA is much higher. Therefore, providing the frequent updates to the device upon a NUMA update are unlikely to be beneficial.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 27 +++++++++++++------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 6 +++-- 2 files changed, 22 insertions(+), 11 deletions(-)
drivers/net/ethernet/amazon/ena/ena_netdev.c +18 -9
@@ -684,6 +684,7 @@ static void ena_init_io_rings_common(struct ena_adapter *adapter, ring->ena_dev = adapter->ena_dev; ring->per_napi_packets =0 ; ring->cpu =0 ; + ring->numa_node =0 ; ring->no_interrupt_event_cnt =0 ;u64_stats_init (&ring->syncp); }
@@ -787,6 +788,7 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid) tx_ring->next_to_use =0 ; tx_ring->next_to_clean =0 ; tx_ring->cpu = ena_irq->cpu; + tx_ring->numa_node = node;return 0 ; err_push_buf_intermediate_buf:
@@ -919,6 +921,7 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter, rx_ring->next_to_clean =0 ; rx_ring->next_to_use =0 ; rx_ring->cpu = ena_irq->cpu; + rx_ring->numa_node = node;return 0 ; }
@@ -1876,20 +1879,27 @@ static void ena_update_ring_numa_node(struct ena_ring *tx_ring,if (likely (tx_ring->cpu == cpu)) goto out; + tx_ring->cpu = cpu; +if (rx_ring) + rx_ring->cpu = cpu; + numa_node =cpu_to_node (cpu); + +if (likely (tx_ring->numa_node == numa_node)) + goto out; +put_cpu ();if (numa_node !=NUMA_NO_NODE ) {ena_com_update_numa_node (tx_ring->ena_com_io_cq, numa_node); -if (rx_ring) + tx_ring->numa_node = numa_node; +if (rx_ring) { + rx_ring->numa_node = numa_node;ena_com_update_numa_node (rx_ring->ena_com_io_cq, numa_node); + } } - tx_ring->cpu = cpu; -if (rx_ring) - rx_ring->cpu = cpu; -return ; out:put_cpu ();
@@ -2010,11 +2020,10 @@ static int ena_io_poll(struct napi_struct *napi, int budget)if (ena_com_get_adaptive_moderation_enabled (rx_ring->ena_dev))ena_adjust_adaptive_rx_intr_moderation (ena_napi); +ena_update_ring_numa_node (tx_ring, rx_ring);ena_unmask_interrupt (tx_ring, rx_ring); } -ena_update_ring_numa_node (tx_ring, rx_ring); - ret = rx_work_done; }else { ret = budget;
@@ -2401,7 +2410,7 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid) ctx.mem_queue_type = ena_dev->tx_mem_queue_type; ctx.msix_vector = msix_vector; ctx.queue_size = tx_ring->ring_size; - ctx.numa_node =cpu_to_node (tx_ring->cpu); + ctx.numa_node = tx_ring->numa_node; rc =ena_com_create_io_queue (ena_dev, &ctx);if (rc) {
@@ -2469,7 +2478,7 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid) ctx.mem_queue_type =ENA_ADMIN_PLACEMENT_POLICY_HOST ; ctx.msix_vector = msix_vector; ctx.queue_size = rx_ring->ring_size; - ctx.numa_node =cpu_to_node (rx_ring->cpu); + ctx.numa_node = rx_ring->numa_node; rc =ena_com_create_io_queue (ena_dev, &ctx);if (rc) {
drivers/net/ethernet/amazon/ena/ena_netdev.h +4 -2
@@ -273,9 +273,11 @@ struct ena_ring {bool disable_meta_caching;u16 no_interrupt_event_cnt; -/* cpu for TPH */ +/* cpu and NUMA for TPH */ int cpu; -/* number of tx/rx_buffer_info's entries */ +int numa_node; + +/* number of tx/rx_buffer_info's entries */ int ring_size;enum ena_admin_placement_policy_type tx_mem_queue_type;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 237/290 net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit d039535850ee47079d59527e96be18d8e0daa84b ]
of_phy_find_device() return device node with refcount incremented. Call put_device() to relese it when not needed anymore.
--- drivers/net/phy/xilinx_gmii2rgmii.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/phy/xilinx_gmii2rgmii.c +1 -0
@@ -105,6 +105,7 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev)if (!priv->phy_dev->drv) {dev_info (dev,"Attached phy not ready\n" ); +put_device (&priv->phy_dev->mdio.dev);return -EPROBE_DEFER ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 238/290 RDMA/mlx5: Fix mlx5_ib_get_hw_stats when used for device
In reply to Greg Kroah-HartmanFrom: Shay Drory <[email protected]>
[ Upstream commit 38b50aa44495d5eb4218f0b82fc2da76505cec53 ]
Currently, when mlx5_ib_get_hw_stats() is used for device (port_num = 0), there is a special handling in order to use the correct counters, but, port_num is being passed down the stack without any change. Also, some functions assume that port_num >=1. As a result, the following oops can occur.
BUG: unable to handle page fault for address: ffff89510294f1a8 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP CPU: 8 PID: 1382 Comm: devlink Tainted: G W 6.1.0-rc4_for_upstream_base_2022_11_10_16_12 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 RIP: 0010:_raw_spin_lock+0xc/0x20 Call Trace: <TASK> mlx5_ib_get_native_port_mdev+0x73/0xe0 [mlx5_ib] do_get_hw_stats.constprop.0+0x109/0x160 [mlx5_ib] mlx5_ib_get_hw_stats+0xad/0x180 [mlx5_ib] ib_setup_device_attrs+0xf0/0x290 [ib_core] ib_register_device+0x3bb/0x510 [ib_core] ? atomic_notifier_chain_register+0x67/0x80 __mlx5_ib_add+0x2b/0x80 [mlx5_ib] mlx5r_probe+0xb8/0x150 [mlx5_ib] ? auxiliary_match_id+0x6a/0x90 auxiliary_bus_probe+0x3c/0x70 ? driver_sysfs_add+0x6b/0x90 really_probe+0xcd/0x380 __driver_probe_device+0x80/0x170 driver_probe_device+0x1e/0x90 __device_attach_driver+0x7d/0x100 ? driver_allows_async_probing+0x60/0x60 ? driver_allows_async_probing+0x60/0x60 bus_for_each_drv+0x7b/0xc0 __device_attach+0xbc/0x200 bus_probe_device+0x87/0xa0 device_add+0x404/0x940 ? dev_set_name+0x53/0x70 __auxiliary_device_add+0x43/0x60 add_adev+0x99/0xe0 [mlx5_core] mlx5_attach_device+0xc8/0x120 [mlx5_core] mlx5_load_one_devl_locked+0xb2/0xe0 [mlx5_core] devlink_reload+0x133/0x250 devlink_nl_cmd_reload+0x480/0x570 ? devlink_nl_pre_doit+0x44/0x2b0 genl_family_rcv_msg_doit.isra.0+0xc2/0x110 genl_rcv_msg+0x180/0x2b0 ? devlink_nl_cmd_region_read_dumpit+0x540/0x540 ? devlink_reload+0x250/0x250 ? devlink_put+0x50/0x50 ? genl_family_rcv_msg_doit.isra.0+0x110/0x110 netlink_rcv_skb+0x54/0x100 genl_rcv+0x24/0x40 netlink_unicast+0x1f6/0x2c0 netlink_sendmsg+0x237/0x490 sock_sendmsg+0x33/0x40 __sys_sendto+0x103/0x160 ? handle_mm_fault+0x10e/0x290 ? do_user_addr_fault+0x1c0/0x5f0 __x64_sys_sendto+0x25/0x30 do_syscall_64+0x3d/0x90 entry_SYSCALL_64_after_hwframe+0x46/0xb0
Fix it by setting port_num to 1 in order to get device status and remove unused variable.
--- drivers/infiniband/hw/mlx5/counters.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/infiniband/hw/mlx5/counters.c +3 -3
@@ -249,7 +249,6 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev,const struct mlx5_ib_counters *cnts =get_counters (dev, port_num -1 );struct mlx5_core_dev *mdev;int ret, num_counters; -u32 mdev_port_num;if (!stats)return -EINVAL ;
@@ -270,8 +269,9 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev, }if (MLX5_CAP_GEN (dev->mdev, cc_query_allowed)) { - mdev =mlx5_ib_get_native_port_mdev (dev, port_num, - &mdev_port_num); +if (!port_num) + port_num =1 ; + mdev =mlx5_ib_get_native_port_mdev (dev, port_num,NULL );if (!mdev) {/* If port is not affiliated yet, its in down state * which doesn't have any counters yet, so it would be
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 239/290 RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
In reply to Greg Kroah-HartmanFrom: Maor Gottlieb <[email protected]>
[ Upstream commit 8de8482fe5732fbef4f5af82bc0c0362c804cd1f ]
Currently, when modifying DC, we validate max_rd_atomic user attribute against the RC cap, validate against DC. RC and DC QP types have different device limitations.
This can cause userspace created DC QPs to malfunction.
--- drivers/infiniband/hw/mlx5/qp.c | 49 +++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 14 deletions(-)
drivers/infiniband/hw/mlx5/qp.c +35 -14
@@ -4499,6 +4499,40 @@ static bool mlx5_ib_modify_qp_allowed(struct mlx5_ib_dev *dev,return false; } +static int validate_rd_atomic (struct mlx5_ib_dev *dev,struct ib_qp_attr *attr, +int attr_mask,enum ib_qp_type qp_type) +{ +int log_max_ra_res; +int log_max_ra_req; + +if (qp_type ==MLX5_IB_QPT_DCI ) { + log_max_ra_res =1 <<MLX5_CAP_GEN (dev->mdev, + log_max_ra_res_dc); + log_max_ra_req =1 <<MLX5_CAP_GEN (dev->mdev, + log_max_ra_req_dc); + }else { + log_max_ra_res =1 <<MLX5_CAP_GEN (dev->mdev, + log_max_ra_res_qp); + log_max_ra_req =1 <<MLX5_CAP_GEN (dev->mdev, + log_max_ra_req_qp); + } + +if (attr_mask &IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > log_max_ra_res) { +mlx5_ib_dbg (dev,"invalid max_rd_atomic value %d\n" , + attr->max_rd_atomic); +return false; + } + +if (attr_mask &IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > log_max_ra_req) { +mlx5_ib_dbg (dev,"invalid max_dest_rd_atomic value %d\n" , + attr->max_dest_rd_atomic); +return false; + } +return true; +} +int mlx5_ib_modify_qp (struct ib_qp *ibqp,struct ib_qp_attr *attr,int attr_mask,struct ib_udata *udata) {
@@ -4586,21 +4620,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; } -if (attr_mask &IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > - (1 <<MLX5_CAP_GEN (dev->mdev, log_max_ra_res_qp))) { -mlx5_ib_dbg (dev,"invalid max_rd_atomic value %d\n" , - attr->max_rd_atomic); - goto out; - } - -if (attr_mask &IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > - (1 <<MLX5_CAP_GEN (dev->mdev, log_max_ra_req_qp))) { -mlx5_ib_dbg (dev,"invalid max_dest_rd_atomic value %d\n" , - attr->max_dest_rd_atomic); +if (!validate_rd_atomic (dev, attr, attr_mask, qp_type)) goto out; - }if (cur_state == new_state && cur_state ==IB_QPS_RESET ) { err =0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 240/290 drm/meson: Reduce the FIFO lines held when AFBC is not used
In reply to Greg Kroah-HartmanFrom: Carlo Caione <[email protected]>
[ Upstream commit 3b754ed6d1cd90017e66e5cc16f3923e4a952ffc ]
Having a bigger number of FIFO lines held after vsync is only useful to SoCs using AFBC to give time to the AFBC decoder to be reset, configured and enabled again.
For SoCs not using AFBC this, on the contrary, is causing on some displays issues and a few pixels vertical offset in the displayed image.
Conditionally increase the number of lines held after vsync only for SoCs using AFBC, leaving the default value for all the others.
--- drivers/gpu/drm/meson/meson_viu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/gpu/drm/meson/meson_viu.c +2 -3
@@ -436,15 +436,14 @@ void meson_viu_init(struct meson_drm *priv)/* Initialize OSD1 fifo control register */ reg =VIU_OSD_DDR_PRIORITY_URGENT | -VIU_OSD_HOLD_FIFO_LINES (31 ) |VIU_OSD_FIFO_DEPTH_VAL (32 ) |/* fifo_depth_val: 32*8=256 */ VIU_OSD_WORDS_PER_BURST (4 ) |/* 4 words in 1 burst */ VIU_OSD_FIFO_LIMITS (2 );/* fifo_lim: 2*16=32 */ if (meson_vpu_is_compatible (priv,VPU_COMPATIBLE_G12A )) - reg |=VIU_OSD_BURST_LENGTH_32 ; + reg |= (VIU_OSD_BURST_LENGTH_32 |VIU_OSD_HOLD_FIFO_LINES (31 ));else - reg |=VIU_OSD_BURST_LENGTH_64 ; + reg |= (VIU_OSD_BURST_LENGTH_64 |VIU_OSD_HOLD_FIFO_LINES (4 ));writel_relaxed (reg, priv->io_base +_REG (VIU_OSD1_FIFO_CTRL_STAT ));writel_relaxed (reg, priv->io_base +_REG (VIU_OSD2_FIFO_CTRL_STAT ));
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 241/290 filelock: new helper: vfs_inode_has_locks
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
[ Upstream commit ab1ddef98a715eddb65309ffa83267e4e84a571e ]
Ceph has a need to know whether a particular inode has any locks set on it. It's currently tracking that by a num_locks field in its filp->private_data, but that's problematic as it tries to decrement this field when releasing locks and that can race with the file being torn down.
Add a new vfs_inode_has_locks helper that just returns whether any locks are currently held on the inode.
Stable-dep-of: 461ab10ef7e6 ("ceph: switch to vfs_inode_has_locks() to fix file lock bug")
--- fs/locks.c | 23 +++++++++++++++++++++++ include/linux/fs.h | 6 ++++++ 2 files changed, 29 insertions(+)
fs/locks.c +23 -0
@@ -2703,6 +2703,29 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) }EXPORT_SYMBOL_GPL (vfs_cancel_lock); +/** +* vfs_inode_has_locks - are any file locks held on @inode? +* @inode: inode to check for locks +* +* Return true if there are any FL_POSIX or FL_FLOCK locks currently +* set on @inode. +*/ +bool vfs_inode_has_locks (struct inode *inode) +{ +struct file_lock_context *ctx; +bool ret; + + ctx =smp_load_acquire (&inode->i_flctx); +if (!ctx) +return false; + +spin_lock (&ctx->flc_lock); + ret = !list_empty (&ctx->flc_posix) || !list_empty (&ctx->flc_flock); +spin_unlock (&ctx->flc_lock); +return ret; +} +EXPORT_SYMBOL_GPL (vfs_inode_has_locks); +#ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> #include <linux/seq_file.h>
include/linux/fs.h +6 -0
@@ -1195,6 +1195,7 @@ extern int locks_delete_block(struct file_lock *);extern int vfs_test_lock (struct file *,struct file_lock *);extern int vfs_lock_file (struct file *,unsigned int ,struct file_lock *,struct file_lock *);extern int vfs_cancel_lock (struct file *filp,struct file_lock *fl); +bool vfs_inode_has_locks (struct inode *inode);extern int locks_lock_inode_wait (struct inode *inode,struct file_lock *fl);extern int __break_lease (struct inode *inode,unsigned int flags,unsigned int type);extern void lease_get_mtime (struct inode *,struct timespec64 *time);
@@ -1307,6 +1308,11 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl)return 0 ; } +static inline bool vfs_inode_has_locks (struct inode *inode) +{ +return false; +} +static inline int locks_lock_inode_wait (struct inode *inode,struct file_lock *fl) {return -ENOLCK ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 242/290 ceph: switch to vfs_inode_has_locks() to fix file lock bug
In reply to Greg Kroah-HartmanFrom: Xiubo Li <[email protected]>
[ Upstream commit 461ab10ef7e6ea9b41a0571a7fc6a72af9549a3c ]
For the POSIX locks they are using the same owner, which is the thread id. And multiple POSIX locks could be merged into single one, so when checking whether the 'file' has locks may fail.
For a file where some openers use locking and others don't is a really odd usage pattern though. Locks are like stoplights -- they only work if everyone pays attention to them.
Just switch ceph_get_caps() to check whether any locks are set on the inode. If there are POSIX/OFD/FLOCK locks on the file at the time, we should set CHECK_FILELOCK, regardless of what fd was used to set the lock.
--- fs/ceph/caps.c | 2 +- fs/ceph/locks.c | 4 ---- fs/ceph/super.h | 1 - 3 files changed, 1 insertion(+), 6 deletions(-)
fs/ceph/caps.c +1 -1
@@ -2872,7 +2872,7 @@ int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *gotwhile (true) { flags &=CEPH_FILE_MODE_MASK ; -if (atomic_read (&fi->num_locks)) +if (vfs_inode_has_locks (inode)) flags |=CHECK_FILELOCK ; _got =0 ; ret = try_get_cap_refs(inode, need, want, endoff,
fs/ceph/locks.c +0 -4
@@ -32,18 +32,14 @@ void __init ceph_flock_init(void)static void ceph_fl_copy_lock (struct file_lock *dst,struct file_lock *src) { -struct ceph_file_info *fi = dst->fl_file->private_data;struct inode *inode =file_inode (dst->fl_file);atomic_inc (&ceph_inode (inode)->i_filelock_ref); -atomic_inc (&fi->num_locks); }static void ceph_fl_release_lock (struct file_lock *fl) { -struct ceph_file_info *fi = fl->fl_file->private_data;struct inode *inode =file_inode (fl->fl_file);struct ceph_inode_info *ci =ceph_inode (inode); -atomic_dec (&fi->num_locks);if (atomic_dec_and_test (&ci->i_filelock_ref)) {/* clear error when all locks are released */ spin_lock (&ci->i_ceph_lock);
fs/ceph/super.h +0 -1
@@ -773,7 +773,6 @@ struct ceph_file_info {struct list_head rw_contexts;u32 filp_gen; -atomic_t num_locks; };struct ceph_dir_file_info {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 243/290 gpio: sifive: Fix refcount leak in sifive_gpio_probe
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit 694175cd8a1643cde3acb45c9294bca44a8e08e9 ]
of_irq_find_parent() returns a node pointer with refcount incremented, We should use of_node_put() on it when not needed anymore. Add missing of_node_put() to avoid refcount leak.
--- drivers/gpio/gpio-sifive.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpio/gpio-sifive.c +1 -0
@@ -209,6 +209,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)return -ENODEV ; } parent =irq_find_host (irq_parent); +of_node_put (irq_parent);if (!parent) {dev_err (dev,"no IRQ parent domain\n" );return -ENODEV ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 244/290 net: sched: atm: dont intepret cls results when asked to drop
In reply to Greg Kroah-HartmanFrom: Jamal Hadi Salim <[email protected]>
[ Upstream commit a2965c7be0522eaa18808684b7b82b248515511b ]
If asked to drop a packet via TC_ACT_SHOT it is unsafe to assume res.class contains a valid pointer
--- net/sched/sch_atm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/sched/sch_atm.c +4 -1
@@ -397,10 +397,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch, result =tcf_classify (skb,NULL , fl, &res, true);if (result <0 )continue ; +if (result ==TC_ACT_SHOT ) + goto done; + flow = (struct atm_flow_data *)res.class;if (!flow) flow =lookup_flow (sch, res.classid); - goto done; + goto drop; } } flow =NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 245/290 net: sched: cbq: dont intepret cls results when asked to drop
In reply to Greg Kroah-HartmanFrom: Jamal Hadi Salim <[email protected]>
[ Upstream commit caa4b35b4317d5147b3ab0fbdc9c075c7d2e9c12 ]
If asked to drop a packet via TC_ACT_SHOT it is unsafe to assume that res.class contains a valid pointer
Sample splat reported by Kyle Zeng
[ 5.405624] 0: reclassify loop, rule prio 0, protocol 800 [ 5.406326] ================================================================== [ 5.407240] BUG: KASAN: slab-out-of-bounds in cbq_enqueue+0x54b/0xea0 [ 5.407987] Read of size 1 at addr ffff88800e3122aa by task poc/299 [ 5.408731] [ 5.408897] CPU: 0 PID: 299 Comm: poc Not tainted 5.10.155+ #15 [ 5.409516] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 5.410439] Call Trace: [ 5.410764] dump_stack+0x87/0xcd [ 5.411153] print_address_description+0x7a/0x6b0 [ 5.411687] ? vprintk_func+0xb9/0xc0 [ 5.411905] ? printk+0x76/0x96 [ 5.412110] ? cbq_enqueue+0x54b/0xea0 [ 5.412323] kasan_report+0x17d/0x220 [ 5.412591] ? cbq_enqueue+0x54b/0xea0 [ 5.412803] __asan_report_load1_noabort+0x10/0x20 [ 5.413119] cbq_enqueue+0x54b/0xea0 [ 5.413400] ? __kasan_check_write+0x10/0x20 [ 5.413679] __dev_queue_xmit+0x9c0/0x1db0 [ 5.413922] dev_queue_xmit+0xc/0x10 [ 5.414136] ip_finish_output2+0x8bc/0xcd0 [ 5.414436] __ip_finish_output+0x472/0x7a0 [ 5.414692] ip_finish_output+0x5c/0x190 [ 5.414940] ip_output+0x2d8/0x3c0 [ 5.415150] ? ip_mc_finish_output+0x320/0x320 [ 5.415429] __ip_queue_xmit+0x753/0x1760 [ 5.415664] ip_queue_xmit+0x47/0x60 [ 5.415874] __tcp_transmit_skb+0x1ef9/0x34c0 [ 5.416129] tcp_connect+0x1f5e/0x4cb0 [ 5.416347] tcp_v4_connect+0xc8d/0x18c0 [ 5.416577] __inet_stream_connect+0x1ae/0xb40 [ 5.416836] ? local_bh_enable+0x11/0x20 [ 5.417066] ? lock_sock_nested+0x175/0x1d0 [ 5.417309] inet_stream_connect+0x5d/0x90 [ 5.417548] ? __inet_stream_connect+0xb40/0xb40 [ 5.417817] __sys_connect+0x260/0x2b0 [ 5.418037] __x64_sys_connect+0x76/0x80 [ 5.418267] do_syscall_64+0x31/0x50 [ 5.418477] entry_SYSCALL_64_after_hwframe+0x61/0xc6 [ 5.418770] RIP: 0033:0x473bb7 [ 5.418952] Code: 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2a 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 18 89 54 24 0c 48 89 34 24 89 [ 5.420046] RSP: 002b:00007fffd20eb0f8 EFLAGS: 00000246 ORIG_RAX: 000000000000002a [ 5.420472] RAX: ffffffffffffffda RBX: 00007fffd20eb578 RCX: 0000000000473bb7 [ 5.420872] RDX: 0000000000000010 RSI: 00007fffd20eb110 RDI: 0000000000000007 [ 5.421271] RBP: 00007fffd20eb150 R08: 0000000000000001 R09: 0000000000000004 [ 5.421671] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 [ 5.422071] R13: 00007fffd20eb568 R14: 00000000004fc740 R15: 0000000000000002 [ 5.422471] [ 5.422562] Allocated by task 299: [ 5.422782] __kasan_kmalloc+0x12d/0x160 [ 5.423007] kasan_kmalloc+0x5/0x10 [ 5.423208] kmem_cache_alloc_trace+0x201/0x2e0 [ 5.423492] tcf_proto_create+0x65/0x290 [ 5.423721] tc_new_tfilter+0x137e/0x1830 [ 5.423957] rtnetlink_rcv_msg+0x730/0x9f0 [ 5.424197] netlink_rcv_skb+0x166/0x300 [ 5.424428] rtnetlink_rcv+0x11/0x20 [ 5.424639] netlink_unicast+0x673/0x860 [ 5.424870] netlink_sendmsg+0x6af/0x9f0 [ 5.425100] __sys_sendto+0x58d/0x5a0 [ 5.425315] __x64_sys_sendto+0xda/0xf0 [ 5.425539] do_syscall_64+0x31/0x50 [ 5.425764] entry_SYSCALL_64_after_hwframe+0x61/0xc6 [ 5.426065] [ 5.426157] The buggy address belongs to the object at ffff88800e312200 [ 5.426157] which belongs to the cache kmalloc-128 of size 128 [ 5.426955] The buggy address is located 42 bytes to the right of [ 5.426955] 128-byte region [ffff88800e312200, ffff88800e312280) [ 5.427688] The buggy address belongs to the page: [ 5.427992] page:000000009875fabc refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xe312 [ 5.428562] flags: 0x100000000000200(slab) [ 5.428812] raw: 0100000000000200 dead000000000100 dead000000000122 ffff888007843680 [ 5.429325] raw: 0000000000000000 0000000000100010 00000001ffffffff ffff88800e312401 [ 5.429875] page dumped because: kasan: bad access detected [ 5.430214] page->mem_cgroup:ffff88800e312401 [ 5.430471] [ 5.430564] Memory state around the buggy address: [ 5.430846] ffff88800e312180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 5.431267] ffff88800e312200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc [ 5.431705] >ffff88800e312280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 5.432123] ^ [ 5.432391] ffff88800e312300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc [ 5.432810] ffff88800e312380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 5.433229] ================================================================== [ 5.433648] Disabling lock debugging due to kernel taint
--- net/sched/sch_cbq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/sched/sch_cbq.c +2 -2
@@ -231,6 +231,8 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) result =tcf_classify (skb,NULL , fl, &res, true);if (!fl || result <0 ) goto fallback; +if (result ==TC_ACT_SHOT ) +return NULL ; cl = (void *)res.class;if (!cl) {
@@ -251,8 +253,6 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)case TC_ACT_TRAP : *qerr =NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; fallthrough; -case TC_ACT_SHOT : -return NULL ;case TC_ACT_RECLASSIFY :return cbq_reclassify (skb, cl); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 246/290 net: sparx5: Fix reading of the MAC address
In reply to Greg Kroah-HartmanFrom: Horatiu Vultur <[email protected]>
[ Upstream commit 588ab2dc25f60efeb516b4abedb6c551949cc185 ]
There is an issue with the checking of the return value of 'of_get_mac_address', which returns 0 on success and negative value on failure. The driver interpretated the result the opposite way. Therefore if there was a MAC address defined in the DT, then the driver was generating a random MAC address otherwise it would use address 0. Fix this by checking correctly the return value of 'of_get_mac_address'
--- drivers/net/ethernet/microchip/sparx5/sparx5_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/microchip/sparx5/sparx5_main.c +1 -1
@@ -779,7 +779,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)if (err) goto cleanup_config; -if (!of_get_mac_address (np, sparx5->base_mac)) { +if (of_get_mac_address (np, sparx5->base_mac)) {dev_info (sparx5->dev,"MAC addr was not set, use random MAC\n" );eth_random_addr (sparx5->base_mac); sparx5->base_mac[5 ] =0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 247/290 netfilter: ipset: fix hash:net,port,net hang with /0 subnet
In reply to Greg Kroah-HartmanFrom: Jozsef Kadlecsik <[email protected]>
[ Upstream commit a31d47be64b9b74f8cfedffe03e0a8a1f9e51f23 ]
The hash:net,port,net set type supports /0 subnets. However, the patch commit 5f7b51bf09baca8e titled "netfilter: ipset: Limit the maximal range of consecutive elements to add/delete" did not take into account it and resulted in an endless loop. The bug is actually older but the patch 5f7b51bf09baca8e brings it out earlier.
Handle /0 subnets properly in hash:net,port,net set types.
--- net/netfilter/ipset/ip_set_hash_netportnet.c | 40 ++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-)
net/netfilter/ipset/ip_set_hash_netportnet.c +21 -19
@@ -173,17 +173,26 @@ hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,return adtfn (set, &e, &ext, &opt->ext, opt->cmdflags); } +static u32 +hash_netportnet4_range_to_cidr (u32 from,u32 to,u8 *cidr) +{ +if (from ==0 && to ==UINT_MAX ) { + *cidr =0 ; +return to; + } +return ip_set_range_to_cidr (from, to, cidr); +} +static int hash_netportnet4_uadt (struct ip_set *set,struct nlattr *tb[],enum ipset_adt adt,u32 *lineno,u32 flags,bool retried) { -const struct hash_netportnet4 *h = set->data; +struct hash_netportnet4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_netportnet4_elem e = { };struct ip_set_ext ext =IP_SET_INIT_UEXT (set);u32 ip =0 , ip_to =0 , p =0 , port, port_to; -u32 ip2_from =0 , ip2_to =0 , ip2, ipn; -u64 n =0 , m =0 ; +u32 ip2_from =0 , ip2_to =0 , ip2, i =0 ;bool with_ports = false;int ret;
@@ -285,19 +294,6 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], }else {ip_set_mask_from_to (ip2_from, ip2_to, e.cidr[1 ]); } - ipn = ip; -do { - ipn =ip_set_range_to_cidr (ipn, ip_to, &e.cidr[0 ]); - n++; - }while (ipn++ < ip_to); - ipn = ip2_from; -do { - ipn =ip_set_range_to_cidr (ipn, ip2_to, &e.cidr[1 ]); - m++; - }while (ipn++ < ip2_to); - -if (n*m*(port_to - port +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ;if (retried) { ip =ntohl (h->next.ip[0 ]);
@@ -310,13 +306,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], do { e.ip[0] = htonl(ip); - ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]); + ip = hash_netportnet4_range_to_cidr(ip, ip_to, &e.cidr[0]); for (; p <= port_to; p++) { e.port = htons(p); do { + i++; e.ip[1] = htonl(ip2); - ip2 = ip_set_range_to_cidr(ip2, ip2_to, - &e.cidr[1]); + if (i > IPSET_MAX_RANGE) { + hash_netportnet4_data_next(&h->next, + &e); + return -ERANGE; + } + ip2 = hash_netportnet4_range_to_cidr(ip2, + ip2_to, &e.cidr[1]); ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags)) return ret;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 248/290 netfilter: ipset: Rework long task execution when adding/deleting entries
In reply to Greg Kroah-HartmanFrom: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 5e29dc36bd5e2166b834ceb19990d9e68a734d7d ]
When adding/deleting large number of elements in one step in ipset, it can take a reasonable amount of time and can result in soft lockup errors. The patch 5f7b51bf09ba ("netfilter: ipset: Limit the maximal range of consecutive elements to add/delete") tried to fix it by limiting the max elements to process at all. However it was not enough, it is still possible that we get hung tasks. Lowering the limit is not reasonable, so the approach in this patch is as follows: rely on the method used at resizing sets and save the state when we reach a smaller internal batch limit, unlock/lock and proceed from the saved state. Thus we can avoid long continuous tasks and at the same time removed the limit to add/delete large number of elements in one step.
The nfnl mutex is held during the whole operation which prevents one to issue other ipset commands in parallel.
--- include/linux/netfilter/ipset/ip_set.h | 2 +- net/netfilter/ipset/ip_set_core.c | 7 ++++--- net/netfilter/ipset/ip_set_hash_ip.c | 14 ++++++------- net/netfilter/ipset/ip_set_hash_ipmark.c | 13 ++++++------ net/netfilter/ipset/ip_set_hash_ipport.c | 13 ++++++------ net/netfilter/ipset/ip_set_hash_ipportip.c | 13 ++++++------ net/netfilter/ipset/ip_set_hash_ipportnet.c | 13 +++++++----- net/netfilter/ipset/ip_set_hash_net.c | 17 +++++++-------- net/netfilter/ipset/ip_set_hash_netiface.c | 15 ++++++-------- net/netfilter/ipset/ip_set_hash_netnet.c | 23 +++++++-------------- net/netfilter/ipset/ip_set_hash_netport.c | 19 +++++++---------- 11 files changed, 68 insertions(+), 81 deletions(-)
include/linux/netfilter/ipset/ip_set.h +1 -1
@@ -197,7 +197,7 @@ struct ip_set_region { };/* Max range where every element is added/deleted in one step */ -#define IPSET_MAX_RANGE (1<<20) +#define IPSET_MAX_RANGE (1<<14)/* The max revision number supported by any set type + 1 */ #define IPSET_REVISION_MAX 9
net/netfilter/ipset/ip_set_core.c +4 -3
@@ -1698,9 +1698,10 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb, ret = set->variant->uadt (set, tb, adt, &lineno, flags, retried);ip_set_unlock (set); retried = true; - }while (ret == -EAGAIN && - set->variant->resize && - (ret = set->variant->resize (set, retried)) ==0 ); + }while (ret == -ERANGE || + (ret == -EAGAIN && + set->variant->resize && + (ret = set->variant->resize (set, retried)) ==0 ));if (!ret || (ret == -IPSET_ERR_EXIST && eexist))return 0 ;
net/netfilter/ipset/ip_set_hash_ip.c +7 -7
@@ -98,11 +98,11 @@ static int hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_ip4 *h = set->data; + struct hash_ip4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_ip4_elem e = {0 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip =0 , ip_to =0 , hosts; +u32 ip =0 , ip_to =0 , hosts, i =0 ;int ret =0 ;if (tb[IPSET_ATTR_LINENO ])
@@ -147,14 +147,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], hosts = h->netmask ==32 ?1 :2 << (32 - h->netmask -1 ); -/* 64bit division is not allowed on 32bit */ -if (((u64 )ip_to - ip +1 ) >> (32 - h->netmask) >IPSET_MAX_RANGE ) -return -ERANGE ; -if (retried) ip =ntohl (h->next.ip); -for (; ip <= ip_to;) { +for (; ip <= ip_to; i++) { e.ip =htonl (ip); +if (i >IPSET_MAX_RANGE ) { +hash_ip4_data_next (&h->next, &e); +return -ERANGE ; + } ret =adtfn (set, &e, &ext, &ext, flags);if (ret && !ip_set_eexist (ret, flags))return ret;
net/netfilter/ipset/ip_set_hash_ipmark.c +7 -6
@@ -97,11 +97,11 @@ static int hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_ipmark4 *h = set->data; + struct hash_ipmark4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_ipmark4_elem e = { };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip, ip_to =0 ; +u32 ip, ip_to =0 , i =0 ;int ret;if (tb[IPSET_ATTR_LINENO ])
@@ -148,13 +148,14 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],ip_set_mask_from_to (ip, ip_to, cidr); } -if (((u64 )ip_to - ip +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ; -if (retried) ip =ntohl (h->next.ip); -for (; ip <= ip_to; ip++) { +for (; ip <= ip_to; ip++, i++) { e.ip =htonl (ip); +if (i >IPSET_MAX_RANGE ) { +hash_ipmark4_data_next (&h->next, &e); +return -ERANGE ; + } ret =adtfn (set, &e, &ext, &ext, flags);if (ret && !ip_set_eexist (ret, flags))
net/netfilter/ipset/ip_set_hash_ipport.c +7 -6
@@ -105,11 +105,11 @@ static int hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_ipport4 *h = set->data; + struct hash_ipport4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_ipport4_elem e = { .ip =0 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip, ip_to =0 , p =0 , port, port_to; +u32 ip, ip_to =0 , p =0 , port, port_to, i =0 ;bool with_ports = false;int ret;
@@ -173,17 +173,18 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],swap (port, port_to); } -if (((u64 )ip_to - ip +1 )*(port_to - port +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ; -if (retried) ip =ntohl (h->next.ip);for (; ip <= ip_to; ip++) { p = retried && ip ==ntohl (h->next.ip) ?ntohs (h->next.port) : port; -for (; p <= port_to; p++) { +for (; p <= port_to; p++, i++) { e.ip =htonl (ip); e.port =htons (p); +if (i >IPSET_MAX_RANGE ) { +hash_ipport4_data_next (&h->next, &e); +return -ERANGE ; + } ret =adtfn (set, &e, &ext, &ext, flags);if (ret && !ip_set_eexist (ret, flags))
net/netfilter/ipset/ip_set_hash_ipportip.c +7 -6
@@ -108,11 +108,11 @@ static int hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_ipportip4 *h = set->data; + struct hash_ipportip4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_ipportip4_elem e = { .ip =0 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip, ip_to =0 , p =0 , port, port_to; +u32 ip, ip_to =0 , p =0 , port, port_to, i =0 ;bool with_ports = false;int ret;
@@ -180,17 +180,18 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],swap (port, port_to); } -if (((u64 )ip_to - ip +1 )*(port_to - port +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ; -if (retried) ip =ntohl (h->next.ip);for (; ip <= ip_to; ip++) { p = retried && ip ==ntohl (h->next.ip) ?ntohs (h->next.port) : port; -for (; p <= port_to; p++) { +for (; p <= port_to; p++, i++) { e.ip =htonl (ip); e.port =htons (p); +if (i >IPSET_MAX_RANGE ) { +hash_ipportip4_data_next (&h->next, &e); +return -ERANGE ; + } ret =adtfn (set, &e, &ext, &ext, flags);if (ret && !ip_set_eexist (ret, flags))
net/netfilter/ipset/ip_set_hash_ipportnet.c +8 -5
@@ -160,12 +160,12 @@ static int hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_ipportnet4 *h = set->data; + struct hash_ipportnet4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_ipportnet4_elem e = { .cidr =HOST_MASK -1 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set);u32 ip =0 , ip_to =0 , p =0 , port, port_to; -u32 ip2_from =0 , ip2_to =0 , ip2; +u32 ip2_from =0 , ip2_to =0 , ip2, i =0 ;bool with_ports = false;u8 cidr;int ret;
@@ -253,9 +253,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],swap (port, port_to); } -if (((u64 )ip_to - ip +1 )*(port_to - port +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ; - ip2_to = ip2_from;if (tb[IPSET_ATTR_IP2_TO ]) { ret =ip_set_get_hostipaddr4 (tb[IPSET_ATTR_IP2_TO ], &ip2_to);
@@ -282,9 +279,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],for (; p <= port_to; p++) { e.port =htons (p); do { + i++; e.ip2 = htonl(ip2); ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr); e.cidr = cidr - 1; + if (i > IPSET_MAX_RANGE) { + hash_ipportnet4_data_next(&h->next, + &e); + return -ERANGE; + } ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags))
net/netfilter/ipset/ip_set_hash_net.c +7 -10
@@ -136,11 +136,11 @@ static int hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_net4 *h = set->data; + struct hash_net4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_net4_elem e = { .cidr =HOST_MASK };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip =0 , ip_to =0 , ipn, n =0 ; +u32 ip =0 , ip_to =0 , i =0 ;int ret;if (tb[IPSET_ATTR_LINENO ])
@@ -188,19 +188,16 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],if (ip +UINT_MAX == ip_to)return -IPSET_ERR_HASH_RANGE ; } - ipn = ip; -do { - ipn =ip_set_range_to_cidr (ipn, ip_to, &e.cidr); - n++; - }while (ipn++ < ip_to); - -if (n >IPSET_MAX_RANGE ) -return -ERANGE ;if (retried) ip =ntohl (h->next.ip); do { + i++; e.ip = htonl(ip); + if (i > IPSET_MAX_RANGE) { + hash_net4_data_next(&h->next, &e); + return -ERANGE; + } ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr); ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags))
net/netfilter/ipset/ip_set_hash_netiface.c +6 -9
@@ -202,7 +202,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],ipset_adtfn adtfn = set->variant->adt[adt];struct hash_netiface4_elem e = { .cidr =HOST_MASK , .elem =1 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 ip =0 , ip_to =0 , ipn, n =0 ; +u32 ip =0 , ip_to =0 , i =0 ;int ret;if (tb[IPSET_ATTR_LINENO ])
@@ -256,19 +256,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], }else {ip_set_mask_from_to (ip, ip_to, e.cidr); } - ipn = ip; -do { - ipn =ip_set_range_to_cidr (ipn, ip_to, &e.cidr); - n++; - }while (ipn++ < ip_to); - -if (n >IPSET_MAX_RANGE ) -return -ERANGE ;if (retried) ip =ntohl (h->next.ip); do { + i++; e.ip = htonl(ip); + if (i > IPSET_MAX_RANGE) { + hash_netiface4_data_next(&h->next, &e); + return -ERANGE; + } ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr); ret = adtfn(set, &e, &ext, &ext, flags);
net/netfilter/ipset/ip_set_hash_netnet.c +7 -16
@@ -163,13 +163,12 @@ static int hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_netnet4 *h = set->data; + struct hash_netnet4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_netnet4_elem e = { };struct ip_set_ext ext =IP_SET_INIT_UEXT (set);u32 ip =0 , ip_to =0 ; -u32 ip2 =0 , ip2_from =0 , ip2_to =0 , ipn; -u64 n =0 , m =0 ; +u32 ip2 =0 , ip2_from =0 , ip2_to =0 , i =0 ;int ret;if (tb[IPSET_ATTR_LINENO ])
@@ -245,19 +244,6 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], }else {ip_set_mask_from_to (ip2_from, ip2_to, e.cidr[1 ]); } - ipn = ip; -do { - ipn =ip_set_range_to_cidr (ipn, ip_to, &e.cidr[0 ]); - n++; - }while (ipn++ < ip_to); - ipn = ip2_from; -do { - ipn =ip_set_range_to_cidr (ipn, ip2_to, &e.cidr[1 ]); - m++; - }while (ipn++ < ip2_to); - -if (n*m >IPSET_MAX_RANGE ) -return -ERANGE ;if (retried) { ip =ntohl (h->next.ip[0 ]);
@@ -270,7 +256,12 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], e.ip[0 ] =htonl (ip); ip =ip_set_range_to_cidr (ip, ip_to, &e.cidr[0 ]); do { + i++; e.ip[1] = htonl(ip2); + if (i > IPSET_MAX_RANGE) { + hash_netnet4_data_next(&h->next, &e); + return -ERANGE; + } ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]); ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags))
net/netfilter/ipset/ip_set_hash_netport.c +7 -12
@@ -154,12 +154,11 @@ static int hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { - const struct hash_netport4 *h = set->data; + struct hash_netport4 *h = set->data;ipset_adtfn adtfn = set->variant->adt[adt];struct hash_netport4_elem e = { .cidr =HOST_MASK -1 };struct ip_set_ext ext =IP_SET_INIT_UEXT (set); -u32 port, port_to, p =0 , ip =0 , ip_to =0 , ipn; -u64 n =0 ; +u32 port, port_to, p =0 , ip =0 , ip_to =0 , i =0 ;bool with_ports = false;u8 cidr;int ret;
@@ -236,14 +235,6 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], }else {ip_set_mask_from_to (ip, ip_to, e.cidr +1 ); } - ipn = ip; -do { - ipn =ip_set_range_to_cidr (ipn, ip_to, &cidr); - n++; - }while (ipn++ < ip_to); - -if (n*(port_to - port +1 ) >IPSET_MAX_RANGE ) -return -ERANGE ;if (retried) { ip =ntohl (h->next.ip);
@@ -255,8 +246,12 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], e.ip =htonl (ip); ip =ip_set_range_to_cidr (ip, ip_to, &cidr); e.cidr = cidr -1 ; -for (; p <= port_to; p++) { +for (; p <= port_to; p++, i++) { e.port =htons (p); +if (i >IPSET_MAX_RANGE ) { +hash_netport4_data_next (&h->next, &e); +return -ERANGE ; + } ret =adtfn (set, &e, &ext, &ext, flags);if (ret && !ip_set_eexist (ret, flags))return ret;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 249/290 perf tools: Fix resources leak in perf_data__open_dir()
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit 0a6564ebd953c4590663c9a3c99a3ea9920ade6f ]
In perf_data__open_dir(), opendir() opens the directory stream. Add missing closedir() to release it after use.
--- tools/perf/util/data.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/data.c +2 -0
@@ -127,6 +127,7 @@ int perf_data__open_dir(struct perf_data *data) file->size = st.st_size; } +closedir (dir);if (!files)return -EINVAL ;
@@ -135,6 +136,7 @@ int perf_data__open_dir(struct perf_data *data)return 0 ; out_err: +closedir (dir);close_dir (files, nr);return ret; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 250/290 drm/imx: ipuv3-plane: Fix overlay plane width
In reply to Greg Kroah-HartmanFrom: Philipp Zabel <[email protected]>
[ Upstream commit 92d43bd3bc9728c1fb114d7011d46f5ea9489e28 ]
ipu_src_rect_width() was introduced to support odd screen resolutions such as 1366x768 by internally rounding up primary plane width to a multiple of 8 and compensating with reduced horizontal blanking. This also caused overlay plane width to be rounded up, which was not intended. Fix overlay plane width by limiting the rounding up to the primary plane.
drm_rect_width(&new_state->src) >> 16 is the same value as drm_rect_width(dst) because there is no plane scaling support.
--- drivers/gpu/drm/imx/ipuv3-plane.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/gpu/drm/imx/ipuv3-plane.c +8 -6
@@ -619,6 +619,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,break ; } +if (ipu_plane->dp_flow ==IPU_DP_FLOW_SYNC_BG ) + width =ipu_src_rect_width (new_state); +else + width =drm_rect_width (&new_state->src) >>16 ; + eba =drm_plane_state_to_eba (new_state,0 );/*
@@ -627,8 +632,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,*/ if (ipu_state->use_pre) { axi_id =ipu_chan_assign_axi_id (ipu_plane->dma); -ipu_prg_channel_configure (ipu_plane->ipu_ch, axi_id, -ipu_src_rect_width (new_state), +ipu_prg_channel_configure (ipu_plane->ipu_ch, axi_id, width,drm_rect_height (&new_state->src) >>16 , fb->pitches[0 ], fb->format->format, fb->modifier, &eba);
@@ -683,9 +687,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,break ; } -ipu_dmfc_config_wait4eot (ipu_plane->dmfc,ALIGN (drm_rect_width (dst),8 )); +ipu_dmfc_config_wait4eot (ipu_plane->dmfc, width); - width =ipu_src_rect_width (new_state); height =drm_rect_height (&new_state->src) >>16 ; info =drm_format_info (fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
@@ -749,8 +752,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,ipu_cpmem_set_burstsize (ipu_plane->ipu_ch,16 );ipu_cpmem_zero (ipu_plane->alpha_ch); -ipu_cpmem_set_resolution (ipu_plane->alpha_ch, -ipu_src_rect_width (new_state), +ipu_cpmem_set_resolution (ipu_plane->alpha_ch, width,drm_rect_height (&new_state->src) >>16 );ipu_cpmem_set_format_passthrough (ipu_plane->alpha_ch,8 );ipu_cpmem_set_high_priority (ipu_plane->alpha_ch);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 251/290 fs/ntfs3: dont hold ni_lock when calling truncate_setsize()
In reply to Greg Kroah-HartmanFrom: Tetsuo Handa <[email protected]>
[ Upstream commit 0226635c304cfd5c9db9b78c259cb713819b057e ]
syzbot is reporting hung task at do_user_addr_fault() [1], for there is a silent deadlock between PG_locked bit and ni_lock lock.
Since filemap_update_page() calls filemap_read_folio() after calling folio_trylock() which will set PG_locked bit, ntfs_truncate() must not call truncate_setsize() which will wait for PG_locked bit to be cleared when holding ni_lock lock.
--- fs/ntfs3/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/ntfs3/file.c +2 -2
@@ -488,10 +488,10 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size) new_valid =ntfs_up_block (sb,min_t (u64, ni->i_valid, new_size)); -ni_lock (ni); -truncate_setsize (inode, new_size); +ni_lock (ni); +down_write (&ni->file.run_lock); err =attr_set_size (ni,ATTR_DATA ,NULL ,0 , &ni->file.run, new_size, &new_valid, ni->mi.sbi->options->prealloc,NULL );
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 252/290 drivers/net/bonding/bond_3ad: return when theres no aggregator
In reply to Greg Kroah-HartmanFrom: Daniil Tatianin <[email protected]>
[ Upstream commit 9c807965483f42df1d053b7436eedd6cf28ece6f ]
Otherwise we would dereference a NULL aggregator pointer when calling __set_agg_ports_ready on the line below.
Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool.
--- drivers/net/bonding/bond_3ad.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/bonding/bond_3ad.c +1 -0
@@ -1539,6 +1539,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)slave_err (bond->dev, port->slave->dev,"Port %d did not find a suitable aggregator\n" , port->actor_port_number); +return ; } }/* if all aggregator's ports are READY_N == TRUE, set ready=TRUE
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 253/290 octeontx2-pf: Fix lmtst ID used in aura free
In reply to Greg Kroah-HartmanFrom: Geetha sowjanya <[email protected]>
[ Upstream commit 4af1b64f80fbe1275fb02c5f1c0cef099a4a231f ]
Current code uses per_cpu pointer to get the lmtst_id mapped to the core on which aura_free() is executed. Using per_cpu pointer without preemption disable causing mismatch between lmtst_id and core on which pointer gets freed. This patch fixes the issue by disabling preemption around aura_free.
--- .../marvell/octeontx2/nic/otx2_common.c | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +21 -9
@@ -962,6 +962,7 @@ static void otx2_pool_refill_task(struct work_struct *work) rbpool = cq->rbpool; free_ptrs = cq->pool_ptrs; +get_cpu ();while (cq->pool_ptrs) {if (otx2_alloc_rbuf (pfvf, rbpool, &bufptr)) {/* Schedule a WQ if we fails to free atleast half of the
@@ -981,6 +982,7 @@ static void otx2_pool_refill_task(struct work_struct *work) pfvf->hw_ops->aura_freeptr (pfvf, qidx, bufptr +OTX2_HEAD_ROOM ); cq->pool_ptrs--; } +put_cpu (); cq->refill_task_sched = false; }
@@ -1314,6 +1316,7 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf)if (err) goto fail; +get_cpu ();/* Allocate pointers and free them to aura/pool */ for (qidx =0 ; qidx < hw->tx_queues; qidx++) { pool_id =otx2_get_pool_idx (pfvf,AURA_NIX_SQ , qidx);
@@ -1322,18 +1325,24 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf) sq = &qset->sq[qidx]; sq->sqb_count =0 ; sq->sqb_ptrs =kcalloc (num_sqbs,sizeof (*sq->sqb_ptrs),GFP_KERNEL ); -if (!sq->sqb_ptrs) -return -ENOMEM ; +if (!sq->sqb_ptrs) { + err = -ENOMEM ; + goto err_mem; + }for (ptr =0 ; ptr < num_sqbs; ptr++) { -if (otx2_alloc_rbuf (pfvf, pool, &bufptr)) -return -ENOMEM ; + err =otx2_alloc_rbuf (pfvf, pool, &bufptr); +if (err) + goto err_mem; pfvf->hw_ops->aura_freeptr (pfvf, pool_id, bufptr); sq->sqb_ptrs[sq->sqb_count++] = (u64 )bufptr; } } -return 0 ; +err_mem: +put_cpu (); +return err ? -ENOMEM :0 ; + fail:otx2_mbox_reset (&pfvf->mbox.mbox,0 );otx2_aura_pool_free (pfvf);
@@ -1372,18 +1381,21 @@ int otx2_rq_aura_pool_init(struct otx2_nic *pfvf)if (err) goto fail; +get_cpu ();/* Allocate pointers and free them to aura/pool */ for (pool_id =0 ; pool_id < hw->rqpool_cnt; pool_id++) { pool = &pfvf->qset.pool[pool_id];for (ptr =0 ; ptr < num_ptrs; ptr++) { -if (otx2_alloc_rbuf (pfvf, pool, &bufptr)) -return -ENOMEM ; + err =otx2_alloc_rbuf (pfvf, pool, &bufptr); +if (err) + goto err_mem; pfvf->hw_ops->aura_freeptr (pfvf, pool_id, bufptr +OTX2_HEAD_ROOM ); } } - -return 0 ; +err_mem: +put_cpu (); +return err ? -ENOMEM :0 ; fail:otx2_mbox_reset (&pfvf->mbox.mbox,0 );otx2_aura_pool_free (pfvf);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 254/290 usb: rndis_host: Secure rndis_query check against int overflow
In reply to Greg Kroah-HartmanFrom: Szymon Heidrich <[email protected]>
[ Upstream commit c7dd13805f8b8fc1ce3b6d40f6aff47e66b72ad2 ]
Variables off and len typed as uint32 in rndis_query function are controlled by incoming RNDIS response message thus their value may be manipulated. Setting off to a unexpectetly large value will cause the sum with len and 8 to overflow and pass the implemented validation step. Consequently the response pointer will be referring to a location past the expected buffer boundaries allowing information leakage e.g. via RNDIS_OID_802_3_PERMANENT_ADDRESS OID.
--- drivers/net/usb/rndis_host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/usb/rndis_host.c +2 -1
@@ -255,7 +255,8 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, off =le32_to_cpu (u.get_c->offset); len =le32_to_cpu (u.get_c->len); -if (unlikely ((8 + off + len) >CONTROL_BUFFER_SIZE )) +if (unlikely ((off >CONTROL_BUFFER_SIZE -8 ) || + (len >CONTROL_BUFFER_SIZE -8 - off))) goto response_error;if (*reply_len !=-1 && len != *reply_len)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 255/290 perf stat: Fix handling of --for-each-cgroup with --bpf-counters to match non BPF mode
In reply to Greg Kroah-HartmanFrom: Namhyung Kim <[email protected]>
[ Upstream commit 54b353a20c7e8be98414754f5aff98c8a68fcc1f ]
The --for-each-cgroup can have the same cgroup multiple times, but this confuses BPF counters (since they have the same cgroup id), making only the last cgroup events to be counted.
Let's check the cgroup name before adding a new entry to the cgroups list.
Before:
$ sudo ./perf stat -a --bpf-counters --for-each-cgroup /,/ sleep 1
Performance counter stats for 'system wide':
<not counted> msec cpu-clock /
<not counted> context-switches /
<not counted> cpu-migrations /
<not counted> page-faults /
<not counted> cycles /
<not counted> instructions /
<not counted> branches /
<not counted> branch-misses /
8,016.04 msec cpu-clock / # 7.998 CPUs utilized
6,152 context-switches / # 767.461 /sec
250 cpu-migrations / # 31.187 /sec
442 page-faults / # 55.139 /sec
613,111,487 cycles / # 0.076 GHz
280,599,604 instructions / # 0.46 insn per cycle
57,692,724 branches / # 7.197 M/sec
3,385,168 branch-misses / # 5.87% of all branches1.002220125 seconds time elapsed
After it becomes similar to the non-BPF mode:
$ sudo ./perf stat -a --bpf-counters --for-each-cgroup /,/ sleep 1
Performance counter stats for 'system wide':
8,013.38 msec cpu-clock / # 7.998 CPUs utilized
6,859 context-switches / # 855.944 /sec
334 cpu-migrations / # 41.680 /sec
345 page-faults / # 43.053 /sec
782,326,119 cycles / # 0.098 GHz
471,645,724 instructions / # 0.60 insn per cycle
94,963,430 branches / # 11.851 M/sec
3,685,511 branch-misses / # 3.88% of all branches1.001864539 seconds time elapsed
Committer notes:
As a reminder, to test with BPF counters one has to use BUILD_BPF_SKEL=1 in the make command line and have clang/llvm installed when building perf, otherwise the --bpf-counters option will not be available:
# perf stat -a --bpf-counters --for-each-cgroup /,/ sleep 1 Error: unknown option `bpf-counters'
Usage: perf stat [<options>] [<command>]
-a, --all-cpus system-wide collection from all CPUs
<SNIP>
#
--- tools/perf/util/cgroup.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
tools/perf/util/cgroup.c +18 -5
@@ -224,6 +224,19 @@ static int add_cgroup_name(const char *fpath, const struct stat *sb __maybe_unusreturn 0 ; } +static int check_and_add_cgroup_name (const char *fpath) +{ +struct cgroup_name *cn; + +list_for_each_entry (cn, &cgroup_list, list) { +if (!strcmp (cn->name, fpath)) +return 0 ; + } + +/* pretend if it's added by ftw() */ +return add_cgroup_name (fpath,NULL ,FTW_D ,NULL ); +} +static void release_cgroup_list (void ) {struct cgroup_name *cn;
@@ -242,7 +255,7 @@ static int list_cgroups(const char *str)struct cgroup_name *cn;char *s; -/* use given name as is - for testing purpose */ +/* use given name as is when no regex is given */ for (;;) { p =strchr (str,',' ); e = p ? p : eos;
@@ -253,13 +266,13 @@ static int list_cgroups(const char *str) s =strndup (str, e - str);if (!s)return -1 ; -/* pretend if it's added by ftw() */ - ret =add_cgroup_name (s,NULL ,FTW_D ,NULL ); + + ret =check_and_add_cgroup_name (s);free (s); -if (ret) +if (ret <0 )return -1 ; }else { -if (add_cgroup_name ("" ,NULL ,FTW_D ,NULL ) <0 ) +if (check_and_add_cgroup_name ("/" ) <0 )return -1 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 256/290 drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit 3792fc508c095abd84b10ceae12bd773e61fdc36 ]
Call intel_vgpu_unpin_mm() on this error path.
--- drivers/gpu/drm/i915/gvt/scheduler.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/i915/gvt/scheduler.c +1 -0
@@ -694,6 +694,7 @@ intel_vgpu_shadow_mm_pin(struct intel_vgpu_workload *workload)if (workload->shadow_mm->type !=INTEL_GVT_MM_PPGTT || !workload->shadow_mm->ppgtt_mm.shadowed) { +intel_vgpu_unpin_mm (workload->shadow_mm);gvt_vgpu_err ("workload shadow ppgtt isn't ready\n" );return -EINVAL ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 257/290 caif: fix memory leak in cfctrl_linkup_request()
In reply to Greg Kroah-HartmanFrom: Zhengchao Shao <[email protected]>
[ Upstream commit fe69230f05897b3de758427b574fc98025dfc907 ]
When linktype is unknown or kzalloc failed in cfctrl_linkup_request(), pkt is not released. Add release process to error path.
--- net/caif/cfctrl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/caif/cfctrl.c +5 -1
@@ -269,11 +269,15 @@ int cfctrl_linkup_request(struct cflayer *layer,default :pr_warn ("Request setup of bad link type = %d\n" , param->linktype); +cfpkt_destroy (pkt);return -EINVAL ; } req =kzalloc (sizeof (*req),GFP_KERNEL ); -if (!req) +if (!req) { +cfpkt_destroy (pkt);return -ENOMEM ; + } + req->client_layer = user_layer; req->cmd =CFCTRL_CMD_LINK_SETUP ; req->param = *param;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 258/290 udf: Fix extension of the last extent in the file
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
[ Upstream commit 83c7423d1eb6806d13c521d1002cc1a012111719 ]
When extending the last extent in the file within the last block, we wrongly computed the length of the last extent. This is mostly a cosmetical problem since the extent does not contain any data and the length will be fixed up by following operations but still.
--- fs/udf/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/udf/inode.c +1 -1
@@ -599,7 +599,7 @@ static void udf_do_extend_final_block(struct inode *inode,*/ if (new_elen <= (last_ext->extLength &UDF_EXTENT_LENGTH_MASK ))return ; - added_bytes = (last_ext->extLength &UDF_EXTENT_LENGTH_MASK ) - new_elen; + added_bytes = new_elen - (last_ext->extLength &UDF_EXTENT_LENGTH_MASK ); last_ext->extLength += added_bytes;UDF_I (inode)->i_lenExtents += added_bytes;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 259/290 ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit a1dec9d70b6ad97087b60b81d2492134a84208c6 ]
The Advantech MICA-071 tablet deviates from the defaults for a non CR Bay Trail based tablet in several ways:
1. It uses an analog MIC on IN3 rather then using DMIC1
2. It only has 1 speaker
3. It needs the OVCD current threshold to be set to 1500uA instead of the default 2000uA to reliable differentiate between headphones vs headsets
Add a quirk with these settings for this tablet.
--- sound/soc/intel/boards/bytcr_rt5640.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
sound/soc/intel/boards/bytcr_rt5640.c +15 -0
@@ -570,6 +570,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { +/* Advantech MICA-071 */ + .matches = { +DMI_EXACT_MATCH (DMI_SYS_VENDOR ,"Advantech" ), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"), + }, +/* OVCD Th = 1500uA to reliable detect head-phones vs -set */ + .driver_data = (void *)(BYT_RT5640_IN3_MAP | +BYT_RT5640_JD_SRC_JD2_IN4N | +BYT_RT5640_OVCD_TH_1500UA | +BYT_RT5640_OVCD_SF_0P75 | +BYT_RT5640_MONO_SPEAKER | +BYT_RT5640_DIFF_MIC | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 260/290 nvme: fix multipath crash caused by flush request when blktrace is enabled
In reply to Greg Kroah-HartmanFrom: Yanjun Zhang <[email protected]>
[ Upstream commit 3659fb5ac29a5e6102bebe494ac789fd47fb78f4 ]
The flush request initialized by blk_kick_flush has NULL bio, and it may be dealt with nvme_end_req during io completion. When blktrace is enabled, nvme_trace_bio_complete with multipath activated trying to access NULL pointer bio from flush request results in the following crash:
[ 2517.831677] BUG: kernel NULL pointer dereference, address: 000000000000001a [ 2517.835213] #PF: supervisor read access in kernel mode [ 2517.838724] #PF: error_code(0x0000) - not-present page [ 2517.842222] PGD 7b2d51067 P4D 0 [ 2517.845684] Oops: 0000 [#1] SMP NOPTI [ 2517.849125] CPU: 2 PID: 732 Comm: kworker/2:1H Kdump: loaded Tainted: G S 5.15.67-0.cl9.x86_64 #1 [ 2517.852723] Hardware name: XFUSION 2288H V6/BC13MBSBC, BIOS 1.13 07/27/2022 [ 2517.856358] Workqueue: nvme_tcp_wq nvme_tcp_io_work [nvme_tcp] [ 2517.859993] RIP: 0010:blk_add_trace_bio_complete+0x6/0x30 [ 2517.863628] Code: 1f 44 00 00 48 8b 46 08 31 c9 ba 04 00 10 00 48 8b 80 50 03 00 00 48 8b 78 50 e9 e5 fe ff ff 0f 1f 44 00 00 41 54 49 89 f4 55 <0f> b6 7a 1a 48 89 d5 e8 3e 1c 2b 00 48 89 ee 4c 89 e7 5d 89 c1 ba [ 2517.871269] RSP: 0018:ff7f6a008d9dbcd0 EFLAGS: 00010286 [ 2517.875081] RAX: ff3d5b4be00b1d50 RBX: 0000000002040002 RCX: ff3d5b0a270f2000 [ 2517.878966] RDX: 0000000000000000 RSI: ff3d5b0b021fb9f8 RDI: 0000000000000000 [ 2517.882849] RBP: ff3d5b0b96a6fa00 R08: 0000000000000001 R09: 0000000000000000 [ 2517.886718] R10: 000000000000000c R11: 000000000000000c R12: ff3d5b0b021fb9f8 [ 2517.890575] R13: 0000000002000000 R14: ff3d5b0b021fb1b0 R15: 0000000000000018 [ 2517.894434] FS: 0000000000000000(0000) GS:ff3d5b42bfc80000(0000) knlGS:0000000000000000 [ 2517.898299] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2517.902157] CR2: 000000000000001a CR3: 00000004f023e005 CR4: 0000000000771ee0 [ 2517.906053] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 2517.909930] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 2517.913761] PKRU: 55555554 [ 2517.917558] Call Trace: [ 2517.921294] <TASK> [ 2517.924982] nvme_complete_rq+0x1c3/0x1e0 [nvme_core] [ 2517.928715] nvme_tcp_recv_pdu+0x4d7/0x540 [nvme_tcp] [ 2517.932442] nvme_tcp_recv_skb+0x4f/0x240 [nvme_tcp] [ 2517.936137] ? nvme_tcp_recv_pdu+0x540/0x540 [nvme_tcp] [ 2517.939830] tcp_read_sock+0x9c/0x260 [ 2517.943486] nvme_tcp_try_recv+0x65/0xa0 [nvme_tcp] [ 2517.947173] nvme_tcp_io_work+0x64/0x90 [nvme_tcp] [ 2517.950834] process_one_work+0x1e8/0x390 [ 2517.954473] worker_thread+0x53/0x3c0 [ 2517.958069] ? process_one_work+0x390/0x390 [ 2517.961655] kthread+0x10c/0x130 [ 2517.965211] ? set_kthread_struct+0x40/0x40 [ 2517.968760] ret_from_fork+0x1f/0x30 [ 2517.972285] </TASK>
To avoid this situation, add a NULL check for req->bio before calling trace_block_bio_complete.
--- drivers/nvme/host/nvme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/host/nvme.h +1 -1
@@ -799,7 +799,7 @@ static inline void nvme_trace_bio_complete(struct request *req) {struct nvme_ns *ns = req->q->queuedata; -if (req->cmd_flags &REQ_NVME_MPATH ) +if ((req->cmd_flags &REQ_NVME_MPATH ) && req->bio)trace_block_bio_complete (ns->head->disk->queue, req->bio); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 261/290 io_uring: check for valid register opcode earlier
In reply to Greg Kroah-HartmanFrom: Jens Axboe <[email protected]>
[ Upstream commit 343190841a1f22b96996d9f8cfab902a4d1bfd0e ]
We only check the register opcode value inside the restricted ring section, move it into the main io_uring_register() function instead and check it up front.
--- io_uring/io_uring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
io_uring/io_uring.c +3 -2
@@ -10895,8 +10895,6 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,return -ENXIO ;if (ctx->restricted) { -if (opcode >=IORING_REGISTER_LAST ) -return -EINVAL ; opcode =array_index_nospec (opcode,IORING_REGISTER_LAST );if (!test_bit (opcode, ctx->restrictions.register_op))return -EACCES ;
@@ -11028,6 +11026,9 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,long ret = -EBADF ;struct fd f; +if (opcode >=IORING_REGISTER_LAST ) +return -EINVAL ; + f =fdget (fd);if (!f.file)return -EBADF ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 262/290 nvmet: use NVME_CMD_EFFECTS_CSUPP instead of open coding it
In reply to Greg Kroah-HartmanFrom: Christoph Hellwig <[email protected]>
[ Upstream commit 61f37154c599cf9f2f84dcbd9be842f8645a7099 ]
Use NVME_CMD_EFFECTS_CSUPP instead of open coding it and assign a single value to multiple array entries instead of repeated assignments.
--- drivers/nvme/target/admin-cmd.c | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-)
drivers/nvme/target/admin-cmd.c +19 -16
@@ -164,26 +164,29 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)static void nvmet_get_cmd_effects_nvm (struct nvme_effects_log *log) { - log->acs[nvme_admin_get_log_page] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_identify] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_abort_cmd] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_set_features] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_get_features] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_async_event] =cpu_to_le32 (1 <<0 ); - log->acs[nvme_admin_keep_alive] =cpu_to_le32 (1 <<0 ); - - log->iocs[nvme_cmd_read] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_write] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_flush] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_dsm] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_write_zeroes] =cpu_to_le32 (1 <<0 ); + log->acs[nvme_admin_get_log_page] = + log->acs[nvme_admin_identify] = + log->acs[nvme_admin_abort_cmd] = + log->acs[nvme_admin_set_features] = + log->acs[nvme_admin_get_features] = + log->acs[nvme_admin_async_event] = + log->acs[nvme_admin_keep_alive] = +cpu_to_le32 (NVME_CMD_EFFECTS_CSUPP ); + + log->iocs[nvme_cmd_read] = + log->iocs[nvme_cmd_write] = + log->iocs[nvme_cmd_flush] = + log->iocs[nvme_cmd_dsm] = + log->iocs[nvme_cmd_write_zeroes] = +cpu_to_le32 (NVME_CMD_EFFECTS_CSUPP ); }static void nvmet_get_cmd_effects_zns (struct nvme_effects_log *log) { - log->iocs[nvme_cmd_zone_append] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_zone_mgmt_send] =cpu_to_le32 (1 <<0 ); - log->iocs[nvme_cmd_zone_mgmt_recv] =cpu_to_le32 (1 <<0 ); + log->iocs[nvme_cmd_zone_append] = + log->iocs[nvme_cmd_zone_mgmt_send] = + log->iocs[nvme_cmd_zone_mgmt_recv] = +cpu_to_le32 (NVME_CMD_EFFECTS_CSUPP ); }static void nvmet_execute_get_log_cmd_effects_ns (struct nvmet_req *req)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 263/290 nvme: also return I/O command effects from nvme_command_effects
In reply to Greg Kroah-HartmanFrom: Christoph Hellwig <[email protected]>
[ Upstream commit 831ed60c2aca2d7c517b2da22897a90224a97d27 ]
To be able to use the Commands Supported and Effects Log for allowing unprivileged passtrough, it needs to be corretly reported for I/O commands as well. Return the I/O command effects from nvme_command_effects, and also add a default list of effects for the NVM command set. For other command sets, the Commands Supported and Effects log is required to be present already.
--- drivers/nvme/host/core.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)
drivers/nvme/host/core.c +26 -6
@@ -1113,6 +1113,18 @@ static u32 nvme_known_admin_effects(u8 opcode)return 0 ; } +static u32 nvme_known_nvm_effects (u8 opcode) +{ +switch (opcode) { +case nvme_cmd_write: +case nvme_cmd_write_zeroes: +case nvme_cmd_write_uncor: +return NVME_CMD_EFFECTS_LBCC ; +default : +return 0 ; + } +} +u32 nvme_command_effects (struct nvme_ctrl *ctrl,struct nvme_ns *ns,u8 opcode) {u32 effects =0 ;
@@ -1120,16 +1132,24 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)if (ns) {if (ns->head->effects) effects =le32_to_cpu (ns->head->effects->iocs[opcode]); +if (ns->head->ids.csi ==NVME_CAP_CSS_NVM ) + effects |=nvme_known_nvm_effects (opcode);if (effects & ~(NVME_CMD_EFFECTS_CSUPP |NVME_CMD_EFFECTS_LBCC ))dev_warn_once (ctrl->device, -"IO command:%02x has unhandled effects:%08x\n" , +"IO command:%02x has unusual effects:%08x\n" , opcode, effects); -return 0 ; - } -if (ctrl->effects) - effects =le32_to_cpu (ctrl->effects->acs[opcode]); - effects |=nvme_known_admin_effects (opcode); +/* +* NVME_CMD_EFFECTS_CSE_MASK causes a freeze all I/O queues, +* which would deadlock when done on an I/O command. Note that +* We already warn about an unusual effect above. +*/ + effects &= ~NVME_CMD_EFFECTS_CSE_MASK ; + }else { +if (ctrl->effects) + effects =le32_to_cpu (ctrl->effects->acs[opcode]); + effects |=nvme_known_admin_effects (opcode); + }return effects; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 264/290 btrfs: check superblock to ensure the fs was not modified at thaw time
In reply to Greg Kroah-HartmanFrom: Qu Wenruo <[email protected]>
[ Upstream commit a05d3c9153145283ce9c58a1d7a9056fbb85f6a1 ]
[BACKGROUND]
There is an incident report that, one user hibernated the system, with one btrfs on removable device still mounted.
Then by some incident, the btrfs got mounted and modified by another system/OS, then back to the hibernated system.
After resuming from the hibernation, new write happened into the victim btrfs.
Now the fs is completely broken, since the underlying btrfs is no longer the same one before the hibernation, and the user lost their data due to various transid mismatch.
[REPRODUCER]
We can emulate the situation using the following small script:
truncate -s 1G $dev
mkfs.btrfs -f $dev
mount $dev $mnt
fsstress -w -d $mnt -n 500
sync
xfs_freeze -f $mnt
cp $dev $dev.backup
# There is no way to mount the same cloned fs on the same system,
# as the conflicting fsid will be rejected by btrfs. # Thus here we have to wipe the fs using a different btrfs. mkfs.btrfs -f $dev.backup
dd if=$dev.backup of=$dev bs=1M
xfs_freeze -u $mnt
fsstress -w -d $mnt -n 20
umount $mnt
btrfs check $dev
The final fsck will fail due to some tree blocks has incorrect fsid.
This is enough to emulate the problem hit by the unfortunate user.
[ENHANCEMENT]
Although such case should not be that common, it can still happen from time to time.
Quoted 1 line
From the view of btrfs, we can detect any unexpected super block change,
and if there is any unexpected change, we just mark the fs read-only, and thaw the fs.
By this we can limit the damage to minimal, and I hope no one would lose their data by this anymore.
--- fs/btrfs/disk-io.c | 25 ++++++++++++++----- fs/btrfs/disk-io.h | 4 +++- fs/btrfs/super.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/volumes.c | 2 +- 4 files changed, 83 insertions(+), 8 deletions(-)
fs/btrfs/disk-io.c +19 -6
@@ -2491,8 +2491,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)* 1, 2 2nd and 3rd backup copy * -1 skip bytenr check */ -static int validate_super (struct btrfs_fs_info *fs_info, -struct btrfs_super_block *sb,int mirror_num) +int btrfs_validate_super (struct btrfs_fs_info *fs_info, +struct btrfs_super_block *sb,int mirror_num) {u64 nodesize =btrfs_super_nodesize (sb);u64 sectorsize =btrfs_super_sectorsize (sb);
@@ -2675,7 +2675,7 @@ static int validate_super(struct btrfs_fs_info *fs_info,*/ static int btrfs_validate_mount_super (struct btrfs_fs_info *fs_info) { -return validate_super (fs_info, fs_info->super_copy,0 ); +return btrfs_validate_super (fs_info, fs_info->super_copy,0 ); }/*
@@ -2689,7 +2689,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info, {int ret; - ret =validate_super (fs_info, sb,-1 ); + ret =btrfs_validate_super (fs_info, sb,-1 );if (ret <0 ) goto out;if (!btrfs_supported_super_csum (btrfs_super_csum_type (sb))) {
@@ -3703,7 +3703,7 @@ static void btrfs_end_super_write(struct bio *bio) }struct btrfs_super_block *btrfs_read_dev_one_super (struct block_device *bdev, -int copy_num) +int copy_num,bool drop_cache) {struct btrfs_super_block *super;struct page *page;
@@ -3721,6 +3721,19 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev,if (bytenr +BTRFS_SUPER_INFO_SIZE >=i_size_read (bdev->bd_inode))return ERR_PTR (-EINVAL ); +if (drop_cache) { +/* This should only be called with the primary sb. */ +ASSERT (copy_num ==0 ); + +/* +* Drop the page of the primary superblock, so later read will +* always read from the device. +*/ +invalidate_inode_pages2_range (mapping, + bytenr >>PAGE_SHIFT , + (bytenr +BTRFS_SUPER_INFO_SIZE ) >>PAGE_SHIFT ); + } + page =read_cache_page_gfp (mapping, bytenr >>PAGE_SHIFT ,GFP_NOFS );if (IS_ERR (page))return ERR_CAST (page);
@@ -3752,7 +3765,7 @@ struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev)* later supers, using BTRFS_SUPER_MIRROR_MAX instead */ for (i =0 ; i <1 ; i++) { - super =btrfs_read_dev_one_super (bdev, i); + super =btrfs_read_dev_one_super (bdev, i, false);if (IS_ERR (super))continue ;
fs/btrfs/disk-io.h +3 -1
@@ -56,10 +56,12 @@ int __cold open_ctree(struct super_block *sb,struct btrfs_fs_devices *fs_devices, char *options);void __cold close_ctree (struct btrfs_fs_info *fs_info); +int btrfs_validate_super (struct btrfs_fs_info *fs_info, +struct btrfs_super_block *sb,int mirror_num);int write_all_supers (struct btrfs_fs_info *fs_info,int max_mirrors);struct btrfs_super_block *btrfs_read_dev_super (struct block_device *bdev);struct btrfs_super_block *btrfs_read_dev_one_super (struct block_device *bdev, -int copy_num); +int copy_num,bool drop_cache);int btrfs_commit_super (struct btrfs_fs_info *fs_info);struct btrfs_root *btrfs_read_tree_root (struct btrfs_root *tree_root,struct btrfs_key *key);
fs/btrfs/super.c +60 -0
71 lines not on this page · raw message
fs/btrfs/volumes.c +1 -1
@@ -2074,7 +2074,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,struct page *page;int ret; - disk_super =btrfs_read_dev_one_super (bdev, copy_num); + disk_super =btrfs_read_dev_one_super (bdev, copy_num, false);if (IS_ERR (disk_super))continue ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 265/290 x86/kexec: Fix double-free of elf header buffer
In reply to Greg Kroah-HartmanFrom: Takashi Iwai <[email protected]>
commit d00dd2f2645dca04cf399d8fc692f3f69b6dd996 upstream.
After
b3e34a47f989 ("x86/kexec: fix memory leak of elf header buffer"),
freeing image->elf_headers in the error path of crash_load_segments() is not needed because kimage_file_post_load_cleanup() will take care of that later. And not clearing it could result in a double-free.
Drop the superfluous vfree() call at the error path of crash_load_segments().
--- arch/x86/kernel/crash.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/crash.c +1 -3
@@ -401,10 +401,8 @@ int crash_load_segments(struct kimage *i kbuf.buf_align =ELF_CORE_HEADER_ALIGN ; kbuf.mem =KEXEC_BUF_MEM_UNKNOWN ; ret =kexec_add_buffer (&kbuf); -if (ret) { -vfree ((void *)image->elf_headers); +if (ret)return ret; - } image->elf_load_addr = kbuf.mem;pr_debug ("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , image->elf_load_addr, kbuf.bufsz, kbuf.bufsz);
Greg Kroah-Hartman
maintainerPATCH 266/290 x86/bugs: Flush IBP in ib_prctl_set()
In reply to Greg Kroah-HartmanFrom: Rodrigo Branco <[email protected]>
commit a664ec9158eeddd75121d39c9a0758016097fa96 upstream.
We missed the window between the TIF flag update and the next reschedule.
--- arch/x86/kernel/cpu/bugs.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kernel/cpu/bugs.c +2 -0
@@ -1951,6 +1951,8 @@ static int ib_prctl_set(struct task_struif (ctrl ==PR_SPEC_FORCE_DISABLE )task_set_spec_ib_force_disable (task);task_update_spec_tif (task); +if (task == current) +indirect_branch_prediction_barrier ();break ;default :return -ERANGE ;
Greg Kroah-Hartman
maintainerPATCH 267/290 nfsd: fix handling of readdir in v4root vs. mount upcall timeout
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
commit cad853374d85fe678d721512cecfabd7636e51f3 upstream.
If v4 READDIR operation hits a mountpoint and gets back an error, then it will include that entry in the reply and set RDATTR_ERROR for it to the error.
That's fine for "normal" exported filesystems, but on the v4root, we need to be more careful to only expose the existence of dentries that lead to exports.
If the mountd upcall times out while checking to see whether a mountpoint on the v4root is exported, then we have no recourse other than to fail the whole operation.
--- fs/nfsd/nfs4xdr.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/nfsd/nfs4xdr.c +11 -0
@@ -3514,6 +3514,17 @@ nfsd4_encode_dirent(void *ccdv, const chcase nfserr_noent:xdr_truncate_encode (xdr, start_offset); goto skip_entry; +case nfserr_jukebox: +/* +* The pseudoroot should only display dentries that lead to +* exports. If we get EJUKEBOX here, then we can't tell whether +* this entry should be included. Just fail the whole READDIR +* with NFS4ERR_DELAY in that case, and hope that the situation +* will resolve itself by the client's next attempt. +*/ +if (cd->rd_fhp->fh_export->ex_flags &NFSEXP_V4ROOT ) + goto fail; + fallthrough;default :/* * If the client requested the RDATTR_ERROR attribute,
Greg Kroah-Hartman
maintainerPATCH 268/290 fbdev: matroxfb: G200eW: Increase max memory from 1 MB to 16 MB
In reply to Greg Kroah-HartmanFrom: Paul Menzel <[email protected]>
commit f685dd7a8025f2554f73748cfdb8143a21fb92c7 upstream.
Commit 62d89a7d49af ("video: fbdev: matroxfb: set maxvram of vbG200eW to the same as vbG200 to avoid black screen") accidently decreases the maximum memory size for the Matrox G200eW (102b:0532) from 8 MB to 1 MB by missing one zero. This caused the driver initialization to fail with the messages below, as the minimum required VRAM size is 2 MB:
[ 9.436420] matroxfb: Matrox MGA-G200eW (PCI) detected
[ 9.444502] matroxfb: cannot determine memory size
[ 9.449316] matroxfb: probe of 0000:0a:03.0 failed with error -1So, add the missing 0 to make it the intended 16 MB. Successfully tested on the Dell PowerEdge R910/0KYD3D, BIOS 2.10.0 08/29/2013, that the warning is gone.
While at it, add a leading 0 to the maxdisplayable entry, so it’s aligned properly. The value could probably also be increased from 8 MB to 16 MB, as the G200 uses the same values, but I have not checked any datasheet.
Note, matroxfb is obsolete and superseded by the maintained DRM driver mga200, which is used by default on most systems where both drivers are available. Therefore, on most systems it was only a cosmetic issue.
--- drivers/video/fbdev/matrox/matroxfb_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/video/fbdev/matrox/matroxfb_base.c +2 -2
@@ -1377,8 +1377,8 @@ static struct video_board vbG200 = { .lowlevel = &matrox_G100 };static struct video_board vbG200eW = { - .maxvram =0x100000 , - .maxdisplayable =0x800000 , + .maxvram =0x1000000 , + .maxdisplayable =0x0800000 , .accelID =FB_ACCEL_MATROX_MGAG200 , .lowlevel = &matrox_G100 };
Greg Kroah-Hartman
maintainerPATCH 269/290 block: dont allow splitting of a REQ_NOWAIT bio
In reply to Greg Kroah-HartmanFrom: Jens Axboe <[email protected]>
commit 9cea62b2cbabff8ed46f2df17778b624ad9dd25a upstream.
If we split a bio marked with REQ_NOWAIT, then we can trigger spurious EAGAIN if constituent parts of that split bio end up failing request allocations. Parts will complete just fine, but just a single failure in one of the chained bios will yield an EAGAIN final result for the parent bio.
Return EAGAIN early if we end up needing to split such a bio, which allows for saner recovery handling.
--- block/blk-merge.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
block/blk-merge.c +10 -0
@@ -279,6 +279,16 @@ static struct bio *blk_bio_segment_split *segs = nsegs;return NULL ; split: +/* +* We can't sanely support splitting for a REQ_NOWAIT bio. End it +* with EAGAIN if splitting is required and return an error pointer. +*/ +if (bio->bi_opf &REQ_NOWAIT ) { + bio->bi_status =BLK_STS_AGAIN ; +bio_endio (bio); +return ERR_PTR (-EAGAIN ); + } + *segs = nsegs;/*
Greg Kroah-Hartman
maintainerPATCH 270/290 io_uring: fix CQ waiting timeout handling
In reply to Greg Kroah-HartmanFrom: Pavel Begunkov <[email protected]>
commit 12521a5d5cb7ff0ad43eadfc9c135d86e1131fa8 upstream.
Jiffy to ktime CQ waiting conversion broke how we treat timeouts, in particular we rearm it anew every time we get into io_cqring_wait_schedule() without adjusting the timeout. Waiting for 2 CQEs and getting a task_work in the middle may double the timeout value, or even worse in some cases task may wait indefinitely.
--- io_uring/io_uring.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
io_uring/io_uring.c +3 -3
@@ -7598,7 +7598,7 @@ static int io_run_task_work_sig(void)/* when returns >0, the caller should retry */ static inline int io_cqring_wait_schedule (struct io_ring_ctx *ctx,struct io_wait_queue *iowq, -ktime_t timeout) +ktime_t *timeout) {int ret;
@@ -7610,7 +7610,7 @@ static inline int io_cqring_wait_schedulif (test_bit (0 , &ctx->check_cq_overflow))return 1 ; -if (!schedule_hrtimeout (&timeout,HRTIMER_MODE_ABS )) +if (!schedule_hrtimeout (timeout,HRTIMER_MODE_ABS ))return -ETIME ;return 1 ; }
@@ -7673,7 +7673,7 @@ static int io_cqring_wait(struct io_ring }prepare_to_wait_exclusive (&ctx->cq_wait, &iowq.wq,TASK_INTERRUPTIBLE ); - ret =io_cqring_wait_schedule (ctx, &iowq, timeout); + ret =io_cqring_wait_schedule (ctx, &iowq, &timeout);finish_wait (&ctx->cq_wait, &iowq.wq);cond_resched (); }while (ret >0 );
Greg Kroah-Hartman
maintainerPATCH 271/290 thermal: int340x: Add missing attribute for data rate base
In reply to Greg Kroah-HartmanFrom: Srinivas Pandruvada <[email protected]>
commit b878d3ba9bb41cddb73ba4b56e5552f0a638daca upstream.
Commit 473be51142ad ("thermal: int340x: processor_thermal: Add RFIM driver")' added rfi_restriction_data_rate_base string, mmio details and documentation, but missed adding attribute to sysfs.
Add missing sysfs attribute.
--- drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +4 -0
@@ -172,6 +172,7 @@ static const struct attribute_group fivr RFIM_SHOW(rfi_restriction_run_busy, 1) RFIM_SHOW(rfi_restriction_err_code, 1) RFIM_SHOW(rfi_restriction_data_rate, 1) +RFIM_SHOW(rfi_restriction_data_rate_base, 1) RFIM_SHOW(ddr_data_rate_point_0, 1) RFIM_SHOW(ddr_data_rate_point_1, 1)RFIM_SHOW (ddr_data_rate_point_2,1 )
@@ -181,11 +182,13 @@ RFIM_SHOW(rfi_disable, 1) RFIM_STORE(rfi_restriction_run_busy, 1) RFIM_STORE(rfi_restriction_err_code, 1) RFIM_STORE(rfi_restriction_data_rate, 1) +RFIM_STORE(rfi_restriction_data_rate_base, 1) RFIM_STORE(rfi_disable, 1)static DEVICE_ATTR_RW (rfi_restriction_run_busy);static DEVICE_ATTR_RW (rfi_restriction_err_code);static DEVICE_ATTR_RW (rfi_restriction_data_rate); +static DEVICE_ATTR_RW (rfi_restriction_data_rate_base);static DEVICE_ATTR_RO (ddr_data_rate_point_0);static DEVICE_ATTR_RO (ddr_data_rate_point_1);static DEVICE_ATTR_RO (ddr_data_rate_point_2);
@@ -248,6 +251,7 @@ static struct attribute *dvfs_attrs[] = &dev_attr_rfi_restriction_run_busy.attr, &dev_attr_rfi_restriction_err_code.attr, &dev_attr_rfi_restriction_data_rate.attr, + &dev_attr_rfi_restriction_data_rate_base.attr, &dev_attr_ddr_data_rate_point_0.attr, &dev_attr_ddr_data_rate_point_1.attr, &dev_attr_ddr_data_rate_point_2.attr,
Greg Kroah-Hartman
maintainerPATCH 272/290 riscv: uaccess: fix type of 0 variable on error in get_user()
In reply to Greg Kroah-HartmanFrom: Ben Dooks <[email protected]>
commit b9b916aee6715cd7f3318af6dc360c4729417b94 upstream.
If the get_user(x, ptr) has x as a pointer, then the setting of (x) = 0 is going to produce the following sparse warning, so fix this by forcing the type of 'x' when access_ok() fails.
fs/aio.c:2073:21: warning: Using plain integer as NULL pointer
--- arch/riscv/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/include/asm/uaccess.h +1 -1
@@ -216,7 +216,7 @@ do { \might_fault (); \access_ok (__p,sizeof (*__p)) ? \__get_user ((x), __p) : \ - ((x) =0 , -EFAULT ); \ + ((x) = (__force __typeof__(x))0, -EFAULT); \ })#define __put_user_asm (insn, x, ptr, err) \
Greg Kroah-Hartman
maintainerPATCH 273/290 riscv, kprobes: Stricter c.jr/c.jalr decoding
In reply to Greg Kroah-HartmanFrom: Björn Töpel <[email protected]>
commit b2d473a6019ef9a54b0156ecdb2e0398c9fa6a24 upstream.
In the compressed instruction extension, c.jr, c.jalr, c.mv, and c.add is encoded the following way (each instruction is 16b):
---+-+-----------+-----------+--
100 0 rs1[4:0]!=0 00000 10 : c.jr
100 1 rs1[4:0]!=0 00000 10 : c.jalr
100 0 rd[4:0]!=0 rs2[4:0]!=0 10 : c.mv
100 1 rd[4:0]!=0 rs2[4:0]!=0 10 : c.add
The following logic is used to decode c.jr and c.jalr:
insn & 0xf007 == 0x8002 => instruction is an c.jr insn & 0xf007 == 0x9002 => instruction is an c.jalr
When 0xf007 is used to mask the instruction, c.mv can be incorrectly decoded as c.jr, and c.add as c.jalr.
Correct the decoding by changing the mask from 0xf007 to 0xf07f.
--- arch/riscv/kernel/probes/simulate-insn.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/kernel/probes/simulate-insn.h +2 -2
@@ -31,9 +31,9 @@ __RISCV_INSN_FUNCS(fence, 0x7f, 0x0f); }while (0 )__RISCV_INSN_FUNCS (c_j,0xe003 ,0xa001 ); -__RISCV_INSN_FUNCS (c_jr,0xf007 ,0x8002 ); +__RISCV_INSN_FUNCS (c_jr,0xf07f ,0x8002 );__RISCV_INSN_FUNCS (c_jal,0xe003 ,0x2001 ); -__RISCV_INSN_FUNCS (c_jalr,0xf007 ,0x9002 ); +__RISCV_INSN_FUNCS (c_jalr,0xf07f ,0x9002 );__RISCV_INSN_FUNCS (c_beqz,0xe003 ,0xc001 );__RISCV_INSN_FUNCS (c_bnez,0xe003 ,0xe001 );__RISCV_INSN_FUNCS (c_ebreak,0xffff ,0x9002 );
Greg Kroah-Hartman
maintainerPATCH 274/290 drm/i915/gvt: fix gvt debugfs destroy
In reply to Greg Kroah-HartmanFrom: Zhenyu Wang <[email protected]>
commit c4b850d1f448a901fbf4f7f36dec38c84009b489 upstream.
When gvt debug fs is destroyed, need to have a sane check if drm minor's debugfs root is still available or not, otherwise in case like device remove through unbinding, drm minor's debugfs directory has already been removed, then intel_gvt_debugfs_clean() would act upon dangling pointer like below oops.
i915 0000:00:02.0: Direct firmware load for i915/gvt/vid_0x8086_did_0x1926_rid_0x0a.golden_hw_state failed with error -2 i915 0000:00:02.0: MDEV: Registered
Console: switching to colour dummy device 80x25
i915 0000:00:02.0: MDEV: Unregistering
BUG: kernel NULL pointer dereference, address: 00000000000000a0 PGD 0 P4D 0 Oops: 0002 [#1] PREEMPT SMP PTI CPU: 2 PID: 2486 Comm: gfx-unbind.sh Tainted: G I 6.1.0-rc8+ #15 Hardware name: Dell Inc. XPS 13 9350/0JXC1H, BIOS 1.13.0 02/10/2020 RIP: 0010:down_write+0x1f/0x90 Code: 1d ff ff 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 53 48 89 fb e8 62 c0 ff ff bf 01 00 00 00 e8 28 5e 31 ff 31 c0 ba 01 00 00 00 <f0> 48 0f b1 13 75 33 65 48 8b 04 25 c0 bd 01 00 48 89 43 08 bf 01 RSP: 0018:ffff9eb3036ffcc8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 00000000000000a0 RCX: ffffff8100000000 RDX: 0000000000000001 RSI: 0000000000000064 RDI: ffffffffa48787a8 RBP: ffff9eb3036ffd30 R08: ffffeb1fc45a0608 R09: ffffeb1fc45a05c0 R10: 0000000000000002 R11: 0000000000000000 R12: 0000000000000000 R13: ffff91acc33fa328 R14: ffff91acc033f080 R15: ffff91acced533e0 FS: 00007f6947bba740(0000) GS:ffff91ae36d00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000000000a0 CR3: 00000001133a2002 CR4: 00000000003706e0 Call Trace: <TASK> simple_recursive_removal+0x9f/0x2a0 ? start_creating.part.0+0x120/0x120 ? _raw_spin_lock+0x13/0x40 debugfs_remove+0x40/0x60 intel_gvt_debugfs_clean+0x15/0x30 [kvmgt] intel_gvt_clean_device+0x49/0xe0 [kvmgt] intel_gvt_driver_remove+0x2f/0xb0 i915_driver_remove+0xa4/0xf0 i915_pci_remove+0x1a/0x30 pci_device_remove+0x33/0xa0 device_release_driver_internal+0x1b2/0x230 unbind_store+0xe0/0x110 kernfs_fop_write_iter+0x11b/0x1f0 vfs_write+0x203/0x3d0 ksys_write+0x63/0xe0 do_syscall_64+0x37/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f6947cb5190 Code: 40 00 48 8b 15 71 9c 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 80 3d 51 24 0e 00 00 74 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89 RSP: 002b:00007ffcbac45a28 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 000000000000000d RCX: 00007f6947cb5190 RDX: 000000000000000d RSI: 0000555e35c866a0 RDI: 0000000000000001 RBP: 0000555e35c866a0 R08: 0000000000000002 R09: 0000555e358cb97c R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000001 R13: 000000000000000d R14: 0000000000000000 R15: 0000555e358cb8e0 </TASK> Modules linked in: kvmgt CR2: 00000000000000a0 ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/i915/gvt/debugfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/gvt/debugfs.c +6 -2
@@ -199,6 +199,10 @@ void intel_gvt_debugfs_init(struct intel*/ void intel_gvt_debugfs_clean (struct intel_gvt *gvt) { -debugfs_remove_recursive (gvt->debugfs_root); - gvt->debugfs_root =NULL ; +struct drm_minor *minor = gvt->gt->i915->drm.primary; + +if (minor->debugfs_root) { +debugfs_remove_recursive (gvt->debugfs_root); + gvt->debugfs_root =NULL ; + } }
Greg Kroah-Hartman
maintainerPATCH 275/290 drm/i915/gvt: fix vgpu debugfs clean in remove
In reply to Greg Kroah-HartmanFrom: Zhenyu Wang <[email protected]>
commit 704f3384f322b40ba24d958473edfb1c9750c8fd upstream.
Check carefully on root debugfs available when destroying vgpu, e.g in remove case drm minor's debugfs root might already be destroyed, which led to kernel oops like below.
Console: switching to colour dummy device 80x25
i915 0000:00:02.0: MDEV: Unregisteringintel_vgpu_mdev b1338b2d-a709-4c23-b766-cc436c36cdf0: Removing from iommu group 14
BUG: kernel NULL pointer dereference, address: 0000000000000150 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP CPU: 3 PID: 1046 Comm: driverctl Not tainted 6.1.0-rc2+ #6 Hardware name: HP HP ProDesk 600 G3 MT/829D, BIOS P02 Ver. 02.44 09/13/2022 RIP: 0010:__lock_acquire+0x5e2/0x1f90 Code: 87 ad 09 00 00 39 05 e1 1e cc 02 0f 82 f1 09 00 00 ba 01 00 00 00 48 83 c4 48 89 d0 5b 5d 41 5c 41 5d 41 5e 41 5f c3 45 31 ff <48> 81 3f 60 9e c2 b6 45 0f 45 f8 83 fe 01 0f 87 55 fa ff ff 89 f0 RSP: 0018:ffff9f770274f948 EFLAGS: 00010046 RAX: 0000000000000003 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000150 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 R10: ffff8895d1173300 R11: 0000000000000001 R12: 0000000000000000 R13: 0000000000000150 R14: 0000000000000000 R15: 0000000000000000 FS: 00007fc9b2ba0740(0000) GS:ffff889cdfcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000150 CR3: 000000010fd93005 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> lock_acquire+0xbf/0x2b0 ? simple_recursive_removal+0xa5/0x2b0 ? lock_release+0x13d/0x2d0 down_write+0x2a/0xd0 ? simple_recursive_removal+0xa5/0x2b0 simple_recursive_removal+0xa5/0x2b0 ? start_creating.part.0+0x110/0x110 ? _raw_spin_unlock+0x29/0x40 debugfs_remove+0x40/0x60 intel_gvt_debugfs_remove_vgpu+0x15/0x30 [kvmgt] intel_gvt_destroy_vgpu+0x60/0x100 [kvmgt] intel_vgpu_release_dev+0xe/0x20 [kvmgt] device_release+0x30/0x80 kobject_put+0x79/0x1b0 device_release_driver_internal+0x1b8/0x230 bus_remove_device+0xec/0x160 device_del+0x189/0x400 ? up_write+0x9c/0x1b0 ? mdev_device_remove_common+0x60/0x60 [mdev] mdev_device_remove_common+0x22/0x60 [mdev] mdev_device_remove_cb+0x17/0x20 [mdev] device_for_each_child+0x56/0x80 mdev_unregister_parent+0x5a/0x81 [mdev] intel_gvt_clean_device+0x2d/0xe0 [kvmgt] intel_gvt_driver_remove+0x2e/0xb0 [i915] i915_driver_remove+0xac/0x100 [i915] i915_pci_remove+0x1a/0x30 [i915] pci_device_remove+0x31/0xa0 device_release_driver_internal+0x1b8/0x230 unbind_store+0xd8/0x100 kernfs_fop_write_iter+0x156/0x210 vfs_write+0x236/0x4a0 ksys_write+0x61/0xd0 do_syscall_64+0x55/0x80 ? find_held_lock+0x2b/0x80 ? lock_release+0x13d/0x2d0 ? up_read+0x17/0x20 ? lock_is_held_type+0xe3/0x140 ? asm_exc_page_fault+0x22/0x30 ? lockdep_hardirqs_on+0x7d/0x100 entry_SYSCALL_64_after_hwframe+0x46/0xb0 RIP: 0033:0x7fc9b2c9e0c4 Code: 15 71 7d 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 80 3d 3d 05 0e 00 00 74 13 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 48 83 ec 28 48 89 54 24 18 48 RSP: 002b:00007ffec29c81c8 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 000000000000000d RCX: 00007fc9b2c9e0c4 RDX: 000000000000000d RSI: 0000559f8b5f48a0 RDI: 0000000000000001 RBP: 0000559f8b5f48a0 R08: 0000559f8b5f3540 R09: 00007fc9b2d76d30 R10: 0000000000000000 R11: 0000000000000202 R12: 000000000000000d R13: 00007fc9b2d77780 R14: 000000000000000d R15: 00007fc9b2d72a00 </TASK> Modules linked in: sunrpc intel_rapl_msr intel_rapl_common intel_pmc_core_pltdrv intel_pmc_core intel_tcc_cooling x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel ee1004 igbvf rapl vfat fat intel_cstate intel_uncore pktcdvd i2c_i801 pcspkr wmi_bmof i2c_smbus acpi_pad vfio_pci vfio_pci_core vfio_virqfd zram fuse dm_multipath kvmgt mdev vfio_iommu_type1 vfio kvm irqbypass i915 nvme e1000e igb nvme_core crct10dif_pclmul crc32_pclmul crc32c_intel polyval_clmulni polyval_generic serio_raw ghash_clmulni_intel sha512_ssse3 dca drm_buddy intel_gtt video wmi drm_display_helper ttm CR2: 0000000000000150 ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/i915/gvt/debugfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/gvt/debugfs.c +7 -2
@@ -175,8 +175,13 @@ void intel_gvt_debugfs_add_vgpu(struct i*/ void intel_gvt_debugfs_remove_vgpu (struct intel_vgpu *vgpu) { -debugfs_remove_recursive (vgpu->debugfs); - vgpu->debugfs =NULL ; +struct intel_gvt *gvt = vgpu->gvt; +struct drm_minor *minor = gvt->gt->i915->drm.primary; + +if (minor->debugfs_root && gvt->debugfs_root) { +debugfs_remove_recursive (vgpu->debugfs); + vgpu->debugfs =NULL ; + } }/**
Greg Kroah-Hartman
maintainerPATCH 276/290 hfs/hfsplus: use WARN_ON for sanity check
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
commit 55d1cbbbb29e6656c662ee8f73ba1fc4777532eb upstream.
gcc warns about a couple of instances in which a sanity check exists but the author wasn't sure how to react to it failing, which makes it look like a possible bug:
fs/hfsplus/inode.c: In function 'hfsplus_cat_read_inode':
fs/hfsplus/inode.c:503:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
503 | /* panic? */;
| ^
fs/hfsplus/inode.c:524:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
524 | /* panic? */;
| ^
fs/hfsplus/inode.c: In function 'hfsplus_cat_write_inode':
fs/hfsplus/inode.c:582:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
582 | /* panic? */;
| ^
fs/hfsplus/inode.c:608:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
608 | /* panic? */;
| ^
fs/hfs/inode.c: In function 'hfs_write_inode':
fs/hfs/inode.c:464:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
464 | /* panic? */;
| ^
fs/hfs/inode.c:485:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body]
485 | /* panic? */;
| ^panic() is probably not the correct choice here, but a WARN_ON seems appropriate and avoids the compile-time warning.
--- fs/hfs/inode.c | 6 ++---- fs/hfsplus/inode.c | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-)
fs/hfs/inode.c +2 -4
@@ -464,8 +464,7 @@ int hfs_write_inode(struct inode *inode, goto out;if (S_ISDIR (main_inode->i_mode)) { -if (fd.entrylength <sizeof (struct hfs_cat_dir )) -/* panic? */ ; +WARN_ON (fd.entrylength <sizeof (struct hfs_cat_dir ));hfs_bnode_read (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_dir )); if (rec.type != HFS_CDR_DIR ||
@@ -485,8 +484,7 @@ int hfs_write_inode(struct inode *inode,hfs_bnode_write (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); }else { -if (fd.entrylength <sizeof (struct hfs_cat_file )) -/* panic? */ ; +WARN_ON (fd.entrylength <sizeof (struct hfs_cat_file ));hfs_bnode_read (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); if (rec.type != HFS_CDR_FIL ||
fs/hfsplus/inode.c +4 -8
@@ -509,8 +509,7 @@ int hfsplus_cat_read_inode(struct inodeif (type ==HFSPLUS_FOLDER ) {struct hfsplus_cat_folder *folder = &entry.folder; -if (fd->entrylength <sizeof (struct hfsplus_cat_folder )) -/* panic? */ ; +WARN_ON (fd->entrylength <sizeof (struct hfsplus_cat_folder ));hfs_bnode_read (fd->bnode, &entry, fd->entryoffset,sizeof (struct hfsplus_cat_folder ));hfsplus_get_perms (inode, &folder->permissions,1 );
@@ -530,8 +529,7 @@ int hfsplus_cat_read_inode(struct inode }else if (type ==HFSPLUS_FILE ) {struct hfsplus_cat_file *file = &entry.file; -if (fd->entrylength <sizeof (struct hfsplus_cat_file )) -/* panic? */ ; +WARN_ON (fd->entrylength <sizeof (struct hfsplus_cat_file ));hfs_bnode_read (fd->bnode, &entry, fd->entryoffset,sizeof (struct hfsplus_cat_file ));
@@ -588,8 +586,7 @@ int hfsplus_cat_write_inode(struct inodeif (S_ISDIR (main_inode->i_mode)) {struct hfsplus_cat_folder *folder = &entry.folder; -if (fd.entrylength <sizeof (struct hfsplus_cat_folder )) -/* panic? */ ; +WARN_ON (fd.entrylength <sizeof (struct hfsplus_cat_folder ));hfs_bnode_read (fd.bnode, &entry, fd.entryoffset,sizeof (struct hfsplus_cat_folder ));/* simple node checks? */
@@ -614,8 +611,7 @@ int hfsplus_cat_write_inode(struct inode }else {struct hfsplus_cat_file *file = &entry.file; -if (fd.entrylength <sizeof (struct hfsplus_cat_file )) -/* panic? */ ; +WARN_ON (fd.entrylength <sizeof (struct hfsplus_cat_file ));hfs_bnode_read (fd.bnode, &entry, fd.entryoffset,sizeof (struct hfsplus_cat_file ));hfsplus_inode_write_fork (inode, &file->data_fork);
Greg Kroah-Hartman
maintainerPATCH 277/290 hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
In reply to Greg Kroah-HartmanFrom: Linus Torvalds <[email protected]>
commit cb7a95af78d29442b8294683eca4897544b8ef46 upstream.
Commit 55d1cbbbb29e ("hfs/hfsplus: use WARN_ON for sanity check") fixed a build warning by turning a comment into a WARN_ON(), but it turns out that syzbot then complains because it can trigger said warning with a corrupted hfs image.
The warning actually does warn about a bad situation, but we are much better off just handling it as the error it is. So rather than warn about us doing bad things, stop doing the bad things and return -EIO.
While at it, also fix a memory leak that was introduced by an earlier fix for a similar syzbot warning situation, and add a check for one case that historically wasn't handled at all (ie neither comment nor subsequent WARN_ON).
--- fs/hfs/inode.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
fs/hfs/inode.c +10 -5
@@ -456,15 +456,16 @@ int hfs_write_inode(struct inode *inode,/* panic? */ return -EIO ; + res = -EIO ;if (HFS_I (main_inode)->cat_key.CName.len >HFS_NAMELEN ) -return -EIO ; + goto out; fd.search_key->cat =HFS_I (main_inode)->cat_key;if (hfs_brec_find (&fd)) -/* panic? */ goto out;if (S_ISDIR (main_inode->i_mode)) { -WARN_ON (fd.entrylength <sizeof (struct hfs_cat_dir )); +if (fd.entrylength <sizeof (struct hfs_cat_dir )) + goto out;hfs_bnode_read (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_dir )); if (rec.type != HFS_CDR_DIR ||
@@ -477,6 +478,8 @@ int hfs_write_inode(struct inode *inode,hfs_bnode_write (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_dir )); }else if (HFS_IS_RSRC (inode)) { +if (fd.entrylength <sizeof (struct hfs_cat_file )) + goto out;hfs_bnode_read (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); hfs_inode_write_fork(inode, rec.file.RExtRec,
@@ -484,7 +487,8 @@ int hfs_write_inode(struct inode *inode,hfs_bnode_write (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); }else { -WARN_ON (fd.entrylength <sizeof (struct hfs_cat_file )); +if (fd.entrylength <sizeof (struct hfs_cat_file )) + goto out;hfs_bnode_read (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); if (rec.type != HFS_CDR_FIL ||
@@ -501,9 +505,10 @@ int hfs_write_inode(struct inode *inode,hfs_bnode_write (fd.bnode, &rec, fd.entryoffset,sizeof (struct hfs_cat_file )); } + res =0 ; out:hfs_find_exit (&fd); -return 0 ; +return res; } static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
Greg Kroah-Hartman
maintainerPATCH 278/290 ksmbd: fix infinite loop in ksmbd_conn_handler_loop()
In reply to Greg Kroah-HartmanFrom: Namjae Jeon <[email protected]>
commit 83dcedd5540d4ac61376ddff5362f7d9f866a6ec upstream.
If kernel_recvmsg() return -EAGAIN in ksmbd_tcp_readv() and go round again, It will cause infinite loop issue. And all threads from next connections would be doing that. This patch add max retry count(2) to avoid it. kernel_recvmsg() will wait during 7sec timeout and try to retry two time if -EAGAIN is returned. And add flags of kvmalloc to __GFP_NOWARN and __GFP_NORETRY to disconnect immediately without retrying on memory alloation failure.
--- fs/ksmbd/connection.c | 7 +++++-- fs/ksmbd/transport_tcp.c | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-)
fs/ksmbd/connection.c +5 -2
@@ -310,9 +310,12 @@ int ksmbd_conn_handler_loop(void *p)/* 4 for rfc1002 length field */ size = pdu_size +4 ; - conn->request_buf =kvmalloc (size,GFP_KERNEL ); + conn->request_buf =kvmalloc (size, +GFP_KERNEL | + __GFP_NOWARN | + __GFP_NORETRY);if (!conn->request_buf) -continue ; +break ;memcpy (conn->request_buf, hdr_buf,sizeof (hdr_buf));if (!ksmbd_smb_request (conn))
fs/ksmbd/transport_tcp.c +4 -1
@@ -295,6 +295,7 @@ static int ksmbd_tcp_readv(struct tcp_trstruct msghdr ksmbd_msg;struct kvec *iov;struct ksmbd_conn *conn =KSMBD_TRANS (t)->conn; +int max_retry =2 ; iov =get_conn_iovec (t, nr_segs);if (!iov)
@@ -321,9 +322,11 @@ static int ksmbd_tcp_readv(struct tcp_tr }else if (conn->status ==KSMBD_SESS_NEED_RECONNECT ) { total_read = -EAGAIN ;break ; - }else if (length == -ERESTARTSYS || length == -EAGAIN ) { + }else if ((length == -ERESTARTSYS || length == -EAGAIN ) && + max_retry) {usleep_range (1000 ,2000 ); length =0 ; + max_retry--;continue ; }else if (length <=0 ) { total_read = -EAGAIN ;
Greg Kroah-Hartman
maintainerPATCH 279/290 ksmbd: check nt_len to be at least CIFS_ENCPWD_SIZE in ksmbd_decode_ntlmssp_auth_blob
In reply to Greg Kroah-HartmanFrom: William Liu <[email protected]>
commit 797805d81baa814f76cf7bdab35f86408a79d707 upstream.
"nt_len - CIFS_ENCPWD_SIZE" is passed directly from ksmbd_decode_ntlmssp_auth_blob to ksmbd_auth_ntlmv2. Malicious requests can set nt_len to less than CIFS_ENCPWD_SIZE, which results in a negative number (or large unsigned value) used for a subsequent memcpy in ksmbd_auth_ntlvm2 and can cause a panic.
--- fs/ksmbd/auth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ksmbd/auth.c +2 -1
@@ -319,7 +319,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struc dn_off =le32_to_cpu (authblob->DomainName.BufferOffset); dn_len =le16_to_cpu (authblob->DomainName.Length); -if (blob_len < (u64 )dn_off + dn_len || blob_len < (u64 )nt_off + nt_len) +if (blob_len < (u64 )dn_off + dn_len || blob_len < (u64 )nt_off + nt_len || + nt_len <CIFS_ENCPWD_SIZE )return -EINVAL ;/* TODO : use domain name that imported from configuration file */
Greg Kroah-Hartman
maintainerPATCH 280/290 Revert "ACPI: PM: Add support for upcoming AMD uPEP HID AMDI007"
In reply to Greg Kroah-HartmanFrom: Mario Limonciello <[email protected]>
A number of AMD based Rembrandt laptops are not working properly in suspend/resume. This has been root caused to be from the BIOS implementation not populating code for the AMD GUID in uPEP, but instead only the Microsoft one.
In later kernels this has been fixed by using the Microsoft GUID instead.
The following series of patches has fixed it in newer kernels:
commit ed470febf837 ("ACPI: PM: s2idle: Add support for upcoming AMD uPEP HID AMDI008") commit 1a2dcab517cb ("ACPI: PM: s2idle: Use LPS0 idle if ACPI_FADT_LOW_POWER_S0 is unset") commit 100a57379380 ("ACPI: x86: s2idle: Move _HID handling for AMD systems into structures") commit fd894f05cf30 ("ACPI: x86: s2idle: If a new AMD _HID is missing assume Rembrandt") commit a0bc002393d4 ("ACPI: x86: s2idle: Add module parameter to prefer Microsoft GUID") commit d0f61e89f08d ("ACPI: x86: s2idle: Add a quirk for ASUS TUF Gaming A17 FA707RE") commit ddeea2c3cb88 ("ACPI: x86: s2idle: Add a quirk for ASUS ROG Zephyrus G14") commit 888ca9c7955e ("ACPI: x86: s2idle: Add a quirk for Lenovo Slim 7 Pro 14ARH7") commit 631b54519e8e ("ACPI: x86: s2idle: Add a quirk for ASUSTeK COMPUTER INC. ROG Flow X13") commit 39f81776c680 ("ACPI: x86: s2idle: Fix a NULL pointer dereference") commit 54bd1e548701 ("ACPI: x86: s2idle: Add another ID to s2idle_dmi_table") commit 577821f756cf ("ACPI: x86: s2idle: Force AMD GUID/_REV 2 on HP Elitebook 865") commit e6d180a35bc0 ("ACPI: x86: s2idle: Stop using AMD specific codepath for Rembrandt+")
This is needlessly complex for 5.15.y though. To accomplish the same effective result revert commit f0c6225531e4 ("ACPI: PM: Add support for upcoming AMD uPEP HID AMDI007") instead.
--- drivers/acpi/x86/s2idle.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/acpi/x86/s2idle.c +2 -8
@@ -378,16 +378,13 @@ static int lps0_device_attach(struct acp* AMDI0006: * - should use rev_id 0x0 * - function mask = 0x3: Should use Microsoft method -* AMDI0007: -* - Should use rev_id 0x2 -* - Should only use AMD method */ const char *hid =acpi_device_hid (adev); - rev_id =strcmp (hid,"AMDI0007" ) ?0 :2 ; + rev_id =0 ; lps0_dsm_func_mask =validate_dsm (adev->handle,ACPI_LPS0_DSM_UUID_AMD , rev_id, &lps0_dsm_guid); lps0_dsm_func_mask_microsoft =validate_dsm (adev->handle, -ACPI_LPS0_DSM_UUID_MICROSOFT ,0 , +ACPI_LPS0_DSM_UUID_MICROSOFT , rev_id, &lps0_dsm_guid_microsoft); if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") || !strcmp(hid, "AMD0005") ||
@@ -395,9 +392,6 @@ static int lps0_device_attach(struct acp lps0_dsm_func_mask = (lps0_dsm_func_mask <<1 ) |0x1 ;acpi_handle_debug (adev->handle,"_DSM UUID %s: Adjusted function mask: 0x%x\n" ,ACPI_LPS0_DSM_UUID_AMD , lps0_dsm_func_mask); - }else if (lps0_dsm_func_mask_microsoft >0 && !strcmp (hid,"AMDI0007" )) { - lps0_dsm_func_mask_microsoft = -EINVAL ; -acpi_handle_debug (adev->handle,"_DSM Using AMD method\n" ); } }else { rev_id =1 ;
Greg Kroah-Hartman
maintainerPATCH 281/290 mptcp: dedicated request sock for subflow in v6
In reply to Greg Kroah-HartmanFrom: Matthieu Baerts <[email protected]>
commit 34b21d1ddc8ace77a8fa35c1b1e06377209e0dae upstream.
tcp_request_sock_ops structure is specific to IPv4. It should then not be used with MPTCP subflows on top of IPv6.
For example, it contains the 'family' field, initialised to AF_INET. This 'family' field is used by TCP FastOpen code to generate the cookie but also by TCP Metrics, SELinux and SYN Cookies. Using the wrong family will not lead to crashes but displaying/using/checking wrong things.
Note that 'send_reset' callback from request_sock_ops structure is used in some error paths. It is then also important to use the correct one for IPv4 or IPv6.
The slab name can also be different in IPv4 and IPv6, it will be used when printing some log messages. The slab pointer will anyway be the same because the object size is the same for both v4 and v6. A BUILD_BUG_ON() has also been added to make sure this size is the same.
--- net/mptcp/subflow.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-)
net/mptcp/subflow.c +26 -8
@@ -483,7 +483,7 @@ do_reset:mptcp_subflow_reset (sk); } -static struct request_sock_ops mptcp_subflow_request_sock_ops__ro_after_init ; +static struct request_sock_ops mptcp_subflow_v4_request_sock_ops__ro_after_init ;static struct tcp_request_sock_ops subflow_request_sock_ipv4_ops__ro_after_init ;static int subflow_v4_conn_request (struct sock *sk,struct sk_buff *skb)
@@ -496,7 +496,7 @@ static int subflow_v4_conn_request(strucif (skb_rtable (skb)->rt_flags & (RTCF_BROADCAST |RTCF_MULTICAST )) goto drop; -return tcp_conn_request (&mptcp_subflow_request_sock_ops, +return tcp_conn_request (&mptcp_subflow_v4_request_sock_ops, &subflow_request_sock_ipv4_ops, sk, skb); drop:
@@ -505,6 +505,7 @@ drop: }#if IS_ENABLED (CONFIG_MPTCP_IPV6 ) +static struct request_sock_ops mptcp_subflow_v6_request_sock_ops__ro_after_init ;static struct tcp_request_sock_ops subflow_request_sock_ipv6_ops__ro_after_init ;static struct inet_connection_sock_af_ops subflow_v6_specific__ro_after_init ;static struct inet_connection_sock_af_ops subflow_v6m_specific__ro_after_init ;
@@ -527,7 +528,7 @@ static int subflow_v6_conn_request(strucreturn 0 ; } -return tcp_conn_request (&mptcp_subflow_request_sock_ops, +return tcp_conn_request (&mptcp_subflow_v6_request_sock_ops, &subflow_request_sock_ipv6_ops, sk, skb); drop:
@@ -540,7 +541,12 @@ struct request_sock *mptcp_subflow_reqsk struct sock *sk_listener, bool attach_listener) { - ops = &mptcp_subflow_request_sock_ops; +if (ops->family ==AF_INET ) + ops = &mptcp_subflow_v4_request_sock_ops; +#if IS_ENABLED (CONFIG_MPTCP_IPV6 ) + else if (ops->family == AF_INET6) + ops = &mptcp_subflow_v6_request_sock_ops; +#endif return inet_reqsk_alloc (ops, sk_listener, attach_listener); }
@@ -1791,7 +1797,6 @@ static struct tcp_ulp_ops subflow_ulp_opstatic int subflow_ops_init (struct request_sock_ops *subflow_ops) { subflow_ops->obj_size =sizeof (struct mptcp_subflow_request_sock ); - subflow_ops->slab_name ="request_sock_subflow" ; subflow_ops->slab = kmem_cache_create(subflow_ops->slab_name, subflow_ops->obj_size, 0,
@@ -1808,9 +1813,10 @@ static int subflow_ops_init(struct requevoid __init mptcp_subflow_init (void ) { - mptcp_subflow_request_sock_ops = tcp_request_sock_ops; -if (subflow_ops_init (&mptcp_subflow_request_sock_ops) !=0 ) -panic ("MPTCP: failed to init subflow request sock ops\n" ); + mptcp_subflow_v4_request_sock_ops = tcp_request_sock_ops; + mptcp_subflow_v4_request_sock_ops.slab_name ="request_sock_subflow_v4" ; +if (subflow_ops_init (&mptcp_subflow_v4_request_sock_ops) !=0 ) +panic ("MPTCP: failed to init subflow v4 request sock ops\n" ); subflow_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; subflow_request_sock_ipv4_ops.route_req = subflow_v4_route_req;
@@ -1824,6 +1830,18 @@ void __init mptcp_subflow_init(void) tcp_prot_override.release_cb = tcp_release_cb_override;#if IS_ENABLED (CONFIG_MPTCP_IPV6 ) +/* In struct mptcp_subflow_request_sock, we assume the TCP request sock +* structures for v4 and v6 have the same size. It should not changed in +* the future but better to make sure to be warned if it is no longer +* the case. +*/ +BUILD_BUG_ON (sizeof (struct tcp_request_sock ) !=sizeof (struct tcp6_request_sock )); + + mptcp_subflow_v6_request_sock_ops = tcp6_request_sock_ops; + mptcp_subflow_v6_request_sock_ops.slab_name ="request_sock_subflow_v6" ; +if (subflow_ops_init (&mptcp_subflow_v6_request_sock_ops) !=0 ) +panic ("MPTCP: failed to init subflow v6 request sock ops\n" ); + subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; subflow_request_sock_ipv6_ops.route_req = subflow_v6_route_req;