6.0.3-rc1 review
Subsystems (10)
Greg Kroah-Hartman
maintainerPATCH 117/862 fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE
In reply to Greg Kroah-HartmanFrom: Lukas Czerner <[email protected]>
commit cbfecb927f429a6fa613d74b998496bd71e4438a upstream.
Currently the I_DIRTY_TIME will never get set if the inode already has I_DIRTY_INODE with assumption that it supersedes I_DIRTY_TIME. That's true, however ext4 will only update the on-disk inode in ->dirty_inode(), not on actual writeback. As a result if the inode already has I_DIRTY_INODE state by the time we get to __mark_inode_dirty() only with I_DIRTY_TIME, the time was already filled into on-disk inode and will not get updated until the next I_DIRTY_INODE update, which might never come if we crash or get a power failure.
The problem can be reproduced on ext4 by running xfstest generic/622 with -o iversion mount option.
Fix it by allowing I_DIRTY_TIME to be set even if the inode already has I_DIRTY_INODE. Also make sure that the case is properly handled in writeback_single_inode() as well. Additionally changes in xfs_fs_dirty_inode() was made to accommodate for I_DIRTY_TIME in flag.
Thanks Jan Kara for suggestions on how to make this work properly.
--- Documentation/filesystems/vfs.rst | 3 +++ fs/fs-writeback.c | 37 +++++++++++++++++++++++++------------ fs/xfs/xfs_super.c | 10 ++++++++-- include/linux/fs.h | 9 +++++---- 4 files changed, 41 insertions(+), 18 deletions(-)
Documentation/filesystems/vfs.rst +3 -0
@@ -274,6 +274,9 @@ or bottom half). This is specifically for the inode itself being marked dirty, not its data. If the update needs to be persisted by fdatasync(), then I_DIRTY_DATASYNC will be set in the flags argument. + I_DIRTY_TIME will be set in the flags in case lazytime is enabled + and struct inode has times updated since the last ->dirty_inode + call. ``write_inode`` this method is called when the VFS needs to write an inode to
fs/fs-writeback.c +25 -12
@@ -1718,9 +1718,14 @@ static int writeback_single_inode(struct*/ if (!(inode->i_state &I_DIRTY_ALL ))inode_cgwb_move_to_attached (inode, wb); -else if (!(inode->i_state &I_SYNC_QUEUED ) && - (inode->i_state &I_DIRTY )) -redirty_tail_locked (inode, wb); +else if (!(inode->i_state &I_SYNC_QUEUED )) { +if ((inode->i_state &I_DIRTY )) +redirty_tail_locked (inode, wb); +else if (inode->i_state &I_DIRTY_TIME ) { + inode->dirtied_when = jiffies; +inode_io_list_move_locked (inode, wb, &wb->b_dirty_time); + } + }spin_unlock (&wb->list_lock);inode_sync_complete (inode);
@@ -2370,6 +2375,20 @@ void __mark_inode_dirty(struct inode *inif (flags &I_DIRTY_INODE ) {/* +* Inode timestamp update will piggback on this dirtying. +* We tell ->dirty_inode callback that timestamps need to +* be updated by setting I_DIRTY_TIME in flags. +*/ +if (inode->i_state &I_DIRTY_TIME ) { +spin_lock (&inode->i_lock); +if (inode->i_state &I_DIRTY_TIME ) { + inode->i_state &= ~I_DIRTY_TIME ; + flags |=I_DIRTY_TIME ; + } +spin_unlock (&inode->i_lock); + } + +/* * Notify the filesystem about the inode being dirtied, so that * (if needed) it can update on-disk fields and journal the * inode. This is only needed when the inode itself is being
@@ -2378,7 +2397,8 @@ void __mark_inode_dirty(struct inode *in*/ trace_writeback_dirty_inode_start (inode, flags);if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode (inode, flags &I_DIRTY_INODE ); + sb->s_op->dirty_inode (inode, + flags & (I_DIRTY_INODE |I_DIRTY_TIME ));trace_writeback_dirty_inode (inode, flags);/* I_DIRTY_INODE supersedes I_DIRTY_TIME. */
@@ -2399,21 +2419,15 @@ void __mark_inode_dirty(struct inode *in*/ smp_mb (); -if (((inode->i_state & flags) == flags) || - (dirtytime && (inode->i_state &I_DIRTY_INODE ))) +if ((inode->i_state & flags) == flags)return ;spin_lock (&inode->i_lock); -if (dirtytime && (inode->i_state &I_DIRTY_INODE )) - goto out_unlock_inode;if ((inode->i_state & flags) != flags) {const int was_dirty = inode->i_state &I_DIRTY ;inode_attach_wb (inode,NULL ); -/* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ -if (flags &I_DIRTY_INODE ) - inode->i_state &= ~I_DIRTY_TIME ; inode->i_state |= flags;/*
@@ -2486,7 +2500,6 @@ void __mark_inode_dirty(struct inode *in out_unlock:if (wb)spin_unlock (&wb->list_lock); -out_unlock_inode:spin_unlock (&inode->i_lock); }EXPORT_SYMBOL (__mark_inode_dirty);
fs/xfs/xfs_super.c +8 -2
@@ -653,7 +653,7 @@ xfs_fs_destroy_inode(static void xfs_fs_dirty_inode (struct inode *inode, -int flag) +int flags) {struct xfs_inode *ip =XFS_I (inode);struct xfs_mount *mp = ip->i_mount;
@@ -661,7 +661,13 @@ xfs_fs_dirty_inode(if (!(inode->i_sb->s_flags &SB_LAZYTIME ))return ; -if (flag !=I_DIRTY_SYNC || !(inode->i_state &I_DIRTY_TIME )) + +/* +* Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC) +* and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed +* in flags possibly together with I_DIRTY_SYNC. +*/ +if ((flags & ~I_DIRTY_TIME ) !=I_DIRTY_SYNC || !(flags &I_DIRTY_TIME ))return ;if (xfs_trans_alloc (mp, &M_RES (mp)->tr_fsyncts,0 ,0 ,0 , &tp))
include/linux/fs.h +5 -4
@@ -2371,13 +2371,14 @@ static inline void kiocb_clone(struct ki* don't have to write inode on fdatasync() when only * e.g. the timestamps have changed. * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. -* I_DIRTY_TIME The inode itself only has dirty timestamps, and the +* I_DIRTY_TIME The inode itself has dirty timestamps, and the * lazytime mount option is enabled. We keep track of this * separately from I_DIRTY_SYNC in order to implement * lazytime. This gets cleared if I_DIRTY_INODE -* (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. I.e. -* either I_DIRTY_TIME *or* I_DIRTY_INODE can be set in -* i_state, but not both. I_DIRTY_PAGES may still be set. +* (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. But +* I_DIRTY_TIME can still be set if I_DIRTY_SYNC is already +* in place because writeback might already be in progress +* and we don't want to lose the time update * I_NEW Serves as both a mutex and completion notification. * New inodes set I_NEW. If two processes both create * the same inode, one of them will release its inode and
Greg Kroah-Hartman
maintainerPATCH 118/862 btrfs: fix alignment of VMA for memory mapped files on THP
In reply to Greg Kroah-HartmanFrom: Alexander Zhu <[email protected]>
commit b0c582233a8563f3c4228df838cdc67a8807ec78 upstream.
With CONFIG_READ_ONLY_THP_FOR_FS, the Linux kernel supports using THPs for read-only mmapped files, such as shared libraries. However, the kernel makes no attempt to actually align those mappings on 2MB boundaries, which makes it impossible to use those THPs most of the time. This issue applies to general file mapping THP as well as existing setups using CONFIG_READ_ONLY_THP_FOR_FS. This is easily fixed by using thp_get_unmapped_area for the unmapped_area function in btrfs, which is what ext2, ext4, fuse, and xfs all use.
Initially btrfs had been left out in commit 8c07fc452ac0 ("btrfs: fix alignment of VMA for memory mapped files on THP") as btrfs does not support DAX. However, commit 1854bc6e2420 ("mm/readahead: Align file mappings for non-DAX") removed the DAX requirement. We should now be able to call thp_get_unmapped_area() for btrfs.
The problem can be seen in /proc/PID/smaps where THPeligible is set to 0 on mappings to eligible shared object files as shown below.
Before this patch:
7fc6a7e18000-7fc6a80cc000 r-xp 00000000 00:1e 199856 /usr/lib64/libcrypto.so.1.1.1k
Size: 2768 kB
THPeligible: 0
VmFlags: rd ex mr mw me
With this patch the library is mapped at a 2MB aligned address:
fbdfe200000-7fbdfe4b4000 r-xp 00000000 00:1e 199856 /usr/lib64/libcrypto.so.1.1.1k
Size: 2768 kB
THPeligible: 1
VmFlags: rd ex mr mw me
This fixes the alignment of VMAs for any mmap of a file that has the rd and ex permissions and size >= 2MB. The VMA alignment and THPeligible field for anonymous memory is handled separately and is thus not effected by this change.
--- fs/btrfs/file.c | 1 + 1 file changed, 1 insertion(+)
fs/btrfs/file.c +1 -0
@@ -3810,6 +3810,7 @@ const struct file_operations btrfs_file_ .mmap = btrfs_file_mmap, .open = btrfs_file_open, .release = btrfs_release_file, + .get_unmapped_area = thp_get_unmapped_area, .fsync = btrfs_sync_file, .fallocate = btrfs_fallocate, .unlocked_ioctl = btrfs_ioctl,
Greg Kroah-Hartman
maintainerPATCH 119/862 btrfs: enhance unsupported compat RO flags handling
In reply to Greg Kroah-HartmanFrom: Qu Wenruo <[email protected]>
commit 81d5d61454c365718655cfc87d8200c84e25d596 upstream.
Currently there are two corner cases not handling compat RO flags correctly:
- Remount
We can still mount the fs RO with compat RO flags, then remount it RW. We should not allow any write into a fs with unsupported RO flags.
- Still try to search block group items
In fact, behavior/on-disk format change to extent tree should not need a full incompat flag.
And since we can ensure fs with unsupported RO flags never got any writes (with above case fixed), then we can even skip block group items search at mount time.
This patch will enhance the unsupported RO compat flags by:
- Reject read-write remount if there are unsupported RO compat flags
- Go dummy block group items directly for unsupported RO compat flags In fact, only changes to chunk/subvolume/root/csum trees should go incompat flags.
The latter part should allow future change to extent tree to be compat RO flags.
Thus this patch also needs to be backported to all stable trees.
--- fs/btrfs/block-group.c | 11 ++++++++++- fs/btrfs/super.c | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-)
fs/btrfs/block-group.c +10 -1
@@ -2190,7 +2190,16 @@ int btrfs_read_block_groups(struct btrfsint need_clear =0 ;u64 cache_gen; -if (!root) +/* +* Either no extent root (with ibadroots rescue option) or we have +* unsupported RO options. The fs can never be mounted read-write, so no +* need to waste time searching block group items. +* +* This also allows new extent tree related changes to be RO compat, +* no need for a full incompat flag. +*/ +if (!root || (btrfs_super_compat_ro_flags (info->super_copy) & + ~BTRFS_FEATURE_COMPAT_RO_SUPP ))return fill_dummy_bgs (info); key.objectid =0 ;
fs/btrfs/super.c +9 -0
@@ -2112,6 +2112,15 @@ static int btrfs_remount(struct super_bl ret = -EINVAL ; goto restore; } +if (btrfs_super_compat_ro_flags (fs_info->super_copy) & + ~BTRFS_FEATURE_COMPAT_RO_SUPP ) { +btrfs_err (fs_info, +"can not remount read-write due to unsupported optional flags 0x%llx" , +btrfs_super_compat_ro_flags (fs_info->super_copy) & + ~BTRFS_FEATURE_COMPAT_RO_SUPP ); + ret = -EINVAL ; + goto restore; + }if (fs_info->fs_devices->rw_devices ==0 ) { ret = -EACCES ; goto restore;
Greg Kroah-Hartman
maintainerPATCH 120/862 btrfs: fix race between quota enable and quota rescan ioctl
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit 331cd9461412e103d07595a10289de90004ac890 upstream.
When enabling quotas, at btrfs_quota_enable(), after committing the transaction, we change fs_info->quota_root to point to the quota root we created and set BTRFS_FS_QUOTA_ENABLED at fs_info->flags. Then we try to start the qgroup rescan worker, first by initializing it with a call to qgroup_rescan_init() - however if that fails we end up freeing the quota root but we leave fs_info->quota_root still pointing to it, this can later result in a use-after-free somewhere else.
We have previously set the flags BTRFS_FS_QUOTA_ENABLED and BTRFS_QGROUP_STATUS_FLAG_ON, so we can only fail with -EINPROGRESS at btrfs_quota_enable(), which is possible if someone already called the quota rescan ioctl, and therefore started the rescan worker.
So fix this by ignoring an -EINPROGRESS and asserting we can't get any other error.
--- fs/btrfs/qgroup.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
fs/btrfs/qgroup.c +15 -0
@@ -1174,6 +1174,21 @@ out_add_root: fs_info->qgroup_rescan_running = true;btrfs_queue_work (fs_info->qgroup_rescan_workers, &fs_info->qgroup_rescan_work); + }else { +/* +* We have set both BTRFS_FS_QUOTA_ENABLED and +* BTRFS_QGROUP_STATUS_FLAG_ON, so we can only fail with +* -EINPROGRESS. That can happen because someone started the +* rescan worker by calling quota rescan ioctl before we +* attempted to initialize the rescan worker. Failure due to +* quotas disabled in the meanwhile is not possible, because +* we are holding a write lock on fs_info->subvol_sem, which +* is also acquired when disabling quotas. +* Ignore such error, and any other error would need to undo +* everything we did in the transaction we just committed. +*/ +ASSERT (ret == -EINPROGRESS ); + ret =0 ; } out_free_path:
Greg Kroah-Hartman
maintainerPATCH 121/862 btrfs: fix missed extent on fsync after dropping extent maps
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit cef7820d6abf8d61f8e1db411eae3c712f6d72a2 upstream.
When dropping extent maps for a range, through btrfs_drop_extent_cache(), if we find an extent map that starts before our target range and/or ends before the target range, and we are not able to allocate extent maps for splitting that extent map, then we don't fail and simply remove the entire extent map from the inode's extent map tree.
This is generally fine, because in case anyone needs to access the extent map, it can just load it again later from the respective file extent item(s) in the subvolume btree. However, if that extent map is new and is in the list of modified extents, then a fast fsync will miss the parts of the extent that were outside our range (that needed to be split), therefore not logging them. Fix that by marking the inode for a full fsync. This issue was introduced after removing BUG_ON()s triggered when the split extent map allocations failed, done by commit 7014cdb49305ed ("Btrfs: btrfs_drop_extent_cache should never fail"), back in 2012, and the fast fsync path already existed but was very recent.
Also, in the case where we could allocate extent maps for the split operations but then fail to add a split extent map to the tree, mark the inode for a full fsync as well. This is not supposed to ever fail, and we assert that, but in case assertions are disabled (CONFIG_BTRFS_ASSERT is not set), it's the correct thing to do to make sure a fast fsync will not miss a new extent.
--- fs/btrfs/file.c | 58 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 12 deletions(-)
fs/btrfs/file.c +46 -12
@@ -523,6 +523,7 @@ void btrfs_drop_extent_cache(struct btrf testend =0 ; }while (1 ) { +bool ends_after_range = false;int no_splits =0 ; modified = false;
@@ -539,10 +540,12 @@ void btrfs_drop_extent_cache(struct btrfwrite_unlock (&em_tree->lock);break ; } +if (testend && em->start + em->len > start + len) + ends_after_range = true; flags = em->flags; gen = em->generation;if (skip_pinned &&test_bit (EXTENT_FLAG_PINNED , &em->flags)) { -if (testend && em->start + em->len >= start + len) { +if (ends_after_range) {free_extent_map (em);write_unlock (&em_tree->lock);break ;
@@ -592,7 +595,7 @@ void btrfs_drop_extent_cache(struct btrf split = split2; split2 =NULL ; } -if (testend && em->start + em->len > start + len) { +if (ends_after_range) {u64 diff = start + len - em->start; split->start = start + len;
@@ -630,14 +633,42 @@ void btrfs_drop_extent_cache(struct btrf }else { ret =add_extent_mapping (em_tree, split, modified); -ASSERT (ret ==0 );/* Logic error */ +/* Logic error, shouldn't happen. */ +ASSERT (ret ==0 ); +if (WARN_ON (ret !=0 ) && modified) +btrfs_set_inode_full_sync (inode); }free_extent_map (split); split =NULL ; } next: -if (extent_map_in_tree (em)) +if (extent_map_in_tree (em)) { +/* +* If the extent map is still in the tree it means that +* either of the following is true: +* +* 1) It fits entirely in our range (doesn't end beyond +* it or starts before it); +* +* 2) It starts before our range and/or ends after our +* range, and we were not able to allocate the extent +* maps for split operations, @split and @split2. +* +* If we are at case 2) then we just remove the entire +* extent map - this is fine since if anyone needs it to +* access the subranges outside our range, will just +* load it again from the subvolume tree's file extent +* item. However if the extent map was in the list of +* modified extents, then we must mark the inode for a +* full fsync, otherwise a fast fsync will miss this +* extent if it's new and needs to be logged. +*/ +if ((em->start < start || ends_after_range) && modified) { +ASSERT (no_splits); +btrfs_set_inode_full_sync (inode); + }remove_extent_mapping (em_tree, em); + }write_unlock (&em_tree->lock);/* once for us */
@@ -2201,14 +2232,6 @@ int btrfs_sync_file(struct file *file, latomic_inc (&root->log_batch);/* -* Always check for the full sync flag while holding the inode's lock, -* to avoid races with other tasks. The flag must be either set all the -* time during logging or always off all the time while logging. -*/ - full_sync =test_bit (BTRFS_INODE_NEEDS_FULL_SYNC , - &BTRFS_I (inode)->runtime_flags); - -/* * Before we acquired the inode's lock and the mmap lock, someone may * have dirtied more pages in the target range. We need to make sure * that writeback for any such pages does not start while we are logging
@@ -2233,6 +2256,17 @@ int btrfs_sync_file(struct file *file, l }/* +* Always check for the full sync flag while holding the inode's lock, +* to avoid races with other tasks. The flag must be either set all the +* time during logging or always off all the time while logging. +* We check the flag here after starting delalloc above, because when +* running delalloc the full sync flag may be set if we need to drop +* extra extent map ranges due to temporary memory allocation failures. +*/ + full_sync =test_bit (BTRFS_INODE_NEEDS_FULL_SYNC , + &BTRFS_I (inode)->runtime_flags); + +/* * We have to do this here to avoid the priority inversion of waiting on * IO of a lower priority task while holding a transaction open. *
Greg Kroah-Hartman
maintainerPATCH 122/862 btrfs: set generation before calling btrfs_clean_tree_block in btrfs_init_new_buffer
In reply to Greg Kroah-HartmanFrom: Tetsuo Handa <[email protected]>
commit cbddcc4fa3443fe8cfb2ff8e210deb1f6a0eea38 upstream.
syzbot is reporting uninit-value in btrfs_clean_tree_block() [1], for commit bc877d285ca3dba2 ("btrfs: Deduplicate extent_buffer init code") missed that btrfs_set_header_generation() in btrfs_init_new_buffer() must not be moved to after clean_tree_block() because clean_tree_block() is calling btrfs_header_generation() since commit 55c69072d6bd5be1 ("Btrfs:
Fix extent_buffer usage when nodesize != leafsize").
Since memzero_extent_buffer() will reset "struct btrfs_header" part, we can't move btrfs_set_header_generation() to before memzero_extent_buffer(). Just re-add btrfs_set_header_generation() before btrfs_clean_tree_block().
--- fs/btrfs/extent-tree.c | 3 +++ 1 file changed, 3 insertions(+)
fs/btrfs/extent-tree.c +3 -0
@@ -4888,6 +4888,9 @@ btrfs_init_new_buffer(struct btrfs_trans !test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state)) lockdep_owner =BTRFS_FS_TREE_OBJECTID ; +/* btrfs_clean_tree_block() accesses generation field. */ +btrfs_set_header_generation (buf, trans->transid); +/* * This needs to stay, because we could allocate a freed block from an * old tree into a new tree, so we need to make sure this new block is
Greg Kroah-Hartman
maintainerPATCH 123/862 f2fs: fix wrong continue condition in GC
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit 605b0a778aa2599aa902ae639b8e9937c74b869b upstream.
We should decrease the frozen counter.
--- fs/f2fs/gc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
fs/f2fs/gc.c +4 -8
@@ -97,14 +97,10 @@ static int gc_thread_func(void *data)*/ if (sbi->gc_mode ==GC_URGENT_HIGH ) {spin_lock (&sbi->gc_urgent_high_lock); -if (sbi->gc_urgent_high_limited) { -if (!sbi->gc_urgent_high_remaining) { - sbi->gc_urgent_high_limited = false; -spin_unlock (&sbi->gc_urgent_high_lock); - sbi->gc_mode =GC_NORMAL ; -continue ; - } - sbi->gc_urgent_high_remaining--; +if (sbi->gc_urgent_high_limited && + !sbi->gc_urgent_high_remaining--) { + sbi->gc_urgent_high_limited = false; + sbi->gc_mode =GC_NORMAL ; }spin_unlock (&sbi->gc_urgent_high_lock); }
Greg Kroah-Hartman
maintainerPATCH 124/862 f2fs: complete checkpoints during remount
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit 4f99484d27961cb194cebcd917176fa038a5025f upstream.
Otherwise, pending checkpoints can contribute a race condition to give a quota warning.
- Thread - checkpoint thread
add checkpoints to the listdo_remount()
down_write(&sb->s_umount);
f2fs_remount()
block_operations()
down_read_trylock(&sb->s_umount) = 0
up_write(&sb->s_umount);
f2fs_quota_sync()
dquot_writeback_dquots()
WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));Or,
do_remount()
down_write(&sb->s_umount);
f2fs_remount()
create a ckpt thread f2fs_enable_checkpoint() adds checkpoints wait for f2fs_sync_fs() trigger another pending checkpoint
block_operations()
down_read_trylock(&sb->s_umount) = 0
up_write(&sb->s_umount);
f2fs_quota_sync()
dquot_writeback_dquots()
WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));--- fs/f2fs/super.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/f2fs/super.c +6 -0
@@ -2181,6 +2181,9 @@ static void f2fs_enable_checkpoint(strucf2fs_up_write (&sbi->gc_lock);f2fs_sync_fs (sbi->sb,1 ); + +/* Let's ensure there's no pending checkpoint anymore */ +f2fs_flush_ckpt_thread (sbi); }static int f2fs_remount (struct super_block *sb,int *flags,char *data)
@@ -2346,6 +2349,9 @@ static int f2fs_remount(struct super_blof2fs_stop_ckpt_thread (sbi); need_restart_ckpt = true; }else { +/* Flush if the prevous checkpoint, if exists. */ +f2fs_flush_ckpt_thread (sbi); + err =f2fs_start_ckpt_thread (sbi);if (err) { f2fs_err(sbi,
Greg Kroah-Hartman
maintainerPATCH 125/862 f2fs: flush pending checkpoints when freezing super
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit c7b58576370147833999fd4cc874d0f918bdf9ca upstream.
This avoids -EINVAL when trying to freeze f2fs.
--- fs/f2fs/checkpoint.c | 24 ++++++++++++++++++------ fs/f2fs/f2fs.h | 1 + fs/f2fs/super.c | 5 ++--- 3 files changed, 21 insertions(+), 9 deletions(-)
fs/f2fs/checkpoint.c +18 -6
@@ -1892,15 +1892,27 @@ int f2fs_start_ckpt_thread(struct f2fs_svoid f2fs_stop_ckpt_thread (struct f2fs_sb_info *sbi) {struct ckpt_req_control *cprc = &sbi->cprc_info; +struct task_struct *ckpt_task; -if (cprc->f2fs_issue_ckpt) { -struct task_struct *ckpt_task = cprc->f2fs_issue_ckpt; +if (!cprc->f2fs_issue_ckpt) +return ; - cprc->f2fs_issue_ckpt =NULL ; -kthread_stop (ckpt_task); + ckpt_task = cprc->f2fs_issue_ckpt; + cprc->f2fs_issue_ckpt =NULL ; +kthread_stop (ckpt_task); -flush_remained_ckpt_reqs (sbi,NULL ); - } +f2fs_flush_ckpt_thread (sbi); +} + +void f2fs_flush_ckpt_thread (struct f2fs_sb_info *sbi) +{ +struct ckpt_req_control *cprc = &sbi->cprc_info; + +flush_remained_ckpt_reqs (sbi,NULL ); + +/* Let's wait for the previous dispatched checkpoint. */ +while (atomic_read (&cprc->queued_ckpt)) +io_schedule_timeout (DEFAULT_IO_TIMEOUT ); }void f2fs_init_ckpt_req_control (struct f2fs_sb_info *sbi)
fs/f2fs/f2fs.h +1 -0
@@ -3707,6 +3707,7 @@ static inline bool f2fs_need_rand_seg(st* checkpoint.c */ void f2fs_stop_checkpoint (struct f2fs_sb_info *sbi,bool end_io); +void f2fs_flush_ckpt_thread (struct f2fs_sb_info *sbi);struct page *f2fs_grab_meta_page (struct f2fs_sb_info *sbi,pgoff_t index);struct page *f2fs_get_meta_page (struct f2fs_sb_info *sbi,pgoff_t index);struct page *f2fs_get_meta_page_retry (struct f2fs_sb_info *sbi,pgoff_t index);
fs/f2fs/super.c +2 -3
@@ -1666,9 +1666,8 @@ static int f2fs_freeze(struct super_blocif (is_sbi_flag_set (F2FS_SB (sb),SBI_IS_DIRTY ))return -EINVAL ; -/* ensure no checkpoint required */ -if (!llist_empty (&F2FS_SB (sb)->cprc_info.issue_list)) -return -EINVAL ; +/* Let's flush checkpoints and stop the thread. */ +f2fs_flush_ckpt_thread (F2FS_SB (sb));/* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */ set_sbi_flag (F2FS_SB (sb),SBI_IS_FREEZING );
Greg Kroah-Hartman
maintainerPATCH 126/862 f2fs: increase the limit for reserve_root
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit da35fe96d12d15779f3cb74929b7ed03941cf983 upstream.
This patch increases the threshold that limits the reserved root space from 0.2% to 12.5% by using simple shift operation.
Typically Android sets 128MB, but if the storage capacity is 32GB, 0.2% which is around 64MB becomes too small. Let's relax it.
--- fs/f2fs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/f2fs/super.c +2 -2
@@ -301,10 +301,10 @@ static void f2fs_destroy_casefold_cache(static inline void limit_reserve_root (struct f2fs_sb_info *sbi) { -block_t limit =min ((sbi->user_block_count <<1 ) /1000 , +block_t limit =min ((sbi->user_block_count >>3 ), sbi->user_block_count - sbi->reserved_blocks); -/* limit is 0.2% */ +/* limit is 12.5% */ if (test_opt (sbi,RESERVE_ROOT ) &&F2FS_OPTION (sbi).root_reserved_blocks > limit) {F2FS_OPTION (sbi).root_reserved_blocks = limit;
Greg Kroah-Hartman
maintainerPATCH 127/862 f2fs: fix to do sanity check on destination blkaddr during recovery
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 0ef4ca04a3f9223ff8bc440041c524b2123e09a3 upstream.
As Wenqing Liu reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=216456
loop5: detected capacity change from 0 to 131072 F2FS-fs (loop5): recover_inode: ino = 6, name = hln, inline = 1 F2FS-fs (loop5): recover_data: ino = 6 (i_size: recover) err = 0 F2FS-fs (loop5): recover_inode: ino = 6, name = hln, inline = 1 F2FS-fs (loop5): recover_data: ino = 6 (i_size: recover) err = 0 F2FS-fs (loop5): recover_inode: ino = 6, name = hln, inline = 1 F2FS-fs (loop5): recover_data: ino = 6 (i_size: recover) err = 0 F2FS-fs (loop5): Bitmap was wrongly set, blk:5634
------------[ cut here ]------------ WARNING: CPU: 3 PID: 1013 at fs/f2fs/segment.c:2198 RIP: 0010:update_sit_entry+0xa55/0x10b0 [f2fs] Call Trace: <TASK> f2fs_do_replace_block+0xa98/0x1890 [f2fs] f2fs_replace_block+0xeb/0x180 [f2fs] recover_data+0x1a69/0x6ae0 [f2fs] f2fs_recover_fsync_data+0x120d/0x1fc0 [f2fs] f2fs_fill_super+0x4665/0x61e0 [f2fs] mount_bdev+0x2cf/0x3b0 legacy_get_tree+0xed/0x1d0 vfs_get_tree+0x81/0x2b0 path_mount+0x47e/0x19d0 do_mount+0xce/0xf0 __x64_sys_mount+0x12c/0x1a0 do_syscall_64+0x38/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd
If we enable CONFIG_F2FS_CHECK_FS config, it will trigger a kernel panic instead of warning.
The root cause is: in fuzzed image, SIT table is inconsistent with inode mapping table, result in triggering such warning during SIT table update.
This patch introduces a new flag DATA_GENERIC_ENHANCE_UPDATE, w/ this flag, data block recovery flow can check destination blkaddr's validation in SIT table, and skip f2fs_replace_block() to avoid inconsistent status.
--- fs/f2fs/checkpoint.c | 10 +++++++++- fs/f2fs/f2fs.h | 4 ++++ fs/f2fs/recovery.c | 8 ++++++++ 3 files changed, 21 insertions(+), 1 deletion(-)
fs/f2fs/checkpoint.c +9 -1
@@ -140,7 +140,7 @@ static bool __is_bitmap_valid(struct f2funsigned int segno, offset;bool exist; -if (type !=DATA_GENERIC_ENHANCE && type !=DATA_GENERIC_ENHANCE_READ ) +if (type ==DATA_GENERIC )return true; segno =GET_SEGNO (sbi, blkaddr);
@@ -148,6 +148,13 @@ static bool __is_bitmap_valid(struct f2f se =get_seg_entry (sbi, segno); exist =f2fs_test_bit (offset, se->cur_valid_map); +if (exist && type ==DATA_GENERIC_ENHANCE_UPDATE ) { +f2fs_err (sbi,"Inconsistent error blkaddr:%u, sit bitmap:%d" , + blkaddr, exist); +set_sbi_flag (sbi,SBI_NEED_FSCK ); +return exist; + } +if (!exist && type ==DATA_GENERIC_ENHANCE ) {f2fs_err (sbi,"Inconsistent error blkaddr:%u, sit bitmap:%d" , blkaddr, exist);
@@ -185,6 +192,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_scase DATA_GENERIC :case DATA_GENERIC_ENHANCE :case DATA_GENERIC_ENHANCE_READ : +case DATA_GENERIC_ENHANCE_UPDATE :if (unlikely (blkaddr >=MAX_BLKADDR (sbi) || blkaddr <MAIN_BLKADDR (sbi))) { f2fs_warn(sbi, "access invalid blkaddr:%u",
fs/f2fs/f2fs.h +4 -0
@@ -266,6 +266,10 @@ enum {* condition of read on truncated area * by extent_cache */ +DATA_GENERIC_ENHANCE_UPDATE ,/* +* strong check on range and segment +* bitmap for update case +*/ META_GENERIC, };
fs/f2fs/recovery.c +8 -0
@@ -698,6 +698,14 @@ retry_prev: goto err; } +if (f2fs_is_valid_blkaddr (sbi, dest, +DATA_GENERIC_ENHANCE_UPDATE )) { +f2fs_err (sbi,"Inconsistent dest blkaddr:%u, ino:%lu, ofs:%u" , + dest, inode->i_ino, dn.ofs_in_node); + err = -EFSCORRUPTED ; + goto err; + } +/* write dummy data page */ f2fs_replace_block (sbi, &dn, src, dest, ni.version, false, false);
Greg Kroah-Hartman
maintainerPATCH 128/862 f2fs: fix to do sanity check on summary info
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit c6ad7fd16657ebd34a87a97d9588195aae87597d upstream.
As Wenqing Liu reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=216456
BUG: KASAN: use-after-free in recover_data+0x63ae/0x6ae0 [f2fs] Read of size 4 at addr ffff8881464dcd80 by task mount/1013 CPU: 3 PID: 1013 Comm: mount Tainted: G W 6.0.0-rc4 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 Call Trace: dump_stack_lvl+0x45/0x5e print_report.cold+0xf3/0x68d kasan_report+0xa8/0x130 recover_data+0x63ae/0x6ae0 [f2fs] f2fs_recover_fsync_data+0x120d/0x1fc0 [f2fs] f2fs_fill_super+0x4665/0x61e0 [f2fs] mount_bdev+0x2cf/0x3b0 legacy_get_tree+0xed/0x1d0 vfs_get_tree+0x81/0x2b0 path_mount+0x47e/0x19d0 do_mount+0xce/0xf0 __x64_sys_mount+0x12c/0x1a0 do_syscall_64+0x38/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd
The root cause is: in fuzzed image, SSA table is corrupted: ofs_in_node is larger than ADDRS_PER_PAGE(), result in out-of-range access on 4k-size page.
- recover_data
- do_recover_data
- check_index_in_prev_nodes
- f2fs_data_blkaddr
This patch adds sanity check on summary info in recovery and GC flow in where the flows rely on them.
After patch:
[ 29.310883] F2FS-fs (loop0): Inconsistent ofs_in_node:65286 in summary, ino:0, nid:6, max:1018
--- fs/f2fs/gc.c | 10 +++++++++- fs/f2fs/recovery.c | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-)
fs/f2fs/gc.c +9 -1
@@ -1078,7 +1078,7 @@ static bool is_alive(struct f2fs_sb_info {struct page *node_page;nid_t nid; -unsigned int ofs_in_node; +unsigned int ofs_in_node, max_addrs;block_t source_blkaddr; nid =le32_to_cpu (sum->nid);
@@ -1104,6 +1104,14 @@ static bool is_alive(struct f2fs_sb_inforeturn false; } + max_addrs =IS_INODE (node_page) ?DEF_ADDRS_PER_INODE : +DEF_ADDRS_PER_BLOCK ; +if (ofs_in_node >= max_addrs) { +f2fs_err (sbi,"Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u" , + ofs_in_node, dni->ino, dni->nid, max_addrs); +return false; + } + *nofs =ofs_of_node (node_page); source_blkaddr =data_blkaddr (NULL , node_page, ofs_in_node);f2fs_put_page (node_page,1 );
fs/f2fs/recovery.c +12 -3
@@ -474,7 +474,7 @@ static int check_index_in_prev_nodes(strstruct dnode_of_data tdn = *dn;nid_t ino, nid;struct inode *inode; -unsigned int offset; +unsigned int offset, ofs_in_node, max_addrs;block_t bidx;int i;
@@ -501,15 +501,24 @@ static int check_index_in_prev_nodes(str got_it:/* Use the locked dnode page and inode */ nid =le32_to_cpu (sum.nid); + ofs_in_node =le16_to_cpu (sum.ofs_in_node); + + max_addrs =ADDRS_PER_PAGE (dn->node_page, dn->inode); +if (ofs_in_node >= max_addrs) { +f2fs_err (sbi,"Inconsistent ofs_in_node:%u in summary, ino:%lu, nid:%u, max:%u" , + ofs_in_node, dn->inode->i_ino, nid, max_addrs); +return -EFSCORRUPTED ; + } +if (dn->inode->i_ino == nid) { tdn.nid = nid;if (!dn->inode_page_locked)lock_page (dn->inode_page); tdn.node_page = dn->inode_page; - tdn.ofs_in_node =le16_to_cpu (sum.ofs_in_node); + tdn.ofs_in_node = ofs_in_node; goto truncate_out; }else if (dn->nid == nid) { - tdn.ofs_in_node =le16_to_cpu (sum.ofs_in_node); + tdn.ofs_in_node = ofs_in_node; goto truncate_out; }
Greg Kroah-Hartman
maintainerPATCH 129/862 f2fs: allow direct read for zoned device
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit 689fe57e7ecefd2eeba76c32aa569bb3e1e790d9 upstream.
This reverts dbf8e63f48af ("f2fs: remove device type check for direct IO"), and apply the below first version, since it contributed out-of-order DIO writes.
For zoned devices, f2fs forbids direct IO and forces buffered IO to serialize write IOs. However, the constraint does not apply to read IOs.
--- fs/f2fs/f2fs.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/f2fs/f2fs.h +6 -1
@@ -4513,7 +4513,12 @@ static inline bool f2fs_force_buffered_i/* disallow direct IO if any of devices has unaligned blksize */ if (f2fs_is_multi_device (sbi) && !sbi->aligned_blksize)return true; - +/* +* for blkzoned device, fallback direct IO to buffered IO, so +* all IOs can be serialized by log-structured write. +*/ +if (f2fs_sb_has_blkzoned (sbi) && (rw ==WRITE )) +return true;if (f2fs_lfs_mode (sbi) && (rw ==WRITE )) {if (block_unaligned_IO (inode, iocb, iter))return true;
Greg Kroah-Hartman
maintainerPATCH 130/862 jbd2: wake up journal waiters in FIFO order, not LIFO
In reply to Greg Kroah-HartmanFrom: Andrew Perepechko <[email protected]>
commit 34fc8768ec6089565d6d73bad26724083cecf7bd upstream.
LIFO wakeup order is unfair and sometimes leads to a journal user not being able to get a journal handle for hundreds of transactions in a row.
FIFO wakeup can make things more fair.
--- fs/jbd2/commit.c | 2 +- fs/jbd2/transaction.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
fs/jbd2/commit.c +1 -1
@@ -570,7 +570,7 @@ void jbd2_journal_commit_transaction(jou journal->j_running_transaction =NULL ; start_time =ktime_get (); commit_transaction->t_log_start = journal->j_head; -wake_up (&journal->j_wait_transaction_locked); +wake_up_all (&journal->j_wait_transaction_locked);write_unlock (&journal->j_state_lock);jbd2_debug (3 ,"JBD2: commit phase 2a\n" );
fs/jbd2/transaction.c +3 -3
@@ -168,7 +168,7 @@ static void wait_transaction_locked(jourint need_to_start;tid_t tid = journal->j_running_transaction->t_tid; -prepare_to_wait (&journal->j_wait_transaction_locked, &wait, +prepare_to_wait_exclusive (&journal->j_wait_transaction_locked, &wait,TASK_UNINTERRUPTIBLE ); need_to_start = !tid_geq (journal->j_commit_request, tid);read_unlock (&journal->j_state_lock);
@@ -194,7 +194,7 @@ static void wait_transaction_switching(jread_unlock (&journal->j_state_lock);return ; } -prepare_to_wait (&journal->j_wait_transaction_locked, &wait, +prepare_to_wait_exclusive (&journal->j_wait_transaction_locked, &wait,TASK_UNINTERRUPTIBLE );read_unlock (&journal->j_state_lock);/*
@@ -920,7 +920,7 @@ void jbd2_journal_unlock_updates (journawrite_lock (&journal->j_state_lock); --journal->j_barrier_count;write_unlock (&journal->j_state_lock); -wake_up (&journal->j_wait_transaction_locked); +wake_up_all (&journal->j_wait_transaction_locked); }static void warn_dirty_buffer (struct buffer_head *bh)
Greg Kroah-Hartman
maintainerPATCH 131/862 jbd2: fix potential buffer head reference count leak
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit e0d5fc7a6d80ac2406c7dfc6bb625201d0250a8a upstream.
As in 'jbd2_fc_wait_bufs' if buffer isn't uptodate, will return -EIO without update 'journal->j_fc_off'. But 'jbd2_fc_release_bufs' will release buffer head from ‘j_fc_off - 1’ if 'bh' is NULL will terminal release which will lead to buffer head buffer head reference count leak.
To solve above issue, update 'journal->j_fc_off' before return -EIO.
--- fs/jbd2/journal.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/jbd2/journal.c +7 -1
@@ -925,8 +925,14 @@ int jbd2_fc_wait_bufs(journal_t *journalwait_on_buffer (bh);put_bh (bh); journal->j_fc_wbuf[i] =NULL ; -if (unlikely (!buffer_uptodate (bh))) +/* +* Update j_fc_off so jbd2_fc_release_bufs can release remain +* buffer head. +*/ +if (unlikely (!buffer_uptodate (bh))) { + journal->j_fc_off = i;return -EIO ; + } }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 132/862 jbd2: fix potential use-after-free in jbd2_fc_wait_bufs
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 243d1a5d505d0b0460c9af0ad56ed4a56ef0bebd upstream.
In 'jbd2_fc_wait_bufs' use 'bh' after put buffer head reference count which may lead to use-after-free.
So judge buffer if uptodate before put buffer head reference count.
--- fs/jbd2/journal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/jbd2/journal.c +3 -3
@@ -923,16 +923,16 @@ int jbd2_fc_wait_bufs(journal_t *journalfor (i = j_fc_off -1 ; i >= j_fc_off - num_blks; i--) { bh = journal->j_fc_wbuf[i];wait_on_buffer (bh); -put_bh (bh); - journal->j_fc_wbuf[i] =NULL ;/* * Update j_fc_off so jbd2_fc_release_bufs can release remain * buffer head. */ if (unlikely (!buffer_uptodate (bh))) { - journal->j_fc_off = i; + journal->j_fc_off = i +1 ;return -EIO ; } +put_bh (bh); + journal->j_fc_wbuf[i] =NULL ; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 133/862 jbd2: add miss release buffer head in fc_do_one_pass()
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit dfff66f30f66b9524b661f311bbed8ff3d2ca49f upstream.
In fc_do_one_pass() miss release buffer head after use which will lead to reference count leak.
--- fs/jbd2/recovery.c | 1 + 1 file changed, 1 insertion(+)
fs/jbd2/recovery.c +1 -0
@@ -256,6 +256,7 @@ static int fc_do_one_pass(journal_t *jou err = journal->j_fc_replay_callback (journal, bh, pass, next_fc_block - journal->j_fc_first, expected_commit_id); +brelse (bh); next_fc_block++;if (err <0 || err ==JBD2_FC_REPLAY_STOP )break ;
Greg Kroah-Hartman
maintainerPATCH 134/862 ext2: Add sanity checks for group and filesystem size
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit d766f2d1e3e3bd44024a7f971ffcf8b8fbb7c5d2 upstream.
Add sanity check that filesystem size does not exceed the underlying device size and that group size is big enough so that metadata can fit into it. This avoid trying to mount some crafted filesystems with extremely large group counts.
--- fs/ext2/super.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
fs/ext2/super.c +14 -2
@@ -1052,6 +1052,13 @@ static int ext2_fill_super(struct super_ sbi->s_blocks_per_group); goto failed_mount; } +/* At least inode table, bitmaps, and sb have to fit in one group */ +if (sbi->s_blocks_per_group <= sbi->s_itb_per_group +3 ) { +ext2_msg (sb,KERN_ERR , +"error: #blocks per group smaller than metadata size: %lu <= %lu" , + sbi->s_blocks_per_group, sbi->s_inodes_per_group +3 ); + goto failed_mount; + }if (sbi->s_frags_per_group > sb->s_blocksize *8 ) { ext2_msg(sb, KERN_ERR, "error: #fragments per group too big: %lu",
@@ -1065,9 +1072,14 @@ static int ext2_fill_super(struct super_ sbi->s_inodes_per_group); goto failed_mount; } +if (sb_bdev_nr_blocks (sb) <le32_to_cpu (es->s_blocks_count)) { +ext2_msg (sb,KERN_ERR , +"bad geometry: block count %u exceeds size of device (%u blocks)" , +le32_to_cpu (es->s_blocks_count), + (unsigned )sb_bdev_nr_blocks (sb)); + goto failed_mount; + } -if (EXT2_BLOCKS_PER_GROUP (sb) ==0 ) - goto cantfind_ext2; sbi->s_groups_count = ((le32_to_cpu (es->s_blocks_count) -le32_to_cpu (es->s_first_data_block) -1 ) /EXT2_BLOCKS_PER_GROUP (sb)) +1 ;
Greg Kroah-Hartman
maintainerPATCH 135/862 ext4: avoid crash when inline data creation follows DIO write
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 4bb26f2885ac6930984ee451b952c5a6042f2c0e upstream.
When inode is created and written to using direct IO, there is nothing to clear the EXT4_STATE_MAY_INLINE_DATA flag. Thus when inode gets truncated later to say 1 byte and written using normal write, we will try to store the data as inline data. This confuses the code later because the inode now has both normal block and inline data allocated and the confusion manifests for example as:
kernel BUG at fs/ext4/inode.c:2721!
invalid opcode: 0000 [#1] PREEMPT SMP KASAN
CPU: 0 PID: 359 Comm: repro Not tainted 5.19.0-rc8-00001-g31ba1e3b8305-dirty #15 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.0-1.fc36 04/01/2014 RIP: 0010:ext4_writepages+0x363d/0x3660 RSP: 0018:ffffc90000ccf260 EFLAGS: 00010293 RAX: ffffffff81e1abcd RBX: 0000008000000000 RCX: ffff88810842a180 RDX: 0000000000000000 RSI: 0000008000000000 RDI: 0000000000000000 RBP: ffffc90000ccf650 R08: ffffffff81e17d58 R09: ffffed10222c680b R10: dfffe910222c680c R11: 1ffff110222c680a R12: ffff888111634128 R13: ffffc90000ccf880 R14: 0000008410000000 R15: 0000000000000001 FS: 00007f72635d2640(0000) GS:ffff88811b000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000565243379180 CR3: 000000010aa74000 CR4: 0000000000150eb0 Call Trace: <TASK> do_writepages+0x397/0x640 filemap_fdatawrite_wbc+0x151/0x1b0 file_write_and_wait_range+0x1c9/0x2b0 ext4_sync_file+0x19e/0xa00 vfs_fsync_range+0x17b/0x190 ext4_buffered_write_iter+0x488/0x530 ext4_file_write_iter+0x449/0x1b90 vfs_write+0xbcd/0xf40 ksys_write+0x198/0x2c0 __x64_sys_write+0x7b/0x90 do_syscall_64+0x3d/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd </TASK>
Fix the problem by clearing EXT4_STATE_MAY_INLINE_DATA when we are doing direct IO write to a file.
--- fs/ext4/file.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/ext4/file.c +6 -0
@@ -528,6 +528,12 @@ static ssize_t ext4_dio_write_iter(struc ret = -EAGAIN ; goto out; } +/* +* Make sure inline data cannot be created anymore since we are going +* to allocate blocks for DIO. We know the inode does not have any +* inline data now because ext4_dio_supported() checked for that. +*/ +ext4_clear_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA ); offset = iocb->ki_pos; count = ret;
Greg Kroah-Hartman
maintainerPATCH 136/862 ext4: fix null-ptr-deref in ext4_write_info
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit f9c1f248607d5546075d3f731e7607d5571f2b60 upstream.
I caught a null-ptr-deref bug as follows:
==================================================================
KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f] CPU: 1 PID: 1589 Comm: umount Not tainted 5.10.0-02219-dirty #339 RIP: 0010:ext4_write_info+0x53/0x1b0 [...] Call Trace: dquot_writeback_dquots+0x341/0x9a0 ext4_sync_fs+0x19e/0x800 __sync_filesystem+0x83/0x100 sync_filesystem+0x89/0xf0 generic_shutdown_super+0x79/0x3e0 kill_block_super+0xa1/0x110 deactivate_locked_super+0xac/0x130 deactivate_super+0xb6/0xd0 cleanup_mnt+0x289/0x400 __cleanup_mnt+0x16/0x20 task_work_run+0x11c/0x1c0 exit_to_user_mode_prepare+0x203/0x210 syscall_exit_to_user_mode+0x5b/0x3a0 do_syscall_64+0x59/0x70 entry_SYSCALL_64_after_hwframe+0x44/0xa9 ==================================================================
Above issue may happen as follows:
-------------------------------------exit_to_user_mode_prepare
task_work_run
__cleanup_mnt
cleanup_mnt
deactivate_super
deactivate_locked_super
kill_block_super
generic_shutdown_super
shrink_dcache_for_umount
dentry = sb->s_root
sb->s_root = NULL <--- Here set NULL
sync_filesystem
__sync_filesystem
sb->s_op->sync_fs > ext4_sync_fs
dquot_writeback_dquots
sb->dq_op->write_info > ext4_write_info
ext4_journal_start(d_inode(sb->s_root), EXT4_HT_QUOTA, 2)
d_inode(sb->s_root)
s_root->d_inode <--- Null pointer dereferenceTo solve this problem, we use ext4_journal_start_sb directly to avoid s_root being used.
--- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/super.c +1 -1
@@ -6653,7 +6653,7 @@ static int ext4_write_info(struct super_handle_t *handle;/* Data block + inode block */ - handle =ext4_journal_start (d_inode (sb->s_root),EXT4_HT_QUOTA ,2 ); + handle =ext4_journal_start_sb (sb,EXT4_HT_QUOTA ,2 );if (IS_ERR (handle))return PTR_ERR (handle); ret =dquot_commit_info (sb, type);
Greg Kroah-Hartman
maintainerPATCH 137/862 ext4: make ext4_lazyinit_thread freezable
In reply to Greg Kroah-HartmanFrom: Lalith Rajendran <[email protected]>
commit 3b575495ab8dbb4dbe85b4ac7f991693c3668ff5 upstream.
ext4_lazyinit_thread is not set freezable. Hence when the thread calls try_to_freeze it doesn't freeze during suspend and continues to send requests to the storage during suspend, resulting in suspend failures.
--- fs/ext4/super.c | 1 + 1 file changed, 1 insertion(+)
fs/ext4/super.c +1 -0
@@ -3767,6 +3767,7 @@ static int ext4_lazyinit_thread(void *arunsigned long next_wakeup, cur;BUG_ON (NULL == eli); +set_freezable (); cont_thread:while (true) {
Greg Kroah-Hartman
maintainerPATCH 138/862 ext4: fix check for block being out of directory size
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 61a1d87a324ad5e3ed27c6699dfc93218fcf3201 upstream.
The check in __ext4_read_dirblock() for block being outside of directory size was wrong because it compared block number against directory size in bytes. Fix it.
CVE: CVE-2022-1184
--- fs/ext4/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/namei.c +1 -1
@@ -126,7 +126,7 @@ static struct buffer_head *__ext4_read_dstruct ext4_dir_entry *dirent;int is_dx_block =0 ; -if (block >= inode->i_size) { +if (block >= inode->i_size >> inode->i_blkbits) {ext4_error_inode (inode, func, line, block,"Attempting to read directory block (%u) that is past i_size (%llu)" , block, inode->i_size);
Greg Kroah-Hartman
maintainerPATCH 139/862 ext4: dont increase iversion counter for ea_inodes
In reply to Greg Kroah-HartmanFrom: Lukas Czerner <[email protected]>
commit 50f094a5580e6297bf10a807d16f0ee23fa576cf upstream.
ea_inodes are using i_version for storing part of the reference count so we really need to leave it alone.
The problem can be reproduced by xfstest ext4/026 when iversion is enabled. Fix it by not calling inode_inc_iversion() for EXT4_EA_INODE_FL inodes in ext4_mark_iloc_dirty().
--- fs/ext4/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/ext4/inode.c +6 -1
@@ -5731,7 +5731,12 @@ int ext4_mark_iloc_dirty(handle_t *handl }ext4_fc_track_inode (handle, inode); -if (IS_I_VERSION (inode)) +/* +* ea_inodes are using i_version for storing reference count, don't +* mess with it +*/ +if (IS_I_VERSION (inode) && + !(EXT4_I (inode)->i_flags &EXT4_EA_INODE_FL ))inode_inc_iversion (inode);/* the do_update_inode consumes one bh->b_count */
Greg Kroah-Hartman
maintainerPATCH 140/862 ext4: unconditionally enable the i_version counter
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
commit 1ff20307393e17dc57fde62226df625a3a3c36e9 upstream.
The original i_version implementation was pretty expensive, requiring a log flush on every change. Because of this, it was gated behind a mount option (implemented via the MS_I_VERSION mountoption flag).
Commit ae5e165d855d (fs: new API for handling inode->i_version) made the i_version flag much less expensive, so there is no longer a performance penalty from enabling it. xfs and btrfs already enable it unconditionally when the on-disk format can support it.
Have ext4 ignore the SB_I_VERSION flag, and just enable it unconditionally. While we're in here, mark the i_version mount option Opt_removed.
[ Removed leftover bits of i_version from ext4_apply_options() since it
now can't ever be set in ctx->mask_s_flags -- lczerner ]
--- fs/ext4/inode.c | 5 ++--- fs/ext4/super.c | 22 +++++----------------- 2 files changed, 7 insertions(+), 20 deletions(-)
fs/ext4/inode.c +2 -3
@@ -5425,7 +5425,7 @@ int ext4_setattr(struct user_namespace *return -EINVAL ; } -if (IS_I_VERSION (inode) && attr->ia_size != inode->i_size) +if (attr->ia_size != inode->i_size)inode_inc_iversion (inode);if (shrink) {
@@ -5735,8 +5735,7 @@ int ext4_mark_iloc_dirty(handle_t *handl* ea_inodes are using i_version for storing reference count, don't * mess with it */ -if (IS_I_VERSION (inode) && - !(EXT4_I (inode)->i_flags &EXT4_EA_INODE_FL )) +if (!(EXT4_I (inode)->i_flags &EXT4_EA_INODE_FL ))inode_inc_iversion (inode);/* the do_update_inode consumes one bh->b_count */
fs/ext4/super.c +5 -17
@@ -1585,7 +1585,7 @@ enum { Opt_inlinecrypt, Opt_usrjquota, Opt_grpjquota, Opt_quota, Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, - Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, + Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never, Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error, Opt_nowarn_on_error, Opt_mblk_io_submit, Opt_debug_want_extra_isize,
@@ -1694,7 +1694,7 @@ static const struct fs_parameter_spec exfsparam_flag ("barrier" , Opt_barrier),fsparam_u32 ("barrier" , Opt_barrier),fsparam_flag ("nobarrier" , Opt_nobarrier), -fsparam_flag ("i_version" , Opt_i_version), +fsparam_flag ("i_version" , Opt_removed),fsparam_flag ("dax" , Opt_dax),fsparam_enum ("dax" , Opt_dax_type, ext4_param_dax), fsparam_u32 ("stripe", Opt_stripe),
@@ -2140,11 +2140,6 @@ static int ext4_parse_param(struct fs_cocase Opt_abort:ctx_set_mount_flag (ctx,EXT4_MF_FS_ABORTED );return 0 ; -case Opt_i_version: -ext4_msg (NULL ,KERN_WARNING , deprecated_msg, param->key,"5.20" ); -ext4_msg (NULL ,KERN_WARNING ,"Use iversion instead\n" ); -ctx_set_flags (ctx,SB_I_VERSION ); -return 0 ;case Opt_inlinecrypt:#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT ctx_set_flags (ctx,SB_INLINECRYPT );
@@ -2814,14 +2809,6 @@ static void ext4_apply_options(struct fs sb->s_flags &= ~ctx->mask_s_flags; sb->s_flags |= ctx->vals_s_flags; -/* -* i_version differs from common mount option iversion so we have -* to let vfs know that it was set, otherwise it would get cleared -* on remount -*/ -if (ctx->mask_s_flags &SB_I_VERSION ) - fc->sb_flags |=SB_I_VERSION ; -#define APPLY (X ) ({ if (ctx->spec & EXT4_SPEC_##X) sbi->X = ctx->X; })APPLY (s_commit_interval);APPLY (s_stripe);
@@ -2970,8 +2957,6 @@ static int _ext4_show_options(struct seqSEQ_OPTS_PRINT ("min_batch_time=%u" , sbi->s_min_batch_time);if (nodefs || sbi->s_max_batch_time !=EXT4_DEF_MAX_BATCH_TIME )SEQ_OPTS_PRINT ("max_batch_time=%u" , sbi->s_max_batch_time); -if (sb->s_flags &SB_I_VERSION ) -SEQ_OPTS_PUTS ("i_version" );if (nodefs || sbi->s_stripe)SEQ_OPTS_PRINT ("stripe=%lu" , sbi->s_stripe); if (nodefs || EXT4_MOUNT_DATA_FLAGS &
@@ -4641,6 +4626,9 @@ static int __ext4_fill_super(struct fs_c sb->s_flags = (sb->s_flags & ~SB_POSIXACL ) | (test_opt (sb,POSIX_ACL ) ?SB_POSIXACL :0 ); +/* i_version is always enabled now */ + sb->s_flags |=SB_I_VERSION ; + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV && (ext4_has_compat_features(sb) || ext4_has_ro_compat_features(sb) ||
Greg Kroah-Hartman
maintainerPATCH 141/862 ext4: ext4_read_bh_lock() should submit IO if the buffer isnt uptodate
In reply to Greg Kroah-HartmanFrom: Zhang Yi <[email protected]>
commit 0b73284c564d3ae4feef4bc920292f004acf4980 upstream.
Recently we notice that ext4 filesystem would occasionally fail to read metadata from disk and report error message, but the disk and block layer looks fine. After analyse, we lockon commit 88dbcbb3a484 ("blkdev: avoid migration stalls for blkdev pages"). It provide a migration method for the bdev, we could move page that has buffers without extra users now, but it lock the buffers on the page, which breaks the fragile metadata read operation on ext4 filesystem, ext4_read_bh_lock() was copied from ll_rw_block(), it depends on the assumption of that locked buffer means it is under IO. So it just trylock the buffer and skip submit IO if it lock failed, after wait_on_buffer() we conclude IO error because the buffer is not uptodate.
This issue could be easily reproduced by add some delay just after buffer_migrate_lock_buffers() in __buffer_migrate_folio() and do fsstress on ext4 filesystem.
EXT4-fs error (device pmem1): __ext4_find_entry:1658: inode #73193:
comm fsstress: reading directory lblock 0
EXT4-fs error (device pmem1): __ext4_find_entry:1658: inode #75334:
comm fsstress: reading directory lblock 0
Fix it by removing the trylock logic in ext4_read_bh_lock(), just lock the buffer and submit IO if it's not uptodate, and also leave over readahead helper.
--- fs/ext4/super.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-)
fs/ext4/super.c +5 -11
@@ -205,19 +205,12 @@ int ext4_read_bh(struct buffer_head *bh,int ext4_read_bh_lock (struct buffer_head *bh,blk_opf_t op_flags,bool wait) { -if (trylock_buffer (bh)) { -if (wait) -return ext4_read_bh (bh, op_flags,NULL ); +lock_buffer (bh); +if (!wait) {ext4_read_bh_nowait (bh, op_flags,NULL );return 0 ; } -if (wait) { -wait_on_buffer (bh); -if (buffer_uptodate (bh)) -return 0 ; -return -EIO ; - } -return 0 ; +return ext4_read_bh (bh, op_flags,NULL ); }/*
@@ -264,7 +257,8 @@ void ext4_sb_breadahead_unmovable(structstruct buffer_head *bh =sb_getblk_gfp (sb, block,0 );if (likely (bh)) { -ext4_read_bh_lock (bh,REQ_RAHEAD , false); +if (trylock_buffer (bh)) +ext4_read_bh_nowait (bh,REQ_RAHEAD ,NULL );brelse (bh); } }
Greg Kroah-Hartman
maintainerPATCH 142/862 ext4: place buffer head allocation before handle start
In reply to Greg Kroah-HartmanFrom: Jinke Han <[email protected]>
commit d1052d236eddf6aa851434db1897b942e8db9921 upstream.
In our product environment, we encounter some jbd hung waiting handles to stop while several writters were doing memory reclaim for buffer head allocation in delay alloc write path. Ext4 do buffer head allocation with holding transaction handle which may be blocked too long if the reclaim works not so smooth. According to our bcc trace, the reclaim time in buffer head allocation can reach 258s and the jbd transaction commit also take almost the same time meanwhile. Except for these extreme cases, we often see several seconds delays for cgroup memory reclaim on our servers. This is more likely to happen considering docker environment.
One thing to note, the allocation of buffer heads is as often as page allocation or more often when blocksize less than page size. Just like page cache allocation, we should also place the buffer head allocation before startting the handle.
--- fs/ext4/inode.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/ext4/inode.c +7 -0
@@ -1188,6 +1188,13 @@ retry_grab: page =grab_cache_page_write_begin (mapping, index);if (!page)return -ENOMEM ; +/* +* The same as page allocation, we prealloc buffer heads before +* starting the handle. +*/ +if (!page_has_buffers (page)) +create_empty_buffers (page, inode->i_sb->s_blocksize,0 ); +unlock_page (page); retry_journal:
Greg Kroah-Hartman
maintainerPATCH 143/862 ext4: fix i_version handling in ext4
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
commit a642c2c0827f5604a93f9fa1e5701eecdce4ae22 upstream.
ext4 currently updates the i_version counter when the atime is updated during a read. This is less than ideal as it can cause unnecessary cache invalidations with NFSv4 and unnecessary remeasurements for IMA.
The increment in ext4_mark_iloc_dirty is also problematic since it can corrupt the i_version counter for ea_inodes. We aren't bumping the file times in ext4_mark_iloc_dirty, so changing the i_version there seems wrong, and is the cause of both problems.
Remove that callsite and add increments to the setattr, setxattr and ioctl codepaths, at the same times that we update the ctime. The i_version bump that already happens during timestamp updates should take care of the rest.
In ext4_move_extents, increment the i_version on both inodes, and also add in missing ctime updates.
[ Some minor updates since we've already enabled the i_version counter
unconditionally already via another patch series. -- TYT ]
--- fs/ext4/inode.c | 14 +++++--------- fs/ext4/ioctl.c | 4 ++++ fs/ext4/xattr.c | 1 + 3 files changed, 10 insertions(+), 9 deletions(-)
fs/ext4/inode.c +5 -9
@@ -5349,6 +5349,7 @@ int ext4_setattr(struct user_namespace *int error, rc =0 ;int orphan =0 ;const unsigned int ia_valid = attr->ia_valid; +bool inc_ivers = true;if (unlikely (ext4_forced_shutdown (EXT4_SB (inode->i_sb))))return -EIO ;
@@ -5432,8 +5433,8 @@ int ext4_setattr(struct user_namespace *return -EINVAL ; } -if (attr->ia_size != inode->i_size) -inode_inc_iversion (inode); +if (attr->ia_size == inode->i_size) + inc_ivers = false;if (shrink) {if (ext4_should_order_data (inode)) {
@@ -5535,6 +5536,8 @@ out_mmap_sem: }if (!error) { +if (inc_ivers) +inode_inc_iversion (inode);setattr_copy (mnt_userns, inode, attr);mark_inode_dirty (inode); }
@@ -5738,13 +5741,6 @@ int ext4_mark_iloc_dirty(handle_t *handl }ext4_fc_track_inode (handle, inode); -/* -* ea_inodes are using i_version for storing reference count, don't -* mess with it -*/ -if (!(EXT4_I (inode)->i_flags &EXT4_EA_INODE_FL )) -inode_inc_iversion (inode); -/* the do_update_inode consumes one bh->b_count */ get_bh (iloc->bh);
fs/ext4/ioctl.c +4 -0
@@ -452,6 +452,7 @@ static long swap_inode_boot_loader(strucswap_inode_data (inode, inode_bl); inode->i_ctime = inode_bl->i_ctime =current_time (inode); +inode_inc_iversion (inode); inode->i_generation =prandom_u32 (); inode_bl->i_generation =prandom_u32 ();
@@ -665,6 +666,7 @@ static int ext4_ioctl_setflags(struct inext4_set_inode_flags (inode, false); inode->i_ctime =current_time (inode); +inode_inc_iversion (inode); err =ext4_mark_iloc_dirty (handle, inode, &iloc); flags_err:
@@ -775,6 +777,7 @@ static int ext4_ioctl_setproject(structEXT4_I (inode)->i_projid = kprojid; inode->i_ctime =current_time (inode); +inode_inc_iversion (inode); out_dirty: rc =ext4_mark_iloc_dirty (handle, inode, &iloc);if (!err)
@@ -1257,6 +1260,7 @@ static long __ext4_ioctl(struct file *fi err =ext4_reserve_inode_write (handle, inode, &iloc);if (err ==0 ) { inode->i_ctime =current_time (inode); +inode_inc_iversion (inode); inode->i_generation = generation; err =ext4_mark_iloc_dirty (handle, inode, &iloc); }
fs/ext4/xattr.c +1 -0
@@ -2412,6 +2412,7 @@ retry_inode:if (!error) {ext4_xattr_update_super_block (handle, inode->i_sb); inode->i_ctime =current_time (inode); +inode_inc_iversion (inode);if (!value) no_expand =0 ; error =ext4_mark_iloc_dirty (handle, inode, &is.iloc);
Greg Kroah-Hartman
maintainerPATCH 144/862 ext4: fix dir corruption when ext4_dx_add_entry() fails
In reply to Greg Kroah-HartmanFrom: Zhihao Cheng <[email protected]>
commit 7177dd009c7c04290891e9a534cd47d1b620bd04 upstream.
Following process may lead to fs corruption:
1. ext4_create(dir/foo)
ext4_add_nondir
ext4_add_entry
ext4_dx_add_entry
a. add_dirent_to_buf
ext4_mark_inode_dirty
ext4_handle_dirty_metadata // dir inode bh is recorded into journal
b. ext4_append // dx_get_count(entries) == dx_get_limit(entries)
ext4_bread(EXT4_GET_BLOCKS_CREATE)
ext4_getblk
ext4_map_blocks
ext4_ext_map_blocks
ext4_mb_new_blocks
dquot_alloc_block
dquot_alloc_space_nodirty
inode_add_bytes // update dir's i_blocks
ext4_ext_insert_extent
ext4_ext_dirty // record extent bh into journal
ext4_handle_dirty_metadata(bh)
// record new block into journal
inode->i_size += inode->i_sb->s_blocksize // new size(in mem)
c. ext4_handle_dirty_dx_node(bh2)
// record dir's new block(dx_node) into journal
d. ext4_handle_dirty_dx_node((frame - 1)->bh)
e. ext4_handle_dirty_dx_node(frame->bh)
f. do_split // ret err!
g. add_dirent_to_buf
ext4_mark_inode_dirty(dir) // update raw_inode on disk(skipped)2. fsck -a /dev/sdb
drop last block(dx_node) which beyonds dir's i_size.
/dev/sdb: recovering journal
/dev/sdb contains a file system with errors, check forced. /dev/sdb: Inode 12, end of extent exceeds allowed value
(logical block 128, physical block 3938, len 1)
3. fsck -fn /dev/sdb
dx_node->entry[i].blk > dir->i_size
Pass 2: Checking directory structure
Problem in HTREE directory inode 12 (/dir): bad block number 128. Clear HTree index? no
Problem in HTREE directory inode 12: block #3 has invalid depth (2) Problem in HTREE directory inode 12: block #3 has bad max hash Problem in HTREE directory inode 12: block #3 not referenced
Fix it by marking inode dirty directly inside ext4_append(). Fetch a reproducer in [Link].
--- fs/ext4/namei.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
fs/ext4/namei.c +10 -5
@@ -85,15 +85,20 @@ static struct buffer_head *ext4_append(hreturn bh; inode->i_size += inode->i_sb->s_blocksize;EXT4_I (inode)->i_disksize = inode->i_size; + err =ext4_mark_inode_dirty (handle, inode); +if (err) + goto out;BUFFER_TRACE (bh,"get_write_access" ); err =ext4_journal_get_write_access (handle, inode->i_sb, bh,EXT4_JTR_NONE ); -if (err) { -brelse (bh); -ext4_std_error (inode->i_sb, err); -return ERR_PTR (err); - } +if (err) + goto out;return bh; + +out: +brelse (bh); +ext4_std_error (inode->i_sb, err); +return ERR_PTR (err); } static int ext4_dx_csum_verify(struct inode *inode,
Greg Kroah-Hartman
maintainerPATCH 145/862 ext4: fix miss release buffer head in ext4_fc_write_inode
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit ccbf8eeb39f2ff00b54726a2b20b35d788c4ecb5 upstream.
In 'ext4_fc_write_inode' function first call 'ext4_get_inode_loc' get 'iloc', after use it miss release 'iloc.bh'.
So just release 'iloc.bh' before 'ext4_fc_write_inode' return.
--- fs/ext4/fast_commit.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
fs/ext4/fast_commit.c +9 -6
@@ -874,22 +874,25 @@ static int ext4_fc_write_inode(struct in tl.fc_tag =cpu_to_le16 (EXT4_FC_TAG_INODE ); tl.fc_len =cpu_to_le16 (inode_len +sizeof (fc_inode.fc_ino)); + ret = -ECANCELED ; dst =ext4_fc_reserve_space (inode->i_sb,sizeof (tl) + inode_len +sizeof (fc_inode.fc_ino), crc);if (!dst) -return -ECANCELED ; + goto err;if (!ext4_fc_memcpy (inode->i_sb, dst, &tl,sizeof (tl), crc)) -return -ECANCELED ; + goto err; dst +=sizeof (tl);if (!ext4_fc_memcpy (inode->i_sb, dst, &fc_inode,sizeof (fc_inode), crc)) -return -ECANCELED ; + goto err; dst +=sizeof (fc_inode);if (!ext4_fc_memcpy (inode->i_sb, dst, (u8 *)ext4_raw_inode (&iloc), inode_len, crc)) -return -ECANCELED ; - -return 0 ; + goto err; + ret =0 ; +err: +brelse (iloc.bh); +return ret; }/*
Greg Kroah-Hartman
maintainerPATCH 146/862 ext4: fix potential memory leak in ext4_fc_record_modified_inode()
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 9305721a309fa1bd7c194e0d4a2335bf3b29dca4 upstream.
As krealloc may return NULL, in this case 'state->fc_modified_inodes' may not be freed by krealloc, but 'state->fc_modified_inodes' already set NULL. Then will lead to 'state->fc_modified_inodes' memory leak.
--- fs/ext4/fast_commit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
fs/ext4/fast_commit.c +5 -3
@@ -1494,13 +1494,15 @@ static int ext4_fc_record_modified_inodeif (state->fc_modified_inodes[i] == ino)return 0 ;if (state->fc_modified_inodes_used == state->fc_modified_inodes_size) { - state->fc_modified_inodes =krealloc ( - state->fc_modified_inodes, +int *fc_modified_inodes; + + fc_modified_inodes =krealloc (state->fc_modified_inodes,sizeof (int ) * (state->fc_modified_inodes_size +EXT4_FC_REPLAY_REALLOC_INCREMENT ),GFP_KERNEL ); -if (!state->fc_modified_inodes) +if (!fc_modified_inodes)return -ENOMEM ; + state->fc_modified_inodes = fc_modified_inodes; state->fc_modified_inodes_size +=EXT4_FC_REPLAY_REALLOC_INCREMENT ; }
Greg Kroah-Hartman
maintainerPATCH 147/862 ext4: fix potential memory leak in ext4_fc_record_regions()
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 7069d105c1f15c442b68af43f7fde784f3126739 upstream.
As krealloc may return NULL, in this case 'state->fc_regions' may not be freed by krealloc, but 'state->fc_regions' already set NULL. Then will lead to 'state->fc_regions' memory leak.
--- fs/ext4/fast_commit.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
fs/ext4/fast_commit.c +8 -6
@@ -1687,15 +1687,17 @@ int ext4_fc_record_regions(struct super_if (replay && state->fc_regions_used != state->fc_regions_valid) state->fc_regions_used = state->fc_regions_valid;if (state->fc_regions_used == state->fc_regions_size) { +struct ext4_fc_alloc_region *fc_regions; + state->fc_regions_size +=EXT4_FC_REPLAY_REALLOC_INCREMENT ; - state->fc_regions =krealloc ( - state->fc_regions, - state->fc_regions_size * -sizeof (struct ext4_fc_alloc_region ), -GFP_KERNEL ); -if (!state->fc_regions) + fc_regions =krealloc (state->fc_regions, + state->fc_regions_size * +sizeof (struct ext4_fc_alloc_region ), +GFP_KERNEL ); +if (!fc_regions)return -ENOMEM ; + state->fc_regions = fc_regions; } region = &state->fc_regions[state->fc_regions_used++]; region->ino = ino;
Greg Kroah-Hartman
maintainerPATCH 148/862 ext4: update state->fc_regions_size after successful memory allocation
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 27cd49780381c6ccbf248798e5e8fd076200ffba upstream.
To avoid to 'state->fc_regions_size' mismatch with 'state->fc_regions' when fail to reallocate 'fc_reqions',only update 'state->fc_regions_size' after 'state->fc_regions' is allocated successfully.
--- fs/ext4/fast_commit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
fs/ext4/fast_commit.c +5 -4
@@ -1689,14 +1689,15 @@ int ext4_fc_record_regions(struct super_if (state->fc_regions_used == state->fc_regions_size) {struct ext4_fc_alloc_region *fc_regions; - state->fc_regions_size += -EXT4_FC_REPLAY_REALLOC_INCREMENT ; fc_regions =krealloc (state->fc_regions, - state->fc_regions_size * -sizeof (struct ext4_fc_alloc_region ), +sizeof (struct ext4_fc_alloc_region ) * + (state->fc_regions_size + +EXT4_FC_REPLAY_REALLOC_INCREMENT ),GFP_KERNEL );if (!fc_regions)return -ENOMEM ; + state->fc_regions_size += +EXT4_FC_REPLAY_REALLOC_INCREMENT ; state->fc_regions = fc_regions; } region = &state->fc_regions[state->fc_regions_used++];
Greg Kroah-Hartman
maintainerPATCH 149/862 livepatch: fix race between fork and KLP transition
In reply to Greg Kroah-HartmanFrom: Rik van Riel <[email protected]>
commit 747f7a2901174c9afa805dddfb7b24db6f65e985 upstream.
The KLP transition code depends on the TIF_PATCH_PENDING and the task->patch_state to stay in sync. On a normal (forward) transition, TIF_PATCH_PENDING will be set on every task in the system, while on a reverse transition (after a failed forward one) first TIF_PATCH_PENDING will be cleared from every task, followed by it being set on tasks that need to be transitioned back to the original code.
However, the fork code copies over the TIF_PATCH_PENDING flag from the parent to the child early on, in dup_task_struct and setup_thread_stack. Much later, klp_copy_process will set child->patch_state to match that of the parent.
However, the parent's patch_state may have been changed by KLP loading or unloading since it was initially copied over into the child.
This results in the KLP code occasionally hitting this warning in klp_complete_transition:
for_each_process_thread(g, task) {
WARN_ON_ONCE(test_tsk_thread_flag(task, TIF_PATCH_PENDING));
task->patch_state = KLP_UNDEFINED;
}Set, or clear, the TIF_PATCH_PENDING flag in the child task depending on whether or not it is needed at the time klp_copy_process is called, at a point in copy_process where the tasklist_lock is held exclusively, preventing races with the KLP code.
The KLP code does have a few places where the state is changed without the tasklist_lock held, but those should not cause problems because klp_update_patch_state(current) cannot be called while the current task is in the middle of fork, klp_check_and_switch_task() which is called under the pi_lock, which prevents rescheduling, and manipulation of the patch state of idle tasks, which do not fork.
This should prevent this warning from triggering again in the future, and close the race for both normal and reverse transitions.
--- kernel/livepatch/transition.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
kernel/livepatch/transition.c +16 -2
@@ -610,9 +610,23 @@ void klp_reverse_transition(void)/* Called from copy_process() during fork */ void klp_copy_process (struct task_struct *child) { - child->patch_state = current->patch_state; -/* TIF_PATCH_PENDING gets copied in setup_thread_stack() */ +/* +* The parent process may have gone through a KLP transition since +* the thread flag was copied in setup_thread_stack earlier. Bring +* the task flag up to date with the parent here. +* +* The operation is serialized against all klp_*_transition() +* operations by the tasklist_lock. The only exception is +* klp_update_patch_state(current), but we cannot race with +* that because we are current. +*/ +if (test_tsk_thread_flag (current,TIF_PATCH_PENDING )) +set_tsk_thread_flag (child,TIF_PATCH_PENDING ); +else +clear_tsk_thread_flag (child,TIF_PATCH_PENDING ); + + child->patch_state = current->patch_state; }/*
Greg Kroah-Hartman
maintainerPATCH 150/862 ftrace: Properly unset FTRACE_HASH_FL_MOD
In reply to Greg Kroah-HartmanFrom: Zheng Yejian <[email protected]>
commit 0ce0638edf5ec83343302b884fa208179580700a upstream.
When executing following commands like what document said, but the log "#### all functions enabled ####" was not shown as expect:
1. Set a 'mod' filter:
$ echo 'write*:mod:ext3' > /sys/kernel/tracing/set_ftrace_filter
2. Invert above filter:
$ echo '!write*:mod:ext3' >> /sys/kernel/tracing/set_ftrace_filter
3. Read the file:
$ cat /sys/kernel/tracing/set_ftrace_filterBy some debugging, I found that flag FTRACE_HASH_FL_MOD was not unset after inversion like above step 2 and then result of ftrace_hash_empty() is incorrect.
--- kernel/trace/ftrace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/trace/ftrace.c +6 -2
@@ -6081,8 +6081,12 @@ int ftrace_regex_release(struct inode *iif (filter_hash) { orig_hash = &iter->ops->func_hash->filter_hash; -if (iter->tr && !list_empty (&iter->tr->mod_trace)) - iter->hash->flags |=FTRACE_HASH_FL_MOD ; +if (iter->tr) { +if (list_empty (&iter->tr->mod_trace)) + iter->hash->flags &= ~FTRACE_HASH_FL_MOD ; +else + iter->hash->flags |=FTRACE_HASH_FL_MOD ; + } }else orig_hash = &iter->ops->func_hash->notrace_hash;
Greg Kroah-Hartman
maintainerPATCH 151/862 ftrace: Still disable enabled records marked as disabled
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit cf04f2d5df0037741207382ac8fe289e8bf84ced upstream.
Weak functions started causing havoc as they showed up in the "available_filter_functions" and this confused people as to why some functions marked as "notrace" were listed, but when enabled they did nothing. This was because weak functions can still have fentry calls, and these addresses get added to the "available_filter_functions" file. kallsyms is what converts those addresses to names, and since the weak functions are not listed in kallsyms, it would just pick the function before that.
To solve this, there was a trick to detect weak functions listed, and these records would be marked as DISABLED so that they do not get enabled and are mostly ignored. As the processing of the list of all functions to figure out what is weak or not can take a long time, this process is put off into a kernel thread and run in parallel with the rest of start up.
Now the issue happens whet function tracing is enabled via the kernel command line. As it starts very early in boot up, it can be enabled before the records that are weak are marked to be disabled. This causes an issue in the accounting, as the weak records are enabled by the command line function tracing, but after boot up, they are not disabled.
The ftrace records have several accounting flags and a ref count. The DISABLED flag is just one. If the record is enabled before it is marked DISABLED it will get an ENABLED flag and also have its ref counter incremented. After it is marked for DISABLED, neither the ENABLED flag nor the ref counter is cleared. There's sanity checks on the records that are performed after an ftrace function is registered or unregistered, and this detected that there were records marked as ENABLED with ref counter that should not have been.
Note, the module loading code uses the DISABLED flag as well to keep its functions from being modified while its being loaded and some of these flags may get set in this process. So changing the verification code to ignore DISABLED records is a no go, as it still needs to verify that the module records are working too.
Also, the weak functions still are calling a trampoline. Even though they should never be called, it is dangerous to leave these weak functions calling a trampoline that is freed, so they should still be set back to nops.
There's two places that need to not skip records that have the ENABLED and the DISABLED flags set. That is where the ftrace_ops is processed and sets the records ref counts, and then later when the function itself is to be updated, and the ENABLED flag gets removed. Add a helper function "skip_record()" that returns true if the record has the DISABLED flag set but not the ENABLED flag.
--- kernel/trace/ftrace.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
kernel/trace/ftrace.c +16 -4
@@ -1644,6 +1644,18 @@ ftrace_find_tramp_ops_any_other(struct dstatic struct ftrace_ops *ftrace_find_tramp_ops_next (struct dyn_ftrace *rec,struct ftrace_ops *ops); +static bool skip_record (struct dyn_ftrace *rec) +{ +/* +* At boot up, weak functions are set to disable. Function tracing +* can be enabled before they are, and they still need to be disabled now. +* If the record is disabled, still continue if it is marked as already +* enabled (this is needed to keep the accounting working). +*/ +return rec->flags &FTRACE_FL_DISABLED && + !(rec->flags &FTRACE_FL_ENABLED ); +} +static bool __ftrace_hash_rec_update (struct ftrace_ops *ops,int filter_hash,bool inc)
@@ -1693,7 +1705,7 @@ static bool __ftrace_hash_rec_update(strint in_hash =0 ;int match =0 ; -if (rec->flags &FTRACE_FL_DISABLED ) +if (skip_record (rec))continue ;if (all) {
@@ -2126,7 +2138,7 @@ static int ftrace_check_record(struct dy ftrace_bug_type =FTRACE_BUG_UNKNOWN ; -if (rec->flags &FTRACE_FL_DISABLED ) +if (skip_record (rec))return FTRACE_UPDATE_IGNORE ;/*
@@ -2241,7 +2253,7 @@ static int ftrace_check_record(struct dyif (update) {/* If there's no more users, clear all flags */ if (!ftrace_rec_count (rec)) - rec->flags =0 ; + rec->flags &=FTRACE_FL_DISABLED ;else /* * Just disable the record, but keep the ops TRAMP
@@ -2634,7 +2646,7 @@ void __weak ftrace_replace_code(int mod_do_for_each_ftrace_rec (pg, rec) { -if (rec->flags &FTRACE_FL_DISABLED ) +if (skip_record (rec))continue ; failed =__ftrace_replace_code (rec, enable);
Greg Kroah-Hartman
maintainerPATCH 152/862 ring-buffer: Allow splice to read previous partially read pages
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit fa8f4a89736b654125fb254b0db753ac68a5fced upstream.
If a page is partially read, and then the splice system call is run against the ring buffer, it will always fail to read, no matter how much is in the ring buffer. That's because the code path for a partial read of the page does will fail if the "full" flag is set.
The splice system call wants full pages, so if the read of the ring buffer is not yet full, it should return zero, and the splice will block. But if a previous read was done, where the beginning has been consumed, it should still be given to the splice caller if the rest of the page has been written to.
This caused the splice command to never consume data in this scenario, and let the ring buffer just fill up and lose events.
--- kernel/trace/ring_buffer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +9 -1
@@ -5616,7 +5616,15 @@ int ring_buffer_read_page(struct trace_bunsigned int pos =0 ;unsigned int size; -if (full) +/* +* If a full page is expected, this can still be returned +* if there's been a previous partial read and the +* rest of the page can be read and the commit page is off +* the reader page. +*/ +if (full && + (!read || (len < (commit - read)) || + cpu_buffer->reader_page == cpu_buffer->commit_page)) goto out_unlock;if (len > (commit - read))
Greg Kroah-Hartman
maintainerPATCH 153/862 ring-buffer: Have the shortest_full queue be the shortest not longest
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 3b19d614b61b93a131f463817e08219c9ce1fee3 upstream.
The logic to know when the shortest waiters on the ring buffer should be woken up or not has uses a less than instead of a greater than compare, which causes the shortest_full to actually be the longest.
--- kernel/trace/ring_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/ring_buffer.c +1 -1
@@ -1011,7 +1011,7 @@ int ring_buffer_wait(struct trace_buffer nr_pages = cpu_buffer->nr_pages; dirty =ring_buffer_nr_dirty_pages (buffer, cpu);if (!cpu_buffer->shortest_full || - cpu_buffer->shortest_full < full) + cpu_buffer->shortest_full > full) cpu_buffer->shortest_full = full;raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags); if (!pagebusy &&
Greg Kroah-Hartman
maintainerPATCH 154/862 ring-buffer: Check pending waiters when doing wake ups as well
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit ec0bbc5ec5664dcee344f79373852117dc672c86 upstream.
The wake up waiters only checks the "wakeup_full" variable and not the "full_waiters_pending". The full_waiters_pending is set when a waiter is added to the wait queue. The wakeup_full is only set when an event is triggered, and it clears the full_waiters_pending to avoid multiple calls to irq_work_queue().
The irq_work callback really needs to check both wakeup_full as well as full_waiters_pending such that this code can be used to wake up waiters when a file is closed that represents the ring buffer and the waiters need to be woken up.
--- kernel/trace/ring_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +2 -1
@@ -917,8 +917,9 @@ static void rb_wake_up_waiters(struct ir struct rb_irq_work *rbwork = container_of(work, struct rb_irq_work, work);wake_up_all (&rbwork->waiters); -if (rbwork->wakeup_full) { +if (rbwork->full_waiters_pending || rbwork->wakeup_full) { rbwork->wakeup_full = false; + rbwork->full_waiters_pending = false;wake_up_all (&rbwork->full_waiters); } }
Greg Kroah-Hartman
maintainerPATCH 155/862 ring-buffer: Add ring_buffer_wake_waiters()
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 7e9fbbb1b776d8d7969551565bc246f74ec53b27 upstream.
On closing of a file that represents a ring buffer or flushing the file, there may be waiters on the ring buffer that needs to be woken up and exit the ring_buffer_wait() function.
Add ring_buffer_wake_waiters() to wake up the waiters on the ring buffer and allow them to exit the wait loop.
--- include/linux/ring_buffer.h | 2 +- kernel/trace/ring_buffer.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-)
include/linux/ring_buffer.h +1 -1
@@ -101,7 +101,7 @@ __ring_buffer_alloc(unsigned long size,int ring_buffer_wait (struct trace_buffer *buffer,int cpu,int full);__poll_t ring_buffer_poll_wait (struct trace_buffer *buffer,int cpu,struct file *filp,poll_table *poll_table); - +void ring_buffer_wake_waiters (struct trace_buffer *buffer,int cpu);#define RING_BUFFER_ALL_CPUS -1
kernel/trace/ring_buffer.c +39 -0
@@ -413,6 +413,7 @@ struct rb_irq_work {struct irq_work work;wait_queue_head_t waiters;wait_queue_head_t full_waiters; +long wait_index;bool waiters_pending;bool full_waiters_pending;bool wakeup_full;
@@ -925,6 +926,37 @@ static void rb_wake_up_waiters(struct ir }/** +* ring_buffer_wake_waiters - wake up any waiters on this ring buffer +* @buffer: The ring buffer to wake waiters on +* +* In the case of a file that represents a ring buffer is closing, +* it is prudent to wake up any waiters that are on this. +*/ +void ring_buffer_wake_waiters (struct trace_buffer *buffer,int cpu) +{ +struct ring_buffer_per_cpu *cpu_buffer; +struct rb_irq_work *rbwork; + +if (cpu ==RING_BUFFER_ALL_CPUS ) { + +/* Wake up individual ones too. One level recursion */ +for_each_buffer_cpu (buffer, cpu) +ring_buffer_wake_waiters (buffer, cpu); + + rbwork = &buffer->irq_work; + }else { + cpu_buffer = buffer->buffers[cpu]; + rbwork = &cpu_buffer->irq_work; + } + + rbwork->wait_index++; +/* make sure the waiters see the new index */ +smp_wmb (); + +rb_wake_up_waiters (&rbwork->work); +} + +/** * ring_buffer_wait - wait for input to the ring buffer * @buffer: buffer to wait on * @cpu: the cpu buffer to wait on
@@ -939,6 +971,7 @@ int ring_buffer_wait(struct trace_bufferstruct ring_buffer_per_cpu *cpu_buffer;DEFINE_WAIT (wait);struct rb_irq_work *work; +long wait_index;int ret =0 ;/*
@@ -957,6 +990,7 @@ int ring_buffer_wait(struct trace_buffer work = &cpu_buffer->irq_work; } + wait_index =READ_ONCE (work->wait_index);while (true) {if (full)
@@ -1021,6 +1055,11 @@ int ring_buffer_wait(struct trace_buffer }schedule (); + +/* Make sure to see the new wait index */ +smp_rmb (); +if (wait_index != work->wait_index) +break ; }if (full)
Greg Kroah-Hartman
maintainerPATCH 156/862 ring-buffer: Fix race between reset page and reading page
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit a0fcaaed0c46cf9399d3a2d6e0c87ddb3df0e044 upstream.
The ring buffer is broken up into sub buffers (currently of page size). Each sub buffer has a pointer to its "tail" (the last event written to the sub buffer). When a new event is requested, the tail is locally incremented to cover the size of the new event. This is done in a way that there is no need for locking.
If the tail goes past the end of the sub buffer, the process of moving to the next sub buffer takes place. After setting the current sub buffer to the next one, the previous one that had the tail go passed the end of the sub buffer needs to be reset back to the original tail location (before the new event was requested) and the rest of the sub buffer needs to be "padded".
The race happens when a reader takes control of the sub buffer. As readers do a "swap" of sub buffers from the ring buffer to get exclusive access to the sub buffer, it replaces the "head" sub buffer with an empty sub buffer that goes back into the writable portion of the ring buffer. This swap can happen as soon as the writer moves to the next sub buffer and before it updates the last sub buffer with padding.
Because the sub buffer can be released to the reader while the writer is still updating the padding, it is possible for the reader to see the event that goes past the end of the sub buffer. This can cause obvious issues.
To fix this, add a few memory barriers so that the reader definitely sees the updates to the sub buffer, and also waits until the writer has put back the "tail" of the sub buffer back to the last event that was written on it.
To be paranoid, it will only spin for 1 second, otherwise it will warn and shutdown the ring buffer code. 1 second should be enough as the writer does have preemption disabled. If the writer doesn't move within 1 second (with preemption disabled) something is horribly wrong. No interrupt should last 1 second!
--- kernel/trace/ring_buffer.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
kernel/trace/ring_buffer.c +33 -0
@@ -2648,6 +2648,9 @@ rb_reset_tail(struct ring_buffer_per_cpu/* Mark the rest of the page with padding */ rb_event_set_padding (event); +/* Make sure the padding is visible before the write update */ +smp_wmb (); +/* Set the write back to the previous setting */ local_sub (length, &tail_page->write);return ;
@@ -2659,6 +2662,9 @@ rb_reset_tail(struct ring_buffer_per_cpu/* time delta must be non zero */ event->time_delta =1 ; +/* Make sure the padding is visible before the tail_page->write update */ +smp_wmb (); +/* Set write to end of buffer */ length = (tail + length) -BUF_PAGE_SIZE ;local_sub (length, &tail_page->write);
@@ -4627,6 +4633,33 @@ rb_get_reader_page(struct ring_buffer_pearch_spin_unlock (&cpu_buffer->lock);local_irq_restore (flags); +/* +* The writer has preempt disable, wait for it. But not forever +* Although, 1 second is pretty much "forever" +*/ +#define USECS_WAIT 1000000 +for (nr_loops =0 ; nr_loops <USECS_WAIT ; nr_loops++) { +/* If the write is past the end of page, a writer is still updating it */ +if (likely (!reader ||rb_page_write (reader) <=BUF_PAGE_SIZE )) +break ; + +udelay (1 ); + +/* Get the latest version of the reader write value */ +smp_rmb (); + } + +/* The writer is not moving forward? Something is wrong */ +if (RB_WARN_ON (cpu_buffer, nr_loops ==USECS_WAIT )) + reader =NULL ; + +/* +* Make sure we see any padding after the write update +* (see rb_reset_tail()) +*/ +smp_rmb (); + +return reader; }
Greg Kroah-Hartman
maintainerPATCH 157/862 tracing/eprobe: Fix alloc event dir failed when event name no set
In reply to Greg Kroah-HartmanFrom: Tao Chen <[email protected]>
commit dc399adecd4e2826868e5d116a58e33071b18346 upstream.
The event dir will alloc failed when event name no set, using the command:
"echo "e:esys/ syscalls/sys_enter_openat file=\$filename:string"
Quoted 1 line
Quoted 1 line
dynamic_events"
It seems that dir name="syscalls/sys_enter_openat" is not allowed in debugfs. So just use the "sys_enter_openat" as the event name.
--- kernel/trace/trace_eprobe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/trace/trace_eprobe.c +1 -2
@@ -968,8 +968,7 @@ static int __trace_eprobe_create(int arg }if (!event) { -strscpy (buf1, argv[1 ],MAX_EVENT_NAME_LEN ); -sanitize_event_name (buf1); +strscpy (buf1, sys_event,MAX_EVENT_NAME_LEN ); event = buf1; }
Greg Kroah-Hartman
maintainerPATCH 158/862 tracing: Disable interrupt or preemption before acquiring arch_spinlock_t
In reply to Greg Kroah-HartmanFrom: Waiman Long <[email protected]>
commit c0a581d7126c0bbc96163276f585fd7b4e4d8d0e upstream.
It was found that some tracing functions in kernel/trace/trace.c acquire an arch_spinlock_t with preemption and irqs enabled. An example is the tracing_saved_cmdlines_size_read() function which intermittently causes a "BUG: using smp_processor_id() in preemptible" warning when the LTP read_all_proc test is run.
That can be problematic in case preemption happens after acquiring the lock. Add the necessary preemption or interrupt disabling code in the appropriate places before acquiring an arch_spinlock_t.
The convention here is to disable preemption for trace_cmdline_lock and interupt for max_lock.
--- kernel/trace/trace.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
kernel/trace/trace.c +23 -0
@@ -1193,12 +1193,14 @@ void *tracing_cond_snapshot_data(struct {void *cond_data =NULL ; +local_irq_disable ();arch_spin_lock (&tr->max_lock);if (tr->cond_snapshot) cond_data = tr->cond_snapshot->cond_data;arch_spin_unlock (&tr->max_lock); +local_irq_enable ();return cond_data; }
@@ -1334,9 +1336,11 @@ int tracing_snapshot_cond_enable(struct goto fail_unlock; } +local_irq_disable ();arch_spin_lock (&tr->max_lock); tr->cond_snapshot = cond_snapshot;arch_spin_unlock (&tr->max_lock); +local_irq_enable ();mutex_unlock (&trace_types_lock);
@@ -1363,6 +1367,7 @@ int tracing_snapshot_cond_disable(struct {int ret =0 ; +local_irq_disable ();arch_spin_lock (&tr->max_lock);if (!tr->cond_snapshot)
@@ -1373,6 +1378,7 @@ int tracing_snapshot_cond_disable(struct }arch_spin_unlock (&tr->max_lock); +local_irq_enable ();return ret; }
@@ -2200,6 +2206,11 @@ static size_t tgid_map_max;#define SAVED_CMDLINES_DEFAULT 128#define NO_CMDLINE_MAP UINT_MAX +/* +* Preemption must be disabled before acquiring trace_cmdline_lock. +* The various trace_arrays' max_lock must be acquired in a context +* where interrupt is disabled. +*/ static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;struct saved_cmdlines_buffer {unsigned map_pid_to_cmdline[PID_MAX_DEFAULT +1 ];
@@ -2412,7 +2423,11 @@ static int trace_save_cmdline(struct tas* the lock, but we also don't want to spin * nor do we want to disable interrupts, * so if we miss here, then better luck next time. +* +* This is called within the scheduler and wake up, so interrupts +* had better been disabled and run queue lock been held. */ +lockdep_assert_preemption_disabled ();if (!arch_spin_trylock (&trace_cmdline_lock))return 0 ;
@@ -5890,9 +5905,11 @@ tracing_saved_cmdlines_size_read(structchar buf[64 ];int r; +preempt_disable ();arch_spin_lock (&trace_cmdline_lock); r =scnprintf (buf,sizeof (buf),"%u\n" , savedcmd->cmdline_num);arch_spin_unlock (&trace_cmdline_lock); +preempt_enable ();return simple_read_from_buffer (ubuf, cnt, ppos, buf, r); }
@@ -5917,10 +5934,12 @@ static int tracing_resize_saved_cmdlinesreturn -ENOMEM ; } +preempt_disable ();arch_spin_lock (&trace_cmdline_lock); savedcmd_temp = savedcmd; savedcmd = s;arch_spin_unlock (&trace_cmdline_lock); +preempt_enable ();free_saved_cmdlines_buffer (savedcmd_temp);return 0 ;
@@ -6373,10 +6392,12 @@ int tracing_set_tracer(struct trace_arra#ifdef CONFIG_TRACER_SNAPSHOT if (t->use_max_tr) { +local_irq_disable ();arch_spin_lock (&tr->max_lock);if (tr->cond_snapshot) ret = -EBUSY ;arch_spin_unlock (&tr->max_lock); +local_irq_enable ();if (ret) goto out; }
@@ -7436,10 +7457,12 @@ tracing_snapshot_write(struct file *filp goto out; } +local_irq_disable ();arch_spin_lock (&tr->max_lock);if (tr->cond_snapshot) ret = -EBUSY ;arch_spin_unlock (&tr->max_lock); +local_irq_enable ();if (ret) goto out;
Greg Kroah-Hartman
maintainerPATCH 159/862 tracing: Wake up ring buffer waiters on closing of the file
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit f3ddb74ad0790030c9592229fb14d8c451f4e9a8 upstream.
When the file that represents the ring buffer is closed, there may be waiters waiting on more input from the ring buffer. Call ring_buffer_wake_waiters() to wake up any waiters when the file is closed.
--- include/linux/trace_events.h | 1 + kernel/trace/trace.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+)
include/linux/trace_events.h +1 -0
@@ -92,6 +92,7 @@ struct trace_iterator {unsigned int temp_size;char *fmt;/* modified format holder */ unsigned int fmt_size; +long wait_index;/* trace_seq for __print_flags() and __print_symbolic() etc. */ struct trace_seq tmp_seq;
kernel/trace/trace.c +15 -0
@@ -8160,6 +8160,12 @@ static int tracing_buffers_release(struc__trace_array_put (iter->tr); + iter->wait_index++; +/* Make sure the waiters see the new wait_index */ +smp_wmb (); + +ring_buffer_wake_waiters (iter->array_buffer->buffer, iter->cpu_file); +if (info->spare)ring_buffer_free_read_page (iter->array_buffer->buffer, info->spare_cpu, info->spare);
@@ -8313,6 +8319,8 @@ tracing_buffers_splice_read(struct file/* did we read anything? */ if (!spd.nr_pages) { +long wait_index; +if (ret) goto out;
@@ -8320,10 +8328,17 @@ tracing_buffers_splice_read(struct fileif ((file->f_flags &O_NONBLOCK ) || (flags &SPLICE_F_NONBLOCK )) goto out; + wait_index =READ_ONCE (iter->wait_index); + ret =wait_on_pipe (iter, iter->tr->buffer_percent);if (ret) goto out; +/* Make sure we see the new wait_index */ +smp_rmb (); +if (wait_index != iter->wait_index) + goto out; + goto again; }
Greg Kroah-Hartman
maintainerPATCH 160/862 tracing: Wake up waiters when tracing is disabled
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 2b0fd9a59b7990c161fa1cb7b79edb22847c87c2 upstream.
When tracing is disabled, there's no reason that waiters should stay waiting, wake them up, otherwise tasks get stuck when they should be flushing the buffers.
--- kernel/trace/trace.c | 6 ++++++ 1 file changed, 6 insertions(+)
kernel/trace/trace.c +6 -0
@@ -8334,6 +8334,10 @@ tracing_buffers_splice_read(struct fileif (ret) goto out; +/* No need to wait after waking up when tracing is off */ +if (!tracer_tracing_is_on (iter->tr)) + goto out; +/* Make sure we see the new wait_index */ smp_rmb ();if (wait_index != iter->wait_index)
@@ -9043,6 +9047,8 @@ rb_simple_write(struct file *filp, consttracer_tracing_off (tr);if (tr->current_trace->stop) tr->current_trace->stop (tr); +/* Wake up any waiters */ +ring_buffer_wake_waiters (buffer,RING_BUFFER_ALL_CPUS ); }mutex_unlock (&trace_types_lock); }
Greg Kroah-Hartman
maintainerPATCH 161/862 tracing: Add ioctl() to force ring buffer waiters to wake up
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 01b2a52171735c6eea80ee2f355f32bea6c41418 upstream.
If a process is waiting on the ring buffer for data, there currently isn't a clean way to force it to wake up. Add an ioctl call that will force any tasks that are waiting on the trace_pipe_raw file to wake up.
--- kernel/trace/trace.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
kernel/trace/trace.c +22 -0
@@ -8353,12 +8353,34 @@ out:return ret; } +/* An ioctl call with cmd 0 to the ring buffer file will wake up all waiters */ +static long tracing_buffers_ioctl (struct file *file,unsigned int cmd,unsigned long arg) +{ +struct ftrace_buffer_info *info = file->private_data; +struct trace_iterator *iter = &info->iter; + +if (cmd) +return -ENOIOCTLCMD ; + +mutex_lock (&trace_types_lock); + + iter->wait_index++; +/* Make sure the waiters see the new wait_index */ +smp_wmb (); + +ring_buffer_wake_waiters (iter->array_buffer->buffer, iter->cpu_file); + +mutex_unlock (&trace_types_lock); +return 0 ; +} +static const struct file_operations tracing_buffers_fops = { .open = tracing_buffers_open, .read = tracing_buffers_read, .poll = tracing_buffers_poll, .release = tracing_buffers_release, .splice_read = tracing_buffers_splice_read, + .unlocked_ioctl = tracing_buffers_ioctl, .llseek = no_llseek, };
Greg Kroah-Hartman
maintainerPATCH 162/862 tracing: Do not free snapshot if tracer is on cmdline
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit a541a9559bb0a8ecc434de01d3e4826c32e8bb53 upstream.
The ftrace_boot_snapshot and alloc_snapshot cmdline options allocate the snapshot buffer at boot up for use later. The ftrace_boot_snapshot in particular requires the snapshot to be allocated because it will take a snapshot at the end of boot up allowing to see the traces that happened during boot so that it's not lost when user space takes over.
When a tracer is registered (started) there's a path that checks if it requires the snapshot buffer or not, and if it does not and it was allocated it will do a synchronization and free the snapshot buffer.
This is only required if the previous tracer was using it for "max latency" snapshots, as it needs to make sure all max snapshots are complete before freeing. But this is only needed if the previous tracer was using the snapshot buffer for latency (like irqoff tracer and friends). But it does not make sense to free it, if the previous tracer was not using it, and the snapshot was allocated by the cmdline parameters. This basically takes away the point of allocating it in the first place!
Note, the allocated snapshot worked fine for just trace events, but fails when a tracer is enabled on the cmdline.
Further investigation, this goes back even further and it does not require a tracer on the cmdline to fail. Simply enable snapshots and then enable a tracer, and it will remove the snapshot.
--- kernel/trace/trace.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
kernel/trace/trace.c +6 -4
@@ -6428,12 +6428,12 @@ int tracing_set_tracer(struct trace_arraif (tr->current_trace->reset) tr->current_trace->reset (tr); +#ifdef CONFIG_TRACER_MAX_TRACE + had_max_tr = tr->current_trace->use_max_tr; +/* Current trace needs to be nop_trace before synchronize_rcu */ tr->current_trace = &nop_trace; -#ifdef CONFIG_TRACER_MAX_TRACE - had_max_tr = tr->allocated_snapshot; -if (had_max_tr && !t->use_max_tr) {/* * We need to make sure that the update_max_tr sees that
@@ -6446,11 +6446,13 @@ int tracing_set_tracer(struct trace_arra free_snapshot(tr); } -if (t->use_max_tr && !had_max_tr) { +if (t->use_max_tr && !tr->allocated_snapshot) { ret =tracing_alloc_snapshot_instance (tr);if (ret <0 ) goto out; } +#else + tr->current_trace = &nop_trace;#endif if (t->init) {
Greg Kroah-Hartman
maintainerPATCH 163/862 tracing: Move duplicate code of trace_kprobe/eprobe.c into header
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit f1d3cbfaafc10464550c6d3a125f4fc802bbaed5 upstream.
The functions:
fetch_store_strlen_user()
fetch_store_strlen()
fetch_store_string_user()
fetch_store_string()
are identical in both trace_kprobe.c and trace_eprobe.c. Move them into a new header file trace_probe_kernel.h to share it. This code will later be used by the synthetic events as well.
Marked for stable as a fix for a crash in synthetic events requires it.
--- kernel/trace/trace_eprobe.c | 60 +---------------------- kernel/trace/trace_kprobe.c | 60 +---------------------- kernel/trace/trace_probe_kernel.h | 96 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 110 deletions(-) create mode 100644 kernel/trace/trace_probe_kernel.h
kernel/trace/trace_eprobe.c +5 -55
@@ -16,6 +16,7 @@#include "trace_dynevent.h" #include "trace_probe.h" #include "trace_probe_tmpl.h" +#include "trace_probe_kernel.h" #define EPROBE_EVENT_SYSTEM "eprobes"
@@ -453,29 +454,14 @@ NOKPROBE_SYMBOL(process_fetch_insn) static nokprobe_inline intfetch_store_strlen_user (unsigned long addr) { -const void __user *uaddr = (__force const void __user *)addr; - -return strnlen_user_nofault (uaddr,MAX_STRING_SIZE ); +return kern_fetch_store_strlen_user (addr); }/* Return the length of string -- including null terminal byte */ static nokprobe_inline intfetch_store_strlen (unsigned long addr) { -int ret, len =0 ; -u8 c; - -#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE -if (addr <TASK_SIZE ) -return fetch_store_strlen_user (addr); -#endif - -do { - ret =copy_from_kernel_nofault (&c, (u8 *)addr + len,1 ); - len++; - }while (c && ret ==0 && len <MAX_STRING_SIZE ); - -return (ret <0 ) ? ret : len; +return kern_fetch_store_strlen (addr); }/*
@@ -485,21 +471,7 @@ fetch_store_strlen(unsigned long addr) static nokprobe_inline intfetch_store_string_user (unsigned long addr,void *dest,void *base) { -const void __user *uaddr = (__force const void __user *)addr; -int maxlen =get_loc_len (*(u32 *)dest); -void *__dest; -long ret; - -if (unlikely (!maxlen)) -return -ENOMEM ; - - __dest =get_loc_data (dest, base); - - ret =strncpy_from_user_nofault (__dest, uaddr, maxlen); -if (ret >=0 ) - *(u32 *)dest =make_data_loc (ret, __dest - base); - -return ret; +return kern_fetch_store_string_user (addr, dest, base); }/*
@@ -509,29 +481,7 @@ fetch_store_string_user(unsigned long ad static nokprobe_inline intfetch_store_string (unsigned long addr,void *dest,void *base) { -int maxlen =get_loc_len (*(u32 *)dest); -void *__dest; -long ret; - -#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE -if ((unsigned long )addr <TASK_SIZE ) -return fetch_store_string_user (addr, dest, base); -#endif - -if (unlikely (!maxlen)) -return -ENOMEM ; - - __dest =get_loc_data (dest, base); - -/* -* Try to get string again, since the string can be changed while -* probing. -*/ - ret =strncpy_from_kernel_nofault (__dest, (void *)addr, maxlen); -if (ret >=0 ) - *(u32 *)dest =make_data_loc (ret, __dest - base); - -return ret; +return kern_fetch_store_string (addr, dest, base); }static nokprobe_inline int
kernel/trace/trace_kprobe.c +5 -55
90 lines not on this page · raw message
kernel/trace/trace_probe_kernel.h new file +96 -0
96 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 164/862 tracing: Add "(fault)" name injection to kernel probes
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 2e9906f84fc7c99388bb7123ade167250d50f1c0 upstream.
Have the specific functions for kernel probes that read strings to inject the "(fault)" name directly. trace_probes.c does this too (for uprobes) but as the code to read strings are going to be used by synthetic events (and perhaps other utilities), it simplifies the code by making sure those other uses do not need to implement the "(fault)" name injection as well.
--- kernel/trace/trace_probe_kernel.h | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
kernel/trace/trace_probe_kernel.h +25 -6
@@ -2,6 +2,8 @@#ifndef __TRACE_PROBE_KERNEL_H_#define __TRACE_PROBE_KERNEL_H_ +#define FAULT_STRING "(fault)" +/* * This depends on trace_probe.h, but can not include it due to * the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c.
@@ -13,8 +15,16 @@ static nokprobe_inline int kern_fetch_store_strlen_user(unsigned long addr) {const void __user *uaddr = (__force const void __user *)addr; +int ret; -return strnlen_user_nofault (uaddr,MAX_STRING_SIZE ); + ret =strnlen_user_nofault (uaddr,MAX_STRING_SIZE ); +/* +* strnlen_user_nofault returns zero on fault, insert the +* FAULT_STRING when that occurs. +*/ +if (ret <=0 ) +return strlen (FAULT_STRING ) +1 ; +return ret; }/* Return the length of string -- including null terminal byte */
@@ -34,7 +44,18 @@ kern_fetch_store_strlen(unsigned long ad len++; }while (c && ret ==0 && len <MAX_STRING_SIZE ); -return (ret <0 ) ? ret : len; +/* For faults, return enough to hold the FAULT_STRING */ +return (ret <0 ) ?strlen (FAULT_STRING ) +1 : len; +} + +static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base, int len) +{ +if (ret >=0 ) { + *(u32 *)dest =make_data_loc (ret, __dest - base); + }else { +strscpy (__dest,FAULT_STRING , len); + ret =strlen (__dest) +1 ; + } }/*
@@ -55,8 +76,7 @@ kern_fetch_store_string_user(unsigned lo __dest =get_loc_data (dest, base); ret =strncpy_from_user_nofault (__dest, uaddr, maxlen); -if (ret >=0 ) - *(u32 *)dest =make_data_loc (ret, __dest - base); +set_data_loc (ret, dest, __dest, base, maxlen);return ret; }
@@ -87,8 +107,7 @@ kern_fetch_store_string(unsigned long ad* probing. */ ret =strncpy_from_kernel_nofault (__dest, (void *)addr, maxlen); -if (ret >=0 ) - *(u32 *)dest =make_data_loc (ret, __dest - base); +set_data_loc (ret, dest, __dest, base, maxlen);return ret; }
Greg Kroah-Hartman
maintainerPATCH 165/862 tracing: Fix reading strings from synthetic events
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 0934ae9977c27133449b6dd8c6213970e7eece38 upstream.
The follow commands caused a crash:
# cd /sys/kernel/tracing # echo 's:open char file[]' > dynamic_events # echo 'hist:keys=common_pid:file=filename:onchange($file).trace(open,$file)' > events/syscalls/sys_enter_openat/trigger' # echo 1 > events/synthetic/open/enable
BOOM!
The problem is that the synthetic event field "char file[]" will read the value given to it as a string without any memory checks to make sure the address is valid. The above example will pass in the user space address and the sythetic event code will happily call strlen() on it and then strscpy() where either one will cause an oops when accessing user space addresses.
Use the helper functions from trace_kprobe and trace_eprobe that can read strings safely (and actually succeed when the address is from user space and the memory is mapped in).
Now the above can show:
packagekitd-1721 [000] ...2. 104.597170: open: file=/usr/lib/rpm/fileattrs/cmake.attr
in:imjournal-978 [006] ...2. 104.599642: open: file=/var/lib/rsyslog/imjournal.state.tmp
packagekitd-1721 [000] ...2. 104.626308: open: file=/usr/lib/rpm/fileattrs/debuginfo.attr--- kernel/trace/trace_events_synth.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
kernel/trace/trace_events_synth.c +17 -6
@@ -17,6 +17,8 @@/* for gfp flag names */ #include <linux/trace_events.h> #include <trace/events/mmflags.h> +#include "trace_probe.h" +#include "trace_probe_kernel.h" #include "trace_synth.h"
@@ -409,6 +411,7 @@ static unsigned int trace_string(struct {unsigned int len =0 ;char *str_field; +int ret;if (is_dynamic) {u32 data_offset;
@@ -417,19 +420,27 @@ static unsigned int trace_string(struct data_offset += event->n_u64 *sizeof (u64); data_offset += data_size; - str_field = (char *)entry + data_offset; - - len =strlen (str_val) +1 ; -strscpy (str_field, str_val, len); + len =kern_fetch_store_strlen ((unsigned long )str_val); data_offset |= len <<16 ; *(u32 *)&entry->fields[*n_u64] = data_offset; + ret =kern_fetch_store_string ((unsigned long )str_val, &entry->fields[*n_u64], entry); + (*n_u64)++; }else { str_field = (char *)&entry->fields[*n_u64]; -strscpy (str_field, str_val,STR_VAR_LEN_MAX ); +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE +if ((unsigned long )str_val <TASK_SIZE ) + ret =strncpy_from_user_nofault (str_field, str_val,STR_VAR_LEN_MAX ); + else +#endif + ret =strncpy_from_kernel_nofault (str_field, str_val,STR_VAR_LEN_MAX ); + +if (ret <0 ) +strcpy (str_field,FAULT_STRING ); + (*n_u64) +=STR_VAR_LEN_MAX /sizeof (u64); }
@@ -462,7 +473,7 @@ static notrace void trace_event_raw_even val_idx = var_ref_idx[field_pos]; str_val = (char *)(long )var_ref_vals[val_idx]; - len =strlen (str_val) +1 ; + len =kern_fetch_store_strlen ((unsigned long )str_val); fields_size += len; }
Greg Kroah-Hartman
maintainerPATCH 166/862 rpmsg: char: Avoid double destroy of default endpoint
In reply to Greg Kroah-HartmanFrom: Shengjiu Wang <[email protected]>
commit 467233a4ac29b215d492843d067a9f091e6bf0c5 upstream.
The rpmsg_dev_remove() in rpmsg_core is the place for releasing this default endpoint.
So need to avoid destroying the default endpoint in rpmsg_chrdev_eptdev_destroy(), this should be the same as rpmsg_eptdev_release(). Otherwise there will be double destroy issue that ept->refcount report warning:
refcount_t: underflow; use-after-free.
Call trace: refcount_warn_saturate+0xf8/0x150 virtio_rpmsg_destroy_ept+0xd4/0xec rpmsg_dev_remove+0x60/0x70
The issue can be reproduced by stopping remoteproc before closing the /dev/rpmsgX.
--- drivers/rpmsg/rpmsg_char.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/rpmsg/rpmsg_char.c +3 -1
@@ -76,7 +76,9 @@ int rpmsg_chrdev_eptdev_destroy(struct dmutex_lock (&eptdev->ept_lock);if (eptdev->ept) { -rpmsg_destroy_ept (eptdev->ept); +/* The default endpoint is released by the rpmsg core */ +if (!eptdev->default_ept) +rpmsg_destroy_ept (eptdev->ept); eptdev->ept =NULL ; }mutex_unlock (&eptdev->ept_lock);
Greg Kroah-Hartman
maintainerPATCH 167/862 thunderbolt: Explicitly enable lane adapter hotplug events at startup
In reply to Greg Kroah-HartmanFrom: Mario Limonciello <[email protected]>
commit 5d2569cb4a65c373896ec0217febdf88739ed295 upstream.
Software that has run before the USB4 CM in Linux runs may have disabled hotplug events for a given lane adapter.
Other CMs such as that one distributed with Windows 11 will enable hotplug events. Do the same thing in the Linux CM which fixes hotplug events on "AMD Pink Sardine".
--- drivers/thunderbolt/switch.c | 24 ++++++++++++++++++++++++ drivers/thunderbolt/tb.h | 1 + drivers/thunderbolt/tb_regs.h | 1 + drivers/thunderbolt/usb4.c | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+)
drivers/thunderbolt/switch.c +24 -0
@@ -2822,6 +2822,26 @@ static void tb_switch_credits_init(structb_sw_info (sw,"failed to determine preferred buffer allocation, using defaults\n" ); } +static int tb_switch_port_hotplug_enable (struct tb_switch *sw) +{ +struct tb_port *port; + +if (tb_switch_is_icm (sw)) +return 0 ; + +tb_switch_for_each_port (sw, port) { +int res; + +if (!port->cap_usb4) +continue ; + + res =usb4_port_hotplug_enable (port); +if (res) +return res; + } +return 0 ; +} +/** * tb_switch_add() - Add a switch to the domain * @sw: Switch to add
@@ -2891,6 +2911,10 @@ int tb_switch_add(struct tb_switch *sw)return ret; } + ret =tb_switch_port_hotplug_enable (sw); +if (ret) +return ret; + ret =device_add (&sw->dev);if (ret) {dev_err (&sw->dev,"failed to add device: %d\n" , ret);
drivers/thunderbolt/tb.h +1 -0
@@ -1174,6 +1174,7 @@ int usb4_switch_add_ports(struct tb_switvoid usb4_switch_remove_ports (struct tb_switch *sw);int usb4_port_unlock (struct tb_port *port); +int usb4_port_hotplug_enable (struct tb_port *port);int usb4_port_configure (struct tb_port *port);void usb4_port_unconfigure (struct tb_port *port);int usb4_port_configure_xdomain (struct tb_port *port);
drivers/thunderbolt/tb_regs.h +1 -0
@@ -308,6 +308,7 @@ struct tb_regs_port_header {#define ADP_CS_5 0x05#define ADP_CS_5_LCA_MASK GENMASK(28, 22)#define ADP_CS_5_LCA_SHIFT 22 +#define ADP_CS_5_DHP BIT(31)/* TMU adapter registers */ #define TMU_ADP_CS_3 0x03
drivers/thunderbolt/usb4.c +20 -0
@@ -1046,6 +1046,26 @@ int usb4_port_unlock(struct tb_port *porreturn tb_port_write (port, &val,TB_CFG_PORT ,ADP_CS_4 ,1 ); } +/** +* usb4_port_hotplug_enable() - Enables hotplug for a port +* @port: USB4 port to operate on +* +* Enables hot plug events on a given port. This is only intended +* to be used on lane, DP-IN, and DP-OUT adapters. +*/ +int usb4_port_hotplug_enable (struct tb_port *port) +{ +int ret; +u32 val; + + ret =tb_port_read (port, &val,TB_CFG_PORT ,ADP_CS_5 ,1 ); +if (ret) +return ret; + + val &= ~ADP_CS_5_DHP ; +return tb_port_write (port, &val,TB_CFG_PORT ,ADP_CS_5 ,1 ); +} +static int usb4_port_set_configured (struct tb_port *port,bool configured) {int ret;
Greg Kroah-Hartman
maintainerPATCH 168/862 efi: libstub: drop pointless get_memory_map() call
In reply to Greg Kroah-HartmanFrom: Ard Biesheuvel <[email protected]>
commit d80ca810f096ff66f451e7a3ed2f0cd9ef1ff519 upstream.
Currently, the non-x86 stub code calls get_memory_map() redundantly, given that the data it returns is never used anywhere. So drop the call.
--- drivers/firmware/efi/libstub/fdt.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/firmware/efi/libstub/fdt.c +0 -8
@@ -280,14 +280,6 @@ efi_status_t allocate_new_fdt_and_exit_b goto fail; } -/* -* Now that we have done our final memory allocation (and free) -* we can get the memory map key needed for exit_boot_services(). -*/ - status =efi_get_memory_map (&map); -if (status !=EFI_SUCCESS ) - goto fail_free_new_fdt; - status =update_fdt ((void *)fdt_addr, fdt_size, (void *)*new_fdt_addr,MAX_FDT_SIZE , cmdline_ptr, initrd_addr, initrd_size);
Greg Kroah-Hartman
maintainerPATCH 169/862 media: cedrus: Fix watchdog race condition
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit fe8b81fde69acfcbb5af9e85328e5b9549999fdb upstream.
The watchdog needs to be scheduled before we trigger the decode operation, otherwise there is a risk that the decoder IRQ will be called before we have schedule the watchdog. As a side effect, the watchdog would never be cancelled and its function would be called at an inappropriate time.
This was observed while running Fluster with GStreamer as a backend. Some programming error would cause the decoder IRQ to be call very quickly after the trigger. Later calls into the driver would deadlock due to the unbalanced state.
--- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/media/sunxi/cedrus/cedrus_dec.c +2 -2
@@ -106,11 +106,11 @@ void cedrus_device_run(void *priv)/* Trigger decoding if setup went well, bail out otherwise. */ if (!error) { - dev->dec_ops[ctx->current_codec]->trigger (ctx); -/* Start the watchdog timer. */ schedule_delayed_work (&dev->watchdog_work,msecs_to_jiffies (2000 )); + + dev->dec_ops[ctx->current_codec]->trigger (ctx); }else { v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
Greg Kroah-Hartman
maintainerPATCH 170/862 media: cedrus: Set the platform driver data earlier
In reply to Greg Kroah-HartmanFrom: Dmitry Osipenko <[email protected]>
commit 708938f8495147fe2e77a9a3e1015d8e6899323e upstream.
The cedrus_hw_resume() crashes with NULL deference on driver probe if runtime PM is disabled because it uses platform data that hasn't been set up yet. Fix this by setting the platform data earlier during probe.
--- drivers/staging/media/sunxi/cedrus/cedrus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/media/sunxi/cedrus/cedrus.c +2 -2
@@ -448,6 +448,8 @@ static int cedrus_probe(struct platform_if (!dev)return -ENOMEM ; +platform_set_drvdata (pdev, dev); + dev->vfd = cedrus_video_device; dev->dev = &pdev->dev; dev->pdev = pdev;
@@ -521,8 +523,6 @@ static int cedrus_probe(struct platform_ goto err_m2m_mc; } -platform_set_drvdata (pdev, dev); -return 0 ; err_m2m_mc:
Greg Kroah-Hartman
maintainerPATCH 171/862 media: cedrus: Fix endless loop in cedrus_h265_skip_bits()
In reply to Greg Kroah-HartmanFrom: Dmitry Osipenko <[email protected]>
commit 91db7a3fc7fe670cf1770a398a43bb4a1f776bf1 upstream.
The busy status bit may never de-assert if number of programmed skip bits is incorrect, resulting in a kernel hang because the bit is polled endlessly in the code. Fix it by adding timeout for the bit-polling. This problem is reproducible by setting the data_bit_offset field of the HEVC slice params to a wrong value by userspace.
--- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/staging/media/sunxi/cedrus/cedrus_h265.c +3 -2
@@ -234,8 +234,9 @@ static void cedrus_h265_skip_bits(structcedrus_write (dev,VE_DEC_H265_TRIGGER ,VE_DEC_H265_TRIGGER_FLUSH_BITS |VE_DEC_H265_TRIGGER_TYPE_N_BITS (tmp)); -while (cedrus_read (dev,VE_DEC_H265_STATUS ) &VE_DEC_H265_STATUS_VLD_BUSY ) -udelay (1 ); + +if (cedrus_wait_for (dev,VE_DEC_H265_STATUS ,VE_DEC_H265_STATUS_VLD_BUSY )) +dev_err_ratelimited (dev->dev,"timed out waiting to skip bits\n" ); count += tmp; }
Greg Kroah-Hartman
maintainerPATCH 172/862 blk-throttle: fix that io throttle can only work for single bio
In reply to Greg Kroah-HartmanFrom: Yu Kuai <[email protected]>
commit 320fb0f91e55ba248d4bad106b408e59099cfa89 upstream.
Test scripts:
cd /sys/fs/cgroup/blkio/
echo "8:0 1024" > blkio.throttle.write_bps_device echo $$ > cgroup.procs
dd if=/dev/zero of=/dev/sda bs=10k count=1 oflag=direct & dd if=/dev/zero of=/dev/sda bs=10k count=1 oflag=direct &
Test result:
10240 bytes (10 kB, 10 KiB) copied, 10.0134 s, 1.0 kB/s 10240 bytes (10 kB, 10 KiB) copied, 10.0135 s, 1.0 kB/s
The problem is that the second bio is finished after 10s instead of 20s.
Root cause:
1) second bio will be flagged:
__blk_throtl_bio
while (true) {
...
if (sq->nr_queued[rw]) -> some bio is throttled already
break
};
bio_set_flag(bio, BIO_THROTTLED); -> flag the bio
2) flagged bio will be dispatched without waiting:
throtl_dispatch_tg
tg_may_dispatch
tg_with_in_bps_limit
if (bps_limit == U64_MAX || bio_flagged(bio, BIO_THROTTLED))
*wait = 0; -> wait time is zero
return true;commit 9f5ede3c01f9 ("block: throttle split bio in case of iops limit") support to count split bios for iops limit, thus it adds flagged bio checking in tg_with_in_bps_limit() so that split bios will only count once for bps limit, however, it introduce a new problem that io throttle won't work if multiple bios are throttled.
In order to fix the problem, handle iops/bps limit in different ways:
1) for iops limit, there is no flag to record if the bio is throttled, and iops is always applied.
2) for bps limit, original bio will be flagged with BIO_BPS_THROTTLED, and io throttle will ignore bio with the flag.
Noted this patch also remove the code to set flag in __bio_clone(), it's introduced in commit 111be8839817 ("block-throttle: avoid double charge"), and author thinks split bio can be resubmited and throttled again, which is wrong because split bio will continue to dispatch from caller.
--- block/bio.c | 2 -- block/blk-throttle.c | 20 ++++++-------------- block/blk-throttle.h | 2 +- include/linux/bio.h | 2 +- include/linux/blk_types.h | 2 +- 5 files changed, 9 insertions(+), 19 deletions(-)
block/bio.c +0 -2
@@ -760,8 +760,6 @@ EXPORT_SYMBOL(bio_put);static int __bio_clone (struct bio *bio,struct bio *bio_src,gfp_t gfp) {bio_set_flag (bio,BIO_CLONED ); -if (bio_flagged (bio_src,BIO_THROTTLED )) -bio_set_flag (bio,BIO_THROTTLED ); bio->bi_ioprio = bio_src->bi_ioprio; bio->bi_iter = bio_src->bi_iter;
block/blk-throttle.c +6 -14
@@ -811,7 +811,7 @@ static bool tg_with_in_bps_limit(structunsigned int bio_size =throtl_bio_data_size (bio);/* no need to throttle if this bio's bytes have been accounted */ -if (bps_limit ==U64_MAX ||bio_flagged (bio,BIO_THROTTLED )) { +if (bps_limit ==U64_MAX ||bio_flagged (bio,BIO_BPS_THROTTLED )) {if (wait) *wait =0 ;return true;
@@ -921,22 +921,13 @@ static void throtl_charge_bio(struct thrunsigned int bio_size =throtl_bio_data_size (bio);/* Charge the bio to the group */ -if (!bio_flagged (bio,BIO_THROTTLED )) { +if (!bio_flagged (bio,BIO_BPS_THROTTLED )) { tg->bytes_disp[rw] += bio_size; tg->last_bytes_disp[rw] += bio_size; } tg->io_disp[rw]++; tg->last_io_disp[rw]++; - -/* -* BIO_THROTTLED is used to prevent the same bio to be throttled -* more than once as a throttled bio will go through blk-throtl the -* second time when it eventually gets issued. Set it when a bio -* is being charged to a tg. -*/ -if (!bio_flagged (bio,BIO_THROTTLED )) -bio_set_flag (bio,BIO_THROTTLED ); }/**
@@ -1026,6 +1017,7 @@ static void tg_dispatch_one_bio(struct t sq->nr_queued[rw]--;throtl_charge_bio (tg, bio); +bio_set_flag (bio,BIO_BPS_THROTTLED );/* * If our parent is another tg, we just need to transfer @bio to
@@ -2159,8 +2151,10 @@ again: qn = &tg->qnode_on_parent[rw]; sq = sq->parent_sq; tg =sq_to_tg (sq); -if (!tg) +if (!tg) { +bio_set_flag (bio,BIO_BPS_THROTTLED ); goto out_unlock; + } }/* out-of-limit, queue to @tg */
@@ -2189,8 +2183,6 @@ again: } out_unlock: -bio_set_flag (bio,BIO_THROTTLED ); -#ifdef CONFIG_BLK_DEV_THROTTLING_LOW if (throttled || !td->track_bio_latency) bio->bi_issue.value |=BIO_ISSUE_THROTL_SKIP_LATENCY ;
block/blk-throttle.h +1 -1
@@ -175,7 +175,7 @@ static inline bool blk_throtl_bio(structstruct throtl_grp *tg =blkg_to_tg (bio->bi_blkg);/* no need to throttle bps any more if the bio has been throttled */ -if (bio_flagged (bio,BIO_THROTTLED ) && +if (bio_flagged (bio,BIO_BPS_THROTTLED ) && !(tg->flags &THROTL_TG_HAS_IOPS_LIMIT ))return false;
include/linux/bio.h +1 -1
@@ -509,7 +509,7 @@ static inline void bio_set_dev(struct bi {bio_clear_flag (bio,BIO_REMAPPED );if (bio->bi_bdev != bdev) -bio_clear_flag (bio,BIO_THROTTLED ); +bio_clear_flag (bio,BIO_BPS_THROTTLED ); bio->bi_bdev = bdev;bio_associate_blkg (bio); }
include/linux/blk_types.h +1 -1
@@ -325,7 +325,7 @@ enum {BIO_QUIET ,/* Make BIO Quiet */ BIO_CHAIN ,/* chained bio, ->bi_remaining in effect */ BIO_REFFED ,/* bio has elevated ->bi_cnt */ -BIO_THROTTLED ,/* This bio has already been subjected to +BIO_BPS_THROTTLED ,/* This bio has already been subjected to * throttling rules. Don't do it again. */ BIO_TRACE_COMPLETION, /* bio_endio() should trace the final completion* of this bio. */
Greg Kroah-Hartman
maintainerPATCH 173/862 blk-wbt: call rq_qos_add() after wb_normal is initialized
In reply to Greg Kroah-HartmanFrom: Yu Kuai <[email protected]>
commit 8c5035dfbb9475b67c82b3fdb7351236525bf52b upstream.
Our test found a problem that wbt inflight counter is negative, which will cause io hang(noted that this problem doesn't exist in mainline):
t1: device create t2: issue ioadd_disk
blk_register_queue
wbt_enable_default
wbt_init
rq_qos_add
// wb_normal is still 0
/*
* in mainline, disk can't be opened before
* bdev_add(), however, in old kernels, disk
* can be opened before blk_register_queue().
*/
blkdev_issue_flush
// disk size is 0, however, it's not checked
submit_bio_wait
submit_bio
blk_mq_submit_bio
rq_qos_throttle
wbt_wait
bio_to_wbt_flags
rwb_enabled
// wb_normal is 0, inflight is not increased
wbt_queue_depth_changed(&rwb->rqos);
wbt_update_limits
// wb_normal is initialized
rq_qos_track
wbt_track
rq->wbt_flags |= bio_to_wbt_flags(rwb, bio);
// wb_normal is not 0,wbt_flags will be sett3: io completionblk_mq_free_request
rq_qos_done
wbt_done
wbt_is_tracked
// return true
__wbt_done
wbt_rqw_done
atomic_dec_return(&rqw->inflight);
// inflight is decreasedcommit 8235b5c1e8c1 ("block: call bdev_add later in device_add_disk") can avoid this problem, however it's better to fix this problem in wbt:
1) Lower kernel can't backport this patch due to lots of refactor.
2) Root cause is that wbt call rq_qos_add() before wb_normal is initialized.
--- block/blk-wbt.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
block/blk-wbt.c +4 -5
@@ -843,6 +843,10 @@ int wbt_init(struct request_queue *q) rwb->enable_state =WBT_STATE_ON_DEFAULT ; rwb->wc =1 ; rwb->rq_depth.default_depth =RWB_DEF_DEPTH ; + rwb->min_lat_nsec =wbt_default_latency_nsec (q); + +wbt_queue_depth_changed (&rwb->rqos); +wbt_set_write_cache (q,test_bit (QUEUE_FLAG_WC , &q->queue_flags));/* * Assign rwb and add the stats callback.
@@ -853,11 +857,6 @@ int wbt_init(struct request_queue *q)blk_stat_add_callback (q, rwb->cb); - rwb->min_lat_nsec =wbt_default_latency_nsec (q); - -wbt_queue_depth_changed (&rwb->rqos); -wbt_set_write_cache (q,test_bit (QUEUE_FLAG_WC , &q->queue_flags)); -return 0 ; err_free:
Greg Kroah-Hartman
maintainerPATCH 174/862 KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
In reply to Greg Kroah-HartmanFrom: Michal Luczaj <[email protected]>
commit 6aa5c47c351b22c21205c87977c84809cd015fcf upstream.
The emulator checks the wrong variable while setting the CPU interruptibility state, the target segment is embedded in the instruction opcode, not the ModR/M register. Fix the condition.
--- arch/x86/kvm/emulate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/emulate.c +1 -1
@@ -1953,7 +1953,7 @@ static int em_pop_sreg(struct x86_emulatif (rc !=X86EMUL_CONTINUE )return rc; -if (ctxt->modrm_reg ==VCPU_SREG_SS ) +if (seg ==VCPU_SREG_SS ) ctxt->interruptibility =KVM_X86_SHADOW_INT_MOV_SS ;if (ctxt->op_bytes >2 )rsp_increment (ctxt, ctxt->op_bytes -2 );
Greg Kroah-Hartman
maintainerPATCH 175/862 KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit d953540430c5af57f5de97ea9e36253908204027 upstream.
Drop pending exceptions and events queued for re-injection when leaving nested guest mode, even if the "exit" is due to VM-Fail, SMI, or forced by host userspace. Failure to purge events could result in an event belonging to L2 being injected into L1.
This _should_ never happen for VM-Fail as all events should be blocked by nested_run_pending, but it's possible if KVM, not the L1 hypervisor, is the source of VM-Fail when running vmcs02.
SMI is a nop (barring unknown bugs) as recognition of SMI and thus entry to SMM is blocked by pending exceptions and re-injected events.
Forced exit is definitely buggy, but has likely gone unnoticed because userspace probably follows the forced exit with KVM_SET_VCPU_EVENTS (or some other ioctl() that purges the queue).
--- arch/x86/kvm/vmx/nested.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
arch/x86/kvm/vmx/nested.c +11 -8
@@ -4255,14 +4255,6 @@ static void prepare_vmcs12(struct kvm_vcnested_vmx_abort (vcpu,VMX_ABORT_SAVE_GUEST_MSR_FAIL ); } - -/* -* Drop what we picked up for L2 via vmx_complete_interrupts. It is -* preserved above and would only end up incorrectly in L1. -*/ - vcpu->arch.nmi_injected = false; -kvm_clear_exception_queue (vcpu); -kvm_clear_interrupt_queue (vcpu); }/*
@@ -4602,6 +4594,17 @@ void nested_vmx_vmexit(struct kvm_vcpu *WARN_ON_ONCE (nested_early_check); } +/* +* Drop events/exceptions that were queued for re-injection to L2 +* (picked up via vmx_complete_interrupts()), as well as exceptions +* that were pending for L2. Note, this must NOT be hoisted above +* prepare_vmcs12(), events/exceptions queued for re-injection need to +* be captured in vmcs12 (see vmcs12_save_pending_event()). +*/ + vcpu->arch.nmi_injected = false; +kvm_clear_exception_queue (vcpu); +kvm_clear_interrupt_queue (vcpu); +vmx_switch_vmcs (vcpu, &vmx->vmcs01);/* Update any VMCS fields that might have changed while L2 ran */
Greg Kroah-Hartman
maintainerPATCH 176/862 KVM: nVMX: Dont propagate vmcs12s PERF_GLOBAL_CTRL settings to vmcs02
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit def9d705c05eab3fdedeb10ad67907513b12038e upstream.
Don't propagate vmcs12's VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL to vmcs02. KVM doesn't disallow L1 from using VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL even when KVM itself doesn't use the control, e.g. due to the various CPU errata that where the MSR can be corrupted on VM-Exit.
Preserve KVM's (vmcs01) setting to hopefully avoid having to toggle the bit in vmcs02 at a later point. E.g. if KVM is loading PERF_GLOBAL_CTRL when running L1, then odds are good KVM will also load the MSR when running L2.
--- arch/x86/kvm/vmx/nested.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +6 -1
@@ -2328,9 +2328,14 @@ static void prepare_vmcs02_early(struct* are emulated by vmx_set_efer() in prepare_vmcs02(), but speculate * on the related bits (if supported by the CPU) in the hope that * we can avoid VMWrites during vmx_set_efer(). +* +* Similarly, take vmcs01's PERF_GLOBAL_CTRL in the hope that if KVM is +* loading PERF_GLOBAL_CTRL via the VMCS for L1, then KVM will want to +* do the same for L2. */ exec_control =__vm_entry_controls_get (vmcs01); - exec_control |= vmcs12->vm_entry_controls; + exec_control |= (vmcs12->vm_entry_controls & + ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ); exec_control &= ~(VM_ENTRY_IA32E_MODE |VM_ENTRY_LOAD_IA32_EFER );if (cpu_has_load_ia32_efer ()) {if (guest_efer &EFER_LMA )
Greg Kroah-Hartman
maintainerPATCH 177/862 KVM: x86: Treat #DBs from the emulator as fault-like (code and DR7.GD=1)
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 5623f751bd9c438ed12840e086f33c4646440d19 upstream.
Add a dedicated "exception type" for #DBs, as #DBs can be fault-like or trap-like depending the sub-type of #DB, and effectively defer the decision of what to do with the #DB to the caller.
For the emulator's two calls to exception_type(), treat the #DB as fault-like, as the emulator handles only code breakpoint and general detect #DBs, both of which are fault-like.
For event injection, which uses exception_type() to determine whether to set EFLAGS.RF=1 on the stack, keep the current behavior of not setting RF=1 for #DBs. Intel and AMD explicitly state RF isn't set on code #DBs, so exempting by failing the "== EXCPT_FAULT" check is correct. The only other fault-like #DB is General Detect, and despite Intel and AMD both strongly implying (through omission) that General Detect #DBs should set RF=1, hardware (multiple generations of both Intel and AMD), in fact does not. Through insider knowledge, extreme foresight, sheer dumb luck, or some combination thereof, KVM correctly handled RF for General Detect #DBs.
--- arch/x86/kvm/x86.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +25 -2
@@ -528,6 +528,7 @@ static int exception_class(int vector)#define EXCPT_TRAP 1#define EXCPT_ABORT 2#define EXCPT_INTERRUPT 3 +#define EXCPT_DB 4static int exception_type (int vector) {
@@ -538,8 +539,14 @@ static int exception_type(int vector) mask =1 << vector; -/* #DB is trap, as instruction watchpoints are handled elsewhere */ -if (mask & ((1 <<DB_VECTOR ) | (1 <<BP_VECTOR ) | (1 <<OF_VECTOR ))) +/* +* #DBs can be trap-like or fault-like, the caller must check other CPU +* state, e.g. DR6, to determine whether a #DB is a trap or fault. +*/ +if (mask & (1 <<DB_VECTOR )) +return EXCPT_DB ; + +if (mask & ((1 <<BP_VECTOR ) | (1 <<OF_VECTOR )))return EXCPT_TRAP ;if (mask & ((1 <<DF_VECTOR ) | (1 <<MC_VECTOR )))
@@ -8801,6 +8808,12 @@ writeback:unsigned long rflags =static_call (kvm_x86_get_rflags)(vcpu);toggle_interruptibility (vcpu, ctxt->interruptibility); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; + +/* +* Note, EXCPT_DB is assumed to be fault-like as the emulator +* only supports code breakpoints and general detect #DB, both +* of which are fault-like. +*/ if (!ctxt->have_exception ||exception_type (ctxt->exception.vector) ==EXCPT_TRAP ) {kvm_pmu_trigger_event (vcpu,PERF_COUNT_HW_INSTRUCTIONS );
@@ -9724,6 +9737,16 @@ static int inject_pending_event(struct k/* try to inject new event if pending */ if (vcpu->arch.exception.pending) { +/* +* Fault-class exceptions, except #DBs, set RF=1 in the RFLAGS +* value pushed on the stack. Trap-like exception and all #DBs +* leave RF as-is (KVM follows Intel's behavior in this regard; +* AMD states that code breakpoint #DBs excplitly clear RF=0). +* +* Note, most versions of Intel's SDM and AMD's APM incorrectly +* describe the behavior of General Detect #DBs, which are +* fault-like. They do _not_ set RF, a la code breakpoints. +*/ if (exception_type (vcpu->arch.exception.nr) ==EXCPT_FAULT )__kvm_set_rflags (vcpu,kvm_get_rflags (vcpu) |X86_EFLAGS_RF );
Greg Kroah-Hartman
maintainerPATCH 178/862 KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit eba9799b5a6efe2993cf92529608e4aa8163d73b upstream.
Deliberately truncate the exception error code when shoving it into the VMCS (VM-Entry field for vmcs01 and vmcs02, VM-Exit field for vmcs12). Intel CPUs are incapable of handling 32-bit error codes and will never generate an error code with bits 31:16, but userspace can provide an arbitrary error code via KVM_SET_VCPU_EVENTS. Failure to drop the bits on exception injection results in failed VM-Entry, as VMX disallows setting bits 31:16. Setting the bits on VM-Exit would at best confuse L1, and at worse induce a nested VM-Entry failure, e.g. if L1 decided to reinject the exception back into L2.
--- arch/x86/kvm/vmx/nested.c | 11 ++++++++++- arch/x86/kvm/vmx/vmx.c | 12 +++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/nested.c +10 -1
@@ -3832,7 +3832,16 @@ static void nested_vmx_inject_exception_u32 intr_info = nr |INTR_INFO_VALID_MASK ;if (vcpu->arch.exception.has_error_code) { - vmcs12->vm_exit_intr_error_code = vcpu->arch.exception.error_code; +/* +* Intel CPUs do not generate error codes with bits 31:16 set, +* and more importantly VMX disallows setting bits 31:16 in the +* injected error code for VM-Entry. Drop the bits to mimic +* hardware and avoid inducing failure on nested VM-Entry if L1 +* chooses to inject the exception back to L2. AMD CPUs _do_ +* generate "full" 32-bit error codes, so KVM allows userspace +* to inject exception error codes with bits 31:16 set. +*/ + vmcs12->vm_exit_intr_error_code = (u16 )vcpu->arch.exception.error_code; intr_info |=INTR_INFO_DELIVER_CODE_MASK ; }
arch/x86/kvm/vmx/vmx.c +11 -1
@@ -1695,7 +1695,17 @@ static void vmx_queue_exception(struct kkvm_deliver_exception_payload (vcpu);if (has_error_code) { -vmcs_write32 (VM_ENTRY_EXCEPTION_ERROR_CODE , error_code); +/* +* Despite the error code being architecturally defined as 32 +* bits, and the VMCS field being 32 bits, Intel CPUs and thus +* VMX don't actually supporting setting bits 31:16. Hardware +* will (should) never provide a bogus error code, but AMD CPUs +* do generate error codes with bits 31:16 set, and so KVM's +* ABI lets userspace shove in arbitrary 32-bit values. Drop +* the upper bits to avoid VM-Fail, losing information that +* does't really exist is preferable to killing the VM. +*/ +vmcs_write32 (VM_ENTRY_EXCEPTION_ERROR_CODE , (u16 )error_code); intr_info |=INTR_INFO_DELIVER_CODE_MASK ; }
Greg Kroah-Hartman
maintainerPATCH 179/862 staging: greybus: audio_helper: remove unused and wrong debugfs usage
In reply to Greg Kroah-HartmanFrom: Greg Kroah-Hartman <[email protected]>
commit d517cdeb904ddc0cbebcc959d43596426cac40b0 upstream.
In the greybus audio_helper code, the debugfs file for the dapm has the potential to be removed and memory will be leaked. There is also the very real potential for this code to remove ALL debugfs entries from the system, and it seems like this is what will really happen if this code ever runs. This all is very wrong as the greybus audio driver did not create this debugfs file, the sound core did and controls the lifespan of it.
So remove all of the debugfs logic from the audio_helper code as there's no way it could be correct. If this really is needed, it can come back with a fixup for the incorrect usage of the debugfs_lookup() call which is what caused this to be noticed at all.
--- drivers/staging/greybus/audio_helper.c | 11 ----------- 1 file changed, 11 deletions(-)
drivers/staging/greybus/audio_helper.c +0 -11
@@ -3,7 +3,6 @@* Greybus Audio Sound SoC helper APIs */ -#include <linux/debugfs.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h>
@@ -116,10 +115,6 @@ int gbaudio_dapm_free_controls(struct sn {int i;struct snd_soc_dapm_widget *w, *tmp_w; -#ifdef CONFIG_DEBUG_FS -struct dentry *parent = dapm->debugfs_dapm; -struct dentry *debugfs_w =NULL ; -#endif mutex_lock (&dapm->card->dapm_mutex);for (i =0 ; i < num; i++) {
@@ -139,12 +134,6 @@ int gbaudio_dapm_free_controls(struct sncontinue ; } widget++; -#ifdef CONFIG_DEBUG_FS -if (!parent) - debugfs_w =debugfs_lookup (w->name, parent); -debugfs_remove (debugfs_w); - debugfs_w =NULL ; -#endif gbaudio_dapm_free_widget (w); }mutex_unlock (&dapm->card->dapm_mutex);
Greg Kroah-Hartman
maintainerPATCH 180/862 drm/nouveau/kms/nv140-: Disable interlacing
In reply to Greg Kroah-HartmanFrom: Lyude Paul <[email protected]>
commit 8ba9249396bef37cb68be9e8dee7847f1737db9d upstream.
As it turns out: while Nvidia does actually have interlacing knobs on their GPU still pretty much no current GPUs since Volta actually support it. Trying interlacing on these GPUs will result in NVDisplay being quite unhappy like so:
nouveau 0000:1f:00.0: disp: chid 0 stat 00004802 reason 4 [INVALID_ARG] mthd 2008 data 00000001 code 00080000 nouveau 0000:1f:00.0: disp: chid 0 stat 10005080 reason 5 [INVALID_STATE] mthd 0200 data 00000001 code 00000001
So let's fix this by following the same behavior Nvidia's driver does and disable interlacing entirely.
--- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_connector.c +2 -1
@@ -504,7 +504,8 @@ nouveau_connector_set_encoder(struct drm connector->interlace_allowed = nv_encoder->caps.dp_interlace; else - connector->interlace_allowed = true; + connector->interlace_allowed = + drm->client.device.info.family <NV_DEVICE_INFO_V0_VOLTA ; connector->doublescan_allowed = true; }else if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
Greg Kroah-Hartman
maintainerPATCH 181/862 drm/nouveau: fix a use-after-free in nouveau_gem_prime_import_sg_table()
In reply to Greg Kroah-HartmanFrom: Jianglei Nie <[email protected]>
commit 540dfd188ea2940582841c1c220bd035a7db0e51 upstream.
nouveau_bo_init() is backed by ttm_bo_init() and ferries its return code back to the caller. On failures, ttm will call nouveau_bo_del_ttm() and free the memory.Thus, when nouveau_bo_init() returns an error, the gem object has already been released. Then the call to nouveau_bo_ref() will use the freed "nvbo->bo" and lead to a use-after-free bug.
We should delete the call to nouveau_bo_ref() to avoid the use-after-free.
--- drivers/gpu/drm/nouveau/nouveau_prime.c | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_prime.c +0 -1
@@ -71,7 +71,6 @@ struct drm_gem_object *nouveau_gem_prime ret =nouveau_bo_init (nvbo, size, align,NOUVEAU_GEM_DOMAIN_GART , sg, robj);if (ret) { -nouveau_bo_ref (NULL , &nvbo); obj =ERR_PTR (ret); goto unlock; }
Greg Kroah-Hartman
maintainerPATCH 182/862 drm/i915/gt: Use i915_vm_put on ppgtt_create error paths
In reply to Greg Kroah-HartmanFrom: Chris Wilson <[email protected]>
commit 20e377e7b2e7c327039f10db80ba5bcc1f6c882d upstream.
Now that the scratch page and page directories have a reference back to the i915_address_space, we cannot do an immediate free of the ppgtt upon error as those buffer objects will perform a later i915_vm_put in their deferred frees.
The downside is that by replacing the onion unwind along the error paths, the ppgtt cleanup must handle a partially constructed vm. This includes ensuring that the vm->cleanup is set prior to the error path.
--- drivers/gpu/drm/i915/gt/gen6_ppgtt.c | 16 ++++----- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 58 ++++++++++++++++++----------------- drivers/gpu/drm/i915/gt/intel_gtt.c | 3 + 3 files changed, 41 insertions(+), 36 deletions(-)
drivers/gpu/drm/i915/gt/gen6_ppgtt.c +8 -8
@@ -247,6 +247,7 @@ err_scratch1:i915_gem_object_put (vm->scratch[1 ]); err_scratch0:i915_gem_object_put (vm->scratch[0 ]); + vm->scratch[0 ] =NULL ;return ret; }
@@ -268,9 +269,10 @@ static void gen6_ppgtt_cleanup(struct i9gen6_ppgtt_free_pd (ppgtt);free_scratch (vm); -mutex_destroy (&ppgtt->flush); +if (ppgtt->base.pd) +free_pd (&ppgtt->base.vm, ppgtt->base.pd); -free_pd (&ppgtt->base.vm, ppgtt->base.pd); +mutex_destroy (&ppgtt->flush); } static void pd_vma_bind(struct i915_address_space *vm,
@@ -449,19 +451,17 @@ struct i915_ppgtt *gen6_ppgtt_create(str err =gen6_ppgtt_init_scratch (ppgtt);if (err) - goto err_free; + goto err_put; ppgtt->base.pd =gen6_alloc_top_pd (ppgtt);if (IS_ERR (ppgtt->base.pd)) { err =PTR_ERR (ppgtt->base.pd); - goto err_scratch; + goto err_put; }return &ppgtt->base; -err_scratch: -free_scratch (&ppgtt->base.vm); -err_free: -kfree (ppgtt); +err_put: +i915_vm_put (&ppgtt->base.vm);return ERR_PTR (err); }
drivers/gpu/drm/i915/gt/gen8_ppgtt.c +30 -28
101 lines not on this page · raw message
drivers/gpu/drm/i915/gt/intel_gtt.c +3 -0
@@ -405,6 +405,9 @@ void free_scratch(struct i915_address_sp {int i; +if (!vm->scratch[0 ]) +return ; +for (i =0 ; i <= vm->top; i++)i915_gem_object_put (vm->scratch[i]); }
Greg Kroah-Hartman
maintainerPATCH 183/862 drm/i915/guc: Fix revocation of non-persistent contexts
In reply to Greg Kroah-HartmanFrom: Tvrtko Ursulin <[email protected]>
commit 7023472834a39341460dae5c9b506c76c5940cad upstream.
Patch which added graceful exit for non-persistent contexts missed the fact it is not enough to set the exiting flag on a context and let the backend handle it from there.
GuC backend cannot handle it because it runs independently in the firmware and driver might not see the requests ever again. Patch also missed the fact some usages of intel_context_is_banned in the GuC backend needed replacing with newly introduced intel_context_is_schedulable.
Fix the first issue by calling into backend revoke when we know this is the last chance to do it. Fix the second issue by replacing intel_context_is_banned with intel_context_is_schedulable, which should always be safe since latter is a superset of the former.
v2:
* Just call ce->ops->revoke unconditionally. (Andrzej)
--- drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ------ drivers/gpu/drm/i915/gt/intel_context.c | 5 +--- drivers/gpu/drm/i915/gt/intel_context.h | 3 -- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 26 +++++++++++----------- 4 files changed, 17 insertions(+), 25 deletions(-)
drivers/gpu/drm/i915/gem/i915_gem_context.c +1 -7
@@ -1387,14 +1387,8 @@ kill_engines(struct i915_gem_engines *en*/ for_each_gem_engine (ce, engines, it) {struct intel_engine_cs *engine; -bool skip = false; -if (exit) - skip =intel_context_set_exiting (ce); -else if (!persistent) - skip =intel_context_exit_nonpersistent (ce,NULL ); - -if (skip) +if ((exit || !persistent) &&intel_context_revoke (ce))continue ;/* Already marked. */ /*
drivers/gpu/drm/i915/gt/intel_context.c +2 -3
@@ -614,13 +614,12 @@ bool intel_context_ban(struct intel_contreturn ret; } -bool intel_context_exit_nonpersistent (struct intel_context *ce, -struct i915_request *rq) +bool intel_context_revoke (struct intel_context *ce) {bool ret =intel_context_set_exiting (ce);if (ce->ops->revoke) - ce->ops->revoke (ce, rq, ce->engine->props.preempt_timeout_ms); + ce->ops->revoke (ce,NULL , ce->engine->props.preempt_timeout_ms);return ret; }
drivers/gpu/drm/i915/gt/intel_context.h +1 -2
@@ -329,8 +329,7 @@ static inline bool intel_context_set_exireturn test_and_set_bit (CONTEXT_EXITING , &ce->flags); } -bool intel_context_exit_nonpersistent (struct intel_context *ce, -struct i915_request *rq); +bool intel_context_revoke (struct intel_context *ce);static inline bool intel_context_force_single_submission (const struct intel_context *ce)
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +13 -13
@@ -684,7 +684,7 @@ static int __guc_add_request(struct inte* Corner case where requests were sitting in the priority list or a * request resubmitted after the context was banned. */ -if (unlikely (intel_context_is_banned (ce))) { +if (unlikely (!intel_context_is_schedulable (ce))) {i915_request_put (i915_request_mark_eio (rq));intel_engine_signal_breadcrumbs (ce->engine);return 0 ;
@@ -870,15 +870,15 @@ static int guc_wq_item_append(struct int struct i915_request *rq) {struct intel_context *ce =request_to_scheduling_context (rq); -int ret =0 ; +int ret; -if (likely (!intel_context_is_banned (ce))) { - ret =__guc_wq_item_append (rq); +if (unlikely (!intel_context_is_schedulable (ce))) +return 0 ; -if (unlikely (ret == -EBUSY )) { - guc->stalled_request = rq; - guc->submission_stall_reason =STALL_MOVE_LRC_TAIL ; - } + ret =__guc_wq_item_append (rq); +if (unlikely (ret == -EBUSY )) { + guc->stalled_request = rq; + guc->submission_stall_reason =STALL_MOVE_LRC_TAIL ; }return ret;
@@ -897,7 +897,7 @@ static bool multi_lrc_submit(struct i915* submitting all the requests generated in parallel. */ return test_bit (I915_FENCE_FLAG_SUBMIT_PARALLEL , &rq->fence.flags) || -intel_context_is_banned (ce); + !intel_context_is_schedulable (ce); }static int guc_dequeue_one_context (struct intel_guc *guc)
@@ -966,7 +966,7 @@ register_context:struct intel_context *ce =request_to_scheduling_context (last);if (unlikely (!ctx_id_mapped (guc, ce->guc_id.id) && - !intel_context_is_banned (ce))) { +intel_context_is_schedulable (ce))) { ret =try_context_registration (ce, false);if (unlikely (ret == -EPIPE )) { goto deadlk;
@@ -1576,7 +1576,7 @@ static void guc_reset_state(struct intel {struct intel_engine_cs *engine =__context_to_physical_engine (ce); -if (intel_context_is_banned (ce)) +if (!intel_context_is_schedulable (ce))return ;GEM_BUG_ON (!intel_context_is_pinned (ce));
@@ -4434,12 +4434,12 @@ static void guc_handle_context_reset(str {trace_intel_context_reset (ce); -if (likely (!intel_context_is_banned (ce))) { +if (likely (intel_context_is_schedulable (ce))) {capture_error_state (guc, ce);guc_context_replay (ce); }else {drm_info (&guc_to_gt (guc)->i915->drm, -"Ignoring context reset notification of banned context 0x%04X on %s" , +"Ignoring context reset notification of exiting context 0x%04X on %s" , ce->guc_id.id, ce->engine->name); } }
Greg Kroah-Hartman
maintainerPATCH 184/862 drm/i915: Fix watermark calculations for gen12+ RC CCS modifier
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit c56453a00f19ccddee302f5f9fe96b80e0b47fd3 upstream.
Take the gen12+ RC CCS modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear.
The rc_surface part is actually a nop since that is not used for any glk+ platform.
v2: Split RC CCS vs. MC CCS to separate patches
--- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_pm.c +4 -2
@@ -5308,10 +5308,12 @@ skl_compute_wm_params(const struct intel modifier ==I915_FORMAT_MOD_4_TILED || modifier == I915_FORMAT_MOD_Yf_TILED || modifier ==I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; + modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ; wp->x_tiled = modifier ==I915_FORMAT_MOD_X_TILED ; wp->rc_surface = modifier ==I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; + modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ; wp->is_planar =intel_format_info_is_yuv_semiplanar (format, modifier); wp->width = width;
Greg Kroah-Hartman
maintainerPATCH 185/862 drm/i915: Fix watermark calculations for gen12+ MC CCS modifier
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit 484b2b9281000274ef7c5cb0a9ebc5da6f5c281c upstream.
Take the gen12+ MC CCS modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear.
The rc_surface part is actually a nop since that is not used for any glk+ platform.
v2: Split RC CCS vs. MC CCS to separate patches
--- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_pm.c +4 -2
@@ -5309,11 +5309,13 @@ skl_compute_wm_params(const struct intel modifier == I915_FORMAT_MOD_Yf_TILED || modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ; wp->x_tiled = modifier ==I915_FORMAT_MOD_X_TILED ; wp->rc_surface = modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ; wp->is_planar =intel_format_info_is_yuv_semiplanar (format, modifier); wp->width = width;
Greg Kroah-Hartman
maintainerPATCH 186/862 drm/i915: Fix watermark calculations for gen12+ CCS+CC modifier
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit 070a2855900de17b1e11a0dc35af9794e80f1a28 upstream.
Take the gen12+ CCS+CC modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear.
The rc_surface part is actually a nop since that is not used for any glk+ platform.
--- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_pm.c +4 -2
@@ -5310,12 +5310,14 @@ skl_compute_wm_params(const struct intel modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ; wp->x_tiled = modifier ==I915_FORMAT_MOD_X_TILED ; wp->rc_surface = modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ; wp->is_planar =intel_format_info_is_yuv_semiplanar (format, modifier); wp->width = width;
Greg Kroah-Hartman
maintainerPATCH 187/862 drm/i915: Fix watermark calculations for DG2 CCS modifiers
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit ccfa6d35f9233702c924316cdf40c05b6ce88113 upstream.
Take the DG2 CCS modifiers into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking these tile-4 modifiers are linear.
The rc_surface part is actually a nop since that is not used for any glk+ platform.
--- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_pm.c +6 -2
@@ -5311,13 +5311,17 @@ skl_compute_wm_params(const struct intel modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ; wp->x_tiled = modifier ==I915_FORMAT_MOD_X_TILED ; wp->rc_surface = modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ; + modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ; wp->is_planar =intel_format_info_is_yuv_semiplanar (format, modifier); wp->width = width;
Greg Kroah-Hartman
maintainerPATCH 188/862 drm/i915: Fix watermark calculations for DG2 CCS+CC modifier
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit b2e3a1af8cce4117de06ff1a4eab0749753ede27 upstream.
Take the DG2 CCS+CC modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this tile-4 modifier is linear.
The rc_surface part is actually a nop since that is not used for any glk+ platform.
--- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_pm.c +4 -2
@@ -5313,7 +5313,8 @@ skl_compute_wm_params(const struct intel modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ; + modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC ; wp->x_tiled = modifier ==I915_FORMAT_MOD_X_TILED ; wp->rc_surface = modifier ==I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
@@ -5321,7 +5322,8 @@ skl_compute_wm_params(const struct intel modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || modifier ==I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ; + modifier ==I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || + modifier ==I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC ; wp->is_planar =intel_format_info_is_yuv_semiplanar (format, modifier); wp->width = width;
Greg Kroah-Hartman
maintainerPATCH 189/862 drm/i915: Fix display problems after resume
In reply to Greg Kroah-HartmanFrom: Thomas Hellström <[email protected]>
commit 6c482c62a635aa4f534d2439fbf8afa37452b986 upstream.
Commit 39a2bd34c933 ("drm/i915: Use the vma resource as argument for gtt binding / unbinding") introduced a regression that due to the vma resource tracking of the binding state, dpt ptes were not correctly repopulated. Fix this by clearing the vma resource state before repopulating. The state will subsequently be restored by the bind_vma operation.
--- drivers/gpu/drm/i915/gt/intel_ggtt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_ggtt.c +7 -1
@@ -1267,10 +1267,16 @@ bool i915_ggtt_resume_vm(struct i915_addatomic_read (&vma->flags) &I915_VMA_BIND_MASK ;GEM_BUG_ON (!was_bound); -if (!retained_ptes) +if (!retained_ptes) { +/* +* Clear the bound flags of the vma resource to allow +* ptes to be repopulated. +*/ + vma->resource->bound_flags =0 ; vma->ops->bind_vma (vm,NULL , vma->resource, obj ? obj->cache_level :0 , was_bound); + }if (obj) {/* only used during resume => exclusive access */ write_domain_objs |=fetch_and_zero (&obj->write_domain); obj->read_domains |=I915_GEM_DOMAIN_GTT ;
Greg Kroah-Hartman
maintainerPATCH 190/862 drm/amd/display: Fix watermark calculation
In reply to Greg Kroah-HartmanFrom: Alvin Lee <[email protected]>
commit 9799702360d51a714e888fef4ab5fb9123dfb41f upstream.
Watermark calculation was incorrect due to missing brackets.
--- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +1 -1
@@ -719,7 +719,7 @@ void dc_dmub_setup_subvp_dmub_command(st// Store the original watermark value for this SubVP config so we can lower it when the // MCLK switch starts wm_val_refclk = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns * - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz /1000 /1000 ; + (dc->res_pool->ref_clocks.dchub_ref_clock_inKhz /1000 ) /1000 ; cmd.fw_assisted_mclk_switch_v2.config_data.watermark_a_cache = wm_val_refclk <0xFFFF ? wm_val_refclk :0xFFFF ; }
Greg Kroah-Hartman
maintainerPATCH 191/862 drm/amd/display: Update PMFW z-state interface for DCN314
In reply to Greg Kroah-HartmanFrom: Nicholas Kazlauskas <[email protected]>
commit 4f5bdde386d3b8e9317df5562950e1b4fa177599 upstream.
[Why]
Request from PMFW to change the messaging format to specify whether we support z-state via individual bits.
[How]
Update the args we pass in the support message.
--- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c | 11 +++-------- drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c +3 -8
@@ -339,29 +339,24 @@ void dcn314_smu_set_zstate_support(strucif (!clk_mgr->smu_present)return ; -if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface && - (support ==DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY )) - support =DCN_ZSTATE_SUPPORT_DISALLOW ; - -// Arg[15:0] = 8/9/0 for Z8/Z9/disallow -> existing bits // Arg[16] = Disallow Z9 -> new bit switch (support) {case DCN_ZSTATE_SUPPORT_ALLOW : msg_id = VBIOSSMC_MSG_AllowZstatesEntry; - param =9 ; + param = (1 <<10 ) | (1 <<9 ) | (1 <<8 );break ;case DCN_ZSTATE_SUPPORT_DISALLOW : msg_id = VBIOSSMC_MSG_AllowZstatesEntry; - param =8 ; + param =0 ;break ;case DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY : msg_id = VBIOSSMC_MSG_AllowZstatesEntry; - param =0x00010008 ; + param = (1 <<10 );break ;default ://DCN_ZSTATE_SUPPORT_UNKNOWN
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +2 -1
@@ -881,7 +881,8 @@ static const struct dc_plane_cap plane_c };static const struct dc_debug_options debug_defaults_drv = { - .disable_z10 = true,/*hw not support it*/ + .disable_z10 = false, + .enable_z9_disable_interface = true, .disable_dmcu = true, .force_abm_enable = false, .timing_trace = false,
Greg Kroah-Hartman
maintainerPATCH 192/862 drm/amd/display: zeromem mypipe heap struct before using it
In reply to Greg Kroah-HartmanFrom: Martin Leung <[email protected]>
commit 5ff32b52995155f91de582124485d0f0f8881363 upstream.
[Why & How]
bug was caused when moving variable from stack to
heap because it was reusable and garbage was left
over, so we need to zero mem
--- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +2 -0
@@ -733,6 +733,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleep mode_lib->vba.FCLKChangeLatency, v->UrgentLatency, mode_lib->vba.SREnterPlusExitTime); +memset (&v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe,0 ,sizeof (DmlPipe)); + v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe.Dppclk = mode_lib->vba.DPPCLK[k]; v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe.Dispclk = mode_lib->vba.DISPCLK; v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe.PixelClock = mode_lib->vba.PixelClock[k];
Greg Kroah-Hartman
maintainerPATCH 193/862 drm/amd/display: Validate DSC After Enable All New CRTCs
In reply to Greg Kroah-HartmanFrom: Fangzhi Zuo <[email protected]>
commit 876fcc4222e1d0e5b73343f4010a8b66be058f48 upstream.
Before enabling new crtc, stream_count in dc_state does not sync with that in drm_atomic_state. Validating dsc in such case would leave newly added stream not jointly participating in dsc optimization with existing streams, but simply using default initialized vcpi all the time which gives wrong dsc determination decision.
Consider the scenaio where one 4k60 connected to the dock under dp-alt mode. Since dp-alt mode is 2-lane setup, stream 1 consumes 63 slots with dsc needed. Then hook up a second 4k60 to the dock.
stream 2 connected with 65 slot initialized by default without dsc. dsc pre validate will not jointly optimize stream 2 with stream 1 before crtc 2 added into the dc_state. That leads to stream 2 not getting dsc optimization, and trigger atomic_check failure all the time, as 65 > 63 limit.
After getting all new crtcs added into the state, stream_count in dc_state correctly reflect that in drm_atomic_state which comes up with correct dsc decision.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +9 -4
@@ -9408,10 +9408,6 @@ static int amdgpu_dm_atomic_check(struct } } } -if (!pre_validate_dsc (state, &dm_state, vars)) { - ret = -EINVAL ; - goto fail; - } }#endif for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -9545,6 +9541,15 @@ static int amdgpu_dm_atomic_check(struct } } +#if defined(CONFIG_DRM_AMD_DC_DCN ) +if (dc_resource_is_dsc_encoding_supported (dc)) { +if (!pre_validate_dsc (state, &dm_state, vars)) { + ret = -EINVAL ; + goto fail; + } + } +#endif +/* Run this here since we want to validate the streams we created */ ret =drm_atomic_helper_check_planes (dev, state);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 194/862 drm/amd/display: Enable dpia support for dcn314
In reply to Greg Kroah-HartmanFrom: Roman Li <[email protected]>
commit f6aa84b83aee629fbbbc4ea16c2c142caf920d5a upstream.
[Why]
DCN 3.1.4 supports DPIA.
[How]
- Set dpia_supported flag for dcn314 in dmub_hw_init()
- Remove comment that becomes irrelevant after this change.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -1
@@ -1109,7 +1109,8 @@ static int dm_dmub_hw_init(struct amdgpu hw_params.fb[i] = &fb_info->fb[i];switch (adev->ip_versions[DCE_HWIP ][0 ]) { -case IP_VERSION (3 ,1 ,3 ):/* Only for this asic hw internal rev B0 */ +case IP_VERSION (3 ,1 ,3 ): +case IP_VERSION (3 ,1 ,4 ): hw_params.dpia_supported = true; hw_params.disable_dpia = adev->dm.dc->debug.dpia_debug.bits.disable_dpia;break ;
Greg Kroah-Hartman
maintainerPATCH 195/862 drm/amd/display: Enable 2 to 1 ODM policy if supported
In reply to Greg Kroah-HartmanFrom: Rodrigo Siqueira <[email protected]>
commit 54fae65ff469a79fc0ca46f480c4e7fce50f3963 upstream.
If the current configuration supports 2 to 1 ODM policy, let's also enable the windowed MPO feature.
--- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +4 -0
@@ -1001,6 +1001,10 @@ void dcn32_init_hw(struct dc *dc)dc_dmub_srv_query_caps_cmd (dc->ctx->dmub_srv->dmub); dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; } + +/* Enable support for ODM and windowed MPO if policy flag is set */ +if (dc->debug.enable_single_display_2to1_odm_policy) + dc->config.enable_windowed_mpo_odm = true; } static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
Greg Kroah-Hartman
maintainerPATCH 196/862 drm/amd/display: Fix vblank refcount in vrr transition
In reply to Greg Kroah-HartmanFrom: Yunxiang Li <[email protected]>
commit 8799c0be89ebb99a16098bdf618f49f817bef76a upstream.
manage_dm_interrupts disable/enable vblank using drm_crtc_vblank_off/on which causes drm_crtc_vblank_get in vrr_transition to fail, and later when drm_crtc_vblank_put is called the refcount on vblank will be messed up. Therefore move the call to after manage_dm_interrupts.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 55 ++++++++++------------ 1 file changed, 26 insertions(+), 29 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +26 -29
@@ -7491,15 +7491,15 @@ static void amdgpu_dm_handle_vrr_transit* We also need vupdate irq for the actual core vblank handling * at end of vblank. */ -dm_set_vupdate_irq (new_state->base.crtc, true); -drm_crtc_vblank_get (new_state->base.crtc); +WARN_ON (dm_set_vupdate_irq (new_state->base.crtc, true) !=0 ); +WARN_ON (drm_crtc_vblank_get (new_state->base.crtc) !=0 );DRM_DEBUG_DRIVER ("%s: crtc=%u VRR off->on: Get vblank ref\n" , __func__, new_state->base.crtc->base.id); }else if (old_vrr_active && !new_vrr_active) {/* Transition VRR active -> inactive: * Allow vblank irq disable again for fixed refresh rate. */ -dm_set_vupdate_irq (new_state->base.crtc, false); +WARN_ON (dm_set_vupdate_irq (new_state->base.crtc, false) !=0 );drm_crtc_vblank_put (new_state->base.crtc);DRM_DEBUG_DRIVER ("%s: crtc=%u VRR on->off: Drop vblank ref\n" , __func__, new_state->base.crtc->base.id);
@@ -8254,23 +8254,6 @@ static void amdgpu_dm_atomic_commit_tailmutex_unlock (&dm->dc_lock); } -/* Count number of newly disabled CRTCs for dropping PM refs later. */ -for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state, - new_crtc_state, i) { -if (old_crtc_state->active && !new_crtc_state->active) - crtc_disable_count++; - - dm_new_crtc_state =to_dm_crtc_state (new_crtc_state); - dm_old_crtc_state =to_dm_crtc_state (old_crtc_state); - -/* For freesync config update on crtc state and params for irq */ -update_stream_irq_parameters (dm, dm_new_crtc_state); - -/* Handle vrr on->off / off->on transitions */ -amdgpu_dm_handle_vrr_transition (dm_old_crtc_state, - dm_new_crtc_state); - } -/** * Enable interrupts for CRTCs that are newly enabled or went through * a modeset. It was intentionally deferred until after the front end
@@ -8280,16 +8263,29 @@ static void amdgpu_dm_atomic_commit_tailfor_each_oldnew_crtc_in_state (state, crtc, old_crtc_state, new_crtc_state, i) {struct amdgpu_crtc *acrtc =to_amdgpu_crtc (crtc);#ifdef CONFIG_DEBUG_FS -bool configure_crc = false;enum amdgpu_dm_pipe_crc_source cur_crc_src;#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY ) -struct crc_rd_work *crc_rd_wrk = dm->crc_rd_wrk; +struct crc_rd_work *crc_rd_wrk; +#endif +#endif +/* Count number of newly disabled CRTCs for dropping PM refs later. */ +if (old_crtc_state->active && !new_crtc_state->active) + crtc_disable_count++; + + dm_new_crtc_state =to_dm_crtc_state (new_crtc_state); + dm_old_crtc_state =to_dm_crtc_state (old_crtc_state); + +/* For freesync config update on crtc state and params for irq */ +update_stream_irq_parameters (dm, dm_new_crtc_state); + +#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY ) + crc_rd_wrk = dm->crc_rd_wrk;#endif spin_lock_irqsave (&adev_to_drm (adev)->event_lock, flags); cur_crc_src = acrtc->dm_irq_params.crc_src;spin_unlock_irqrestore (&adev_to_drm (adev)->event_lock, flags);#endif - dm_new_crtc_state =to_dm_crtc_state (new_crtc_state); if (new_crtc_state->active && (!old_crtc_state->active ||
@@ -8297,16 +8293,19 @@ static void amdgpu_dm_atomic_commit_taildc_stream_retain (dm_new_crtc_state->stream); acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;manage_dm_interrupts (adev, acrtc, true); + } +/* Handle vrr on->off / off->on transitions */ +amdgpu_dm_handle_vrr_transition (dm_old_crtc_state, dm_new_crtc_state);#ifdef CONFIG_DEBUG_FS +if (new_crtc_state->active && + (!old_crtc_state->active || +drm_atomic_crtc_needs_modeset (new_crtc_state))) {/** * Frontend may have changed so reapply the CRC capture * settings for the stream. */ - dm_new_crtc_state =to_dm_crtc_state (new_crtc_state); -if (amdgpu_dm_is_valid_crc_source (cur_crc_src)) { - configure_crc = true;#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY )if (amdgpu_dm_crc_window_is_activated (crtc)) {spin_lock_irqsave (&adev_to_drm (adev)->event_lock, flags);
@@ -8318,12 +8317,10 @@ static void amdgpu_dm_atomic_commit_tailspin_unlock_irqrestore (&adev_to_drm (adev)->event_lock, flags); }#endif - } - -if (configure_crc)if (amdgpu_dm_crtc_configure_crc_source ( crtc, dm_new_crtc_state, cur_crc_src))DRM_DEBUG_DRIVER ("Failed to configure crc source" ); + }#endif } }
Greg Kroah-Hartman
maintainerPATCH 197/862 drm/amd/display: Add HUBP surface flip interrupt handler
In reply to Greg Kroah-HartmanFrom: Aurabindo Pillai <[email protected]>
commit 0811b9e4530d7c46542a8993ce6b725d042c6154 upstream.
Add the hubp surface flip handler. This fixes some flip timeout issues.
--- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c +1 -0
@@ -179,6 +179,7 @@ static struct hubp_funcs dcn32_hubp_func .hubp_init = hubp3_init, .set_unbounded_requesting = hubp31_set_unbounded_requesting, .hubp_soft_reset = hubp31_soft_reset, + .hubp_set_flip_int = hubp1_set_flip_int, .hubp_in_blank = hubp1_in_blank, .hubp_update_force_pstate_disallow = hubp32_update_force_pstate_disallow, .phantom_hubp_post_enable = hubp32_phantom_hubp_post_enable,
Greg Kroah-Hartman
maintainerPATCH 198/862 drm/amd/display: explicitly disable psr_feature_enable appropriately
In reply to Greg Kroah-HartmanFrom: Shirish S <[email protected]>
commit 6094b9136ca9038b61e9c4b5d25cd5512ce50b34 upstream.
[Why]
If psr_feature_enable is set to true by default, it continues to be enabled for non capable links.
[How]
explicitly disable the feature on links that are not capable of the same.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +6 -2
@@ -60,11 +60,15 @@ static bool link_supports_psrsu(struct d*/ void amdgpu_dm_set_psr_caps (struct dc_link *link) { -if (!(link->connector_signal &SIGNAL_TYPE_EDP )) +if (!(link->connector_signal &SIGNAL_TYPE_EDP )) { + link->psr_settings.psr_feature_enabled = false;return ; + } -if (link->type == dc_connection_none) +if (link->type == dc_connection_none) { + link->psr_settings.psr_feature_enabled = false;return ; + }if (link->dpcd_caps.psr_info.psr_version ==0 ) { link->psr_settings.psr_version =DC_PSR_VERSION_UNSUPPORTED ;
Greg Kroah-Hartman
maintainerPATCH 199/862 drm/amdgpu: Enable VCN PG on GC11_0_1
In reply to Greg Kroah-HartmanFrom: Sonny Jiang <[email protected]>
commit e626d9b9c6e038a6918aad1b5affd38f6b9deaed upstream.
Enable VCN PG on GC11_0_1
--- drivers/gpu/drm/amd/amdgpu/soc21.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/soc21.c +1 -0
@@ -625,6 +625,7 @@ static int soc21_common_early_init(voidAMD_CG_SUPPORT_JPEG_MGCG ; adev->pg_flags =AMD_PG_SUPPORT_GFX_PG | +AMD_PG_SUPPORT_VCN |AMD_PG_SUPPORT_VCN_DPG |AMD_PG_SUPPORT_JPEG ; adev->external_rev_id = adev->rev_id +0x1 ;
Greg Kroah-Hartman
maintainerPATCH 200/862 drm/amdgpu: Enable F32_WPTR_POLL_ENABLE in mqd
In reply to Greg Kroah-HartmanFrom: Ruili Ji <[email protected]>
commit 21a550de5faf9f54013334c9a6a7643b8fd80b36 upstream.
This patch is to fix the SDMA user queue doorbell missing issue on SDMA 6.0. F32_WPTR_POLL_ENABLE has to be set if doorbell mode is used. Otherwise ringing SDMA user queue doorbell can't wake up system from gfxoff.
--- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 3 ++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +2 -1
@@ -910,7 +910,8 @@ static int sdma_v6_0_mqd_init(struct amd m->sdmax_rlcx_rb_cntl =order_base_2 (prop->queue_size /4 ) <<SDMA0_QUEUE0_RB_CNTL__RB_SIZE__SHIFT |1 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT | -4 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT ; +4 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT | +1 <<SDMA0_QUEUE0_RB_CNTL__F32_WPTR_POLL_ENABLE__SHIFT ; m->sdmax_rlcx_rb_base =lower_32_bits (prop->hqd_base_gpu_addr >>8 ); m->sdmax_rlcx_rb_base_hi =upper_32_bits (prop->hqd_base_gpu_addr >>8 );
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +2 -1
@@ -375,7 +375,8 @@ static void update_mqd_sdma(struct mqd_m << SDMA0_QUEUE0_RB_CNTL__RB_SIZE__SHIFT | q->vmid <<SDMA0_QUEUE0_RB_CNTL__RB_VMID__SHIFT |1 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT | -6 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT ; +6 <<SDMA0_QUEUE0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT | +1 <<SDMA0_QUEUE0_RB_CNTL__F32_WPTR_POLL_ENABLE__SHIFT ; m->sdmax_rlcx_rb_base =lower_32_bits (q->queue_address >>8 ); m->sdmax_rlcx_rb_base_hi =upper_32_bits (q->queue_address >>8 );
Greg Kroah-Hartman
maintainerPATCH 201/862 smb3: must initialize two ACL struct fields to zero
In reply to Greg Kroah-HartmanFrom: Steve French <[email protected]>
commit f09bd695af3b8ab46fc24e5d6954a24104c38387 upstream.
Coverity spotted that we were not initalizing Stbz1 and Stbz2 to zero in create_sd_buf.
Addresses-Coverity: 1513848 ("Uninitialized scalar variable")
--- fs/cifs/smb2pdu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/cifs/smb2pdu.c +2 -1
@@ -2411,7 +2411,7 @@ create_sd_buf(umode_t mode, bool set_ownunsigned int acelen, acl_size, ace_count;unsigned int owner_offset =0 ;unsigned int group_offset =0 ; -struct smb3_acl acl; +struct smb3_acl acl = {}; *len =roundup (sizeof (struct crt_sd_ctxt ) + (sizeof (struct cifs_ace ) *4 ),8 );
@@ -2484,6 +2484,7 @@ create_sd_buf(umode_t mode, bool set_own acl.AclRevision =ACL_REVISION ;/* See 2.4.4.1 of MS-DTYP */ acl.AclSize =cpu_to_le16 (acl_size); acl.AceCount =cpu_to_le16 (ace_count); +/* acl.Sbz1 and Sbz2 MBZ so are not set here, but initialized above */ memcpy (aclptr, &acl,sizeof (struct smb3_acl )); buf->ccontext.DataLength =cpu_to_le32 (ptr - (__u8 *)&buf->sd);
Greg Kroah-Hartman
maintainerPATCH 202/862 selinux: use "grep -E" instead of "egrep"
In reply to Greg Kroah-HartmanFrom: Greg Kroah-Hartman <[email protected]>
commit c969bb8dbaf2f3628927eae73e7c579a74cf1b6e upstream.
The latest version of grep claims that egrep is now obsolete so the build now contains warnings that look like:
egrep: warning: egrep is obsolescent; using grep -E
fix this by using "grep -E" instead.
--- scripts/selinux/install_policy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/selinux/install_policy.sh +1 -1
@@ -78,7 +78,7 @@ cd /etc/selinux/dummy/contexts/files $SF -F file_contexts / mounts=`cat /proc/$$/mounts | \ - egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ + grep -E "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ awk '{ print $2 '}` $SF -F file_contexts $mounts
Greg Kroah-Hartman
maintainerPATCH 203/862 ima: fix blocking of security.ima xattrs of unsupported algorithms
In reply to Greg Kroah-HartmanFrom: Mimi Zohar <[email protected]>
[ Upstream commit 5926586f291b53cb8a0c9631fc19489be1186e2d ]
Limit validating the hash algorithm to just security.ima xattr, not the security.evm xattr or any of the protected EVM security xattrs, nor posix acls.
--- security/integrity/ima/ima_appraise.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
security/integrity/ima/ima_appraise.c +8 -4
@@ -750,22 +750,26 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,const struct evm_ima_xattr_data *xvalue = xattr_value;int digsig =0 ;int result; +int err; result =ima_protect_xattr (dentry, xattr_name, xattr_value, xattr_value_len);if (result ==1 ) {if (!xattr_value_len || (xvalue->type >=IMA_XATTR_LAST ))return -EINVAL ; + + err =validate_hash_algo (dentry, xvalue, xattr_value_len); +if (err) +return err; + digsig = (xvalue->type ==EVM_IMA_XATTR_DIGSIG ); }else if (!strcmp (xattr_name,XATTR_NAME_EVM ) && xattr_value_len >0 ) { digsig = (xvalue->type ==EVM_XATTR_PORTABLE_DIGSIG ); }if (result ==1 ||evm_revalidate_status (xattr_name)) { - result =validate_hash_algo (dentry, xvalue, xattr_value_len); -if (result) -return result; -ima_reset_appraise_flags (d_backing_inode (dentry), digsig); +if (result ==1 ) + result =0 ; }return result; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 204/862 userfaultfd: open userfaultfds with O_RDONLY
In reply to Greg Kroah-HartmanFrom: Ondrej Mosnacek <[email protected]>
[ Upstream commit abec3d015fdfb7c63105c7e1c956188bf381aa55 ]
Since userfaultfd doesn't implement a write operation, it is more appropriate to open it read-only.
When userfaultfds are opened read-write like it is now, and such fd is passed from one process to another, SELinux will check both read and write permissions for the target process, even though it can't actually do any write operation on the fd later.
Inspired by the following bug report, which has hit the SELinux scenario described above:
https://bugzilla.redhat.com/show_bug.cgi?id=1974559
--- fs/userfaultfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/userfaultfd.c +2 -2
@@ -991,7 +991,7 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *new,int fd; fd =anon_inode_getfd_secure ("[userfaultfd]" , &userfaultfd_fops, new, -O_RDWR | (new->flags &UFFD_SHARED_FCNTL_FLAGS ), inode); +O_RDONLY | (new->flags &UFFD_SHARED_FCNTL_FLAGS ), inode);if (fd <0 )return fd;
@@ -2094,7 +2094,7 @@ SYSCALL_DEFINE1(userfaultfd, int, flags)mmgrab (ctx->mm); fd =anon_inode_getfd_secure ("[userfaultfd]" , &userfaultfd_fops, ctx, -O_RDWR | (flags &UFFD_SHARED_FCNTL_FLAGS ),NULL ); +O_RDONLY | (flags &UFFD_SHARED_FCNTL_FLAGS ),NULL );if (fd <0 ) {mmdrop (ctx->mm);kmem_cache_free (userfaultfd_ctx_cachep, ctx);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 205/862 ntfs3: rework xattr handlers and switch to POSIX ACL VFS helpers
In reply to Greg Kroah-HartmanFrom: Christian Brauner <[email protected]>
[ Upstream commit a26aa12384158116c0d80d50e0bdc7b3323551e2 ]
The xattr code in ntfs3 is currently a bit confused. For example, it defines a POSIX ACL i_op->set_acl() method but instead of relying on the generic POSIX ACL VFS helpers it defines its own set of xattr helpers with the consequence that i_op->set_acl() is currently dead code.
Switch ntfs3 to rely on the VFS POSIX ACL xattr handlers. Also remove i_op->{g,s}et_acl() methods from symlink inode operations. Symlinks don't support xattrs.
This is a preliminary change for the following patches which move handling idmapped mounts directly in posix_acl_xattr_set().
This survives POSIX ACL xfstests.
--- fs/ntfs3/inode.c | 2 - fs/ntfs3/xattr.c | 102 +++-------------------------------------------- 2 files changed, 6 insertions(+), 98 deletions(-)
fs/ntfs3/inode.c +0 -2
@@ -1927,8 +1927,6 @@ const struct inode_operations ntfs_link_inode_operations = { .setattr = ntfs3_setattr, .listxattr = ntfs_listxattr, .permission = ntfs_permission, - .get_acl = ntfs_get_acl, - .set_acl = ntfs_set_acl, };const struct address_space_operations ntfs_aops = {
fs/ntfs3/xattr.c +6 -96
132 lines not on this page · raw message
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 206/862 acl: return EOPNOTSUPP in posix_acl_fix_xattr_common()
In reply to Greg Kroah-HartmanFrom: Christian Brauner <[email protected]>
[ Upstream commit 985a6d0b3c800265a2d5312a52c549bf09254e55 ]
Return EOPNOTSUPP when the POSIX ACL version doesn't match and zero if there are no entries. This will allow us to reuse the helper in posix_acl_from_xattr(). This change will have no user visible effects.
--- fs/posix_acl.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-)
fs/posix_acl.c +9 -16
@@ -710,9 +710,9 @@ EXPORT_SYMBOL(posix_acl_update_mode);/* * Fix up the uids and gids in posix acl extended attributes in place. */ -static int posix_acl_fix_xattr_common (void *value,size_t size) +static int posix_acl_fix_xattr_common (const void *value,size_t size) { -struct posix_acl_xattr_header *header = value; +const struct posix_acl_xattr_header *header = value;int count;if (!header)
@@ -720,13 +720,13 @@ static int posix_acl_fix_xattr_common(void *value, size_t size)if (size <sizeof (struct posix_acl_xattr_header ))return -EINVAL ;if (header->a_version !=cpu_to_le32 (POSIX_ACL_XATTR_VERSION )) -return -EINVAL ; +return -EOPNOTSUPP ; count =posix_acl_xattr_count (size);if (count <0 )return -EINVAL ;if (count ==0 ) -return -EINVAL ; +return 0 ;return count; }
@@ -748,7 +748,7 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,return ; count =posix_acl_fix_xattr_common (value, size); -if (count <0 ) +if (count <=0 )return ;for (end = entry + count; entry != end; entry++) {
@@ -788,7 +788,7 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,return ; count =posix_acl_fix_xattr_common (value, size); -if (count <0 ) +if (count <=0 )return ;for (end = entry + count; entry != end; entry++) {
@@ -822,7 +822,7 @@ static void posix_acl_fix_xattr_userns(kgid_t gid; count =posix_acl_fix_xattr_common (value, size); -if (count <0 ) +if (count <=0 )return ;for (end = entry + count; entry != end; entry++) {
@@ -870,16 +870,9 @@ posix_acl_from_xattr(struct user_namespace *user_ns,struct posix_acl *acl;struct posix_acl_entry *acl_e; -if (!value) -return NULL ; -if (size <sizeof (struct posix_acl_xattr_header )) -return ERR_PTR (-EINVAL ); -if (header->a_version !=cpu_to_le32 (POSIX_ACL_XATTR_VERSION )) -return ERR_PTR (-EOPNOTSUPP ); - - count =posix_acl_xattr_count (size); + count =posix_acl_fix_xattr_common (value, size);if (count <0 ) -return ERR_PTR (-EINVAL ); +return ERR_PTR (count);if (count ==0 )return NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 207/862 thermal: cpufreq_cooling: Check the policy first in cpufreq_cooling_register()
In reply to Greg Kroah-HartmanFrom: Xuewen Yan <[email protected]>
[ Upstream commit cff895277c8558221ba180aefe26799dcb4eec86 ]
Since the policy needs to be accessed first when obtaining cpu devices, first check whether the policy is legal before this.
--- drivers/thermal/cpufreq_cooling.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/thermal/cpufreq_cooling.c +5 -5
@@ -501,17 +501,17 @@ __cpufreq_cooling_register(struct device_node *np,struct thermal_cooling_device_ops *cooling_ops;char *name; +if (IS_ERR_OR_NULL (policy)) { +pr_err ("%s: cpufreq policy isn't valid: %p\n" , __func__, policy); +return ERR_PTR (-EINVAL ); + } + dev =get_cpu_device (policy->cpu);if (unlikely (!dev)) {pr_warn ("No cpu device for cpu %d\n" , policy->cpu);return ERR_PTR (-ENODEV ); } -if (IS_ERR_OR_NULL (policy)) { -pr_err ("%s: cpufreq policy isn't valid: %p\n" , __func__, policy); -return ERR_PTR (-EINVAL ); - } - i =cpufreq_table_count_valid_entries (policy);if (!i) { pr_debug("%s: CPUFreq table not found or has no valid entries\n",
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 208/862 cpufreq: amd-pstate: Fix initial highest_perf value
In reply to Greg Kroah-HartmanFrom: Perry Yuan <[email protected]>
[ Upstream commit bedadcfb011fef55273bd686e8893fdd8911dcdb ]
To avoid some new AMD processors use wrong highest perf when amd pstate driver loaded, this fix will query the highest perf from MSR register MSR_AMD_CPPC_CAP1 and cppc_acpi interface firstly, then compare with the highest perf value got by calling amd_get_highest_perf() function.
The lower value will be the correct highest perf we need to use. Otherwise the CPU max MHz will be incorrect if the amd_get_highest_perf() did not cover the new process family and model ID.
Like this lscpu info, the max frequency is incorrect.
Vendor ID: AuthenticAMD
Socket(s): 1
Stepping: 2
CPU max MHz: 5410.0000
CPU min MHz: 400.0000
BogoMIPS: 5600.54--- drivers/cpufreq/amd-pstate.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/cpufreq/amd-pstate.c +12 -2
@@ -152,6 +152,7 @@ static inline int amd_pstate_enable(bool enable)static int pstate_init_perf (struct amd_cpudata *cpudata) {u64 cap1; +u32 highest_perf;int ret =rdmsrl_safe_on_cpu (cpudata->cpu,MSR_AMD_CPPC_CAP1 , &cap1);
@@ -163,7 +164,11 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)* * CPPC entry doesn't indicate the highest performance in some ASICs. */ -WRITE_ONCE (cpudata->highest_perf,amd_get_highest_perf ()); + highest_perf =amd_get_highest_perf (); +if (highest_perf >AMD_CPPC_HIGHEST_PERF (cap1)) + highest_perf =AMD_CPPC_HIGHEST_PERF (cap1); + +WRITE_ONCE (cpudata->highest_perf, highest_perf);WRITE_ONCE (cpudata->nominal_perf,AMD_CPPC_NOMINAL_PERF (cap1));WRITE_ONCE (cpudata->lowest_nonlinear_perf,AMD_CPPC_LOWNONLIN_PERF (cap1));
@@ -175,12 +180,17 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)static int cppc_init_perf (struct amd_cpudata *cpudata) {struct cppc_perf_caps cppc_perf; +u32 highest_perf;int ret =cppc_get_perf_caps (cpudata->cpu, &cppc_perf);if (ret)return ret; -WRITE_ONCE (cpudata->highest_perf,amd_get_highest_perf ()); + highest_perf =amd_get_highest_perf (); +if (highest_perf > cppc_perf.highest_perf) + highest_perf = cppc_perf.highest_perf; + +WRITE_ONCE (cpudata->highest_perf, highest_perf);WRITE_ONCE (cpudata->nominal_perf, cppc_perf.nominal_perf); WRITE_ONCE(cpudata->lowest_nonlinear_perf,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 209/862 sh: machvec: Use char[] for section boundaries
In reply to Greg Kroah-HartmanFrom: Kees Cook <[email protected]>
[ Upstream commit c5783af354688b24abd359f7086c282ec74de993 ]
As done for other sections, define the extern as a character array, which relaxes many of the compiler-time object size checks, which would otherwise assume it's a single long. Solves the following build error:
arch/sh/kernel/machvec.c: error: array subscript 'struct sh_machine_vector[0]' is partly outside array bounds of 'long int[1]' [-Werror=array-bounds]: => 105:33
--- arch/sh/include/asm/sections.h | 2 +- arch/sh/kernel/machvec.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-)
arch/sh/include/asm/sections.h +1 -1
@@ -4,7 +4,7 @@#include <asm-generic/sections.h> -extern long __machvec_start, __machvec_end; +extern char __machvec_start[], __machvec_end[];extern char __uncached_start, __uncached_end;extern char __start_eh_frame[], __stop_eh_frame[];
arch/sh/kernel/machvec.c +5 -5
@@ -20,8 +20,8 @@#define MV_NAME_SIZE 32#define for_each_mv (mv) \ - for ((mv) = (struct sh_machine_vector *)&__machvec_start; \ - (mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \ + for ((mv) = (struct sh_machine_vector *)__machvec_start; \ + (mv) && (unsigned long)(mv) < (unsigned long)__machvec_end; \ (mv)++)static struct sh_machine_vector *__init get_mv_byname (const char *name)
@@ -87,8 +87,8 @@ void __init sh_mv_setup(void)if (!machvec_selected) {unsigned long machvec_size; - machvec_size = ((unsigned long )&__machvec_end - - (unsigned long )&__machvec_start); + machvec_size = ((unsigned long )__machvec_end - + (unsigned long )__machvec_start);/* * Sanity check for machvec section alignment. Ensure
@@ -102,7 +102,7 @@ void __init sh_mv_setup(void)* vector (usually the only one) from .machvec.init. */ if (machvec_size >=sizeof (struct sh_machine_vector )) - sh_mv = *(struct sh_machine_vector *)&__machvec_start; + sh_mv = *(struct sh_machine_vector *)__machvec_start; }pr_notice ("Booting machvec: %s\n" ,get_system_type ());
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 210/862 MIPS: SGI-IP30: Fix platform-device leak in bridge_platform_create()
In reply to Greg Kroah-HartmanFrom: Lin Yujun <[email protected]>
[ Upstream commit 1e6d11fe72e311c1989991ee318d239f650fa318 ]
In error case in bridge_platform_create after calling platform_device_add()/platform_device_add_data()/ platform_device_add_resources(), release the failed 'pdev' or it will be leak, call platform_device_put() to fix this problem.
Besides, 'pdev' is divided into 'pdev_wd' and 'pdev_bd', use platform_device_unregister() to release sgi_w1 resources when xtalk-bridge registration fails.
--- arch/mips/sgi-ip30/ip30-xtalk.c | 70 +++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 20 deletions(-)
arch/mips/sgi-ip30/ip30-xtalk.c +50 -20
@@ -40,12 +40,15 @@ static void bridge_platform_create(int widget, int masterwid) {struct xtalk_bridge_platform_data *bd;struct sgi_w1_platform_data *wd; -struct platform_device *pdev; +struct platform_device *pdev_wd; +struct platform_device *pdev_bd;struct resource w1_res; wd =kzalloc (sizeof (*wd),GFP_KERNEL ); -if (!wd) - goto no_mem; +if (!wd) { +pr_warn ("xtalk:%x bridge create out of memory\n" , widget); +return ; + }snprintf (wd->dev_id,sizeof (wd->dev_id),"bridge-%012lx" ,IP30_SWIN_BASE (widget));
@@ -56,24 +59,35 @@ static void bridge_platform_create(int widget, int masterwid) w1_res.end = w1_res.start +3 ; w1_res.flags =IORESOURCE_MEM ; - pdev =platform_device_alloc ("sgi_w1" ,PLATFORM_DEVID_AUTO ); -if (!pdev) { -kfree (wd); - goto no_mem; + pdev_wd =platform_device_alloc ("sgi_w1" ,PLATFORM_DEVID_AUTO ); +if (!pdev_wd) { +pr_warn ("xtalk:%x bridge create out of memory\n" , widget); + goto err_kfree_wd; + } +if (platform_device_add_resources (pdev_wd, &w1_res,1 )) { +pr_warn ("xtalk:%x bridge failed to add platform resources.\n" , widget); + goto err_put_pdev_wd; + } +if (platform_device_add_data (pdev_wd, wd,sizeof (*wd))) { +pr_warn ("xtalk:%x bridge failed to add platform data.\n" , widget); + goto err_put_pdev_wd; + } +if (platform_device_add (pdev_wd)) { +pr_warn ("xtalk:%x bridge failed to add platform device.\n" , widget); + goto err_put_pdev_wd; } -platform_device_add_resources (pdev, &w1_res,1 ); -platform_device_add_data (pdev, wd,sizeof (*wd));/* platform_device_add_data() duplicates the data */ kfree (wd); -platform_device_add (pdev); bd =kzalloc (sizeof (*bd),GFP_KERNEL ); -if (!bd) - goto no_mem; - pdev =platform_device_alloc ("xtalk-bridge" ,PLATFORM_DEVID_AUTO ); -if (!pdev) { -kfree (bd); - goto no_mem; +if (!bd) { +pr_warn ("xtalk:%x bridge create out of memory\n" , widget); + goto err_unregister_pdev_wd; + } + pdev_bd =platform_device_alloc ("xtalk-bridge" ,PLATFORM_DEVID_AUTO ); +if (!pdev_bd) { +pr_warn ("xtalk:%x bridge create out of memory\n" , widget); + goto err_kfree_bd; } bd->bridge_addr =IP30_RAW_SWIN_BASE (widget);
@@ -93,15 +107,31 @@ static void bridge_platform_create(int widget, int masterwid) bd->io.flags =IORESOURCE_IO ; bd->io_offset =IP30_SWIN_BASE (widget); -platform_device_add_data (pdev, bd,sizeof (*bd)); +if (platform_device_add_data (pdev_bd, bd,sizeof (*bd))) { +pr_warn ("xtalk:%x bridge failed to add platform data.\n" , widget); + goto err_put_pdev_bd; + } +if (platform_device_add (pdev_bd)) { +pr_warn ("xtalk:%x bridge failed to add platform device.\n" , widget); + goto err_put_pdev_bd; + }/* platform_device_add_data() duplicates the data */ kfree (bd); -platform_device_add (pdev);pr_info ("xtalk:%x bridge widget\n" , widget);return ; -no_mem: -pr_warn ("xtalk:%x bridge create out of memory\n" , widget); +err_put_pdev_bd: +platform_device_put (pdev_bd); +err_kfree_bd: +kfree (bd); +err_unregister_pdev_wd: +platform_device_unregister (pdev_wd); +return ; +err_put_pdev_wd: +platform_device_put (pdev_wd); +err_kfree_wd: +kfree (wd); +return ; }static unsigned int __init xbow_widget_active (s8 wid)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 211/862 MIPS: SGI-IP27: Fix platform-device leak in bridge_platform_create()
In reply to Greg Kroah-HartmanFrom: Lin Yujun <[email protected]>
[ Upstream commit 11bec9cba4de06b3c0e9e4041453c2caaa1cbec1 ]
In error case in bridge_platform_create after calling platform_device_add()/platform_device_add_data()/ platform_device_add_resources(), release the failed 'pdev' or it will be leak, call platform_device_put() to fix this problem.
Besides, 'pdev' is divided into 'pdev_wd' and 'pdev_bd', use platform_device_unregister() to release sgi_w1 resources when xtalk-bridge registration fails.
--- arch/mips/sgi-ip27/ip27-xtalk.c | 70 +++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 20 deletions(-)
arch/mips/sgi-ip27/ip27-xtalk.c +50 -20
@@ -27,15 +27,18 @@ static void bridge_platform_create(nasid_t nasid, int widget, int masterwid) {struct xtalk_bridge_platform_data *bd;struct sgi_w1_platform_data *wd; -struct platform_device *pdev; +struct platform_device *pdev_wd; +struct platform_device *pdev_bd;struct resource w1_res;unsigned long offset; offset =NODE_OFFSET (nasid); wd =kzalloc (sizeof (*wd),GFP_KERNEL ); -if (!wd) - goto no_mem; +if (!wd) { +pr_warn ("xtalk:n%d/%x bridge create out of memory\n" , nasid, widget); +return ; + }snprintf (wd->dev_id,sizeof (wd->dev_id),"bridge-%012lx" , offset + (widget <<SWIN_SIZE_BITS ));
@@ -46,24 +49,35 @@ static void bridge_platform_create(nasid_t nasid, int widget, int masterwid) w1_res.end = w1_res.start +3 ; w1_res.flags =IORESOURCE_MEM ; - pdev =platform_device_alloc ("sgi_w1" ,PLATFORM_DEVID_AUTO ); -if (!pdev) { -kfree (wd); - goto no_mem; + pdev_wd =platform_device_alloc ("sgi_w1" ,PLATFORM_DEVID_AUTO ); +if (!pdev_wd) { +pr_warn ("xtalk:n%d/%x bridge create out of memory\n" , nasid, widget); + goto err_kfree_wd; + } +if (platform_device_add_resources (pdev_wd, &w1_res,1 )) { +pr_warn ("xtalk:n%d/%x bridge failed to add platform resources.\n" , nasid, widget); + goto err_put_pdev_wd; + } +if (platform_device_add_data (pdev_wd, wd,sizeof (*wd))) { +pr_warn ("xtalk:n%d/%x bridge failed to add platform data.\n" , nasid, widget); + goto err_put_pdev_wd; + } +if (platform_device_add (pdev_wd)) { +pr_warn ("xtalk:n%d/%x bridge failed to add platform device.\n" , nasid, widget); + goto err_put_pdev_wd; } -platform_device_add_resources (pdev, &w1_res,1 ); -platform_device_add_data (pdev, wd,sizeof (*wd));/* platform_device_add_data() duplicates the data */ kfree (wd); -platform_device_add (pdev); bd =kzalloc (sizeof (*bd),GFP_KERNEL ); -if (!bd) - goto no_mem; - pdev =platform_device_alloc ("xtalk-bridge" ,PLATFORM_DEVID_AUTO ); -if (!pdev) { -kfree (bd); - goto no_mem; +if (!bd) { +pr_warn ("xtalk:n%d/%x bridge create out of memory\n" , nasid, widget); + goto err_unregister_pdev_wd; + } + pdev_bd =platform_device_alloc ("xtalk-bridge" ,PLATFORM_DEVID_AUTO ); +if (!pdev_bd) { +pr_warn ("xtalk:n%d/%x bridge create out of memory\n" , nasid, widget); + goto err_kfree_bd; }
@@ -84,15 +98,31 @@ static void bridge_platform_create(nasid_t nasid, int widget, int masterwid) bd->io.flags =IORESOURCE_IO ; bd->io_offset = offset; -platform_device_add_data (pdev, bd,sizeof (*bd)); +if (platform_device_add_data (pdev_bd, bd,sizeof (*bd))) { +pr_warn ("xtalk:n%d/%x bridge failed to add platform data.\n" , nasid, widget); + goto err_put_pdev_bd; + } +if (platform_device_add (pdev_bd)) { +pr_warn ("xtalk:n%d/%x bridge failed to add platform device.\n" , nasid, widget); + goto err_put_pdev_bd; + }/* platform_device_add_data() duplicates the data */ kfree (bd); -platform_device_add (pdev);pr_info ("xtalk:n%d/%x bridge widget\n" , nasid, widget);return ; -no_mem: -pr_warn ("xtalk:n%d/%x bridge create out of memory\n" , nasid, widget); +err_put_pdev_bd: +platform_device_put (pdev_bd); +err_kfree_bd: +kfree (bd); +err_unregister_pdev_wd: +platform_device_unregister (pdev_wd); +return ; +err_put_pdev_wd: +platform_device_put (pdev_wd); +err_kfree_wd: +kfree (wd); +return ; }static int probe_one_port (nasid_t nasid,int widget,int masterwid)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 212/862 erofs: fix order >= MAX_ORDER warning due to crafted negative i_size
In reply to Greg Kroah-HartmanFrom: Gao Xiang <[email protected]>
[ Upstream commit 1dd73601a1cba37a0ed5f89a8662c90191df5873 ]
As syzbot reported [1], the root cause is that i_size field is a signed type, and negative i_size is also less than EROFS_BLKSIZ. As a consequence, it's handled as fast symlink unexpectedly.
Let's fall back to the generic path to deal with such unusual i_size.
[1] https://lore.kernel.org/r/[email protected]
--- fs/erofs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/erofs/inode.c +1 -1
@@ -214,7 +214,7 @@ static int erofs_fill_symlink(struct inode *inode, void *kaddr,/* if it cannot be handled with fast symlink scheme */ if (vi->datalayout !=EROFS_INODE_FLAT_INLINE || - inode->i_size >=EROFS_BLKSIZ ) { + inode->i_size >=EROFS_BLKSIZ || inode->i_size <0 ) { inode->i_op = &erofs_symlink_iops;return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 213/862 erofs: use kill_anon_super() to kill super in fscache mode
In reply to Greg Kroah-HartmanFrom: Jia Zhu <[email protected]>
[ Upstream commit 1015c1016c231b26d4e2c9b3da65b6c043eb97a3 ]
Use kill_anon_super() instead of generic_shutdown_super() since the mount() in erofs fscache mode uses get_tree_nodev() and associated anon bdev needs to be freed.
--- fs/erofs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/erofs/super.c +1 -1
@@ -879,7 +879,7 @@ static void erofs_kill_sb(struct super_block *sb)WARN_ON (sb->s_magic !=EROFS_SUPER_MAGIC );if (erofs_is_fscache_mode (sb)) -generic_shutdown_super (sb); +kill_anon_super (sb);else kill_block_super (sb);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 214/862 ARM: 9243/1: riscpc: Unbreak the build
In reply to Greg Kroah-HartmanFrom: Bart Van Assche <[email protected]>
[ Upstream commit 32844a8eecaa4a3e65841c53e43e04a9087d1ef6 ]
This patch fixes the following build error:
In file included from ./include/linux/io.h:13,
from ./arch/arm/mach-rpc/include/mach/uncompress.h:9, from arch/arm/boot/compressed/misc.c:31:./arch/arm/include/asm/io.h:85:22: error: conflicting types for ‘__raw_writeb’
85 | #define __raw_writeb __raw_writeb
| ^~~~~~~~~~~~
./arch/arm/include/asm/io.h:86:20: note: in expansion of macro ‘__raw_writeb’
86 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
| ^~~~~~~~~~~~
In file included from arch/arm/boot/compressed/misc.c:26:
arch/arm/boot/compressed/misc-ep93xx.h:13:20: note: previous definition of ‘__raw_writeb’ was here
13 | static inline void __raw_writeb(unsigned char value, unsigned int ptr)
| ^~~~~~~~~~~~To: Russell King <[email protected]>
--- arch/arm/boot/compressed/misc.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/boot/compressed/misc.c +2 -0
@@ -23,7 +23,9 @@ unsigned int __machine_arch_type;#include <linux/types.h> #include <linux/linkage.h> #include "misc.h" +#ifdef CONFIG_ARCH_EP93XX #include "misc-ep93xx.h" +#endif static void putstr (const char *ptr);
Signature · 9 lines
2.35.1 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Greg Kroah-Hartman
maintainerPATCH 215/862 ARM: 9244/1: dump: Fix wrong pg_level in walk_pmd()
In reply to Greg Kroah-HartmanFrom: Wang Kefeng <[email protected]>
[ Upstream commit 2ccd19b3ffac07cc7e75a2bd1ed779728bb67197 ]
After ARM supports p4d page tables, the pg_level for note_page() in walk_pmd() should be 4, not 3, fix it.
--- arch/arm/mm/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/mm/dump.c +1 -1
@@ -346,7 +346,7 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) addr = start + i *PMD_SIZE ; domain =get_domain_name (pmd);if (pmd_none (*pmd) ||pmd_large (*pmd) || !pmd_present (*pmd)) -note_page (st, addr,3 ,pmd_val (*pmd), domain); +note_page (st, addr,4 ,pmd_val (*pmd), domain);else walk_pte (st, pmd, addr, domain);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 216/862 ARM: 9247/1: mm: set readonly for MT_MEMORY_RO with ARM_LPAE
In reply to Greg Kroah-HartmanFrom: Wang Kefeng <[email protected]>
[ Upstream commit 14ca1a4690750bb54e1049e49f3140ef48958a6e ]
MT_MEMORY_RO is introduced by commit 598f0a99fa8a ("ARM: 9210/1:
Mark the FDT_FIXED sections as shareable"), which is a readonly memory type for FDT area, but there are some different between ARM_LPAE and non-ARM_LPAE, we need to setup PMD_SECT_AP2 and L_PMD_SECT_RDONLY for MT_MEMORY_RO when ARM_LAPE enabled.
non-ARM_LPAE 0xff800000-0xffa00000 2M PGD KERNEL ro NX SHDARM_LPAE 0xff800000-0xffc00000 4M PMD RW NX SHD
ARM_LPAE+fix 0xff800000-0xffc00000 4M PMD ro NX SHD
--- arch/arm/mm/mmu.c | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm/mm/mmu.c +4 -0
@@ -300,7 +300,11 @@ static struct mem_type mem_types[] __ro_after_init = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN | L_PTE_RDONLY, .prot_l1 =PMD_TYPE_TABLE , +#ifdef CONFIG_ARM_LPAE + .prot_sect = PMD_TYPE_SECT | L_PMD_SECT_RDONLY | PMD_SECT_AP2, +#else .prot_sect = PMD_TYPE_SECT, +#endif .domain = DOMAIN_KERNEL, }, [MT_ROM] = {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 217/862 ACPI: PCC: Release resources on address space setup failure path
In reply to Greg Kroah-HartmanFrom: Rafael Mendonca <[email protected]>
[ Upstream commit f890157e61b85ce8ae01a41ffa375e3b99853698 ]
The allocated memory for the pcc_data struct doesn't get freed under an error path in pcc_mbox_request_channel() or acpi_os_ioremap(). Also, the PCC mailbox channel doesn't get freed under an error path in acpi_os_ioremap().
--- drivers/acpi/acpi_pcc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/acpi/acpi_pcc.c +3 -0
@@ -63,6 +63,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,if (IS_ERR (data->pcc_chan)) {pr_err ("Failed to find PCC channel for subspace %d\n" , ctx->subspace_id); +kfree (data);return AE_NOT_FOUND ; }
@@ -72,6 +73,8 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,if (!data->pcc_comm_addr) {pr_err ("Failed to ioremap PCC comm region mem for %d\n" , ctx->subspace_id); +pcc_mbox_free_channel (data->pcc_chan); +kfree (data);return AE_NO_MEMORY ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 218/862 ACPI: PCC: replace wait_for_completion()
In reply to Greg Kroah-HartmanFrom: Huisong Li <[email protected]>
[ Upstream commit 91cefefb699120efd0a5ba345d12626b688f86ce ]
Currently, the function waiting for completion of mailbox operation is 'wait_for_completion()'. The PCC method will be permanently blocked if this mailbox message fails to execute. So this patch replaces it with 'wait_for_completion_timeout()'. And set the timeout interval to an arbitrary retries on top of nominal to prevent the remote processor is slow to respond to PCC commands.
--- drivers/acpi/acpi_pcc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
drivers/acpi/acpi_pcc.c +21 -2
@@ -23,6 +23,12 @@#include <acpi/pcc.h> +/* +* Arbitrary retries in case the remote processor is slow to respond +* to PCC commands +*/ +#define PCC_CMD_WAIT_RETRIES_NUM 500 +struct pcc_data {struct pcc_mbox_chan *pcc_chan;void __iomem *pcc_comm_addr;
@@ -89,6 +95,7 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, {int ret;struct pcc_data *data = region_context; +u64 usecs_lat;reinit_completion (&data->done);
@@ -99,8 +106,20 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,if (ret <0 )return AE_ERROR ; -if (data->pcc_chan->mchan->mbox->txdone_irq) -wait_for_completion (&data->done); +if (data->pcc_chan->mchan->mbox->txdone_irq) { +/* +* pcc_chan->latency is just a Nominal value. In reality the remote +* processor could be much slower to reply. So add an arbitrary +* amount of wait on top of Nominal. +*/ + usecs_lat =PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency; + ret =wait_for_completion_timeout (&data->done, +usecs_to_jiffies (usecs_lat)); +if (ret ==0 ) { +pr_err ("PCC command executed timeout!\n" ); +return AE_TIME ; + } + }mbox_client_txdone (data->pcc_chan->mchan, ret);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 219/862 ACPI: PCC: Fix Tx acknowledge in the PCC address space handler
In reply to Greg Kroah-HartmanFrom: Huisong Li <[email protected]>
[ Upstream commit 18729106c26fb97d4c9ae63ba7aba9889a058dc4 ]
Currently, mbox_client_txdone() is called from the PCC address space handler and that expects the user the Tx state machine to be controlled by the client which is not the case and the below warning is thrown:
| PCCT: Client can't run the TX ticker
Let the controller run the state machine and the end of Tx can be acknowledge by calling mbox_chan_txdone() instead.
--- drivers/acpi/acpi_pcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/acpi/acpi_pcc.c +1 -1
@@ -121,7 +121,7 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, } } -mbox_client_txdone (data->pcc_chan->mchan, ret); +mbox_chan_txdone (data->pcc_chan->mchan, ret);memcpy_fromio (value, data->pcc_comm_addr, data->ctx.length);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 220/862 objtool: Preserve special st_shndx indexes in elf_update_symbol
In reply to Greg Kroah-HartmanFrom: Sami Tolvanen <[email protected]>
[ Upstream commit 5141d3a06b2da1731ac82091298b766a1f95d3d8 ]
elf_update_symbol fails to preserve the special st_shndx values between [SHN_LORESERVE, SHN_HIRESERVE], which results in it converting SHN_ABS entries into SHN_UNDEF, for example. Explicitly check for the special indexes and ensure these symbols are not marked undefined.
--- tools/objtool/elf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/objtool/elf.c +6 -1
@@ -619,6 +619,11 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,Elf64_Xword entsize = symtab->sh.sh_entsize;int max_idx, idx = sym->idx;Elf_Scn *s, *t =NULL ; +bool is_special_shndx = sym->sym.st_shndx >=SHN_LORESERVE && + sym->sym.st_shndx !=SHN_XINDEX ; + +if (is_special_shndx) + shndx = sym->sym.st_shndx; s =elf_getscn (elf->elf, symtab->idx);if (!s) {
@@ -704,7 +709,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab, }/* setup extended section index magic and write the symbol */ -if (shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) { +if ((shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) || is_special_shndx) { sym->sym.st_shndx = shndx;if (!shndx_data) shndx =0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 221/862 nfsd: Fix a memory leak in an error handling path
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit fd1ef88049de09bc70d60b549992524cfc0e66ff ]
If this memdup_user() call fails, the memory allocated in a previous call a few lines above should be freed. Otherwise it leaks.
--- fs/nfsd/nfs4recover.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfsd/nfs4recover.c +3 -1
@@ -815,8 +815,10 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, princhash.data =memdup_user ( &ci->cc_princhash.cp_data, princhashlen); -if (IS_ERR_OR_NULL (princhash.data)) +if (IS_ERR_OR_NULL (princhash.data)) { +kfree (name.data);return -EFAULT ; + } princhash.len = princhashlen; }else princhash.len =0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 222/862 SUNRPC: Fix svcxdr_init_decodes end-of-buffer calculation
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 90bfc37b5ab91c1a6165e3e5cfc49bf04571b762 ]
Ensure that stream-based argument decoding can't go past the actual end of the receive buffer. xdr_init_decode's calculation of the value of xdr->end over-estimates the end of the buffer because the Linux kernel RPC server code does not remove the size of the RPC header from rqstp->rq_arg before calling the upper layer's dispatcher.
The server-side still uses the svc_getnl() macros to decode the RPC call header. These macros reduce the length of the head iov but do not update the total length of the message in the buffer (buf->len).
A proper fix for this would be to replace the use of svc_getnl() and friends in the RPC header decoder, but that would be a large and invasive change that would be difficult to backport.
--- include/linux/sunrpc/svc.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
include/linux/sunrpc/svc.h +14 -3
@@ -544,16 +544,27 @@ static inline void svc_reserve_auth(struct svc_rqst *rqstp, int space) }/** -* svcxdr_init_decode - Prepare an xdr_stream for svc Call decoding +* svcxdr_init_decode - Prepare an xdr_stream for Call decoding * @rqstp: controlling server RPC transaction context * +* This function currently assumes the RPC header in rq_arg has +* already been decoded. Upon return, xdr->p points to the +* location of the upper layer header. */ static inline void svcxdr_init_decode (struct svc_rqst *rqstp) {struct xdr_stream *xdr = &rqstp->rq_arg_stream; -struct kvec *argv = rqstp->rq_arg.head; +struct xdr_buf *buf = &rqstp->rq_arg; +struct kvec *argv = buf->head; -xdr_init_decode (xdr, &rqstp->rq_arg, argv->iov_base,NULL ); +/* +* svc_getnl() and friends do not keep the xdr_buf's ::len +* field up to date. Refresh that field before initializing +* the argument decoding stream. +*/ + buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len; + +xdr_init_decode (xdr, buf, argv->iov_base,NULL );xdr_set_scratch_page (xdr, rqstp->rq_scratch_page); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 223/862 SUNRPC: Fix svcxdr_init_encodes buflen calculation
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 1242a87da0d8cd2a428e96ca68e7ea899b0f4624 ]
Commit 2825a7f90753 ("nfsd4: allow encoding across page boundaries") added an explicit computation of the remaining length in the rq_res XDR buffer.
The computation appears to suffer from an "off-by-one" bug. Because buflen is too large by one page, XDR encoding can run off the end of the send buffer by eventually trying to use the struct page address in rq_page_end, which always contains NULL.
--- include/linux/sunrpc/svc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/sunrpc/svc.h +1 -1
@@ -587,7 +587,7 @@ static inline void svcxdr_init_encode(struct svc_rqst *rqstp) xdr->end = resv->iov_base +PAGE_SIZE - rqstp->rq_auth_slack; buf->len = resv->iov_len; xdr->page_ptr = buf->pages -1 ; - buf->buflen =PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages); + buf->buflen =PAGE_SIZE * (rqstp->rq_page_end - buf->pages); buf->buflen -= rqstp->rq_auth_slack; xdr->rqst =NULL ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 224/862 NFSD: Protect against send buffer overflow in NFSv2 READDIR
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 00b4492686e0497fdb924a9d4c8f6f99377e176c ]
Restore the previous limit on the @count argument to prevent a buffer overflow attack.
--- fs/nfsd/nfsproc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/nfsd/nfsproc.c +2 -3
@@ -568,12 +568,11 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,struct xdr_buf *buf = &resp->dirlist;struct xdr_stream *xdr = &resp->xdr; - count =clamp (count, (u32)(XDR_UNIT *2 ),svc_max_payload (rqstp)); -memset (buf,0 ,sizeof (*buf));/* Reserve room for the NULL ptr & eof flag (-2 words) */ - buf->buflen = count -XDR_UNIT *2 ; + buf->buflen =clamp (count, (u32)(XDR_UNIT *2 ), (u32 )PAGE_SIZE ); + buf->buflen -=XDR_UNIT *2 ; buf->pages = rqstp->rq_next_page; rqstp->rq_next_page++;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 225/862 NFSD: Fix handling of oversized NFSv4 COMPOUND requests
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 7518a3dc5ea249d4112156ce71b8b184eb786151 ]
If an NFS server returns NFS4ERR_RESOURCE on the first operation in an NFSv4 COMPOUND, there's no way for a client to know where the problem is and then simplify the compound to make forward progress.
So instead, make NFSD process as many operations in an oversized COMPOUND as it can and then return NFS4ERR_RESOURCE on the first operation it did not process.
pynfs NFSv4.0 COMP6 exercises this case, but checks only for the COMPOUND status code, not whether the server has processed any of the operations.
pynfs NFSv4.1 SEQ6 and SEQ7 exercise the NFSv4.1 case, which detects too many operations per COMPOUND by checking against the limits negotiated when the session was created.
--- fs/nfsd/nfs4proc.c | 19 +++++++++++++------ fs/nfsd/nfs4xdr.c | 12 +++--------- fs/nfsd/xdr4.h | 3 ++- 3 files changed, 18 insertions(+), 16 deletions(-)
fs/nfsd/nfs4proc.c +13 -6
@@ -2633,9 +2633,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) status = nfserr_minor_vers_mismatch;if (nfsd_minorversion (nn, args->minorversion,NFSD_TEST ) <=0 ) goto out; - status = nfserr_resource; -if (args->opcnt >NFSD_MAX_OPS_PER_COMPOUND ) - goto out; status =nfs41_check_op_ordering (args);if (status) {
@@ -2648,10 +2645,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) rqstp->rq_lease_breaker = (void **)&cstate->clp; -trace_nfsd_compound (rqstp, args->opcnt); +trace_nfsd_compound (rqstp, args->client_opcnt);while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; +if (unlikely (resp->opcnt ==NFSD_MAX_OPS_PER_COMPOUND )) { +/* If there are still more operations to process, +* stop here and report NFS4ERR_RESOURCE. */ +if (cstate->minorversion ==0 && + args->client_opcnt > resp->opcnt) { + op->status = nfserr_resource; + goto encode_op; + } + } +/* * The XDR decode routines may have pre-set op->status; * for example, if there is a miscellaneous XDR error
@@ -2727,8 +2734,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) status = op->status; } -trace_nfsd_compound_status (args->opcnt, resp->opcnt, status, -nfsd4_op_name (op->opnum)); +trace_nfsd_compound_status (args->client_opcnt, resp->opcnt, + status,nfsd4_op_name (op->opnum));nfsd4_cstate_clear_replay (cstate);nfsd4_increment_op_stats (op->opnum);
fs/nfsd/nfs4xdr.c +3 -9
@@ -2357,16 +2357,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)if (xdr_stream_decode_u32 (argp->xdr, &argp->minorversion) <0 )return false; -if (xdr_stream_decode_u32 (argp->xdr, &argp->opcnt) <0 ) +if (xdr_stream_decode_u32 (argp->xdr, &argp->client_opcnt) <0 )return false; - -/* -* NFS4ERR_RESOURCE is a more helpful error than GARBAGE_ARGS -* here, so we return success at the xdr level so that -* nfsd4_proc can handle this is an NFS-level error. -*/ -if (argp->opcnt >NFSD_MAX_OPS_PER_COMPOUND ) -return true; + argp->opcnt =min_t (u32, argp->client_opcnt, +NFSD_MAX_OPS_PER_COMPOUND );if (argp->opcnt >ARRAY_SIZE (argp->iops)) { argp->ops =kzalloc (argp->opcnt *sizeof (*argp->ops),GFP_KERNEL );
fs/nfsd/xdr4.h +2 -1
@@ -717,9 +717,10 @@ struct nfsd4_compoundargs {struct svcxdr_tmpbuf *to_free;struct svc_rqst *rqstp; -u32 taglen;char * tag; +u32 taglen;u32 minorversion; +u32 client_opcnt;u32 opcnt;struct nfsd4_op *ops;struct nfsd4_op iops[8 ];
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 226/862 x86/paravirt: add extra clobbers with ZERO_CALL_USED_REGS enabled
In reply to Greg Kroah-HartmanFrom: Bill Wendling <[email protected]>
[ Upstream commit 8c86f29bfb18465d15b05cfd26a6454ec787b793 ]
The ZERO_CALL_USED_REGS feature may zero out caller-saved registers before returning.
In spurious_kernel_fault(), the "pte_offset_kernel()" call results in this assembly code:
.Ltmp151:
#APP
# ALT: oldnstr
.Ltmp152:
.Ltmp153:
.Ltmp154:
.section .discard.retpoline_safe,"",@progbits
.quad .Ltmp154
.text
callq *pv_ops+536(%rip).Ltmp155:
.section .parainstructions,"a",@progbits
.p2align 3, 0x0
.quad .Ltmp153
.byte 67
.byte .Ltmp155-.Ltmp153
.short 1
.text.Ltmp156:
# ALT: padding
.zero (-(((.Ltmp157-.Ltmp158)-(.Ltmp156-.Ltmp152))>0))*((.Ltmp157-.Ltmp158)-(.Ltmp156-.Ltmp152)),144
.Ltmp159:
.section .altinstructions,"a",@progbits
.Ltmp160:
.long .Ltmp152-.Ltmp160
.Ltmp161:
.long .Ltmp158-.Ltmp161
.short 33040
.byte .Ltmp159-.Ltmp152
.byte .Ltmp157-.Ltmp158.text
.section .altinstr_replacement,"ax",@progbits
# ALT: replacement 1
.Ltmp158:
movq %rdi, %rax
.Ltmp157:
.text
#NO_APP
.Ltmp162:
testb $-128, %dilThe "testb" here is using %dil, but the %rdi register was cleared before returning from "callq *pv_ops+536(%rip)". Adding the proper constraints results in the use of a different register:
movq %r11, %rdi
# Similar to above.
testb $-128, %r11b--- arch/x86/include/asm/paravirt_types.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/include/asm/paravirt_types.h +10 -1
@@ -414,8 +414,17 @@ int paravirt_disable_iospace(void); "=c" (__ecx)#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax) -/* void functions are still allowed [re]ax for scratch */ +/* +* void functions are still allowed [re]ax for scratch. +* +* The ZERO_CALL_USED REGS feature may end up zeroing out callee-saved +* registers. Make sure we model this with the appropriate clobbers. +*/ +#ifdef CONFIG_ZERO_CALL_USED_REGS +#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), PVOP_VCALL_CLOBBERS +#else #define PVOP_VCALLEE_CLOBBERS "=a" (__eax) +#endif #define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11"
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 227/862 m68k: Process bootinfo records before saving them
In reply to Greg Kroah-HartmanFrom: Jason A. Donenfeld <[email protected]>
[ Upstream commit 7c236d93c6764dcaca7ab66d76768a044647876d ]
The RNG seed boot record is memzeroed after processing, in order to preserve forward secrecy. By saving the bootinfo for procfs prior to that, forward secrecy is violated, since it becomes possible to recover past states. So, save the bootinfo block only after first processing them.
--- arch/m68k/kernel/setup_mm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/m68k/kernel/setup_mm.c +3 -2
@@ -109,10 +109,9 @@ extern void paging_init(void);static void __init m68k_parse_bootinfo (const struct bi_record *record) { +const struct bi_record *first_record = record;uint16_t tag; -save_bootinfo (record); -while ((tag =be16_to_cpu (record->tag)) !=BI_LAST ) {int unknown =0 ;const void *data = record->data;
@@ -182,6 +181,8 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record) record = (struct bi_record *)((unsigned long )record + size); } +save_bootinfo (first_record); + m68k_realnum_memory = m68k_num_memory;#ifdef CONFIG_SINGLE_MEMORY_CHUNK if (m68k_num_memory >1 ) {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 228/862 libbpf: Initialize err in probe_map_create
In reply to Greg Kroah-HartmanFrom: Florian Fainelli <[email protected]>
[ Upstream commit 3045f42a64324d339125a8a1a1763bb9e1e08300 ]
GCC-11 warns about the possibly unitialized err variable in probe_map_create:
libbpf_probes.c: In function 'probe_map_create':
libbpf_probes.c:361:38: error: 'err' may be used uninitialized in this function [-Werror=maybe-uninitialized]
361 | return fd < 0 && err == exp_err ? 1 : 0;
| ~~~~^~~~~~~~~~--- tools/lib/bpf/libbpf_probes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/lib/bpf/libbpf_probes.c +1 -1
@@ -193,7 +193,7 @@ static int probe_map_create(enum bpf_map_type map_type)LIBBPF_OPTS (bpf_map_create_opts, opts);int key_size, value_size, max_entries;__u32 btf_key_type_id =0 , btf_value_type_id =0 ; -int fd =-1 , btf_fd =-1 , fd_inner =-1 , exp_err =0 , err; +int fd =-1 , btf_fd =-1 , fd_inner =-1 , exp_err =0 , err =0 ; key_size =sizeof (__u32); value_size =sizeof (__u32);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 229/862 wifi: rtlwifi: 8192de: correct checking of IQK reload
In reply to Greg Kroah-HartmanFrom: Ping-Ke Shih <[email protected]>
[ Upstream commit 93fbc1ebd978cf408ef5765e9c1630fce9a8621b ]
Since IQK could spend time, we make a cache of IQK result matrix that looks like iqk_matrix[channel_idx].val[x][y], and we can reload the matrix if we have made a cache. To determine a cache is made, we check iqk_matrix[channel_idx].val[0][0].
The initial commit 7274a8c22980 ("rtlwifi: rtl8192de: Merge phy routines") make a mistake that checks incorrect iqk_matrix[channel_idx].val[0] that is always true, and this mistake is found by commit ee3db469dd31 ("wifi: rtlwifi: remove always-true condition pointed out by GCC 12"), so I recall the vendor driver to find fix and apply the correctness.
--- drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +4 -5
@@ -2386,11 +2386,10 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)rtl_dbg (rtlpriv,COMP_SCAN ,DBG_LOUD ,"Just Read IQK Matrix reg for channel:%d....\n" , channel); -_rtl92d_phy_patha_fill_iqk_matrix (hw, true, - rtlphy->iqk_matrix[ - indexforchannel].value,0 , - (rtlphy->iqk_matrix[ - indexforchannel].value[0 ][2 ] ==0 )); +if (rtlphy->iqk_matrix[indexforchannel].value[0 ][0 ] !=0 ) +_rtl92d_phy_patha_fill_iqk_matrix (hw, true, + rtlphy->iqk_matrix[indexforchannel].value,0 , + rtlphy->iqk_matrix[indexforchannel].value[0 ][2 ] ==0 );if (IS_92D_SINGLEPHY (rtlhal->version)) {if ((rtlphy->iqk_matrix[ indexforchannel].value[0][4] != 0)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 230/862 wifi: ath10k: Set tx credit to one for WCN3990 snoc based devices
In reply to Greg Kroah-HartmanFrom: Youghandhar Chintala <[email protected]>
[ Upstream commit d81bbb684c250a637186d9286d75b1cb04d2986c ]
Currently host can send two WMI commands at once. There is possibility to cause SMMU issues or corruption, if host wants to initiate 2 DMA transfers, it is possible when copy complete interrupt for first DMA reaches host, CE has already updated SRRI (Source ring read index) for both DMA transfers and is in the middle of 2nd DMA. Host uses SRRI (Source ring read index) to interpret how many DMA’s have been completed and tries to unmap/free both the DMA entries. Hence now it is limiting to one.Because CE is still in the middle of 2nd DMA which can cause these issues when handling two DMA transfers.
This change will not impact other targets, as it is only for WCN3990.
Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.2.0-01387-QCAHLSWMTPLZ-1
Stable-dep-of: f020d9570a04 ("wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()")
--- drivers/net/wireless/ath/ath10k/core.c | 16 ++++++++++++++++ drivers/net/wireless/ath/ath10k/htc.c | 11 ++++++++--- drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath10k/core.c +16 -0
@@ -98,6 +98,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = true, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA988X_HW_2_0_VERSION,
@@ -136,6 +137,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = true, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9887_HW_1_0_VERSION,
@@ -175,6 +177,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA6174_HW_3_2_VERSION,
@@ -209,6 +212,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .supports_peer_stats_info = true, .dynamic_sar_support = true, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA6174_HW_2_1_VERSION,
@@ -247,6 +251,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA6174_HW_2_1_VERSION,
@@ -285,6 +290,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA6174_HW_3_0_VERSION,
@@ -323,6 +329,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA6174_HW_3_2_VERSION,
@@ -365,6 +372,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .supports_peer_stats_info = true, .dynamic_sar_support = true, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -409,6 +417,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9984_HW_1_0_DEV_VERSION,
@@ -460,6 +469,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9888_HW_2_0_DEV_VERSION,
@@ -508,6 +518,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9377_HW_1_0_DEV_VERSION,
@@ -546,6 +557,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9377_HW_1_1_DEV_VERSION,
@@ -586,6 +598,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA9377_HW_1_1_DEV_VERSION,
@@ -617,6 +630,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = true, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = QCA4019_HW_1_0_DEV_VERSION,
@@ -662,6 +676,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = false, .hw_restart_disconnect = false, + .use_fw_tx_credits = true, }, { .id = WCN3990_HW_1_0_DEV_VERSION,
@@ -693,6 +708,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .dynamic_sar_support = true, .hw_restart_disconnect = true, + .use_fw_tx_credits = false, }, };
drivers/net/wireless/ath/ath10k/htc.c +8 -3
@@ -947,13 +947,18 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)return -ECOMM ; } - htc->total_transmit_credits =__le16_to_cpu (msg->ready.credit_count); +if (ar->hw_params.use_fw_tx_credits) + htc->total_transmit_credits =__le16_to_cpu (msg->ready.credit_count); +else + htc->total_transmit_credits =1 ; + htc->target_credit_size =__le16_to_cpu (msg->ready.credit_size);ath10k_dbg (ar,ATH10K_DBG_HTC , -"Target ready! transmit resources: %d size:%d\n" , +"Target ready! transmit resources: %d size:%d actual credits:%d\n" , htc->total_transmit_credits, - htc->target_credit_size); + htc->target_credit_size, + msg->ready.credit_count);if ((htc->total_transmit_credits ==0 ) || (htc->target_credit_size ==0 )) {
drivers/net/wireless/ath/ath10k/hw.h +2 -0
@@ -635,6 +635,8 @@ struct ath10k_hw_params {bool dynamic_sar_support;bool hw_restart_disconnect; + +bool use_fw_tx_credits; };struct htt_resp ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 231/862 wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
In reply to Greg Kroah-HartmanFrom: Wen Gong <[email protected]>
[ Upstream commit f020d9570a04df0762a2ac5c50cf1d8c511c9164 ]
When peer delete failed in a disconnect operation, use-after-free detected by KFENCE in below log. It is because for each vdev_id and address, it has only one struct ath10k_peer, it is allocated in ath10k_peer_map_event(). When connected to an AP, it has more than one HTT_T2H_MSG_TYPE_PEER_MAP reported from firmware, then the array peer_map of struct ath10k will be set muti-elements to the same ath10k_peer in ath10k_peer_map_event(). When peer delete failed in ath10k_sta_state(), the ath10k_peer will be free for the 1st peer id in array peer_map of struct ath10k, and then use-after-free happened for the 2nd peer id because they map to the same ath10k_peer.
And clean up all peers in array peer_map for the ath10k_peer, then user-after-free disappeared
peer map event log:
[ 306.911021] wlan0: authenticate with b0:2a:43:e6:75:0e [ 306.957187] ath10k_pci 0000:01:00.0: mac vdev 0 peer create b0:2a:43:e6:75:0e (new sta) sta 1 / 32 peer 1 / 33 [ 306.957395] ath10k_pci 0000:01:00.0: htt peer map vdev 0 peer b0:2a:43:e6:75:0e id 246 [ 306.957404] ath10k_pci 0000:01:00.0: htt peer map vdev 0 peer b0:2a:43:e6:75:0e id 198 [ 306.986924] ath10k_pci 0000:01:00.0: htt peer map vdev 0 peer b0:2a:43:e6:75:0e id 166
peer unmap event log:
[ 435.715691] wlan0: deauthenticating from b0:2a:43:e6:75:0e by local choice (Reason: 3=DEAUTH_LEAVING) [ 435.716802] ath10k_pci 0000:01:00.0: mac vdev 0 peer delete b0:2a:43:e6:75:0e sta ffff990e0e9c2b50 (sta gone) [ 435.717177] ath10k_pci 0000:01:00.0: htt peer unmap vdev 0 peer b0:2a:43:e6:75:0e id 246 [ 435.717186] ath10k_pci 0000:01:00.0: htt peer unmap vdev 0 peer b0:2a:43:e6:75:0e id 198 [ 435.717193] ath10k_pci 0000:01:00.0: htt peer unmap vdev 0 peer b0:2a:43:e6:75:0e id 166
use-after-free log:
[21705.888627] wlan0: deauthenticating from d0:76:8f:82:be:75 by local choice (Reason: 3=DEAUTH_LEAVING) [21713.799910] ath10k_pci 0000:01:00.0: failed to delete peer d0:76:8f:82:be:75 for vdev 0: -110 [21713.799925] ath10k_pci 0000:01:00.0: found sta peer d0:76:8f:82:be:75 (ptr 0000000000000000 id 102) entry on vdev 0 after it was supposedly removed [21713.799968] ================================================================== [21713.799991] BUG: KFENCE: use-after-free read in ath10k_sta_state+0x265/0xb8a [ath10k_core] [21713.799991] [21713.799997] Use-after-free read at 0x00000000abe1c75e (in kfence-#69): [21713.800010] ath10k_sta_state+0x265/0xb8a [ath10k_core] [21713.800041] drv_sta_state+0x115/0x677 [mac80211] [21713.800059] __sta_info_destroy_part2+0xb1/0x133 [mac80211] [21713.800076] __sta_info_flush+0x11d/0x162 [mac80211] [21713.800093] ieee80211_set_disassoc+0x12d/0x2f4 [mac80211] [21713.800110] ieee80211_mgd_deauth+0x26c/0x29b [mac80211] [21713.800137] cfg80211_mlme_deauth+0x13f/0x1bb [cfg80211] [21713.800153] nl80211_deauthenticate+0xf8/0x121 [cfg80211] [21713.800161] genl_rcv_msg+0x38e/0x3be [21713.800166] netlink_rcv_skb+0x89/0xf7 [21713.800171] genl_rcv+0x28/0x36 [21713.800176] netlink_unicast+0x179/0x24b [21713.800181] netlink_sendmsg+0x3a0/0x40e [21713.800187] sock_sendmsg+0x72/0x76 [21713.800192] ____sys_sendmsg+0x16d/0x1e3 [21713.800196] ___sys_sendmsg+0x95/0xd1 [21713.800200] __sys_sendmsg+0x85/0xbf [21713.800205] do_syscall_64+0x43/0x55 [21713.800210] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [21713.800213] [21713.800219] kfence-#69: 0x000000009149b0d5-0x000000004c0697fb, size=1064, cache=kmalloc-2k [21713.800219] [21713.800224] allocated by task 13 on cpu 0 at 21705.501373s: [21713.800241] ath10k_peer_map_event+0x7e/0x154 [ath10k_core] [21713.800254] ath10k_htt_t2h_msg_handler+0x586/0x1039 [ath10k_core] [21713.800265] ath10k_htt_htc_t2h_msg_handler+0x12/0x28 [ath10k_core] [21713.800277] ath10k_htc_rx_completion_handler+0x14c/0x1b5 [ath10k_core] [21713.800283] ath10k_pci_process_rx_cb+0x195/0x1df [ath10k_pci] [21713.800294] ath10k_ce_per_engine_service+0x55/0x74 [ath10k_core] [21713.800305] ath10k_ce_per_engine_service_any+0x76/0x84 [ath10k_core] [21713.800310] ath10k_pci_napi_poll+0x49/0x144 [ath10k_pci] [21713.800316] net_rx_action+0xdc/0x361 [21713.800320] __do_softirq+0x163/0x29a [21713.800325] asm_call_irq_on_stack+0x12/0x20 [21713.800331] do_softirq_own_stack+0x3c/0x48 [21713.800337] __irq_exit_rcu+0x9b/0x9d [21713.800342] common_interrupt+0xc9/0x14d [21713.800346] asm_common_interrupt+0x1e/0x40 [21713.800351] ksoftirqd_should_run+0x5/0x16 [21713.800357] smpboot_thread_fn+0x148/0x211 [21713.800362] kthread+0x150/0x15f [21713.800367] ret_from_fork+0x22/0x30 [21713.800370] [21713.800374] freed by task 708 on cpu 1 at 21713.799953s: [21713.800498] ath10k_sta_state+0x2c6/0xb8a [ath10k_core] [21713.800515] drv_sta_state+0x115/0x677 [mac80211] [21713.800532] __sta_info_destroy_part2+0xb1/0x133 [mac80211] [21713.800548] __sta_info_flush+0x11d/0x162 [mac80211] [21713.800565] ieee80211_set_disassoc+0x12d/0x2f4 [mac80211] [21713.800581] ieee80211_mgd_deauth+0x26c/0x29b [mac80211] [21713.800598] cfg80211_mlme_deauth+0x13f/0x1bb [cfg80211] [21713.800614] nl80211_deauthenticate+0xf8/0x121 [cfg80211] [21713.800619] genl_rcv_msg+0x38e/0x3be [21713.800623] netlink_rcv_skb+0x89/0xf7 [21713.800628] genl_rcv+0x28/0x36 [21713.800632] netlink_unicast+0x179/0x24b [21713.800637] netlink_sendmsg+0x3a0/0x40e [21713.800642] sock_sendmsg+0x72/0x76 [21713.800646] ____sys_sendmsg+0x16d/0x1e3 [21713.800651] ___sys_sendmsg+0x95/0xd1 [21713.800655] __sys_sendmsg+0x85/0xbf [21713.800659] do_syscall_64+0x43/0x55 [21713.800663] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1
--- drivers/net/wireless/ath/ath10k/mac.c | 54 ++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-)
drivers/net/wireless/ath/ath10k/mac.c +29 -25
@@ -864,11 +864,36 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)return 0 ; } +static void ath10k_peer_map_cleanup (struct ath10k *ar,struct ath10k_peer *peer) +{ +int peer_id, i; + +lockdep_assert_held (&ar->conf_mutex); + +for_each_set_bit (peer_id, peer->peer_ids, +ATH10K_MAX_NUM_PEER_IDS ) { + ar->peer_map[peer_id] =NULL ; + } + +/* Double check that peer is properly un-referenced from +* the peer_map +*/ +for (i =0 ; i <ARRAY_SIZE (ar->peer_map); i++) { +if (ar->peer_map[i] == peer) { +ath10k_warn (ar,"removing stale peer_map entry for %pM (ptr %pK idx %d)\n" , + peer->addr, peer, i); + ar->peer_map[i] =NULL ; + } + } + +list_del (&peer->list); +kfree (peer); + ar->num_peers--; +} +static void ath10k_peer_cleanup (struct ath10k *ar,u32 vdev_id) {struct ath10k_peer *peer, *tmp; -int peer_id; -int i;lockdep_assert_held (&ar->conf_mutex);
@@ -880,25 +905,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)ath10k_warn (ar,"removing stale peer %pM from vdev_id %d\n" , peer->addr, vdev_id); -for_each_set_bit (peer_id, peer->peer_ids, -ATH10K_MAX_NUM_PEER_IDS ) { - ar->peer_map[peer_id] =NULL ; - } - -/* Double check that peer is properly un-referenced from -* the peer_map -*/ -for (i =0 ; i <ARRAY_SIZE (ar->peer_map); i++) { -if (ar->peer_map[i] == peer) { -ath10k_warn (ar,"removing stale peer_map entry for %pM (ptr %pK idx %d)\n" , - peer->addr, peer, i); - ar->peer_map[i] =NULL ; - } - } - -list_del (&peer->list); -kfree (peer); - ar->num_peers--; +ath10k_peer_map_cleanup (ar, peer); }spin_unlock_bh (&ar->data_lock); }
@@ -7621,10 +7628,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,/* Clean up the peer object as well since we * must have failed to do this above. */ -list_del (&peer->list); - ar->peer_map[i] =NULL ; -kfree (peer); - ar->num_peers--; +ath10k_peer_map_cleanup (ar, peer); } }spin_unlock_bh (&ar->data_lock);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 232/862 bpf: Cleanup check_refcount_ok
In reply to Greg Kroah-HartmanFrom: Dave Marchevsky <[email protected]>
[ Upstream commit b2d8ef19c6e7ed71ba5092feb0710063a751834f ]
Discussion around a recently-submitted patch provided historical context for check_refcount_ok [0]. Specifically, the function and its helpers - may_be_acquire_function and arg_type_may_be_refcounted - predate the OBJ_RELEASE type flag and the addition of many more helpers with acquire/release semantics.
The purpose of check_refcount_ok is to ensure:
1) Helper doesn't have multiple uses of return reg's ref_obj_id
2) Helper with release semantics only has one arg needing to be released, since that's tracked using meta->ref_obj_id
With current verifier, it's safe to remove check_refcount_ok and its helpers. Since addition of OBJ_RELEASE type flag, case 2) has been handled by the arg_type_is_release check in check_func_arg. To ensure case 1) won't result in verifier silently prioritizing one use of ref_obj_id, this patch adds a helper_multiple_ref_obj_use check which fails loudly if a helper passes > 1 test for use of ref_obj_id.
[0]: lore.kernel.org/bpf/[email protected]
Stable-dep-of: 883743422ced ("bpf: Fix ref_obj_id for dynptr data slices in verifier")
--- kernel/bpf/verifier.c | 74 +++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 45 deletions(-)
kernel/bpf/verifier.c +29 -45
@@ -467,25 +467,11 @@ static bool type_is_rdonly_mem(u32 type)return type &MEM_RDONLY ; } -static bool arg_type_may_be_refcounted (enum bpf_arg_type type) -{ -return type ==ARG_PTR_TO_SOCK_COMMON ; -} -static bool type_may_be_null (u32 type) {return type &PTR_MAYBE_NULL ; } -static bool may_be_acquire_function (enum bpf_func_id func_id) -{ -return func_id == BPF_FUNC_sk_lookup_tcp || - func_id == BPF_FUNC_sk_lookup_udp || - func_id == BPF_FUNC_skc_lookup_tcp || - func_id == BPF_FUNC_map_lookup_elem || - func_id == BPF_FUNC_ringbuf_reserve; -} -static bool is_acquire_function (enum bpf_func_id func_id,const struct bpf_map *map) {
@@ -518,6 +504,26 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id) func_id == BPF_FUNC_skc_to_tcp_request_sock; } +static bool is_dynptr_acquire_function (enum bpf_func_id func_id) +{ +return func_id == BPF_FUNC_dynptr_data; +} + +static bool helper_multiple_ref_obj_use (enum bpf_func_id func_id, +const struct bpf_map *map) +{ +int ref_obj_uses =0 ; + +if (is_ptr_cast_function (func_id)) + ref_obj_uses++; +if (is_acquire_function (func_id, map)) + ref_obj_uses++; +if (is_dynptr_acquire_function (func_id)) + ref_obj_uses++; + +return ref_obj_uses >1 ; +} +static bool is_cmpxchg_insn (const struct bpf_insn *insn) { return BPF_CLASS(insn->code) == BPF_STX &&
@@ -6456,33 +6462,6 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)return true; } -static bool check_refcount_ok (const struct bpf_func_proto *fn,int func_id) -{ -int count =0 ; - -if (arg_type_may_be_refcounted (fn->arg1_type)) - count++; -if (arg_type_may_be_refcounted (fn->arg2_type)) - count++; -if (arg_type_may_be_refcounted (fn->arg3_type)) - count++; -if (arg_type_may_be_refcounted (fn->arg4_type)) - count++; -if (arg_type_may_be_refcounted (fn->arg5_type)) - count++; - -/* A reference acquiring function cannot acquire -* another refcounted ptr. -*/ -if (may_be_acquire_function (func_id) && count) -return false; - -/* We only support one arg being unreferenced at the moment, -* which is sufficient for the helper functions we have right now. -*/ -return count <=1 ; -} -static bool check_btf_id_ok (const struct bpf_func_proto *fn) {int i;
@@ -6506,8 +6485,7 @@ static int check_func_proto(const struct bpf_func_proto *fn, int func_id, {return check_raw_mode_ok (fn) &&check_arg_pair_ok (fn) && -check_btf_id_ok (fn) && -check_refcount_ok (fn, func_id) ?0 : -EINVAL ; +check_btf_id_ok (fn) ?0 : -EINVAL ; }/* Packet data might have moved, any old PTR_TO_PACKET[_META,_END]
@@ -7460,6 +7438,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insnif (type_may_be_null (regs[BPF_REG_0 ].type)) regs[BPF_REG_0 ].id = ++env->id_gen; +if (helper_multiple_ref_obj_use (func_id, meta.map_ptr)) { +verbose (env,"verifier internal error: func %s#%d sets ref_obj_id more than once\n" , +func_id_name (func_id), func_id); +return -EFAULT ; + } +if (is_ptr_cast_function (func_id)) {/* For release_reference() */ regs[BPF_REG_0 ].ref_obj_id = meta.ref_obj_id;
@@ -7472,10 +7456,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0 ].id = id;/* For release_reference() */ regs[BPF_REG_0 ].ref_obj_id = id; - }else if (func_id == BPF_FUNC_dynptr_data) { + }else if (is_dynptr_acquire_function (func_id)) {int dynptr_id =0 , i; -/* Find the id of the dynptr we're acquiring a reference to */ +/* Find the id of the dynptr we're tracking the reference of */ for (i =0 ; i <MAX_BPF_FUNC_REG_ARGS ; i++) {if (arg_type_is_dynptr (fn->arg_type[i])) {if (dynptr_id) {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 233/862 bpf: Fix ref_obj_id for dynptr data slices in verifier
In reply to Greg Kroah-HartmanFrom: Joanne Koong <[email protected]>
[ Upstream commit 883743422ced8c961ab05dc63ec81b75a4e56052 ]
When a data slice is obtained from a dynptr (through the bpf_dynptr_data API), the ref obj id of the dynptr must be found and then associated with the data slice.
The ref obj id of the dynptr must be found *before* the caller saved regs are reset. Without this fix, the ref obj id tracking is not correct for dynptrs that are at an offset from the frame pointer.
Please also note that the data slice's ref obj id must be assigned after the ret types are parsed, since RET_PTR_TO_ALLOC_MEM-type return regs get zero-marked.
--- kernel/bpf/verifier.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
kernel/bpf/verifier.c +20 -18
@@ -504,7 +504,7 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id) func_id == BPF_FUNC_skc_to_tcp_request_sock; } -static bool is_dynptr_acquire_function (enum bpf_func_id func_id) +static bool is_dynptr_ref_function (enum bpf_func_id func_id) {return func_id == BPF_FUNC_dynptr_data; }
@@ -518,7 +518,7 @@ static bool helper_multiple_ref_obj_use(enum bpf_func_id func_id, ref_obj_uses++;if (is_acquire_function (func_id, map)) ref_obj_uses++; -if (is_dynptr_acquire_function (func_id)) +if (is_dynptr_ref_function (func_id)) ref_obj_uses++;return ref_obj_uses >1 ;
@@ -7322,6 +7322,23 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn } }break ; +case BPF_FUNC_dynptr_data: +for (i =0 ; i <MAX_BPF_FUNC_REG_ARGS ; i++) { +if (arg_type_is_dynptr (fn->arg_type[i])) { +if (meta.ref_obj_id) { +verbose (env,"verifier internal error: meta.ref_obj_id already set\n" ); +return -EFAULT ; + } +/* Find the id of the dynptr we're tracking the reference of */ + meta.ref_obj_id =stack_slot_get_id (env, ®s[BPF_REG_1 + i]); +break ; + } + } +if (i ==MAX_BPF_FUNC_REG_ARGS ) { +verbose (env,"verifier internal error: no dynptr in bpf_dynptr_data()\n" ); +return -EFAULT ; + } +break ; }if (err)
@@ -7444,7 +7461,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insnreturn -EFAULT ; } -if (is_ptr_cast_function (func_id)) { +if (is_ptr_cast_function (func_id) ||is_dynptr_ref_function (func_id)) {/* For release_reference() */ regs[BPF_REG_0 ].ref_obj_id = meta.ref_obj_id; }else if (is_acquire_function (func_id, meta.map_ptr)) {
@@ -7456,21 +7473,6 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0 ].id = id;/* For release_reference() */ regs[BPF_REG_0 ].ref_obj_id = id; - }else if (is_dynptr_acquire_function (func_id)) { -int dynptr_id =0 , i; - -/* Find the id of the dynptr we're tracking the reference of */ -for (i =0 ; i <MAX_BPF_FUNC_REG_ARGS ; i++) { -if (arg_type_is_dynptr (fn->arg_type[i])) { -if (dynptr_id) { -verbose (env,"verifier internal error: multiple dynptr args in func\n" ); -return -EFAULT ; - } - dynptr_id =stack_slot_get_id (env, ®s[BPF_REG_1 + i]); - } - } -/* For release_reference() */ - regs[BPF_REG_0 ].ref_obj_id = dynptr_id; }do_refine_retval_range (regs, fn->ret_type, func_id, &meta);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 234/862 leds: lm3601x: Dont use mutex after it was destroyed
In reply to Greg Kroah-HartmanFrom: Uwe Kleine-König <[email protected]>
[ Upstream commit 32f7eed0c763a9b89f6b357ec54b48398fc7b99e ]
The mutex might still be in use until the devm cleanup callback devm_led_classdev_flash_release() is called. This only happens some time after lm3601x_remove() completed.
--- drivers/leds/flash/leds-lm3601x.c | 2 -- 1 file changed, 2 deletions(-)
drivers/leds/flash/leds-lm3601x.c +0 -2
@@ -444,8 +444,6 @@ static int lm3601x_remove(struct i2c_client *client) {struct lm3601x_led *led =i2c_get_clientdata (client); -mutex_destroy (&led->lock); -return regmap_update_bits (led->regmap,LM3601X_ENABLE_REG ,LM3601X_ENABLE_MASK ,LM3601X_MODE_STANDBY );
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 235/862 tsnep: Fix TSNEP_INFO_TX_TIME register define
In reply to Greg Kroah-HartmanFrom: Gerhard Engleder <[email protected]>
[ Upstream commit 7d8dd6b5cd1d67dd96c132f91d7ad29c49ed3c59 ]
Fixed register define is not used, but register definition shall be kept in sync.
--- drivers/net/ethernet/engleder/tsnep_hw.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/ethernet/engleder/tsnep_hw.h +1 -2
@@ -92,8 +92,7 @@/* tsnep register */ #define TSNEP_INFO 0x0100 -#define TSNEP_INFO_RX_ASSIGN 0x00010000 -#define TSNEP_INFO_TX_TIME 0x00020000 +#define TSNEP_INFO_TX_TIME 0x00010000#define TSNEP_CONTROL 0x0108#define TSNEP_CONTROL_TX_RESET 0x00000001#define TSNEP_CONTROL_TX_ENABLE 0x00000002
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 236/862 net: prestera: cache port state for non-phylink ports too
In reply to Greg Kroah-HartmanFrom: Maksym Glubokiy <[email protected]>
[ Upstream commit 704438dd4f030c1b3d28a2a9c8f182c32d9b6bc4 ]
Port event data must stored to port-state cache regardless of whether the port uses phylink or not since this data is used by ethtool.
--- .../ethernet/marvell/prestera/prestera_main.c | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-)
drivers/net/ethernet/marvell/prestera/prestera_main.c +17 -19
@@ -799,32 +799,30 @@ static void prestera_port_handle_event(struct prestera_switch *sw, caching_dw = &port->cached_hw_stats.caching_dw; -if (port->phy_link) { -memset (&smac,0 ,sizeof (smac)); - smac.valid = true; - smac.oper = pevt->data.mac.oper; -if (smac.oper) { - smac.mode = pevt->data.mac.mode; - smac.speed = pevt->data.mac.speed; - smac.duplex = pevt->data.mac.duplex; - smac.fc = pevt->data.mac.fc; - smac.fec = pevt->data.mac.fec; -phylink_mac_change (port->phy_link, true); - }else { -phylink_mac_change (port->phy_link, false); - } -prestera_port_mac_state_cache_write (port, &smac); +memset (&smac,0 ,sizeof (smac)); + smac.valid = true; + smac.oper = pevt->data.mac.oper; +if (smac.oper) { + smac.mode = pevt->data.mac.mode; + smac.speed = pevt->data.mac.speed; + smac.duplex = pevt->data.mac.duplex; + smac.fc = pevt->data.mac.fc; + smac.fec = pevt->data.mac.fec; } +prestera_port_mac_state_cache_write (port, &smac);if (port->state_mac.oper) { -if (!port->phy_link) +if (port->phy_link) +phylink_mac_change (port->phy_link, true); +else netif_carrier_on (port->dev);if (!delayed_work_pending (caching_dw))queue_delayed_work (prestera_wq, caching_dw,0 ); - }else if (netif_running (port->dev) && -netif_carrier_ok (port->dev)) { -if (!port->phy_link) + }else { +if (port->phy_link) +phylink_mac_change (port->phy_link, false); +else if (netif_running (port->dev) &&netif_carrier_ok (port->dev))netif_carrier_off (port->dev);if (delayed_work_pending (caching_dw))
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 237/862 bpf: Fix reference state management for synchronous callbacks
In reply to Greg Kroah-HartmanFrom: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit 9d9d00ac29d0ef7ce426964de46fa6b380357d0a ]
Currently, verifier verifies callback functions (sync and async) as if they will be executed once, (i.e. it explores execution state as if the function was being called once). The next insn to explore is set to start of subprog and the exit from nested frame is handled using curframe > 0 and prepare_func_exit. In case of async callback it uses a customized variant of push_stack simulating a kind of branch to set up custom state and execution context for the async callback.
While this approach is simple and works when callback really will be executed only once, it is unsafe for all of our current helpers which are for_each style, i.e. they execute the callback multiple times.
A callback releasing acquired references of the caller may do so multiple times, but currently verifier sees it as one call inside the frame, which then returns to caller. Hence, it thinks it released some reference that the cb e.g. got access through callback_ctx (register filled inside cb from spilled typed register on stack).
Similarly, it may see that an acquire call is unpaired inside the callback, so the caller will copy the reference state of callback and then will have to release the register with new ref_obj_ids. But again, the callback may execute multiple times, but the verifier will only account for acquired references for a single symbolic execution of the callback, which will cause leaks.
Note that for async callback case, things are different. While currently we have bpf_timer_set_callback which only executes it once, even for multiple executions it would be safe, as reference state is NULL and check_reference_leak would force program to release state before BPF_EXIT. The state is also unaffected by analysis for the caller frame. Hence async callback is safe.
Since we want the reference state to be accessible, e.g. for pointers loaded from stack through callback_ctx's PTR_TO_STACK, we still have to copy caller's reference_state to callback's bpf_func_state, but we enforce that whatever references it adds to that reference_state has been released before it hits BPF_EXIT. This requires introducing a new callback_ref member in the reference state to distinguish between caller vs callee references. Hence, check_reference_leak now errors out if it sees we are in callback_fn and we have not released callback_ref refs. Since there can be multiple nested callbacks, like frame 0 -> cb1 -> cb2 etc. we need to also distinguish between whether this particular ref belongs to this callback frame or parent, and only error for our own, so we store state->frameno (which is always non-zero for callbacks).
In short, callbacks can read parent reference_state, but cannot mutate it, to be able to use pointers acquired by the caller. They must only undo their changes (by releasing their own acquired_refs before BPF_EXIT) on top of caller reference_state before returning (at which point the caller and callback state will match anyway, so no need to copy it back to caller).
--- include/linux/bpf_verifier.h | 11 ++++++++++ kernel/bpf/verifier.c | 42 ++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 9 deletions(-)
include/linux/bpf_verifier.h +11 -0
@@ -212,6 +212,17 @@ struct bpf_reference_state {* is used purely to inform the user of a reference leak. */ int insn_idx; +/* There can be a case like: +* main (frame 0) +* cb (frame 1) +* func (frame 3) +* cb (frame 4) +* Hence for frame 4, if callback_ref just stored boolean, it would be +* impossible to distinguish nested callback refs. Hence store the +* frameno and compare that to callback_ref in check_reference_leak when +* exiting a callback function. +*/ +int callback_ref; };/* state of the program:
kernel/bpf/verifier.c +33 -9
84 lines not on this page · raw message
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 238/862 wifi: mac80211: properly set old_links when removing a link
In reply to Greg Kroah-HartmanFrom: Shaul Triebitz <[email protected]>
[ Upstream commit a8f62399daa6917e7f9efeb79bce4dd2cd494a1e ]
In ieee80211_sta_remove_link, valid_links is set to the new_links before calling drv_change_sta_links, but is used for the old_links.
--- net/mac80211/sta_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/mac80211/sta_info.c +2 -2
@@ -2799,6 +2799,7 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)void ieee80211_sta_remove_link (struct sta_info *sta,unsigned int link_id) {struct ieee80211_sub_if_data *sdata = sta->sdata; +u16 old_links = sta->sta.valid_links;lockdep_assert_held (&sdata->local->sta_mtx);
@@ -2806,8 +2807,7 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id)if (test_sta_flag (sta,WLAN_STA_INSERTED ))drv_change_sta_links (sdata->local, sdata, &sta->sta, - sta->sta.valid_links, - sta->sta.valid_links & ~BIT (link_id)); + old_links, sta->sta.valid_links);sta_remove_link (sta, link_id, true); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 239/862 wifi: cfg80211: get correct AP link chandef
In reply to Greg Kroah-HartmanFrom: Shaul Triebitz <[email protected]>
[ Upstream commit bc1857619cc7612117d2ee1ed05b5bfeb638614b ]
When checking for channel regulatory validity, use the AP link chandef (and not mesh's chandef).
--- net/wireless/reg.c | 4 ++++ 1 file changed, 4 insertions(+)
net/wireless/reg.c +4 -0
@@ -2389,6 +2389,10 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)switch (iftype) {case NL80211_IFTYPE_AP :case NL80211_IFTYPE_P2P_GO : +if (!wdev->links[link].ap.beacon_interval) +continue ; + chandef = wdev->links[link].ap.chandef; +break ;case NL80211_IFTYPE_MESH_POINT :if (!wdev->u.mesh.beacon_interval)continue ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 240/862 wifi: mac80211: fix use-after-free
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
[ Upstream commit 40fb87129049ec5876dabf4a4d4aed6642b31f1a ]
We've already freed the assoc_data at this point, so need to use another copy of the AP (MLD) address instead.
--- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mac80211/mlme.c +1 -1
@@ -5122,7 +5122,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, resp.req_ies = ifmgd->assoc_req_ies; resp.req_ies_len = ifmgd->assoc_req_ies_len;if (sdata->vif.valid_links) - resp.ap_mld_addr = assoc_data->ap_addr; + resp.ap_mld_addr = sdata->vif.cfg.ap_addr;cfg80211_rx_assoc_resp (sdata->dev, &resp); notify_driver:drv_mgd_complete_tx (sdata->local, sdata, &info);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 241/862 wifi: mac80211: mlme: dont add empty EML capabilities
In reply to Greg Kroah-HartmanFrom: Mordechay Goodstein <[email protected]>
[ Upstream commit 1cb3cf372abe4a0d16620d2b1201de0e291a6c58 ]
Draft P802.11be_D2.1, section 35.3.17 states that the EML Capabilities Field shouldn't be included in case the device doesn't have support for EMLSR or EMLMR.
--- net/mac80211/mlme.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/mac80211/mlme.c +10 -3
@@ -1220,14 +1220,21 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata, ml_elem =skb_put (skb,sizeof (*ml_elem)); ml_elem->control =cpu_to_le16 (IEEE80211_ML_CONTROL_TYPE_BASIC | -IEEE80211_MLC_BASIC_PRES_EML_CAPA |IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP ); common =skb_put (skb,sizeof (*common)); common->len =sizeof (*common) + -2 +/* EML capabilities */ 2 ;/* MLD capa/ops */ memcpy (common->mld_mac_addr, sdata->vif.addr,ETH_ALEN ); -skb_put_data (skb, &eml_capa,sizeof (eml_capa)); + +/* add EML_CAPA only if needed, see Draft P802.11be_D2.1, 35.3.17 */ +if (eml_capa & +cpu_to_le16 ((IEEE80211_EML_CAP_EMLSR_SUPP | +IEEE80211_EML_CAP_EMLMR_SUPPORT ))) { + common->len +=2 ;/* EML capabilities */ + ml_elem->control |= +cpu_to_le16 (IEEE80211_MLC_BASIC_PRES_EML_CAPA ); +skb_put_data (skb, &eml_capa,sizeof (eml_capa)); + }/* need indication from userspace to support this */ mld_capa_ops &= ~cpu_to_le16 (IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP );skb_put_data (skb, &mld_capa_ops,sizeof (mld_capa_ops));
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 242/862 wifi: mac80211_hwsim: fix link change handling
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
[ Upstream commit 65f7052b6c38f767d95ebfa4ae4b389b6da6a421 ]
The code for determining which links to update in wmediumd or virtio was wrong, fix it to remove the deflink only if there were no old links, and also add the deflink if there are no other new links.
--- drivers/net/wireless/mac80211_hwsim.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/mac80211_hwsim.c +6 -1
@@ -2995,10 +2995,15 @@ static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, u16 old_links, u16 new_links, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { - unsigned long rem = old_links & ~new_links ?: BIT(0); + unsigned long rem = old_links & ~new_links;unsigned long add = new_links & ~old_links;int i; +if (!old_links) + rem |=BIT (0 ); +if (!new_links) + add |=BIT (0 ); +for_each_set_bit (i, &rem,IEEE80211_MLD_MAX_NUM_LINKS )mac80211_hwsim_config_mac_nl (hw, old[i]->addr, false);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 243/862 wifi: mac80211: allow bw change during channel switch in mesh
In reply to Greg Kroah-HartmanFrom: Hari Chandrakanthan <[email protected]>
[ Upstream commit 6b75f133fe05c36c52d691ff21545d5757fff721 ]
Quoted 1 line
From 'IEEE Std 802.11-2020 section 11.8.8.4.1':
The mesh channel switch may be triggered by the need to avoid interference to a detected radar signal, or to reassign mesh STA channels to ensure the MBSS connectivity.
A 20/40 MHz MBSS may be changed to a 20 MHz MBSS and a 20 MHz MBSS may be changed to a 20/40 MHz MBSS.
Since the standard allows the change of bandwidth during the channel switch in mesh, remove the bandwidth check present in ieee80211_set_csa_beacon.
--- net/mac80211/cfg.c | 3 --- 1 file changed, 3 deletions(-)
net/mac80211/cfg.c +0 -3
@@ -3597,9 +3597,6 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,case NL80211_IFTYPE_MESH_POINT : {struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; -if (params->chandef.width != sdata->vif.bss_conf.chandef.width) -return -EINVAL ; -/* changes into another band are not supported */ if (sdata->vif.bss_conf.chandef.chan->band != params->chandef.chan->band)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 244/862 bpftool: Fix a wrong type cast in btf_dumper_int
In reply to Greg Kroah-HartmanFrom: Lam Thai <[email protected]>
[ Upstream commit 7184aef9c0f7a81db8fd18d183ee42481d89bf35 ]
When data points to a boolean value, casting it to int * is problematic and could lead to a wrong value being passed to jsonw_bool. Change the cast to bool * instead.
--- tools/bpf/bpftool/btf_dumper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/bpf/bpftool/btf_dumper.c +1 -1
@@ -452,7 +452,7 @@ static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, *(char *)data);break ;case BTF_INT_BOOL : -jsonw_bool (jw, *(int *)data); +jsonw_bool (jw, *(bool *)data);break ;default :/* shouldn't happen */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 245/862 ice: set tx_tstamps when creating new Tx rings via ethtool
In reply to Greg Kroah-HartmanFrom: Jacob Keller <[email protected]>
[ Upstream commit b3b173745c8cab1e24d6821488b60abed3acb24d ]
When the user changes the number of queues via ethtool, the driver allocates new rings. This allocation did not initialize tx_tstamps. This results in the tx_tstamps field being zero (due to kcalloc allocation), and would result in a NULL pointer dereference when attempting a transmit timestamp on the new ring.
Stable-dep-of: fc5ae5b44eb2 ("Bluetooth: L2CAP: Fix build errors in some archs")
--- drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/intel/ice/ice_ethtool.c +1 -0
@@ -2826,6 +2826,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, tx_rings[i].count = new_tx_cnt; tx_rings[i].desc =NULL ; tx_rings[i].tx_buf =NULL ; + tx_rings[i].tx_tstamps = &pf->ptp.port.tx; err =ice_setup_tx_ring (&tx_rings[i]);if (err) {while (i--)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 246/862 audit: explicitly check audit_context->context enum value
In reply to Greg Kroah-HartmanFrom: Richard Guy Briggs <[email protected]>
[ Upstream commit 3ed66951f952ed8f1a5d03e171722bf2631e8d58 ]
Be explicit in checking the struct audit_context "context" member enum value rather than assuming the order of context enum values.
--- kernel/auditsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/auditsc.c +1 -1
@@ -2069,7 +2069,7 @@ void __audit_syscall_exit(int success, long return_code)/* run through both filters to ensure we set the filterkey properly */ audit_filter_syscall (current, context);audit_filter_inodes (current, context); -if (context->current_state <AUDIT_STATE_RECORD ) +if (context->current_state !=AUDIT_STATE_RECORD ) goto out;audit_log_exit ();
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 247/862 audit: free audit_proctitle only on task exit
In reply to Greg Kroah-HartmanFrom: Richard Guy Briggs <[email protected]>
[ Upstream commit c3f3ea8af44d0c5fba79fe8b198087342d0c7e04 ]
Since audit_proctitle is generated at syscall exit time, its value is used immediately and cached for the next syscall. Since this is the case, then only clear it at task exit time. Otherwise, there is no point in caching the value OR bearing the overhead of regenerating it.
--- kernel/auditsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/auditsc.c +1 -1
@@ -1016,7 +1016,6 @@ static void audit_reset_context(struct audit_context *ctx)WARN_ON (!list_empty (&ctx->killed_trees));audit_free_module (ctx); ctx->fds[0 ] =-1 ; -audit_proctitle_free (ctx); ctx->type =0 ;/* reset last for audit_free_*() */ }
@@ -1077,6 +1076,7 @@ static inline void audit_free_context(struct audit_context *context) {/* resetting is extra work, but it is likely just noise */ audit_reset_context (context); +audit_proctitle_free (context);free_tree_refs (context);kfree (context->filterkey);kfree (context);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 248/862 esp: choose the correct inner protocol for GSO on inter address family tunnels
In reply to Greg Kroah-HartmanFrom: Sabrina Dubroca <[email protected]>
[ Upstream commit 26dbd66eab8080be51759e48280da04015221e22 ]
Commit 23c7f8d7989e ("net: Fix esp GSO on inter address family tunnels.") is incomplete. It passes to skb_eth_gso_segment the protocol for the outer IP version, instead of the inner IP version, so we end up calling inet_gso_segment on an inner IPv6 packet and ipv6_gso_segment on an inner IPv4 packet and the packets are dropped.
This patch completes the fix by selecting the correct protocol based on the inner mode's family.
--- net/ipv4/esp4_offload.c | 5 ++++- net/ipv6/esp6_offload.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-)
net/ipv4/esp4_offload.c +4 -1
@@ -110,7 +110,10 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features) { - return skb_eth_gso_segment(skb, features, htons(ETH_P_IP)); +__be16 type = x->inner_mode.family ==AF_INET6 ?htons (ETH_P_IPV6 ) + :htons (ETH_P_IP ); + +return skb_eth_gso_segment (skb, features, type); } static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
net/ipv6/esp6_offload.c +4 -1
@@ -145,7 +145,10 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features) { - return skb_eth_gso_segment(skb, features, htons(ETH_P_IPV6)); +__be16 type = x->inner_mode.family ==AF_INET ?htons (ETH_P_IP ) + :htons (ETH_P_IPV6 ); + +return skb_eth_gso_segment (skb, features, type); } static struct sk_buff *xfrm6_transport_gso_segment(struct xfrm_state *x,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 249/862 spi: mt7621: Fix an error message in mt7621_spi_probe()
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit 2b2bf6b7faa9010fae10dc7de76627a3fdb525b3 ]
'status' is known to be 0 at this point. The expected error code is PTR_ERR(clk).
Switch to dev_err_probe() in order to display the expected error code (in a human readable way).
This also filters -EPROBE_DEFER cases, should it happen.
--- drivers/spi/spi-mt7621.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/spi/spi-mt7621.c +3 -5
@@ -340,11 +340,9 @@ static int mt7621_spi_probe(struct platform_device *pdev)return PTR_ERR (base); clk =devm_clk_get (&pdev->dev,NULL ); -if (IS_ERR (clk)) { -dev_err (&pdev->dev,"unable to get SYS clock, err=%d\n" , - status); -return PTR_ERR (clk); - } +if (IS_ERR (clk)) +return dev_err_probe (&pdev->dev,PTR_ERR (clk), +"unable to get SYS clock\n" ); status =clk_prepare_enable (clk);if (status)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 250/862 x86/resctrl: Fix to restore to original value when re-enabling hardware prefetch register
In reply to Greg Kroah-HartmanFrom: Kohei Tarumizu <[email protected]>
[ Upstream commit 499c8bb4693d1c8d8f3d6dd38e5bdde3ff5bd906 ]
The current pseudo_lock.c code overwrites the value of the MSR_MISC_FEATURE_CONTROL to 0 even if the original value is not 0. Therefore, modify it to save and restore the original values.
--- arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/resctrl/pseudo_lock.c +9 -3
@@ -420,6 +420,7 @@ static int pseudo_lock_fn(void *_rdtgrp)struct pseudo_lock_region *plr = rdtgrp->plr;u32 rmid_p, closid_p;unsigned long i; +u64 saved_msr;#ifdef CONFIG_KASAN /* * The registers used for local register variables are also used
@@ -463,6 +464,7 @@ static int pseudo_lock_fn(void *_rdtgrp)* the buffer and evict pseudo-locked memory read earlier from the * cache. */ + saved_msr =__rdmsr (MSR_MISC_FEATURE_CONTROL );__wrmsr (MSR_MISC_FEATURE_CONTROL , prefetch_disable_bits,0x0 ); closid_p =this_cpu_read (pqr_state.cur_closid); rmid_p =this_cpu_read (pqr_state.cur_rmid);
@@ -514,7 +516,7 @@ static int pseudo_lock_fn(void *_rdtgrp)__wrmsr (IA32_PQR_ASSOC , rmid_p, closid_p);/* Re-enable the hardware prefetcher(s) */ -wrmsr (MSR_MISC_FEATURE_CONTROL ,0x0 ,0x0 ); +wrmsrl (MSR_MISC_FEATURE_CONTROL , saved_msr);local_irq_enable (); plr->thread_done =1 ;
@@ -871,6 +873,7 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d)static int measure_cycles_lat_fn (void *_plr) {struct pseudo_lock_region *plr = _plr; +u32 saved_low, saved_high;unsigned long i;u64 start, end;void *mem_r;
@@ -879,6 +882,7 @@ static int measure_cycles_lat_fn(void *_plr)/* * Disable hardware prefetchers. */ +rdmsr (MSR_MISC_FEATURE_CONTROL , saved_low, saved_high);wrmsr (MSR_MISC_FEATURE_CONTROL , prefetch_disable_bits,0x0 ); mem_r =READ_ONCE (plr->kmem);/*
@@ -895,7 +899,7 @@ static int measure_cycles_lat_fn(void *_plr) end =rdtsc_ordered ();trace_pseudo_lock_mem_latency ((u32)(end - start)); } -wrmsr (MSR_MISC_FEATURE_CONTROL ,0x0 ,0x0 ); +wrmsr (MSR_MISC_FEATURE_CONTROL , saved_low, saved_high);local_irq_enable (); plr->thread_done =1 ;wake_up_interruptible (&plr->lock_thread_wq);
@@ -940,6 +944,7 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,u64 hits_before =0 , hits_after =0 , miss_before =0 , miss_after =0 ;struct perf_event *miss_event, *hit_event;int hit_pmcnum, miss_pmcnum; +u32 saved_low, saved_high;unsigned int line_size;unsigned int size;unsigned long i;
@@ -973,6 +978,7 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,/* * Disable hardware prefetchers. */ +rdmsr (MSR_MISC_FEATURE_CONTROL , saved_low, saved_high);wrmsr (MSR_MISC_FEATURE_CONTROL , prefetch_disable_bits,0x0 );/* Initialize rest of local variables */
@@ -1031,7 +1037,7 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,*/ rmb ();/* Re-enable hardware prefetchers */ -wrmsr (MSR_MISC_FEATURE_CONTROL ,0x0 ,0x0 ); +wrmsr (MSR_MISC_FEATURE_CONTROL , saved_low, saved_high);local_irq_enable (); out_hit:perf_event_release_kernel (hit_event);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 251/862 xsk: Fix backpressure mechanism on Tx
In reply to Greg Kroah-HartmanFrom: Maciej Fijalkowski <[email protected]>
[ Upstream commit c00c4461689e15ac2cc3b9a595a54e4d8afd3d77 ]
Commit d678cbd2f867 ("xsk: Fix handling of invalid descriptors in XSK TX batching API") fixed batch API usage against set of descriptors with invalid ones but introduced a problem when AF_XDP SW rings are smaller than HW ones. Mismatch of reported Tx'ed frames between HW generator and user space app was observed. It turned out that backpressure mechanism became a bottleneck when the amount of produced descriptors to CQ is lower than what we grabbed from XSK Tx ring.
Say that 512 entries had been taken from XSK Tx ring but we had only 490 free entries in CQ. Then callsite (ZC driver) will produce only 490 entries onto HW Tx ring but 512 entries will be released from Tx ring and this is what will be seen by the user space.
In order to fix this case, mix XSK Tx/CQ ring interractions by moving around internal functions and changing call order:
* pull out xskq_prod_nb_free() from xskq_prod_reserve_addr_batch() up to xsk_tx_peek_release_desc_batch();
** move xskq_cons_release_n() into xskq_cons_read_desc_batch()
After doing so, algorithm can be described as follows:
1. lookup Tx entries
2. use value from 1. to reserve space in CQ (*)
3. Read from Tx ring as much descriptors as value from 2 3a. release descriptors from XSK Tx ring (**)
4. Finally produce addresses to CQ
--- net/xdp/xsk.c | 22 +++++++++++----------- net/xdp/xsk_queue.h | 22 ++++++++++------------ 2 files changed, 21 insertions(+), 23 deletions(-)
net/xdp/xsk.c +11 -11
@@ -355,16 +355,15 @@ static u32 xsk_tx_peek_release_fallback(struct xsk_buff_pool *pool, u32 max_entrreturn nb_pkts; } -u32 xsk_tx_peek_release_desc_batch (struct xsk_buff_pool *pool,u32 max_entries) +u32 xsk_tx_peek_release_desc_batch (struct xsk_buff_pool *pool,u32 nb_pkts) {struct xdp_sock *xs; -u32 nb_pkts;rcu_read_lock ();if (!list_is_singular (&pool->xsk_tx_list)) {/* Fallback to the non-batched version */ rcu_read_unlock (); -return xsk_tx_peek_release_fallback (pool, max_entries); +return xsk_tx_peek_release_fallback (pool, nb_pkts); } xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock, tx_list);
@@ -373,12 +372,7 @@ u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max_entries) goto out; } - max_entries =xskq_cons_nb_entries (xs->tx, max_entries); - nb_pkts =xskq_cons_read_desc_batch (xs->tx, pool, max_entries); -if (!nb_pkts) { - xs->tx->queue_empty_descs++; - goto out; - } + nb_pkts =xskq_cons_nb_entries (xs->tx, nb_pkts);/* This is the backpressure mechanism for the Tx path. Try to * reserve space in the completion queue for all packets, but
@@ -386,12 +380,18 @@ u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max_entries)* packets. This avoids having to implement any buffering in * the Tx path. */ - nb_pkts =xskq_prod_reserve_addr_batch (pool->cq, pool->tx_descs, nb_pkts); + nb_pkts =xskq_prod_nb_free (pool->cq, nb_pkts);if (!nb_pkts) goto out; -xskq_cons_release_n (xs->tx, max_entries); + nb_pkts =xskq_cons_read_desc_batch (xs->tx, pool, nb_pkts); +if (!nb_pkts) { + xs->tx->queue_empty_descs++; + goto out; + } +__xskq_cons_release (xs->tx); +xskq_prod_write_addr_batch (pool->cq, pool->tx_descs, nb_pkts); xs->sk.sk_write_space (&xs->sk); out:
net/xdp/xsk_queue.h +10 -12
@@ -205,6 +205,11 @@ static inline bool xskq_cons_read_desc(struct xsk_queue *q,return false; } +static inline void xskq_cons_release_n (struct xsk_queue *q,u32 cnt) +{ + q->cached_cons += cnt; +} +static inline u32 xskq_cons_read_desc_batch (struct xsk_queue *q,struct xsk_buff_pool *pool,u32 max) {
@@ -226,6 +231,8 @@ static inline u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff cached_cons++; } +/* Release valid plus any invalid entries */ +xskq_cons_release_n (q, cached_cons - q->cached_cons);return nb_entries; }
@@ -291,11 +298,6 @@ static inline void xskq_cons_release(struct xsk_queue *q) q->cached_cons++; } -static inline void xskq_cons_release_n (struct xsk_queue *q,u32 cnt) -{ - q->cached_cons += cnt; -} -static inline u32 xskq_cons_present_entries (struct xsk_queue *q) {/* No barriers needed since data is not accessed */
@@ -350,21 +352,17 @@ static inline int xskq_prod_reserve_addr(struct xsk_queue *q, u64 addr)return 0 ; } -static inline u32 xskq_prod_reserve_addr_batch (struct xsk_queue *q,struct xdp_desc *descs, -u32 max) +static inline void xskq_prod_write_addr_batch (struct xsk_queue *q,struct xdp_desc *descs, +u32 nb_entries) {struct xdp_umem_ring *ring = (struct xdp_umem_ring *)q->ring; -u32 nb_entries, i, cached_prod; - - nb_entries =xskq_prod_nb_free (q, max); +u32 i, cached_prod;/* A, matches D */ cached_prod = q->cached_prod;for (i =0 ; i < nb_entries; i++) ring->desc[cached_prod++ & q->ring_mask] = descs[i].addr; q->cached_prod = cached_prod; - -return nb_entries; } static inline int xskq_prod_reserve_desc(struct xsk_queue *q,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 252/862 selftests/xsk: Add missing close() on netns fd
In reply to Greg Kroah-HartmanFrom: Maciej Fijalkowski <[email protected]>
[ Upstream commit 8a7d61bdc2fac2c460a2f32a062f5c6dbd21a764 ]
Commit 1034b03e54ac ("selftests: xsk: Simplify cleanup of ifobjects") removed close on netns fd, which is not correct, so let us restore it.
--- tools/testing/selftests/bpf/xskxceiver.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/testing/selftests/bpf/xskxceiver.c +4 -0
@@ -1606,6 +1606,8 @@ static struct ifobject *ifobject_create(void)if (!ifobj->umem) goto out_umem; + ifobj->ns_fd =-1 ; +return ifobj; out_umem:
@@ -1617,6 +1619,8 @@ static struct ifobject *ifobject_create(void)static void ifobject_delete (struct ifobject *ifobj) { +if (ifobj->ns_fd !=-1 ) +close (ifobj->ns_fd);free (ifobj->umem);free (ifobj->xsk_arr);free (ifobj);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 253/862 bpf: Disable preemption when increasing per-cpu map_locked
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
[ Upstream commit 2775da21628738ce073a3a6a806adcbaada0f091 ]
Per-cpu htab->map_locked is used to prohibit the concurrent accesses from both NMI and non-NMI contexts. But since commit 74d862b682f5 ("sched: Make migrate_disable/enable() independent of RT"), migrate_disable() is also preemptible under CONFIG_PREEMPT case, so now map_locked also disallows concurrent updates from normal contexts (e.g. userspace processes) unexpectedly as shown below:
process A process B
htab_map_update_elem()
htab_lock_bucket()
migrate_disable()
/* return 1 */
__this_cpu_inc_return()
/* preempted by B */
htab_map_update_elem()
/* the same bucket as A */
htab_lock_bucket()
migrate_disable()
/* return 2, so lock fails */
__this_cpu_inc_return()
return -EBUSYA fix that seems feasible is using in_nmi() in htab_lock_bucket() and only checking the value of map_locked for nmi context. But it will re-introduce dead-lock on bucket lock if htab_lock_bucket() is re-entered through non-tracing program (e.g. fentry program).
One cannot use preempt_disable() to fix this issue as htab_use_raw_lock being false causes the bucket lock to be a spin lock which can sleep and does not work with preempt_disable().
Therefore, use migrate_disable() when using the spinlock instead of preempt_disable() and defer fixing concurrent updates to when the kernel has its own BPF memory allocator.
--- kernel/bpf/hashtab.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
kernel/bpf/hashtab.c +18 -5
@@ -162,17 +162,25 @@ static inline int htab_lock_bucket(const struct bpf_htab *htab, unsigned long *pflags) {unsigned long flags; +bool use_raw_lock; hash = hash &HASHTAB_MAP_LOCK_MASK ; -migrate_disable (); + use_raw_lock =htab_use_raw_lock (htab); +if (use_raw_lock) +preempt_disable (); +else +migrate_disable ();if (unlikely (__this_cpu_inc_return (*(htab->map_locked[hash])) !=1 )) {__this_cpu_dec (*(htab->map_locked[hash])); -migrate_enable (); +if (use_raw_lock) +preempt_enable (); +else +migrate_enable ();return -EBUSY ; } -if (htab_use_raw_lock (htab)) +if (use_raw_lock)raw_spin_lock_irqsave (&b->raw_lock, flags);else spin_lock_irqsave (&b->lock, flags);
@@ -185,13 +193,18 @@ static inline void htab_unlock_bucket(const struct bpf_htab *htab, struct bucket *b, u32 hash, unsigned long flags) { + bool use_raw_lock = htab_use_raw_lock(htab); + hash = hash &HASHTAB_MAP_LOCK_MASK ; -if (htab_use_raw_lock (htab)) +if (use_raw_lock)raw_spin_unlock_irqrestore (&b->raw_lock, flags);else spin_unlock_irqrestore (&b->lock, flags);__this_cpu_dec (*(htab->map_locked[hash])); -migrate_enable (); +if (use_raw_lock) +preempt_enable (); +else +migrate_enable (); }static bool htab_lru_map_delete_node (void *arg,struct bpf_lru_node *node);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 254/862 bpf: Propagate error from htab_lock_bucket() to userspace
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
[ Upstream commit 66a7a92e4d0d091e79148a4c6ec15d1da65f4280 ]
In __htab_map_lookup_and_delete_batch() if htab_lock_bucket() returns -EBUSY, it will go to next bucket. Going to next bucket may not only skip the elements in current bucket silently, but also incur out-of-bound memory access or expose kernel memory to userspace if current bucket_cnt is greater than bucket_size or zero.
Fixing it by stopping batch operation and returning -EBUSY when htab_lock_bucket() fails, and the application can retry or skip the busy batch as needed.
--- kernel/bpf/hashtab.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
kernel/bpf/hashtab.c +5 -2
@@ -1704,8 +1704,11 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,/* do not grab the lock unless need it (bucket_cnt > 0). */ if (locked) { ret =htab_lock_bucket (htab, b, batch, &flags); -if (ret) - goto next_batch; +if (ret) { +rcu_read_unlock (); +bpf_enable_instrumentation (); + goto after_loop; + } } bucket_cnt =0 ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 255/862 wifi: ath11k: Fix incorrect QMI message ID mappings
In reply to Greg Kroah-HartmanFrom: Manikanta Pubbisetty <[email protected]>
[ Upstream commit b3ca32308e46b6384fdcb7e64b3fca4f61aff14b ]
QMI message IDs for some of the QMI messages were incorrectly defined in the original implementation. These have to be corrected to enable cold boot support on WCN6750. These corrections are applicable for all chipsets and will not impact them. Refactor the code accordingly.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00887-QCAMSLSWPLZ-1
--- drivers/net/wireless/ath/ath11k/qmi.c | 38 ++++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/qmi.h | 10 +++++-- 2 files changed, 43 insertions(+), 5 deletions(-)
drivers/net/wireless/ath/ath11k/qmi.c +35 -3
@@ -1696,6 +1696,13 @@ static struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { }, }; +static struct qmi_elem_info qmi_wlfw_fw_init_done_ind_msg_v01_ei[] = { + { + .data_type =QMI_EOTI , + .array_type =NO_ARRAY , + }, +}; +static int ath11k_qmi_host_cap_send (struct ath11k_base *ab) {struct qmi_wlanfw_host_cap_req_msg_v01 req;
@@ -3006,6 +3013,10 @@ static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl,struct ath11k_base *ab = qmi->ab;ath11k_dbg (ab,ATH11K_DBG_QMI ,"qmi firmware ready\n" ); + + ab->qmi.cal_done =1 ; +wake_up (&ab->qmi.cold_boot_waitq); +ath11k_qmi_driver_event_post (qmi,ATH11K_QMI_EVENT_FW_READY ,NULL ); }
@@ -3018,11 +3029,22 @@ static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl, struct ath11k_qmi, handle);struct ath11k_base *ab = qmi->ab; - ab->qmi.cal_done =1 ; -wake_up (&ab->qmi.cold_boot_waitq);ath11k_dbg (ab,ATH11K_DBG_QMI ,"qmi cold boot calibration done\n" ); } +static void ath11k_qmi_msg_fw_init_done_cb (struct qmi_handle *qmi_hdl, +struct sockaddr_qrtr *sq, +struct qmi_txn *txn, +const void *decoded) +{ +struct ath11k_qmi *qmi =container_of (qmi_hdl, + struct ath11k_qmi, handle); +struct ath11k_base *ab = qmi->ab; + +ath11k_qmi_driver_event_post (qmi,ATH11K_QMI_EVENT_FW_INIT_DONE ,NULL ); +ath11k_dbg (ab,ATH11K_DBG_QMI ,"qmi firmware init done\n" ); +} +static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { { .type =QMI_INDICATION ,
@@ -3053,6 +3075,14 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { sizeof(struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01), .fn = ath11k_qmi_msg_cold_boot_cal_done_cb, }, + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01, + .ei = qmi_wlfw_fw_init_done_ind_msg_v01_ei, + .decoded_size = + sizeof(struct qmi_wlfw_fw_init_done_ind_msg_v01), + .fn = ath11k_qmi_msg_fw_init_done_cb, + }, }; static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
@@ -3145,7 +3175,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) }break ; -case ATH11K_QMI_EVENT_FW_READY : +case ATH11K_QMI_EVENT_FW_INIT_DONE :clear_bit (ATH11K_FLAG_QMI_FAIL , &ab->dev_flags);if (test_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags)) {ath11k_hal_dump_srng_stats (ab);
@@ -3168,6 +3198,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)set_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags); } +break ; +case ATH11K_QMI_EVENT_FW_READY :break ;case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE :break ;
drivers/net/wireless/ath/ath11k/qmi.h +8 -2
@@ -31,8 +31,9 @@#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037 -#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0021 -#define QMI_WLFW_FW_READY_IND_V01 0x0038 +#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x003E +#define QMI_WLFW_FW_READY_IND_V01 0x0021 +#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144#define ATH11K_FIRMWARE_MODE_OFF 4
@@ -69,6 +70,7 @@ enum ath11k_qmi_event_type {ATH11K_QMI_EVENT_FORCE_FW_ASSERT ,ATH11K_QMI_EVENT_POWER_UP ,ATH11K_QMI_EVENT_POWER_DOWN , +ATH11K_QMI_EVENT_FW_INIT_DONE , ATH11K_QMI_EVENT_MAX, };
@@ -291,6 +293,10 @@ struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01 {char placeholder; }; +struct qmi_wlfw_fw_init_done_ind_msg_v01 { +char placeholder; +}; +#define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 235#define QMI_WLANFW_CAP_REQ_V01 0x0024
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 256/862 bpf: Use this_cpu_{inc|dec|inc_return} for bpf_task_storage_busy
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
[ Upstream commit 197827a05e13808c60f52632e9887eede63f1c16 ]
Now migrate_disable() does not disable preemption and under some architectures (e.g. arm64) __this_cpu_{inc|dec|inc_return} are neither preemption-safe nor IRQ-safe, so for fully preemptible kernel concurrent lookups or updates on the same task local storage and on the same CPU may make bpf_task_storage_busy be imbalanced, and bpf_task_storage_trylock() on the specific cpu will always fail.
Fixing it by using this_cpu_{inc|dec|inc_return} when manipulating bpf_task_storage_busy.
--- kernel/bpf/bpf_local_storage.c | 4 ++-- kernel/bpf/bpf_task_storage.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-)
kernel/bpf/bpf_local_storage.c +2 -2
@@ -555,11 +555,11 @@ void bpf_local_storage_map_free(struct bpf_local_storage_map *smap, struct bpf_local_storage_elem, map_node))) {if (busy_counter) {migrate_disable (); -__this_cpu_inc (*busy_counter); +this_cpu_inc (*busy_counter); }bpf_selem_unlink (selem, false);if (busy_counter) { -__this_cpu_dec (*busy_counter); +this_cpu_dec (*busy_counter);migrate_enable (); }cond_resched_rcu ();
kernel/bpf/bpf_task_storage.c +4 -4
@@ -26,20 +26,20 @@ static DEFINE_PER_CPU(int, bpf_task_storage_busy);static void bpf_task_storage_lock (void ) {migrate_disable (); -__this_cpu_inc (bpf_task_storage_busy); +this_cpu_inc (bpf_task_storage_busy); }static void bpf_task_storage_unlock (void ) { -__this_cpu_dec (bpf_task_storage_busy); +this_cpu_dec (bpf_task_storage_busy);migrate_enable (); }static bool bpf_task_storage_trylock (void ) {migrate_disable (); -if (unlikely (__this_cpu_inc_return (bpf_task_storage_busy) !=1 )) { -__this_cpu_dec (bpf_task_storage_busy); +if (unlikely (this_cpu_inc_return (bpf_task_storage_busy) !=1 )) { +this_cpu_dec (bpf_task_storage_busy);migrate_enable ();return false; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 257/862 bpf: Use this_cpu_{inc_return|dec} for prog->active
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
[ Upstream commit c89e843a11f1075d27684f6b42256213e4592383 ]
Both __this_cpu_inc_return() and __this_cpu_dec() are not preemption safe and now migrate_disable() doesn't disable preemption, so the update of prog-active is not atomic and in theory under fully preemptible kernel recurisve prevention may do not work.
Fixing by using the preemption-safe and IRQ-safe variants.
--- kernel/bpf/trampoline.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/bpf/trampoline.c +4 -4
@@ -895,7 +895,7 @@ u64 notrace __bpf_prog_enter(struct bpf_prog *prog, struct bpf_tramp_run_ctx *ru run_ctx->saved_run_ctx =bpf_set_run_ctx (&run_ctx->run_ctx); -if (unlikely (__this_cpu_inc_return (*(prog->active)) !=1 )) { +if (unlikely (this_cpu_inc_return (*(prog->active)) !=1 )) {inc_misses_counter (prog);return 0 ; }
@@ -930,7 +930,7 @@ void notrace __bpf_prog_exit(struct bpf_prog *prog, u64 start, struct bpf_tramp_bpf_reset_run_ctx (run_ctx->saved_run_ctx);update_prog_stats (prog, start); -__this_cpu_dec (*(prog->active)); +this_cpu_dec (*(prog->active));migrate_enable ();rcu_read_unlock (); }
@@ -966,7 +966,7 @@ u64 notrace __bpf_prog_enter_sleepable(struct bpf_prog *prog, struct bpf_tramp_rmigrate_disable ();might_fault (); -if (unlikely (__this_cpu_inc_return (*(prog->active)) !=1 )) { +if (unlikely (this_cpu_inc_return (*(prog->active)) !=1 )) {inc_misses_counter (prog);return 0 ; }
@@ -982,7 +982,7 @@ void notrace __bpf_prog_exit_sleepable(struct bpf_prog *prog, u64 start,bpf_reset_run_ctx (run_ctx->saved_run_ctx);update_prog_stats (prog, start); -__this_cpu_dec (*(prog->active)); +this_cpu_dec (*(prog->active));migrate_enable ();rcu_read_unlock_trace (); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 258/862 Bluetooth: btusb: mediatek: fix WMT failure during runtime suspend
In reply to Greg Kroah-HartmanFrom: Sean Wang <[email protected]>
[ Upstream commit fd3f106677bac70437dc12e76c827294ed495a44 ]
WMT cmd/event doesn't follow up the generic HCI cmd/event handling, it needs constantly polling control pipe until the host received the WMT event, thus, we should require to specifically acquire PM counter on the USB to prevent the interface from entering auto suspended while WMT cmd/event in progress.
--- drivers/bluetooth/btusb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/bluetooth/btusb.c +14 -0
@@ -2477,15 +2477,29 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,set_bit (BTUSB_TX_WAIT_VND_EVT , &data->flags); +/* WMT cmd/event doesn't follow up the generic HCI cmd/event handling, +* it needs constantly polling control pipe until the host received the +* WMT event, thus, we should require to specifically acquire PM counter +* on the USB to prevent the interface from entering auto suspended +* while WMT cmd/event in progress. +*/ + err =usb_autopm_get_interface (data->intf); +if (err <0 ) + goto err_free_wc; + err =__hci_cmd_send (hdev,0xfc6f , hlen, wc);if (err <0 ) {clear_bit (BTUSB_TX_WAIT_VND_EVT , &data->flags); +usb_autopm_put_interface (data->intf); goto err_free_wc; }/* Submit control IN URB on demand to process the WMT event */ err =btusb_mtk_submit_wmt_recv_urb (hdev); + +usb_autopm_put_interface (data->intf); +if (err <0 ) goto err_free_wc;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 259/862 bpf: Only add BTF IDs for socket security hooks when CONFIG_SECURITY_NETWORK is on
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
[ Upstream commit ef331a8d4c0061ea4d353cd0db1c9b33fd45f0f2 ]
When CONFIG_SECURITY_NETWORK is disabled, there will be build warnings from resolve_btfids:
WARN: resolve_btfids: unresolved symbol bpf_lsm_socket_socketpair
......
WARN: resolve_btfids: unresolved symbol bpf_lsm_inet_conn_established
Fixing it by wrapping these BTF ID definitions by CONFIG_SECURITY_NETWORK.
--- kernel/bpf/bpf_lsm.c | 6 ++++++ 1 file changed, 6 insertions(+)
kernel/bpf/bpf_lsm.c +6 -0
@@ -41,17 +41,21 @@ BTF_SET_END(bpf_lsm_hooks)*/ BTF_SET_START (bpf_lsm_current_hooks) /* operate on freshly allocated sk without any cgroup association */ +#ifdef CONFIG_SECURITY_NETWORK BTF_ID(func, bpf_lsm_sk_alloc_security) BTF_ID(func, bpf_lsm_sk_free_security) +#endif BTF_SET_END(bpf_lsm_current_hooks) /* List of LSM hooks that trigger while the socket is properly locked. */ BTF_SET_START(bpf_lsm_locked_sockopt_hooks) +#ifdef CONFIG_SECURITY_NETWORK BTF_ID(func, bpf_lsm_socket_sock_rcv_skb) BTF_ID(func, bpf_lsm_sock_graft) BTF_ID(func, bpf_lsm_inet_csk_clone) BTF_ID(func, bpf_lsm_inet_conn_established) +#endif BTF_SET_END(bpf_lsm_locked_sockopt_hooks)/* List of LSM hooks that trigger while the socket is _not_ locked,
@@ -59,8 +63,10 @@ BTF_SET_END(bpf_lsm_locked_sockopt_hooks)* in the early init phase. */ BTF_SET_START(bpf_lsm_unlocked_sockopt_hooks) +#ifdef CONFIG_SECURITY_NETWORK BTF_ID(func, bpf_lsm_socket_post_create) BTF_ID(func, bpf_lsm_socket_socketpair) +#endif BTF_SET_END(bpf_lsm_unlocked_sockopt_hooks)#ifdef CONFIG_CGROUP_BPF
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 260/862 wifi: rtw89: pci: fix interrupt stuck after leaving low power mode
In reply to Greg Kroah-HartmanFrom: Ping-Ke Shih <[email protected]>
[ Upstream commit b7e715d3dcd2e9fa3a689ba0dd7ab85f8aaf6e9a ]
We turn off interrupt in ISR, and re-enable interrupt in threadfn or napi_poll according to the mode it stays. If we are turning off interrupt, rtwpci->running flag is unset and interrupt handler stop processing even if it was called, so disallow to re-enable interrupt in this situation. Or, wifi chip doesn't trigger interrupt events anymore because interrupt status (ISR) isn't clear by interrupt handler anymore.
--- drivers/net/wireless/realtek/rtw89/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw89/pci.c +2 -1
@@ -760,7 +760,8 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) enable_intr:spin_lock_irqsave (&rtwpci->irq_lock, flags); -rtw89_chip_enable_intr (rtwdev, rtwpci); +if (likely (rtwpci->running)) +rtw89_chip_enable_intr (rtwdev, rtwpci);spin_unlock_irqrestore (&rtwpci->irq_lock, flags);return IRQ_HANDLED ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 261/862 wifi: rtw89: pci: correct TX resource checking in low power mode
In reply to Greg Kroah-HartmanFrom: Ping-Ke Shih <[email protected]>
[ Upstream commit 4a29213cd775cabcbe395229d175903accedbb9d ]
Number of TX resource must be minimum of TX_BD and TX_WD. Only considering TX_BD could drop TX packets pulled from mac80211 if TX_WD is unavailable.
--- drivers/net/wireless/realtek/rtw89/pci.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireless/realtek/rtw89/pci.c +2 -0
@@ -926,10 +926,12 @@ u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev, {struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; +struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;u32 cnt;spin_lock_bh (&rtwpci->trx_lock); cnt =rtw89_pci_get_avail_txbd_num (tx_ring); + cnt =min (cnt, wd_ring->curr_num);spin_unlock_bh (&rtwpci->trx_lock);return cnt;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 262/862 wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit 620d5eaeb9059636864bda83ca1c68c20ede34a5 ]
There some bounds checking to ensure that "map_addr" is not out of bounds before the start of the loop. But the checking needs to be done as we iterate through the loop because "map_addr" gets larger as we iterate.
--- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +7 -7
@@ -1878,13 +1878,6 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)/* We have 8 bits to indicate validity */ map_addr = offset *8 ; -if (map_addr >=EFUSE_MAP_LEN ) { -dev_warn (dev,"%s: Illegal map_addr (%04x), " -"efuse corrupt!\n" , - __func__, map_addr); - ret = -EINVAL ; - goto exit; - }for (i =0 ; i <EFUSE_MAX_WORD_UNIT ; i++) {/* Check word enable condition in the section */ if (word_mask &BIT (i)) {
@@ -1895,6 +1888,13 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) ret =rtl8xxxu_read_efuse8 (priv, efuse_addr++, &val8);if (ret) goto exit; +if (map_addr >=EFUSE_MAP_LEN -1 ) { +dev_warn (dev,"%s: Illegal map_addr (%04x), " +"efuse corrupt!\n" , + __func__, map_addr); + ret = -EINVAL ; + goto exit; + } priv->efuse_wifi.raw[map_addr++] = val8; ret =rtl8xxxu_read_efuse8 (priv, efuse_addr++, &val8);
Signature · 1 line
2.35.1