diff --git a/Makefile.rhelver b/Makefile.rhelver index 0985c5ccf4cf5..6a9c10d1e9711 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 10 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 553.74.1 +RHEL_RELEASE = 553.77.1 # # ZSTREAM diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/58f88071.failed b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/58f88071.failed new file mode 100644 index 0000000000000..f2f927fb84000 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/58f88071.failed @@ -0,0 +1,83 @@ +xfs: make sure sb_fdblocks is non-negative + +jira LE-4321 +Rebuild_History Non-Buildable kernel-4.18.0-553.76.1.el8_10 +commit-author Wengang Wang +commit 58f880711f2ba53fd5e959875aff5b3bf6d5c32e +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/58f88071.failed + +A user with a completely full filesystem experienced an unexpected +shutdown when the filesystem tried to write the superblock during +runtime. +kernel shows the following dmesg: + +[ 8.176281] XFS (dm-4): Metadata corruption detected at xfs_sb_write_verify+0x60/0x120 [xfs], xfs_sb block 0x0 +[ 8.177417] XFS (dm-4): Unmount and run xfs_repair +[ 8.178016] XFS (dm-4): First 128 bytes of corrupted metadata buffer: +[ 8.178703] 00000000: 58 46 53 42 00 00 10 00 00 00 00 00 01 90 00 00 XFSB............ +[ 8.179487] 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +[ 8.180312] 00000020: cf 12 dc 89 ca 26 45 29 92 e6 e3 8d 3b b8 a2 c3 .....&E)....;... +[ 8.181150] 00000030: 00 00 00 00 01 00 00 06 00 00 00 00 00 00 00 80 ................ +[ 8.182003] 00000040: 00 00 00 00 00 00 00 81 00 00 00 00 00 00 00 82 ................ +[ 8.182004] 00000050: 00 00 00 01 00 64 00 00 00 00 00 04 00 00 00 00 .....d.......... +[ 8.182004] 00000060: 00 00 64 00 b4 a5 02 00 02 00 00 08 00 00 00 00 ..d............. +[ 8.182005] 00000070: 00 00 00 00 00 00 00 00 0c 09 09 03 17 00 00 19 ................ +[ 8.182008] XFS (dm-4): Corruption of in-memory data detected. Shutting down filesystem +[ 8.182010] XFS (dm-4): Please unmount the filesystem and rectify the problem(s) + +When xfs_log_sb writes super block to disk, b_fdblocks is fetched from +m_fdblocks without any lock. As m_fdblocks can experience a positive -> +negative -> positive changing when the FS reaches fullness (see +xfs_mod_fdblocks). So there is a chance that sb_fdblocks is negative, and +because sb_fdblocks is type of unsigned long long, it reads super big. +And sb_fdblocks being bigger than sb_dblocks is a problem during log +recovery, xfs_validate_sb_write() complains. + +Fix: +As sb_fdblocks will be re-calculated during mount when lazysbcount is +enabled, We just need to make xfs_validate_sb_write() happy -- make sure +sb_fdblocks is not nenative. This patch also takes care of other percpu +counters in xfs_log_sb. + + Signed-off-by: Wengang Wang + Reviewed-by: Darrick J. Wong + Signed-off-by: Chandan Babu R +(cherry picked from commit 58f880711f2ba53fd5e959875aff5b3bf6d5c32e) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/xfs/libxfs/xfs_sb.c +diff --cc fs/xfs/libxfs/xfs_sb.c +index 6b7f3754a5e2,6b56f0f6d4c1..000000000000 +--- a/fs/xfs/libxfs/xfs_sb.c ++++ b/fs/xfs/libxfs/xfs_sb.c +@@@ -800,13 -1031,19 +800,19 @@@ xfs_log_sb + * reservations that have been taken out percpu counters. If we have an + * unclean shutdown, this will be corrected by log recovery rebuilding + * the counters from the AGF block counts. + - * + - * Do not update sb_frextents here because it is not part of the lazy + - * sb counters, despite having a percpu counter. It is always kept + - * consistent with the ondisk rtbitmap by xfs_trans_apply_sb_deltas() + - * and hence we don't need have to update it here. + */ +++<<<<<<< HEAD + + if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { + + mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); +++======= ++ if (xfs_has_lazysbcount(mp)) { ++ mp->m_sb.sb_icount = percpu_counter_sum_positive(&mp->m_icount); +++>>>>>>> 58f880711f2b (xfs: make sure sb_fdblocks is non-negative) + mp->m_sb.sb_ifree = min_t(uint64_t, +- percpu_counter_sum(&mp->m_ifree), ++ percpu_counter_sum_positive(&mp->m_ifree), + mp->m_sb.sb_icount); +- mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); ++ mp->m_sb.sb_fdblocks = ++ percpu_counter_sum_positive(&mp->m_fdblocks); + } + + xfs_sb_to_disk(bp->b_addr, &mp->m_sb); +* Unmerged path fs/xfs/libxfs/xfs_sb.c diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/6773da87.failed b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/6773da87.failed new file mode 100644 index 0000000000000..83ec6a06a73ff --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/6773da87.failed @@ -0,0 +1,277 @@ +xfs: fix error returns from xfs_bmapi_write + +jira LE-4321 +Rebuild_History Non-Buildable kernel-4.18.0-553.76.1.el8_10 +commit-author Christoph Hellwig +commit 6773da870ab89123d1b513da63ed59e32a29cb77 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/6773da87.failed + +xfs_bmapi_write can return 0 without actually returning a mapping in +mval in two different cases: + + 1) when there is absolutely no space available to do an allocation + 2) when converting delalloc space, and the allocation is so small + that it only covers parts of the delalloc extent before the + range requested by the caller + +Callers at best can handle one of these cases, but in many cases can't +cope with either one. Switch xfs_bmapi_write to always return a +mapping or return an error code instead. For case 1) above ENOSPC is +the obvious choice which is very much what the callers expect anyway. +For case 2) there is no really good error code, so pick a funky one +from the SysV streams portfolio. + +This fixes the reproducer here: + + https://lore.kernel.org/linux-xfs/CAEJPjCvT3Uag-pMTYuigEjWZHn1sGMZ0GCjVVCv29tNHK76Cgg@mail.gmail.com0/ + +which uses reserved blocks to create file systems that are gravely +out of space and thus cause at least xfs_file_alloc_space to hang +and trigger the lack of ENOSPC handling in xfs_dquot_disk_alloc. + +Note that this patch does not actually make any caller but +xfs_alloc_file_space deal intelligently with case 2) above. + + Signed-off-by: Christoph Hellwig + Reported-by: 刘通 + Reviewed-by: "Darrick J. Wong" + Signed-off-by: Chandan Babu R +(cherry picked from commit 6773da870ab89123d1b513da63ed59e32a29cb77) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/xfs/libxfs/xfs_bmap.c +# fs/xfs/scrub/quota_repair.c +# fs/xfs/scrub/rtbitmap_repair.c +# fs/xfs/xfs_iomap.c +diff --cc fs/xfs/libxfs/xfs_bmap.c +index e4c9d0ba25a2,14c9781ec0ce..000000000000 +--- a/fs/xfs/libxfs/xfs_bmap.c ++++ b/fs/xfs/libxfs/xfs_bmap.c +@@@ -4579,12 -4716,11 +4610,18 @@@ xfs_bmapi_convert_delalloc + if (error) + goto out_finish; + +++<<<<<<< HEAD + + error = -ENOSPC; + + if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) + + goto out_finish; + + error = -EFSCORRUPTED; + + if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) +++======= ++ if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) { ++ xfs_bmap_mark_sick(ip, whichfork); ++ error = -EFSCORRUPTED; +++>>>>>>> 6773da870ab8 (xfs: fix error returns from xfs_bmapi_write) + goto out_finish; + - } + + XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length)); + XFS_STATS_INC(mp, xs_xstrat_quick); +diff --cc fs/xfs/xfs_iomap.c +index 30306bbdd059,f5d0ed45721b..000000000000 +--- a/fs/xfs/xfs_iomap.c ++++ b/fs/xfs/xfs_iomap.c +@@@ -300,16 -322,10 +300,21 @@@ xfs_iomap_write_direct + if (error) + goto out_unlock; + +++<<<<<<< HEAD + + /* + + * Copy any maps to caller's array and return any error. + + */ + + if (nimaps == 0) { + + error = -ENOSPC; + + goto out_unlock; + + } + + + + if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) +++======= ++ if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) { ++ xfs_bmap_mark_sick(ip, XFS_DATA_FORK); +++>>>>>>> 6773da870ab8 (xfs: fix error returns from xfs_bmapi_write) + error = xfs_alert_fsblock_zero(ip, imap); + - } + + out_unlock: + *seq = xfs_iomap_inode_sequence(ip, 0); +* Unmerged path fs/xfs/scrub/quota_repair.c +* Unmerged path fs/xfs/scrub/rtbitmap_repair.c +diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c +index 0c8bee3abc3b..d21ed06642f9 100644 +--- a/fs/xfs/libxfs/xfs_attr_remote.c ++++ b/fs/xfs/libxfs/xfs_attr_remote.c +@@ -613,7 +613,6 @@ xfs_attr_rmtval_set_blk( + if (error) + return error; + +- ASSERT(nmap == 1); + ASSERT((map->br_startblock != DELAYSTARTBLOCK) && + (map->br_startblock != HOLESTARTBLOCK)); + +* Unmerged path fs/xfs/libxfs/xfs_bmap.c +diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c +index 747ec77912c3..906a60e9355e 100644 +--- a/fs/xfs/libxfs/xfs_da_btree.c ++++ b/fs/xfs/libxfs/xfs_da_btree.c +@@ -2146,8 +2146,8 @@ xfs_da_grow_inode_int( + struct xfs_inode *dp = args->dp; + int w = args->whichfork; + xfs_rfsblock_t nblks = dp->i_nblocks; +- struct xfs_bmbt_irec map, *mapp; +- int nmap, error, got, i, mapi; ++ struct xfs_bmbt_irec map, *mapp = ↦ ++ int nmap, error, got, i, mapi = 1; + + /* + * Find a spot in the file space to put the new block. +@@ -2163,14 +2163,7 @@ xfs_da_grow_inode_int( + error = xfs_bmapi_write(tp, dp, *bno, count, + xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, + args->total, &map, &nmap); +- if (error) +- return error; +- +- ASSERT(nmap <= 1); +- if (nmap == 1) { +- mapp = ↦ +- mapi = 1; +- } else if (nmap == 0 && count > 1) { ++ if (error == -ENOSPC && count > 1) { + xfs_fileoff_t b; + int c; + +@@ -2187,16 +2180,13 @@ xfs_da_grow_inode_int( + args->total, &mapp[mapi], &nmap); + if (error) + goto out_free_map; +- if (nmap < 1) +- break; + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } +- } else { +- mapi = 0; +- mapp = NULL; + } ++ if (error) ++ goto out_free_map; + + /* + * Count the blocks we got, make sure it matches the total. +* Unmerged path fs/xfs/scrub/quota_repair.c +* Unmerged path fs/xfs/scrub/rtbitmap_repair.c +diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c +index a6e40c35e9f1..afcbcf308c46 100644 +--- a/fs/xfs/xfs_bmap_util.c ++++ b/fs/xfs/xfs_bmap_util.c +@@ -861,33 +861,32 @@ xfs_alloc_file_space( + if (error) + goto error; + +- error = xfs_bmapi_write(tp, ip, startoffset_fsb, +- allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, +- &nimaps); +- if (error) +- goto error; +- +- ip->i_diflags |= XFS_DIFLAG_PREALLOC; +- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); +- +- error = xfs_trans_commit(tp); +- xfs_iunlock(ip, XFS_ILOCK_EXCL); +- if (error) +- break; +- + /* + * If the allocator cannot find a single free extent large + * enough to cover the start block of the requested range, +- * xfs_bmapi_write will return 0 but leave *nimaps set to 0. ++ * xfs_bmapi_write will return -ENOSR. + * + * In that case we simply need to keep looping with the same + * startoffset_fsb so that one of the following allocations + * will eventually reach the requested range. + */ +- if (nimaps) { ++ error = xfs_bmapi_write(tp, ip, startoffset_fsb, ++ allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, ++ &nimaps); ++ if (error) { ++ if (error != -ENOSR) ++ goto error; ++ error = 0; ++ } else { + startoffset_fsb += imapp->br_blockcount; + allocatesize_fsb -= imapp->br_blockcount; + } ++ ++ ip->i_diflags |= XFS_DIFLAG_PREALLOC; ++ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); ++ ++ error = xfs_trans_commit(tp); ++ xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + return error; +diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c +index dd541eaca818..2ec2e903dc0b 100644 +--- a/fs/xfs/xfs_dquot.c ++++ b/fs/xfs/xfs_dquot.c +@@ -328,7 +328,6 @@ xfs_dquot_disk_alloc( + if (error) + return error; + ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); +- ASSERT(nmaps == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + +* Unmerged path fs/xfs/xfs_iomap.c +diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c +index ae0964ec5909..c782b20af3f1 100644 +--- a/fs/xfs/xfs_reflink.c ++++ b/fs/xfs/xfs_reflink.c +@@ -428,13 +428,6 @@ xfs_reflink_fill_cow_hole( + if (error) + return error; + +- /* +- * Allocation succeeded but the requested range was not even partially +- * satisfied? Bail out! +- */ +- if (nimaps == 0) +- return -ENOSPC; +- + convert: + return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); + +@@ -497,13 +490,6 @@ xfs_reflink_fill_delalloc( + error = xfs_trans_commit(tp); + if (error) + return error; +- +- /* +- * Allocation succeeded but the requested range was not even +- * partially satisfied? Bail out! +- */ +- if (nimaps == 0) +- return -ENOSPC; + } while (cmap->br_startoff + cmap->br_blockcount <= imap->br_startoff); + + return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); +diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c +index 699066fb9052..32ee98725f54 100644 +--- a/fs/xfs/xfs_rtalloc.c ++++ b/fs/xfs/xfs_rtalloc.c +@@ -815,8 +815,6 @@ xfs_growfs_rt_alloc( + nmap = 1; + error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks, + XFS_BMAPI_METADATA, 0, &map, &nmap); +- if (!error && nmap < 1) +- error = -ENOSPC; + if (error) + goto out_trans_cancel; + /* diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/c0a581d7.failed b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/c0a581d7.failed new file mode 100644 index 0000000000000..5f62b37cac686 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/c0a581d7.failed @@ -0,0 +1,279 @@ +tracing: Disable interrupt or preemption before acquiring arch_spinlock_t + +jira LE-4321 +Rebuild_History Non-Buildable kernel-4.18.0-553.76.1.el8_10 +Rebuild_CHGLOG: - tracing: Disable interrupt or preemption before acquiring arch_spinlock_t (partial) (Luis Claudio R. Goncalves) [RHEL-95713] +Rebuild_FUZZ: 93.59% +commit-author Waiman Long +commit c0a581d7126c0bbc96163276f585fd7b4e4d8d0e +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/c0a581d7.failed + +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. + +Link: https://lkml.kernel.org/r/20220922145622.1744826-1-longman@redhat.com + + Cc: Peter Zijlstra + Cc: Ingo Molnar + Cc: Will Deacon + Cc: Boqun Feng + Cc: stable@vger.kernel.org +Fixes: a35873a0993b ("tracing: Add conditional snapshot") +Fixes: 939c7a4f04fc ("tracing: Introduce saved_cmdlines_size file") + Suggested-by: Steven Rostedt + Signed-off-by: Waiman Long + Signed-off-by: Steven Rostedt (Google) +(cherry picked from commit c0a581d7126c0bbc96163276f585fd7b4e4d8d0e) + Signed-off-by: Jonathan Maple + +# Conflicts: +# kernel/trace/trace.c +diff --cc kernel/trace/trace.c +index 6bd22b13d8d9,aed7ea6e6045..000000000000 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@@ -1086,6 -1156,56 +1086,59 @@@ void tracing_snapshot(void + } + EXPORT_SYMBOL_GPL(tracing_snapshot); + +++<<<<<<< HEAD +++======= ++ /** ++ * tracing_snapshot_cond - conditionally take a snapshot of the current buffer. ++ * @tr: The tracing instance to snapshot ++ * @cond_data: The data to be tested conditionally, and possibly saved ++ * ++ * This is the same as tracing_snapshot() except that the snapshot is ++ * conditional - the snapshot will only happen if the ++ * cond_snapshot.update() implementation receiving the cond_data ++ * returns true, which means that the trace array's cond_snapshot ++ * update() operation used the cond_data to determine whether the ++ * snapshot should be taken, and if it was, presumably saved it along ++ * with the snapshot. ++ */ ++ void tracing_snapshot_cond(struct trace_array *tr, void *cond_data) ++ { ++ tracing_snapshot_instance_cond(tr, cond_data); ++ } ++ EXPORT_SYMBOL_GPL(tracing_snapshot_cond); ++ ++ /** ++ * tracing_cond_snapshot_data - get the user data associated with a snapshot ++ * @tr: The tracing instance ++ * ++ * When the user enables a conditional snapshot using ++ * tracing_snapshot_cond_enable(), the user-defined cond_data is saved ++ * with the snapshot. This accessor is used to retrieve it. ++ * ++ * Should not be called from cond_snapshot.update(), since it takes ++ * the tr->max_lock lock, which the code calling ++ * cond_snapshot.update() has already done. ++ * ++ * Returns the cond_data associated with the trace array's snapshot. ++ */ ++ void *tracing_cond_snapshot_data(struct trace_array *tr) ++ { ++ 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; ++ } ++ EXPORT_SYMBOL_GPL(tracing_cond_snapshot_data); ++ +++>>>>>>> c0a581d7126c (tracing: Disable interrupt or preemption before acquiring arch_spinlock_t) + static int resize_buffer_duplicate_size(struct array_buffer *trace_buf, + struct array_buffer *size_buf, int cpu_id); + static void set_buffer_entries(struct array_buffer *buf, unsigned long val); +@@@ -1165,6 -1285,104 +1218,107 @@@ void tracing_snapshot_alloc(void + tracing_snapshot(); + } + EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); +++<<<<<<< HEAD +++======= ++ ++ /** ++ * tracing_snapshot_cond_enable - enable conditional snapshot for an instance ++ * @tr: The tracing instance ++ * @cond_data: User data to associate with the snapshot ++ * @update: Implementation of the cond_snapshot update function ++ * ++ * Check whether the conditional snapshot for the given instance has ++ * already been enabled, or if the current tracer is already using a ++ * snapshot; if so, return -EBUSY, else create a cond_snapshot and ++ * save the cond_data and update function inside. ++ * ++ * Returns 0 if successful, error otherwise. ++ */ ++ int tracing_snapshot_cond_enable(struct trace_array *tr, void *cond_data, ++ cond_update_fn_t update) ++ { ++ struct cond_snapshot *cond_snapshot; ++ int ret = 0; ++ ++ cond_snapshot = kzalloc(sizeof(*cond_snapshot), GFP_KERNEL); ++ if (!cond_snapshot) ++ return -ENOMEM; ++ ++ cond_snapshot->cond_data = cond_data; ++ cond_snapshot->update = update; ++ ++ mutex_lock(&trace_types_lock); ++ ++ ret = tracing_alloc_snapshot_instance(tr); ++ if (ret) ++ goto fail_unlock; ++ ++ if (tr->current_trace->use_max_tr) { ++ ret = -EBUSY; ++ goto fail_unlock; ++ } ++ ++ /* ++ * The cond_snapshot can only change to NULL without the ++ * trace_types_lock. We don't care if we race with it going ++ * to NULL, but we want to make sure that it's not set to ++ * something other than NULL when we get here, which we can ++ * do safely with only holding the trace_types_lock and not ++ * having to take the max_lock. ++ */ ++ if (tr->cond_snapshot) { ++ ret = -EBUSY; ++ 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); ++ ++ return ret; ++ ++ fail_unlock: ++ mutex_unlock(&trace_types_lock); ++ kfree(cond_snapshot); ++ return ret; ++ } ++ EXPORT_SYMBOL_GPL(tracing_snapshot_cond_enable); ++ ++ /** ++ * tracing_snapshot_cond_disable - disable conditional snapshot for an instance ++ * @tr: The tracing instance ++ * ++ * Check whether the conditional snapshot for the given instance is ++ * enabled; if so, free the cond_snapshot associated with it, ++ * otherwise return -EINVAL. ++ * ++ * Returns 0 if successful, error otherwise. ++ */ ++ int tracing_snapshot_cond_disable(struct trace_array *tr) ++ { ++ int ret = 0; ++ ++ local_irq_disable(); ++ arch_spin_lock(&tr->max_lock); ++ ++ if (!tr->cond_snapshot) ++ ret = -EINVAL; ++ else { ++ kfree(tr->cond_snapshot); ++ tr->cond_snapshot = NULL; ++ } ++ ++ arch_spin_unlock(&tr->max_lock); ++ local_irq_enable(); ++ ++ return ret; ++ } ++ EXPORT_SYMBOL_GPL(tracing_snapshot_cond_disable); +++>>>>>>> c0a581d7126c (tracing: Disable interrupt or preemption before acquiring arch_spinlock_t) + #else + void tracing_snapshot(void) + { +@@@ -1864,10 -2195,22 +2018,15 @@@ void tracing_reset_all_online_cpus(void + } + } + + -/* + - * The tgid_map array maps from pid to tgid; i.e. the value stored at index i + - * is the tgid last observed corresponding to pid=i. + - */ + static int *tgid_map; + + -/* The maximum valid index into tgid_map. */ + -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]; +@@@ -5401,6 -6390,18 +5568,21 @@@ static int tracing_set_tracer(struct tr + if (t == tr->current_trace) + goto out; + +++<<<<<<< HEAD +++======= ++ #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; ++ } ++ #endif +++>>>>>>> c0a581d7126c (tracing: Disable interrupt or preemption before acquiring arch_spinlock_t) + /* Some tracers won't work on kernel command line */ + if (system_state < SYSTEM_RUNNING && t->noboot) { + pr_warn("Tracer '%s' is not allowed on command line, ignored\n", +@@@ -6484,6 -7457,15 +6666,18 @@@ tracing_snapshot_write(struct file *fil + goto out; + } + +++<<<<<<< HEAD +++======= ++ 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; ++ +++>>>>>>> c0a581d7126c (tracing: Disable interrupt or preemption before acquiring arch_spinlock_t) + switch (val) { + case 0: + if (iter->cpu_file != RING_BUFFER_ALL_CPUS) { +* Unmerged path kernel/trace/trace.c diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/cffd0441.failed b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/cffd0441.failed new file mode 100644 index 0000000000000..f4ea401289311 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/cffd0441.failed @@ -0,0 +1,410 @@ +use uniform permission checks for all mount propagation changes + +jira LE-4321 +cve CVE-2025-38498 +Rebuild_History Non-Buildable kernel-4.18.0-553.76.1.el8_10 +commit-author Al Viro +commit cffd0441872e7f6b1fce5e78fb1c99187a291330 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/cffd0441.failed + +do_change_type() and do_set_group() are operating on different +aspects of the same thing - propagation graph. The latter +asks for mounts involved to be mounted in namespace(s) the caller +has CAP_SYS_ADMIN for. The former is a mess - originally it +didn't even check that mount *is* mounted. That got fixed, +but the resulting check turns out to be too strict for userland - +in effect, we check that mount is in our namespace, having already +checked that we have CAP_SYS_ADMIN there. + +What we really need (in both cases) is + * only touch mounts that are mounted. That's a must-have +constraint - data corruption happens if it get violated. + * don't allow to mess with a namespace unless you already +have enough permissions to do so (i.e. CAP_SYS_ADMIN in its userns). + +That's an equivalent of what do_set_group() does; let's extract that +into a helper (may_change_propagation()) and use it in both +do_set_group() and do_change_type(). + +Fixes: 12f147ddd6de "do_change_type(): refuse to operate on unmounted/not ours mounts" + Acked-by: Andrei Vagin + Reviewed-by: Pavel Tikhomirov + Tested-by: Pavel Tikhomirov + Reviewed-by: Christian Brauner + Signed-off-by: Al Viro +(cherry picked from commit cffd0441872e7f6b1fce5e78fb1c99187a291330) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/namespace.c +diff --cc fs/namespace.c +index 8d5d50e2d2ff,88db58061919..000000000000 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@@ -2251,9 -2856,22 +2251,22 @@@ static int graft_tree(struct mount *mnt + d_is_dir(mnt->mnt.mnt_root)) + return -ENOTDIR; + + - return attach_recursive_mnt(mnt, p, mp); + + return attach_recursive_mnt(mnt, p, mp, NULL); + } + ++ static int may_change_propagation(const struct mount *m) ++ { ++ struct mnt_namespace *ns = m->mnt_ns; ++ ++ // it must be mounted in some namespace ++ if (IS_ERR_OR_NULL(ns)) // is_mounted() ++ return -EINVAL; ++ // and the caller must be admin in userns of that namespace ++ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) ++ return -EPERM; ++ return 0; ++ } ++ + /* + * Sanity check the flags to change_mnt_propagation. + */ +@@@ -2612,64 -3347,291 +2625,156 @@@ static inline int tree_contains_unbinda + return 0; + } + +++<<<<<<< HEAD +++======= ++ static int do_set_group(struct path *from_path, struct path *to_path) ++ { ++ struct mount *from, *to; ++ int err; ++ ++ from = real_mount(from_path->mnt); ++ to = real_mount(to_path->mnt); ++ ++ namespace_lock(); ++ ++ err = may_change_propagation(from); ++ if (err) ++ goto out; ++ err = may_change_propagation(to); ++ if (err) ++ goto out; ++ ++ err = -EINVAL; ++ /* To and From paths should be mount roots */ ++ if (!path_mounted(from_path)) ++ goto out; ++ if (!path_mounted(to_path)) ++ goto out; ++ ++ /* Setting sharing groups is only allowed across same superblock */ ++ if (from->mnt.mnt_sb != to->mnt.mnt_sb) ++ goto out; ++ ++ /* From mount root should be wider than To mount root */ ++ if (!is_subdir(to->mnt.mnt_root, from->mnt.mnt_root)) ++ goto out; ++ ++ /* From mount should not have locked children in place of To's root */ ++ if (__has_locked_children(from, to->mnt.mnt_root)) ++ goto out; ++ ++ /* Setting sharing groups is only allowed on private mounts */ ++ if (IS_MNT_SHARED(to) || IS_MNT_SLAVE(to)) ++ goto out; ++ ++ /* From should not be private */ ++ if (!IS_MNT_SHARED(from) && !IS_MNT_SLAVE(from)) ++ goto out; ++ ++ if (IS_MNT_SLAVE(from)) { ++ hlist_add_behind(&to->mnt_slave, &from->mnt_slave); ++ to->mnt_master = from->mnt_master; ++ } ++ ++ if (IS_MNT_SHARED(from)) { ++ to->mnt_group_id = from->mnt_group_id; ++ list_add(&to->mnt_share, &from->mnt_share); ++ set_mnt_shared(to); ++ } ++ ++ err = 0; ++ out: ++ namespace_unlock(); ++ return err; ++ } ++ ++ /** ++ * path_overmounted - check if path is overmounted ++ * @path: path to check ++ * ++ * Check if path is overmounted, i.e., if there's a mount on top of ++ * @path->mnt with @path->dentry as mountpoint. ++ * ++ * Context: namespace_sem must be held at least shared. ++ * MUST NOT be called under lock_mount_hash() (there one should just ++ * call __lookup_mnt() and check if it returns NULL). ++ * Return: If path is overmounted true is returned, false if not. ++ */ ++ static inline bool path_overmounted(const struct path *path) ++ { ++ unsigned seq = read_seqbegin(&mount_lock); ++ bool no_child; ++ ++ rcu_read_lock(); ++ no_child = !__lookup_mnt(path->mnt, path->dentry); ++ rcu_read_unlock(); ++ if (need_seqretry(&mount_lock, seq)) { ++ read_seqlock_excl(&mount_lock); ++ no_child = !__lookup_mnt(path->mnt, path->dentry); ++ read_sequnlock_excl(&mount_lock); ++ } ++ return unlikely(!no_child); ++ } ++ +++>>>>>>> cffd0441872e (use uniform permission checks for all mount propagation changes) + /* + - * Check if there is a possibly empty chain of descent from p1 to p2. + - * Locks: namespace_sem (shared) or mount_lock (read_seqlock_excl). + + * Check that there aren't references to earlier/same mount namespaces in the + + * specified subtree. Such references can act as pins for mount namespaces + + * that aren't checked by the mount-cycle checking code, thereby allowing + + * cycles to be made. + */ + -static bool mount_is_ancestor(const struct mount *p1, const struct mount *p2) + +static bool check_for_nsfs_mounts(struct mount *subtree) + { + - while (p2 != p1 && mnt_has_parent(p2)) + - p2 = p2->mnt_parent; + - return p2 == p1; + + struct mount *p; + + bool ret = false; + + + + lock_mount_hash(); + + for (p = subtree; p; p = next_mnt(p, subtree)) + + if (mnt_ns_loop(p->mnt.mnt_root)) + + goto out; + + + + ret = true; + +out: + + unlock_mount_hash(); + + return ret; + } + + -/** + - * can_move_mount_beneath - check that we can mount beneath the top mount + - * @from: mount to mount beneath + - * @to: mount under which to mount + - * @mp: mountpoint of @to + - * + - * - Make sure that @to->dentry is actually the root of a mount under + - * which we can mount another mount. + - * - Make sure that nothing can be mounted beneath the caller's current + - * root or the rootfs of the namespace. + - * - Make sure that the caller can unmount the topmost mount ensuring + - * that the caller could reveal the underlying mountpoint. + - * - Ensure that nothing has been mounted on top of @from before we + - * grabbed @namespace_sem to avoid creating pointless shadow mounts. + - * - Prevent mounting beneath a mount if the propagation relationship + - * between the source mount, parent mount, and top mount would lead to + - * nonsensical mount trees. + - * + - * Context: This function expects namespace_lock() to be held. + - * Return: On success 0, and on error a negative error code is returned. + - */ + -static int can_move_mount_beneath(const struct path *from, + - const struct path *to, + - const struct mountpoint *mp) + +static int do_move_mount(struct path *old_path, struct path *new_path) + { + - struct mount *mnt_from = real_mount(from->mnt), + - *mnt_to = real_mount(to->mnt), + - *parent_mnt_to = mnt_to->mnt_parent; + + struct path parent_path = {.mnt = NULL, .dentry = NULL}; + + struct mnt_namespace *ns; + + struct mount *p; + + struct mount *old; + + struct mountpoint *mp; + + int err; + + bool attached; + + - if (!mnt_has_parent(mnt_to)) + - return -EINVAL; + + mp = lock_mount(new_path); + + if (IS_ERR(mp)) + + return PTR_ERR(mp); + + - if (!path_mounted(to)) + - return -EINVAL; + + old = real_mount(old_path->mnt); + + p = real_mount(new_path->mnt); + + attached = mnt_has_parent(old); + + ns = old->mnt_ns; + + - if (IS_MNT_LOCKED(mnt_to)) + - return -EINVAL; + - + - /* Avoid creating shadow mounts during mount propagation. */ + - if (path_overmounted(from)) + - return -EINVAL; + - + - /* + - * Mounting beneath the rootfs only makes sense when the + - * semantics of pivot_root(".", ".") are used. + - */ + - if (&mnt_to->mnt == current->fs->root.mnt) + - return -EINVAL; + - if (parent_mnt_to == current->nsproxy->mnt_ns->root) + - return -EINVAL; + - + - if (mount_is_ancestor(mnt_to, mnt_from)) + - return -EINVAL; + - + - /* + - * If the parent mount propagates to the child mount this would + - * mean mounting @mnt_from on @mnt_to->mnt_parent and then + - * propagating a copy @c of @mnt_from on top of @mnt_to. This + - * defeats the whole purpose of mounting beneath another mount. + - */ + - if (propagation_would_overmount(parent_mnt_to, mnt_to, mp)) + - return -EINVAL; + - + - /* + - * If @mnt_to->mnt_parent propagates to @mnt_from this would + - * mean propagating a copy @c of @mnt_from on top of @mnt_from. + - * Afterwards @mnt_from would be mounted on top of + - * @mnt_to->mnt_parent and @mnt_to would be unmounted from + - * @mnt->mnt_parent and remounted on @mnt_from. But since @c is + - * already mounted on @mnt_from, @mnt_to would ultimately be + - * remounted on top of @c. Afterwards, @mnt_from would be + - * covered by a copy @c of @mnt_from and @c would be covered by + - * @mnt_from itself. This defeats the whole purpose of mounting + - * @mnt_from beneath @mnt_to. + - */ + - if (check_mnt(mnt_from) && + - propagation_would_overmount(parent_mnt_to, mnt_from, mp)) + - return -EINVAL; + - + - return 0; + -} + - + -/* may_use_mount() - check if a mount tree can be used + - * @mnt: vfsmount to be used + - * + - * This helper checks if the caller may use the mount tree starting + - * from @path->mnt. The caller may use the mount tree under the + - * following circumstances: + - * + - * (1) The caller is located in the mount namespace of the mount tree. + - * This also implies that the mount does not belong to an anonymous + - * mount namespace. + - * (2) The caller is trying to use a mount tree that belongs to an + - * anonymous mount namespace. + - * + - * For that to be safe, this helper enforces that the origin mount + - * namespace the anonymous mount namespace was created from is the + - * same as the caller's mount namespace by comparing the sequence + - * numbers. + - * + - * The ownership of a non-anonymous mount namespace such as the + - * caller's cannot change. + - * => We know that the caller's mount namespace is stable. + - * + - * If the origin sequence number of the anonymous mount namespace is + - * the same as the sequence number of the caller's mount namespace. + - * => The owning namespaces are the same. + - * + - * ==> The earlier capability check on the owning namespace of the + - * caller's mount namespace ensures that the caller has the + - * ability to use the mount tree. + - * + - * Returns true if the mount tree can be used, false otherwise. + - */ + -static inline bool may_use_mount(struct mount *mnt) + -{ + - if (check_mnt(mnt)) + - return true; + - + - /* + - * Make sure that noone unmounted the target path or somehow + - * managed to get their hands on something purely kernel + - * internal. + - */ + - if (!is_mounted(&mnt->mnt)) + - return false; + - + - return check_anonymous_mnt(mnt); + -} + - + -static int do_move_mount(struct path *old_path, + - struct path *new_path, enum mnt_tree_flags_t flags) + -{ + - struct mnt_namespace *ns; + - struct mount *p; + - struct mount *old; + - struct mount *parent; + - struct pinned_mountpoint mp; + - int err; + - bool beneath = flags & MNT_TREE_BENEATH; + - + - err = do_lock_mount(new_path, &mp, beneath); + - if (err) + - return err; + + err = -EINVAL; + + /* The mountpoint must be in our namespace. */ + + if (!check_mnt(p)) + + goto out; + + - old = real_mount(old_path->mnt); + - p = real_mount(new_path->mnt); + - parent = old->mnt_parent; + - ns = old->mnt_ns; + + /* The thing moved must be mounted... */ + + if (!is_mounted(&old->mnt)) + + goto out; + + - err = -EINVAL; + + /* ... and either ours or the root of anon namespace */ + + if (!(attached ? check_mnt(old) : is_anon_ns(ns))) + + goto out; + + - if (check_mnt(old)) { + - /* if the source is in our namespace... */ + - /* ... it should be detachable from parent */ + - if (!mnt_has_parent(old) || IS_MNT_LOCKED(old)) + - goto out; + - /* ... and the target should be in our namespace */ + - if (!check_mnt(p)) + - goto out; + - /* parent of the source should not be shared */ + - if (IS_MNT_SHARED(parent)) + - goto out; + - } else { + - /* + - * otherwise the source must be the root of some anon namespace. + - */ + - if (!anon_ns_root(old)) + - goto out; + - /* + - * Bail out early if the target is within the same namespace - + - * subsequent checks would've rejected that, but they lose + - * some corner cases if we check it early. + - */ + - if (ns == p->mnt_ns) + - goto out; + - /* + - * Target should be either in our namespace or in an acceptable + - * anon namespace, sensu check_anonymous_mnt(). + - */ + - if (!may_use_mount(p)) + - goto out; + - } + + if (old->mnt.mnt_flags & MNT_LOCKED) + + goto out; + + - if (!path_mounted(old_path)) + + if (old_path->dentry != old_path->mnt->mnt_root) + goto out; + + if (d_is_dir(new_path->dentry) != +* Unmerged path fs/namespace.c diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/f6bfc9af.failed b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/f6bfc9af.failed new file mode 100644 index 0000000000000..f8b873d909346 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/f6bfc9af.failed @@ -0,0 +1,305 @@ +drm/framebuffer: Acquire internal references on GEM handles + +jira LE-4321 +cve CVE-2025-38449 +Rebuild_History Non-Buildable kernel-4.18.0-553.76.1.el8_10 +commit-author Thomas Zimmermann +commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/f6bfc9af.failed + +Acquire GEM handles in drm_framebuffer_init() and release them in +the corresponding drm_framebuffer_cleanup(). Ties the handle's +lifetime to the framebuffer. Not all GEM buffer objects have GEM +handles. If not set, no refcounting takes place. This is the case +for some fbdev emulation. This is not a problem as these GEM objects +do not use dma-bufs and drivers will not release them while fbdev +emulation is running. Framebuffer flags keep a bit per color plane +of which the framebuffer holds a GEM handle reference. + +As all drivers use drm_framebuffer_init(), they will now all hold +dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire +references on GEM handles for framebuffers"). + +In the GEM framebuffer helpers, restore the original ref counting +on buffer objects. As the helpers for handle refcounting are now +no longer called from outside the DRM core, unexport the symbols. + +v3: +- don't mix internal flags with mode flags (Christian) +v2: +- track framebuffer handle refs by flag +- drop gma500 cleanup (Christian) + + Signed-off-by: Thomas Zimmermann +Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers") + Reported-by: Bert Karwatzki +Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/ + Tested-by: Bert Karwatzki + Tested-by: Mario Limonciello + Tested-by: Borislav Petkov (AMD) + Cc: Thomas Zimmermann + Cc: Anusha Srivatsa + Cc: Christian König + Cc: Maarten Lankhorst + Cc: Maxime Ripard + Cc: Sumit Semwal + Cc: "Christian König" + Cc: linux-media@vger.kernel.org + Cc: dri-devel@lists.freedesktop.org + Cc: linaro-mm-sig@lists.linaro.org + Cc: + Reviewed-by: Christian König +Link: https://lore.kernel.org/r/20250707131224.249496-1-tzimmermann@suse.de +(cherry picked from commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280) + Signed-off-by: Jonathan Maple + +# Conflicts: +# include/drm/drm_framebuffer.h +diff --cc include/drm/drm_framebuffer.h +index 0dcc07b68654,38b24fc8978d..000000000000 +--- a/include/drm/drm_framebuffer.h ++++ b/include/drm/drm_framebuffer.h +@@@ -189,17 -192,9 +192,23 @@@ struct drm_framebuffer + */ + int flags; + /** +++<<<<<<< HEAD + + * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor + + * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR + + * universal plane. + + */ + + int hot_x; + + /** + + * @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor + + * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR + + * universal plane. + + */ + + int hot_y; +++======= ++ * @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF. ++ */ ++ unsigned int internal_flags; +++>>>>>>> f6bfc9afc751 (drm/framebuffer: Acquire internal references on GEM handles) + /** + * @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock. + */ +diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c +index aff3746dedfb..ec21defa2642 100644 +--- a/drivers/gpu/drm/drm_framebuffer.c ++++ b/drivers/gpu/drm/drm_framebuffer.c +@@ -844,11 +844,23 @@ void drm_framebuffer_free(struct kref *kref) + int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs) + { ++ unsigned int i; + int ret; ++ bool exists; + + if (WARN_ON_ONCE(fb->dev != dev || !fb->format)) + return -EINVAL; + ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))) ++ fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ if (fb->obj[i]) { ++ exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]); ++ if (exists) ++ fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ } ++ } ++ + INIT_LIST_HEAD(&fb->filp_head); + + fb->funcs = funcs; +@@ -857,7 +869,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB, + false, drm_framebuffer_free); + if (ret) +- goto out; ++ goto err; + + mutex_lock(&dev->mode_config.fb_lock); + dev->mode_config.num_fb++; +@@ -865,7 +877,16 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + mutex_unlock(&dev->mode_config.fb_lock); + + drm_mode_object_register(dev, &fb->base); +-out: ++ ++ return 0; ++ ++err: ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) { ++ drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ } ++ } + return ret; + } + EXPORT_SYMBOL(drm_framebuffer_init); +@@ -942,6 +963,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); + void drm_framebuffer_cleanup(struct drm_framebuffer *fb) + { + struct drm_device *dev = fb->dev; ++ unsigned int i; ++ ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) ++ drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ } + + mutex_lock(&dev->mode_config.fb_lock); + list_del(&fb->head); +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index 34b5934c63db..aa6fd8f5e0a3 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -194,23 +194,34 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj) + } + + /** +- * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles ++ * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any + * @obj: GEM object + * +- * Acquires a reference on the GEM buffer object's handle. Required +- * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked() +- * to release the reference. ++ * Acquires a reference on the GEM buffer object's handle. Required to keep ++ * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() ++ * to release the reference. Does nothing if the buffer object has no handle. ++ * ++ * Returns: ++ * True if a handle exists, or false otherwise + */ +-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj) ++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) + { + struct drm_device *dev = obj->dev; + + guard(mutex)(&dev->object_name_lock); + +- drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */ ++ /* ++ * First ref taken during GEM object creation, if any. Some ++ * drivers set up internal framebuffers with GEM objects that ++ * do not have a GEM handle. Hence, this counter can be zero. ++ */ ++ if (!obj->handle_count) ++ return false; ++ + drm_gem_object_handle_get(obj); ++ ++ return true; + } +-EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked); + + /** + * drm_gem_object_handle_free - release resources bound to userspace handles +@@ -243,7 +254,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj) + } + + /** +- * drm_gem_object_handle_put_unlocked - releases reference on user-space handles ++ * drm_gem_object_handle_put_unlocked - releases reference on user-space handle + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases +@@ -254,14 +265,14 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) + struct drm_device *dev = obj->dev; + bool final = false; + +- if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) ++ if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0)) + return; + + /* +- * Must bump handle count first as this may be the last +- * ref, in which case the object would disappear before we +- * checked for a name +- */ ++ * Must bump handle count first as this may be the last ++ * ref, in which case the object would disappear before ++ * we checked for a name. ++ */ + + mutex_lock(&dev->object_name_lock); + if (--obj->handle_count == 0) { +@@ -274,7 +285,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) + if (final) + drm_gem_object_put(obj); + } +-EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked); + + /* + * Called at device or object close to release the file's +diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c +index 3738474d55ed..235a81c57b7e 100644 +--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c ++++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c +@@ -95,7 +95,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb) + unsigned int i; + + for (i = 0; i < fb->format->num_planes; i++) +- drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ drm_gem_object_put(fb->obj[i]); + + drm_framebuffer_cleanup(fb); + kfree(fb); +@@ -170,10 +170,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, + if (!objs[i]) { + drm_dbg_kms(dev, "Failed to lookup GEM object\n"); + ret = -ENOENT; +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + } +- drm_gem_object_handle_get_unlocked(objs[i]); +- drm_gem_object_put(objs[i]); + + min_size = (height - 1) * mode_cmd->pitches[i] + + drm_format_info_min_pitch(info, i, width) +@@ -183,22 +181,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, + drm_dbg_kms(dev, + "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n", + objs[i]->size, min_size, i); +- drm_gem_object_handle_put_unlocked(objs[i]); ++ drm_gem_object_put(objs[i]); + ret = -EINVAL; +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + } + } + + ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); + if (ret) +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + + return 0; + +-err_gem_object_handle_put_unlocked: ++err_gem_object_put: + while (i > 0) { + --i; +- drm_gem_object_handle_put_unlocked(objs[i]); ++ drm_gem_object_put(objs[i]); + } + return ret; + } +diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h +index ff04c7b3d1bd..4f5d4d9d05c3 100644 +--- a/drivers/gpu/drm/drm_internal.h ++++ b/drivers/gpu/drm/drm_internal.h +@@ -159,7 +159,7 @@ void drm_sysfs_lease_event(struct drm_device *dev); + + /* drm_gem.c */ + int drm_gem_init(struct drm_device *dev); +-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj); ++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj); + void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj); + int drm_gem_handle_create_tail(struct drm_file *file_priv, + struct drm_gem_object *obj, +* Unmerged path include/drm/drm_framebuffer.h diff --git a/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/rebuild.details.txt b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/rebuild.details.txt new file mode 100644 index 0000000000000..84a316f5159c3 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.76.1.el8_10/rebuild.details.txt @@ -0,0 +1,28 @@ +Rebuild_History BUILDABLE +Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50% +Number of commits in upstream range v4.18~1..kernel-mainline: 567757 +Number of commits in rpm: 36 +Number of commits matched with upstream: 29 (80.56%) +Number of commits in upstream but not in rpm: 567729 +Number of commits NOT found in upstream: 7 (19.44%) + +Rebuilding Kernel on Branch rocky8_10_rebuild_kernel-4.18.0-553.76.1.el8_10 for kernel-4.18.0-553.76.1.el8_10 +Clean Cherry Picks: 17 (58.62%) +Empty Cherry Picks: 5 (17.24%) +_______________________________ + +__EMPTY COMMITS__________________________ +6773da870ab89123d1b513da63ed59e32a29cb77 xfs: fix error returns from xfs_bmapi_write +c0a581d7126c0bbc96163276f585fd7b4e4d8d0e tracing: Disable interrupt or preemption before acquiring arch_spinlock_t +f6bfc9afc7510cb5e6fbe0a17c507917b0120280 drm/framebuffer: Acquire internal references on GEM handles +58f880711f2ba53fd5e959875aff5b3bf6d5c32e xfs: make sure sb_fdblocks is non-negative +cffd0441872e7f6b1fce5e78fb1c99187a291330 use uniform permission checks for all mount propagation changes + +__CHANGES NOT IN UPSTREAM________________ +Adding prod certs and changed cert date to 20210620 +Adding Rocky secure boot certs +Fixing vmlinuz removal +Fixing UEFI CA path +Porting to 8.10, debranding and Rocky branding +Fixing pesign_key_name values +mm/page_alloc: make sure free_pcppages_bulk() bails when given count < 0 diff --git a/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/689640ef.failed b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/689640ef.failed new file mode 100644 index 0000000000000..8ae05db414dce --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/689640ef.failed @@ -0,0 +1,70 @@ +firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails + +jira LE-4321 +cve CVE-2022-50087 +Rebuild_History Non-Buildable kernel-4.18.0-553.77.1.el8_10 +commit-author Sudeep Holla +commit 689640efc0a2c4e07e6f88affe6d42cd40cc3f85 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/689640ef.failed + +When scpi probe fails, at any point, we need to ensure that the scpi_info +is not set and will remain NULL until the probe succeeds. If it is not +taken care, then it could result use-after-free as the value is exported +via get_scpi_ops() and could refer to a memory allocated via devm_kzalloc() +but freed when the probe fails. + +Link: https://lore.kernel.org/r/20220701160310.148344-1-sudeep.holla@arm.com + Cc: stable@vger.kernel.org # 4.19+ + Reported-by: huhai + Reviewed-by: Jackie Liu + Signed-off-by: Sudeep Holla +(cherry picked from commit 689640efc0a2c4e07e6f88affe6d42cd40cc3f85) + Signed-off-by: Jonathan Maple + +# Conflicts: +# drivers/firmware/arm_scpi.c +diff --cc drivers/firmware/arm_scpi.c +index c7d06a36b23a,435d0e2658a4..000000000000 +--- a/drivers/firmware/arm_scpi.c ++++ b/drivers/firmware/arm_scpi.c +@@@ -1011,22 -1017,23 +1015,31 @@@ static int scpi_probe(struct platform_d + else + dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n", + FIELD_GET(PROTO_REV_MAJOR_MASK, +- scpi_info->protocol_version), ++ scpi_drvinfo->protocol_version), + FIELD_GET(PROTO_REV_MINOR_MASK, +- scpi_info->protocol_version), ++ scpi_drvinfo->protocol_version), + FIELD_GET(FW_REV_MAJOR_MASK, +- scpi_info->firmware_version), ++ scpi_drvinfo->firmware_version), + FIELD_GET(FW_REV_MINOR_MASK, +- scpi_info->firmware_version), ++ scpi_drvinfo->firmware_version), + FIELD_GET(FW_REV_PATCH_MASK, +- scpi_info->firmware_version)); +- scpi_info->scpi_ops = &scpi_ops; ++ scpi_drvinfo->firmware_version)); + +++<<<<<<< HEAD + + ret = devm_device_add_groups(dev, versions_groups); + + if (ret) + + dev_err(dev, "unable to create sysfs version group\n"); + + + + return devm_of_platform_populate(dev); +++======= ++ scpi_drvinfo->scpi_ops = &scpi_ops; ++ ++ ret = devm_of_platform_populate(dev); ++ if (ret) ++ scpi_info = NULL; ++ ++ return ret; +++>>>>>>> 689640efc0a2 (firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails) + } + + static const struct of_device_id scpi_of_match[] = { +* Unmerged path drivers/firmware/arm_scpi.c diff --git a/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed new file mode 100644 index 0000000000000..b4ece06085396 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed @@ -0,0 +1,251 @@ +nfsd: don't ignore the return code of svc_proc_register() + +jira LE-4321 +cve CVE-2025-22026 +Rebuild_History Non-Buildable kernel-4.18.0-553.77.1.el8_10 +commit-author Jeff Layton +commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed + +Currently, nfsd_proc_stat_init() ignores the return value of +svc_proc_register(). If the procfile creation fails, then the kernel +will WARN when it tries to remove the entry later. + +Fix nfsd_proc_stat_init() to return the same type of pointer as +svc_proc_register(), and fix up nfsd_net_init() to check that and fail +the nfsd_net construction if it occurs. + +svc_proc_register() can fail if the dentry can't be allocated, or if an +identical dentry already exists. The second case is pretty unlikely in +the nfsd_net construction codepath, so if this happens, return -ENOMEM. + + Reported-by: syzbot+e34ad04f27991521104c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-nfs/67a47501.050a0220.19061f.05f9.GAE@google.com/ + Cc: stable@vger.kernel.org # v6.9 + Signed-off-by: Jeff Layton + Signed-off-by: Chuck Lever +(cherry picked from commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/nfsd/nfsctl.c +# fs/nfsd/stats.c +# fs/nfsd/stats.h +diff --cc fs/nfsd/nfsctl.c +index 9bd5cf3f6d3c,ac265d6fde35..000000000000 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@@ -1463,27 -2198,36 +1463,57 @@@ static __net_init int nfsd_init_net(str + retval = nfsd_idmap_init(net); + if (retval) + goto out_idmap_error; + - retval = percpu_counter_init_many(nn->counter, 0, GFP_KERNEL, + - NFSD_STATS_COUNTERS_NUM); + + nn->nfsd_versions = NULL; + + nn->nfsd4_minorversions = NULL; + + retval = nfsd_reply_cache_init(nn); + if (retval) +++<<<<<<< HEAD + + goto out_drc_error; + + nn->nfsd4_lease = 90; /* default lease time */ + + nn->nfsd4_grace = 90; + + nn->somebody_reclaimed = false; + + nn->track_reclaim_completes = false; + + nn->clverifier_counter = prandom_u32(); + + nn->clientid_base = prandom_u32(); + + nn->clientid_counter = nn->clientid_base + 1; + + nn->s2s_cp_cl_id = nn->clientid_counter++; + + + + atomic_set(&nn->ntf_refcnt, 0); + + init_waitqueue_head(&nn->ntf_wq); + + seqlock_init(&nn->boot_lock); + + + + return 0; + + + +out_drc_error: +++======= ++ goto out_repcache_error; ++ ++ memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats)); ++ nn->nfsd_svcstats.program = &nfsd_programs[0]; ++ if (!nfsd_proc_stat_init(net)) { ++ retval = -ENOMEM; ++ goto out_proc_error; ++ } ++ ++ for (i = 0; i < sizeof(nn->nfsd_versions); i++) ++ nn->nfsd_versions[i] = nfsd_support_version(i); ++ for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++) ++ nn->nfsd4_minorversions[i] = nfsd_support_version(4); ++ nn->nfsd_info.mutex = &nfsd_mutex; ++ nn->nfsd_serv = NULL; ++ nfsd4_init_leases_net(nn); ++ get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); ++ seqlock_init(&nn->writeverf_lock); ++ #if IS_ENABLED(CONFIG_NFS_LOCALIO) ++ spin_lock_init(&nn->local_clients_lock); ++ INIT_LIST_HEAD(&nn->local_clients); ++ #endif ++ return 0; ++ ++ out_proc_error: ++ percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM); ++ out_repcache_error: +++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register()) + nfsd_idmap_shutdown(net); + out_idmap_error: + nfsd_export_shutdown(net); +diff --cc fs/nfsd/stats.c +index 9bce3b913189,f7eaf95e20fc..000000000000 +--- a/fs/nfsd/stats.c ++++ b/fs/nfsd/stats.c +@@@ -79,26 -71,16 +79,36 @@@ static int nfsd_proc_show(struct seq_fi + return 0; + } + +++<<<<<<< HEAD + +static int nfsd_proc_open(struct inode *inode, struct file *file) + +{ + + return single_open(file, nfsd_proc_show, NULL); +++======= ++ DEFINE_PROC_SHOW_ATTRIBUTE(nfsd); ++ ++ struct proc_dir_entry *nfsd_proc_stat_init(struct net *net) ++ { ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ ++ return svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops); +++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register()) + +} + + + +static const struct file_operations nfsd_proc_fops = { + + .open = nfsd_proc_open, + + .read = seq_read, + + .llseek = seq_lseek, + + .release = single_release, + +}; + + + +void + +nfsd_stat_init(void) + +{ + + svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops); + } + + -void nfsd_proc_stat_shutdown(struct net *net) + +void + +nfsd_stat_shutdown(void) + { + - svc_proc_unregister(net, "nfsd"); + + svc_proc_unregister(&init_net, "nfsd"); + } +diff --cc fs/nfsd/stats.h +index b23fdac69820,e4efb0e4e56d..000000000000 +--- a/fs/nfsd/stats.h ++++ b/fs/nfsd/stats.h +@@@ -8,37 -8,69 +8,96 @@@ + #define _NFSD_STATS_H + + #include + -#include + +++<<<<<<< HEAD +++======= ++ struct proc_dir_entry *nfsd_proc_stat_init(struct net *net); ++ void nfsd_proc_stat_shutdown(struct net *net); ++ ++ static inline void nfsd_stats_rc_hits_inc(struct nfsd_net *nn) ++ { ++ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_HITS]); ++ } ++ ++ static inline void nfsd_stats_rc_misses_inc(struct nfsd_net *nn) ++ { ++ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_MISSES]); ++ } ++ ++ static inline void nfsd_stats_rc_nocache_inc(struct nfsd_net *nn) ++ { ++ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_NOCACHE]); ++ } ++ ++ static inline void nfsd_stats_fh_stale_inc(struct nfsd_net *nn, ++ struct svc_export *exp) ++ { ++ percpu_counter_inc(&nn->counter[NFSD_STATS_FH_STALE]); ++ if (exp && exp->ex_stats) ++ percpu_counter_inc(&exp->ex_stats->counter[EXP_STATS_FH_STALE]); ++ } ++ ++ static inline void nfsd_stats_io_read_add(struct nfsd_net *nn, ++ struct svc_export *exp, s64 amount) ++ { ++ percpu_counter_add(&nn->counter[NFSD_STATS_IO_READ], amount); ++ if (exp && exp->ex_stats) ++ percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_READ], amount); ++ } ++ ++ static inline void nfsd_stats_io_write_add(struct nfsd_net *nn, ++ struct svc_export *exp, s64 amount) ++ { ++ percpu_counter_add(&nn->counter[NFSD_STATS_IO_WRITE], amount); ++ if (exp && exp->ex_stats) ++ percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_WRITE], amount); ++ } ++ ++ static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn) ++ { ++ percpu_counter_inc(&nn->counter[NFSD_STATS_PAYLOAD_MISSES]); ++ } ++ ++ static inline void nfsd_stats_drc_mem_usage_add(struct nfsd_net *nn, s64 amount) ++ { ++ percpu_counter_add(&nn->counter[NFSD_STATS_DRC_MEM_USAGE], amount); ++ } ++ ++ static inline void nfsd_stats_drc_mem_usage_sub(struct nfsd_net *nn, s64 amount) ++ { ++ percpu_counter_sub(&nn->counter[NFSD_STATS_DRC_MEM_USAGE], amount); ++ } +++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register()) + + +struct nfsd_stats { + + unsigned int rchits; /* repcache hits */ + + unsigned int rcmisses; /* repcache hits */ + + unsigned int rcnocache; /* uncached reqs */ + + unsigned int fh_stale; /* FH stale error */ + + unsigned int fh_lookup; /* dentry cached */ + + unsigned int fh_anon; /* anon file dentry returned */ + + unsigned int fh_nocache_dir; /* filehandle not found in dcache */ + + unsigned int fh_nocache_nondir; /* filehandle not found in dcache */ + + unsigned int io_read; /* bytes returned to read requests */ + + unsigned int io_write; /* bytes passed in write requests */ + + unsigned int th_cnt; /* number of available threads */ + + unsigned int th_usage[10]; /* number of ticks during which n perdeciles + + * of available threads were in use */ + + unsigned int th_fullcnt; /* number of times last free thread was used */ + + unsigned int ra_size; /* size of ra cache */ + + unsigned int ra_depth[11]; /* number of times ra entry was found that deep + + * in the cache (10percentiles). [10] = not found */ + #ifdef CONFIG_NFSD_V4 + -static inline void nfsd_stats_wdeleg_getattr_inc(struct nfsd_net *nn) + -{ + - percpu_counter_inc(&nn->counter[NFSD_STATS_WDELEG_GETATTR]); + -} + + unsigned int nfs4_opcount[LAST_NFS4_OP + 1]; /* count of individual nfsv4 operations */ + #endif + + + +}; + + + + + +extern struct nfsd_stats nfsdstats; + +extern struct svc_stat nfsd_svcstats; + + + +void nfsd_stat_init(void); + +void nfsd_stat_shutdown(void); + + + #endif /* _NFSD_STATS_H */ +* Unmerged path fs/nfsd/nfsctl.c +* Unmerged path fs/nfsd/stats.c +* Unmerged path fs/nfsd/stats.h diff --git a/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/rebuild.details.txt b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/rebuild.details.txt new file mode 100644 index 0000000000000..fa3d8c48f5700 --- /dev/null +++ b/ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/rebuild.details.txt @@ -0,0 +1,24 @@ +Rebuild_History BUILDABLE +Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50% +Number of commits in upstream range v4.18~1..kernel-mainline: 567757 +Number of commits in rpm: 12 +Number of commits matched with upstream: 6 (50.00%) +Number of commits in upstream but not in rpm: 567751 +Number of commits NOT found in upstream: 6 (50.00%) + +Rebuilding Kernel on Branch rocky8_10_rebuild_kernel-4.18.0-553.77.1.el8_10 for kernel-4.18.0-553.77.1.el8_10 +Clean Cherry Picks: 4 (66.67%) +Empty Cherry Picks: 2 (33.33%) +_______________________________ + +__EMPTY COMMITS__________________________ +930b64ca0c511521f0abdd1d57ce52b2a6e3476b nfsd: don't ignore the return code of svc_proc_register() +689640efc0a2c4e07e6f88affe6d42cd40cc3f85 firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails + +__CHANGES NOT IN UPSTREAM________________ +Adding prod certs and changed cert date to 20210620 +Adding Rocky secure boot certs +Fixing vmlinuz removal +Fixing UEFI CA path +Porting to 8.10, debranding and Rocky branding +Fixing pesign_key_name values diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index c7d06a36b23a5..444467e5d0586 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -824,7 +824,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info) info->firmware_version = le32_to_cpu(caps.platform_version); } /* Ignore error if not implemented */ - if (scpi_info->is_legacy && ret == -EOPNOTSUPP) + if (info->is_legacy && ret == -EOPNOTSUPP) return 0; return ret; @@ -914,13 +914,14 @@ static int scpi_probe(struct platform_device *pdev) struct resource res; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + struct scpi_drvinfo *scpi_drvinfo; - scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL); - if (!scpi_info) + scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL); + if (!scpi_drvinfo) return -ENOMEM; if (of_match_device(legacy_scpi_of_match, &pdev->dev)) - scpi_info->is_legacy = true; + scpi_drvinfo->is_legacy = true; count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); if (count < 0) { @@ -928,19 +929,19 @@ static int scpi_probe(struct platform_device *pdev) return -ENODEV; } - scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan), - GFP_KERNEL); - if (!scpi_info->channels) + scpi_drvinfo->channels = + devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL); + if (!scpi_drvinfo->channels) return -ENOMEM; - ret = devm_add_action(dev, scpi_free_channels, scpi_info); + ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo); if (ret) return ret; - for (; scpi_info->num_chans < count; scpi_info->num_chans++) { + for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) { resource_size_t size; - int idx = scpi_info->num_chans; - struct scpi_chan *pchan = scpi_info->channels + idx; + int idx = scpi_drvinfo->num_chans; + struct scpi_chan *pchan = scpi_drvinfo->channels + idx; struct mbox_client *cl = &pchan->cl; struct device_node *shmem = of_parse_phandle(np, "shmem", idx); @@ -984,49 +985,57 @@ static int scpi_probe(struct platform_device *pdev) return ret; } - scpi_info->commands = scpi_std_commands; + scpi_drvinfo->commands = scpi_std_commands; - platform_set_drvdata(pdev, scpi_info); + platform_set_drvdata(pdev, scpi_drvinfo); - if (scpi_info->is_legacy) { + if (scpi_drvinfo->is_legacy) { /* Replace with legacy variants */ scpi_ops.clk_set_val = legacy_scpi_clk_set_val; - scpi_info->commands = scpi_legacy_commands; + scpi_drvinfo->commands = scpi_legacy_commands; /* Fill priority bitmap */ for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++) set_bit(legacy_hpriority_cmds[idx], - scpi_info->cmd_priority); + scpi_drvinfo->cmd_priority); } - ret = scpi_init_versions(scpi_info); + scpi_info = scpi_drvinfo; + + ret = scpi_init_versions(scpi_drvinfo); if (ret) { dev_err(dev, "incorrect or no SCP firmware found\n"); + scpi_info = NULL; return ret; } - if (scpi_info->is_legacy && !scpi_info->protocol_version && - !scpi_info->firmware_version) + if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version && + !scpi_drvinfo->firmware_version) dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n"); else dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n", FIELD_GET(PROTO_REV_MAJOR_MASK, - scpi_info->protocol_version), + scpi_drvinfo->protocol_version), FIELD_GET(PROTO_REV_MINOR_MASK, - scpi_info->protocol_version), + scpi_drvinfo->protocol_version), FIELD_GET(FW_REV_MAJOR_MASK, - scpi_info->firmware_version), + scpi_drvinfo->firmware_version), FIELD_GET(FW_REV_MINOR_MASK, - scpi_info->firmware_version), + scpi_drvinfo->firmware_version), FIELD_GET(FW_REV_PATCH_MASK, - scpi_info->firmware_version)); - scpi_info->scpi_ops = &scpi_ops; + scpi_drvinfo->firmware_version)); + + scpi_drvinfo->scpi_ops = &scpi_ops; ret = devm_device_add_groups(dev, versions_groups); if (ret) dev_err(dev, "unable to create sysfs version group\n"); - return devm_of_platform_populate(dev); + ret = devm_of_platform_populate(dev); + if (ret) + scpi_info = NULL; + + return ret; } static const struct of_device_id scpi_of_match[] = { diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index aff3746dedfb4..0e12350b4eeed 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -844,11 +844,23 @@ void drm_framebuffer_free(struct kref *kref) int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs) { + unsigned int i; int ret; + bool exists; if (WARN_ON_ONCE(fb->dev != dev || !fb->format)) return -EINVAL; + for (i = 0; i < fb->format->num_planes; i++) { + if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))) + fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + if (fb->obj[i]) { + exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]); + if (exists) + fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + } + } + INIT_LIST_HEAD(&fb->filp_head); fb->funcs = funcs; @@ -857,7 +869,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB, false, drm_framebuffer_free); if (ret) - goto out; + goto err; mutex_lock(&dev->mode_config.fb_lock); dev->mode_config.num_fb++; @@ -865,7 +877,16 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, mutex_unlock(&dev->mode_config.fb_lock); drm_mode_object_register(dev, &fb->base); -out: + + return 0; + +err: + for (i = 0; i < fb->format->num_planes; i++) { + if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) { + drm_gem_object_handle_put_unlocked(fb->obj[i]); + fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + } + } return ret; } EXPORT_SYMBOL(drm_framebuffer_init); @@ -943,6 +964,13 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; + unsigned int i; + + for (i = 0; i < fb->format->num_planes; i++) { + if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) + drm_gem_object_handle_put_unlocked(fb->obj[i]); + } + mutex_lock(&dev->mode_config.fb_lock); list_del(&fb->head); dev->mode_config.num_fb--; diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 64135042107cb..83b4027b25a36 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -183,6 +183,46 @@ void drm_gem_private_object_fini(struct drm_gem_object *obj) } EXPORT_SYMBOL(drm_gem_private_object_fini); +static void drm_gem_object_handle_get(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + + drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock)); + + if (obj->handle_count++ == 0) + drm_gem_object_get(obj); +} + +/** + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any + * @obj: GEM object + * + * Acquires a reference on the GEM buffer object's handle. Required to keep + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() + * to release the reference. Does nothing if the buffer object has no handle. + * + * Returns: + * True if a handle exists, or false otherwise + */ +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + + guard(mutex)(&dev->object_name_lock); + + /* + * First ref taken during GEM object creation, if any. Some + * drivers set up internal framebuffers with GEM objects that + * do not have a GEM handle. Hence, this counter can be zero. + */ + if (!obj->handle_count) + return false; + + drm_gem_object_handle_get(obj); + + return true; +} + /** * drm_gem_object_handle_free - release resources bound to userspace handles * @obj: GEM object to clean up. @@ -213,20 +253,26 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj) } } -static void -drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) +/** + * drm_gem_object_handle_put_unlocked - releases reference on user-space handle + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases + * the GEM buffer object and associated dma-buf objects. + */ +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; bool final = false; - if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) + if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0)) return; /* - * Must bump handle count first as this may be the last - * ref, in which case the object would disappear before we - * checked for a name - */ + * Must bump handle count first as this may be the last + * ref, in which case the object would disappear before + * we checked for a name + */ mutex_lock(&dev->object_name_lock); if (--obj->handle_count == 0) { @@ -367,8 +413,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, int ret; WARN_ON(!mutex_is_locked(&dev->object_name_lock)); - if (obj->handle_count++ == 0) - drm_gem_object_get(obj); + + drm_gem_object_handle_get(obj); /* * Get the user-visible handle using idr. Preload and perform diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index ed2103ee272cd..4f5d4d9d05c3f 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -159,6 +159,8 @@ void drm_sysfs_lease_event(struct drm_device *dev); /* drm_gem.c */ int drm_gem_init(struct drm_device *dev); +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj); +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj); int drm_gem_handle_create_tail(struct drm_file *file_priv, struct drm_gem_object *obj, u32 *handlep); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5de505c5f4c7d..3c856712152cb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -50,6 +50,38 @@ static int hid_ignore_special_drivers = 0; module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600); MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver"); +/* + * Convert a signed n-bit integer to signed 32-bit integer. + */ + +static s32 snto32(__u32 value, unsigned int n) +{ + if (!value || !n) + return 0; + + if (n > 32) + n = 32; + + return sign_extend32(value, n - 1); +} + +/* + * Convert a signed 32-bit integer to a signed n-bit integer. + */ + +static u32 s32ton(__s32 value, unsigned int n) +{ + s32 a; + + if (!value || !n) + return 0; + + a = value >> (n - 1); + if (a && a != -1) + return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; + return value & ((1 << n) - 1); +} + /* * Register a new report for a device. */ @@ -423,7 +455,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) * both this and the standard encoding. */ raw_value = item_sdata(item); if (!(raw_value & 0xfffffff0)) - parser->global.unit_exponent = hid_snto32(raw_value, 4); + parser->global.unit_exponent = snto32(raw_value, 4); else parser->global.unit_exponent = raw_value; return 0; @@ -1299,43 +1331,6 @@ int hid_open_report(struct hid_device *device) } EXPORT_SYMBOL_GPL(hid_open_report); -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static s32 snto32(__u32 value, unsigned n) -{ - if (!value || !n) - return 0; - - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (~0U << n) : value; -} - -s32 hid_snto32(__u32 value, unsigned n) -{ - return snto32(value, n); -} -EXPORT_SYMBOL_GPL(hid_snto32); - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static u32 s32ton(__s32 value, unsigned n) -{ - s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - /* * Extract/implement a data field from/to a little endian report (bit array). * diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 70439ff80c697..9b8c289459d71 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -3013,13 +3013,13 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) 120); } - v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); + v = sign_extend32(hid_field_extract(hdev, data + 3, 0, 12), 11); input_report_rel(hidpp->input, REL_X, v); - v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12); + v = sign_extend32(hid_field_extract(hdev, data + 3, 12, 12), 11); input_report_rel(hidpp->input, REL_Y, v); - v = hid_snto32(data[6], 8); + v = sign_extend32(data[6], 7); if (v != 0) hidpp_scroll_counter_handle_scroll(hidpp->input, &hidpp->vertical_wheel_counter, v); diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c index b28991dd18703..48b8e184f3db6 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c +++ b/drivers/net/ethernet/intel/idpf/idpf_controlq.c @@ -96,7 +96,7 @@ static void idpf_ctlq_init_rxq_bufs(struct idpf_ctlq_info *cq) */ static void idpf_ctlq_shutdown(struct idpf_hw *hw, struct idpf_ctlq_info *cq) { - mutex_lock(&cq->cq_lock); + spin_lock(&cq->cq_lock); /* free ring buffers and the ring itself */ idpf_ctlq_dealloc_ring_res(hw, cq); @@ -104,8 +104,7 @@ static void idpf_ctlq_shutdown(struct idpf_hw *hw, struct idpf_ctlq_info *cq) /* Set ring_size to 0 to indicate uninitialized queue */ cq->ring_size = 0; - mutex_unlock(&cq->cq_lock); - mutex_destroy(&cq->cq_lock); + spin_unlock(&cq->cq_lock); } /** @@ -173,7 +172,7 @@ int idpf_ctlq_add(struct idpf_hw *hw, idpf_ctlq_init_regs(hw, cq, is_rxq); - mutex_init(&cq->cq_lock); + spin_lock_init(&cq->cq_lock); list_add(&cq->cq_list, &hw->cq_list_head); @@ -272,7 +271,7 @@ int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq, int err = 0; int i; - mutex_lock(&cq->cq_lock); + spin_lock(&cq->cq_lock); /* Ensure there are enough descriptors to send all messages */ num_desc_avail = IDPF_CTLQ_DESC_UNUSED(cq); @@ -332,7 +331,7 @@ int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq, wr32(hw, cq->reg.tail, cq->next_to_use); err_unlock: - mutex_unlock(&cq->cq_lock); + spin_unlock(&cq->cq_lock); return err; } @@ -364,7 +363,7 @@ int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count, if (*clean_count > cq->ring_size) return -EBADR; - mutex_lock(&cq->cq_lock); + spin_lock(&cq->cq_lock); ntc = cq->next_to_clean; @@ -397,7 +396,7 @@ int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count, cq->next_to_clean = ntc; - mutex_unlock(&cq->cq_lock); + spin_unlock(&cq->cq_lock); /* Return number of descriptors actually cleaned */ *clean_count = i; @@ -435,7 +434,7 @@ int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq, if (*buff_count > 0) buffs_avail = true; - mutex_lock(&cq->cq_lock); + spin_lock(&cq->cq_lock); if (tbp >= cq->ring_size) tbp = 0; @@ -524,7 +523,7 @@ int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq, wr32(hw, cq->reg.tail, cq->next_to_post); } - mutex_unlock(&cq->cq_lock); + spin_unlock(&cq->cq_lock); /* return the number of buffers that were not posted */ *buff_count = *buff_count - i; @@ -552,7 +551,7 @@ int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg, u16 i; /* take the lock before we start messing with the ring */ - mutex_lock(&cq->cq_lock); + spin_lock(&cq->cq_lock); ntc = cq->next_to_clean; @@ -614,7 +613,7 @@ int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg, cq->next_to_clean = ntc; - mutex_unlock(&cq->cq_lock); + spin_unlock(&cq->cq_lock); *num_q_msg = i; if (*num_q_msg == 0) diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h index e8e046ef2f0d7..5890d8adca4a8 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h +++ b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h @@ -99,7 +99,7 @@ struct idpf_ctlq_info { enum idpf_ctlq_type cq_type; int q_id; - struct mutex cq_lock; /* control queue lock */ + spinlock_t cq_lock; /* control queue lock */ /* used for interrupt processing */ u16 next_to_use; u16 next_to_clean; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 74cce7bb9a568..8e8f0b6b99417 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -2338,8 +2338,12 @@ void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem, u64 size) struct idpf_adapter *adapter = hw->back; size_t sz = ALIGN(size, 4096); - mem->va = dma_alloc_coherent(&adapter->pdev->dev, sz, - &mem->pa, GFP_KERNEL); + /* The control queue resources are freed under a spinlock, contiguous + * pages will avoid IOMMU remapping and the use vmap (and vunmap in + * dma_free_*() path. + */ + mem->va = dma_alloc_attrs(&adapter->pdev->dev, sz, &mem->pa, + GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS); mem->size = sz; return mem->va; @@ -2354,8 +2358,8 @@ void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem) { struct idpf_adapter *adapter = hw->back; - dma_free_coherent(&adapter->pdev->dev, mem->size, - mem->va, mem->pa); + dma_free_attrs(&adapter->pdev->dev, mem->size, + mem->va, mem->pa, DMA_ATTR_FORCE_CONTIGUOUS); mem->size = 0; mem->va = NULL; mem->pa = 0; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 645fa87b3fb6f..a6a31a1afcf67 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -2213,6 +2213,13 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING; align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; + if (unlikely(size > skb->len)) { + netif_dbg(dev, rx_err, dev->net, + "size err rx_cmd_a=0x%08x\n", + rx_cmd_a); + return 0; + } + if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { netif_dbg(dev, rx_err, dev->net, "Error rx_cmd_a=0x%08x\n", rx_cmd_a); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index e56e806311e99..cb65600407b06 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1878,8 +1878,8 @@ vmxnet3_rq_destroy_all_rxdataring(struct vmxnet3_adapter *adapter) rq->data_ring.base, rq->data_ring.basePA); rq->data_ring.base = NULL; - rq->data_ring.desc_size = 0; } + rq->data_ring.desc_size = 0; } } diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4d870ed893856..ea255261ac73f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -993,7 +993,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, { struct pci_dev *dev; resource_size_t min_align, align, size, size0, size1; - resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */ + resource_size_t aligns[24]; /* Alignments from 1MB to 8TB */ int order, max_order; struct resource *b_res = find_bus_resource_of_type(bus, mask | IORESOURCE_PREFETCH, type); diff --git a/fs/namespace.c b/fs/namespace.c index 487417f606c93..be37d60995aaa 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2254,6 +2254,19 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp) return attach_recursive_mnt(mnt, p, mp, NULL); } +static int may_change_propagation(const struct mount *m) +{ + struct mnt_namespace *ns = m->mnt_ns; + + // it must be mounted in some namespace + if (IS_ERR_OR_NULL(ns)) // is_mounted() + return -EINVAL; + // and the caller must be admin in userns of that namespace + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + /* * Sanity check the flags to change_mnt_propagation. */ @@ -2290,6 +2303,10 @@ static int do_change_type(struct path *path, int ms_flags) return -EINVAL; namespace_lock(); + err = may_change_propagation(mnt); + if (err) + goto out_unlock; + if (type == MS_SHARED) { err = invent_group_ids(mnt, recurse); if (err) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 9bd5cf3f6d3c9..52cd124c78607 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1519,7 +1519,9 @@ static int __init init_nfsd(void) retval = nfsd4_init_pnfs(); if (retval) goto out_free_slabs; - nfsd_stat_init(); /* Statistics */ + retval = nfsd_stat_init(); /* Statistics */ + if (retval) + goto out_free_pnfs; retval = nfsd_drc_slab_create(); if (retval) goto out_free_stat; @@ -1549,6 +1551,7 @@ static int __init init_nfsd(void) nfsd_drc_slab_free(); out_free_stat: nfsd_stat_shutdown(); +out_free_pnfs: nfsd4_exit_pnfs(); out_free_slabs: nfsd4_free_slabs(); diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index 9bce3b913189c..f2eea44d99c2c 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -91,10 +91,11 @@ static const struct file_operations nfsd_proc_fops = { .release = single_release, }; -void -nfsd_stat_init(void) +int nfsd_stat_init(void) { - svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops); + if (svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops) == NULL) + return -ENOMEM; + return 0; } void diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h index b23fdac698201..97c7d820b295d 100644 --- a/fs/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -38,7 +38,7 @@ struct nfsd_stats { extern struct nfsd_stats nfsdstats; extern struct svc_stat nfsd_svcstats; -void nfsd_stat_init(void); +int nfsd_stat_init(void); void nfsd_stat_shutdown(void); #endif /* _NFSD_STATS_H */ diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c index 0c8bee3abc3b4..d21ed06642f9a 100644 --- a/fs/xfs/libxfs/xfs_attr_remote.c +++ b/fs/xfs/libxfs/xfs_attr_remote.c @@ -613,7 +613,6 @@ xfs_attr_rmtval_set_blk( if (error) return error; - ASSERT(nmap == 1); ASSERT((map->br_startblock != DELAYSTARTBLOCK) && (map->br_startblock != HOLESTARTBLOCK)); diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index e4c9d0ba25a23..fec2e85cbd251 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -4114,8 +4114,10 @@ xfs_bmapi_allocate( } else { error = xfs_bmap_alloc_userdata(bma); } - if (error || bma->blkno == NULLFSBLOCK) + if (error) return error; + if (bma->blkno == NULLFSBLOCK) + return -ENOSPC; if (bma->flags & XFS_BMAPI_ZERO) { error = xfs_zero_extent(bma->ip, bma->blkno, bma->length); @@ -4295,6 +4297,15 @@ xfs_bmapi_finish( * extent state if necessary. Details behaviour is controlled by the flags * parameter. Only allocates blocks from a single allocation group, to avoid * locking problems. + * + * Returns 0 on success and places the extent mappings in mval. nmaps is used + * as an input/output parameter where the caller specifies the maximum number + * of mappings that may be returned and xfs_bmapi_write passes back the number + * of mappings (including existing mappings) it found. + * + * Returns a negative error code on failure, including -ENOSPC when it could not + * allocate any blocks and -ENOSR when it did allocate blocks to convert a + * delalloc range, but those blocks were before the passed in range. */ int xfs_bmapi_write( @@ -4423,10 +4434,16 @@ xfs_bmapi_write( ASSERT(len > 0); ASSERT(bma.length > 0); error = xfs_bmapi_allocate(&bma); - if (error) + if (error) { + /* + * If we already allocated space in a previous + * iteration return what we go so far when + * running out of space. + */ + if (error == -ENOSPC && bma.nallocs) + break; goto error0; - if (bma.blkno == NULLFSBLOCK) - break; + } /* * If this is a CoW allocation, record the data in @@ -4464,7 +4481,6 @@ xfs_bmapi_write( if (!xfs_iext_next_extent(ifp, &bma.icur, &bma.got)) eof = true; } - *nmap = n; error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags, whichfork); @@ -4475,7 +4491,22 @@ xfs_bmapi_write( ifp->if_nextents > XFS_IFORK_MAXEXT(ip, whichfork)); xfs_bmapi_finish(&bma, whichfork, 0); xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, - orig_nmap, *nmap); + orig_nmap, n); + + /* + * When converting delayed allocations, xfs_bmapi_allocate ignores + * the passed in bno and always converts from the start of the found + * delalloc extent. + * + * To avoid a successful return with *nmap set to 0, return the magic + * -ENOSR error code for this particular case so that the caller can + * handle it. + */ + if (!n) { + ASSERT(bma.nallocs >= *nmap); + return -ENOSR; + } + *nmap = n; return 0; error0: xfs_bmapi_finish(&bma, whichfork, error); @@ -4579,9 +4610,6 @@ xfs_bmapi_convert_delalloc( if (error) goto out_finish; - error = -ENOSPC; - if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) - goto out_finish; error = -EFSCORRUPTED; if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) goto out_finish; diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index 747ec77912c3f..c93488d5fa285 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -2146,8 +2146,8 @@ xfs_da_grow_inode_int( struct xfs_inode *dp = args->dp; int w = args->whichfork; xfs_rfsblock_t nblks = dp->i_nblocks; - struct xfs_bmbt_irec map, *mapp; - int nmap, error, got, i, mapi; + struct xfs_bmbt_irec map, *mapp = ↦ + int nmap, error, got, i, mapi = 1; /* * Find a spot in the file space to put the new block. @@ -2163,14 +2163,8 @@ xfs_da_grow_inode_int( error = xfs_bmapi_write(tp, dp, *bno, count, xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, args->total, &map, &nmap); - if (error) - return error; - ASSERT(nmap <= 1); - if (nmap == 1) { - mapp = ↦ - mapi = 1; - } else if (nmap == 0 && count > 1) { + if (error == -ENOSPC && count > 1) { xfs_fileoff_t b; int c; @@ -2187,16 +2181,13 @@ xfs_da_grow_inode_int( args->total, &mapp[mapi], &nmap); if (error) goto out_free_map; - if (nmap < 1) - break; mapi += nmap; b = mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount; } - } else { - mapi = 0; - mapp = NULL; } + if (error) + goto out_free_map; /* * Count the blocks we got, make sure it matches the total. diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 6b7f3754a5e24..e8355703f5850 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -802,11 +802,12 @@ xfs_log_sb( * the counters from the AGF block counts. */ if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { - mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); + mp->m_sb.sb_icount = percpu_counter_sum_positive(&mp->m_icount); mp->m_sb.sb_ifree = min_t(uint64_t, - percpu_counter_sum(&mp->m_ifree), + percpu_counter_sum_positive(&mp->m_ifree), mp->m_sb.sb_icount); - mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); + mp->m_sb.sb_fdblocks = + percpu_counter_sum_positive(&mp->m_fdblocks); } xfs_sb_to_disk(bp->b_addr, &mp->m_sb); diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index dade78786373f..a30e2a840a91f 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -778,12 +778,10 @@ xfs_alloc_file_space( { xfs_mount_t *mp = ip->i_mount; xfs_off_t count; - xfs_filblks_t allocated_fsb; xfs_filblks_t allocatesize_fsb; xfs_extlen_t extsz, temp; xfs_fileoff_t startoffset_fsb; xfs_fileoff_t endoffset_fsb; - int nimaps; int rt; xfs_trans_t *tp; xfs_bmbt_irec_t imaps[1], *imapp; @@ -806,7 +804,6 @@ xfs_alloc_file_space( count = len; imapp = &imaps[0]; - nimaps = 1; startoffset_fsb = XFS_B_TO_FSBT(mp, offset); endoffset_fsb = XFS_B_TO_FSB(mp, offset + count); allocatesize_fsb = endoffset_fsb - startoffset_fsb; @@ -817,6 +814,7 @@ xfs_alloc_file_space( while (allocatesize_fsb && !error) { xfs_fileoff_t s, e; unsigned int dblocks, rblocks, resblks; + int nimaps = 1; /* * Determine space reservations for data/realtime. @@ -863,29 +861,32 @@ xfs_alloc_file_space( if (error) goto error; + /* + * If the allocator cannot find a single free extent large + * enough to cover the start block of the requested range, + * xfs_bmapi_write will return -ENOSR. + * + * In that case we simply need to keep looping with the same + * startoffset_fsb so that one of the following allocations + * will eventually reach the requested range. + */ error = xfs_bmapi_write(tp, ip, startoffset_fsb, - allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, - &nimaps); - if (error) - goto error; + allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, + &nimaps); + if (error) { + if (error != -ENOSR) + goto error; + error = 0; + } else { + startoffset_fsb += imapp->br_blockcount; + allocatesize_fsb -= imapp->br_blockcount; + } ip->i_diflags |= XFS_DIFLAG_PREALLOC; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (error) - break; - - allocated_fsb = imapp->br_blockcount; - - if (nimaps == 0) { - error = -ENOSPC; - break; - } - - startoffset_fsb += allocated_fsb; - allocatesize_fsb -= allocated_fsb; } return error; diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index dd541eaca818c..2ec2e903dc0b5 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -328,7 +328,6 @@ xfs_dquot_disk_alloc( if (error) return error; ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); - ASSERT(nmaps == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 30306bbdd059f..631c06544689b 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -300,14 +300,6 @@ xfs_iomap_write_direct( if (error) goto out_unlock; - /* - * Copy any maps to caller's array and return any error. - */ - if (nimaps == 0) { - error = -ENOSPC; - goto out_unlock; - } - if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) error = xfs_alert_fsblock_zero(ip, imap); diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index ae0964ec59097..1066533e0f354 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -428,13 +428,6 @@ xfs_reflink_fill_cow_hole( if (error) return error; - /* - * Allocation succeeded but the requested range was not even partially - * satisfied? Bail out! - */ - if (nimaps == 0) - return -ENOSPC; - convert: return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); @@ -498,12 +491,6 @@ xfs_reflink_fill_delalloc( if (error) return error; - /* - * Allocation succeeded but the requested range was not even - * partially satisfied? Bail out! - */ - if (nimaps == 0) - return -ENOSPC; } while (cmap->br_startoff + cmap->br_blockcount <= imap->br_startoff); return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 699066fb9052d..32ee98725f54b 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -815,8 +815,6 @@ xfs_growfs_rt_alloc( nmap = 1; error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks, XFS_BMAPI_METADATA, 0, &map, &nmap); - if (!error && nmap < 1) - error = -ENOSPC; if (error) goto out_trans_cancel; /* diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 0dcc07b686548..f7f19de680e6a 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -23,6 +23,7 @@ #ifndef __DRM_FRAMEBUFFER_H__ #define __DRM_FRAMEBUFFER_H__ +#include #include #include #include @@ -100,6 +101,8 @@ struct drm_framebuffer_funcs { unsigned num_clips); }; +#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i)) + /** * struct drm_framebuffer - frame buffer object * @@ -193,6 +196,11 @@ struct drm_framebuffer { * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR * universal plane. */ + /** + * @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF. + */ + unsigned int internal_flags; + int hot_x; /** * @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor diff --git a/include/linux/hid.h b/include/linux/hid.h index 9e067f937dbc2..6a405e3f06507 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -919,7 +919,6 @@ const struct hid_device_id *hid_match_device(struct hid_device *hdev, struct hid_driver *hdrv); bool hid_compare_device_paths(struct hid_device *hdev_a, struct hid_device *hdev_b, char separator); -s32 hid_snto32(__u32 value, unsigned n); __u32 hid_field_extract(const struct hid_device *hid, __u8 *report, unsigned offset, unsigned n); diff --git a/include/linux/sched.h b/include/linux/sched.h index 61e2c57963653..4574fcc3a6bbd 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1635,7 +1635,6 @@ extern struct pid *cad_pid; #define PF_MEMALLOC 0x00000800 /* Allocating memory */ #define PF_NPROC_EXCEEDED 0x00001000 /* set_user() noticed that RLIMIT_NPROC was exceeded */ #define PF_USED_MATH 0x00002000 /* If unset the fpu must be initialized before use */ -#define PF_USED_ASYNC 0x00004000 /* Used async_schedule*(), used by module init */ #define PF_NOFREEZE 0x00008000 /* This thread should not be frozen */ #define PF_FROZEN 0x00010000 /* Frozen for system suspend */ #define PF_KSWAPD 0x00020000 /* I am kswapd */ diff --git a/kernel/async.c b/kernel/async.c index 12c332e4e13e1..e3b5bbeb4fa36 100644 --- a/kernel/async.c +++ b/kernel/async.c @@ -209,9 +209,6 @@ async_cookie_t async_schedule_node_domain(async_func_t func, void *data, atomic_inc(&entry_count); spin_unlock_irqrestore(&async_lock, flags); - /* mark that this task has queued an async job, used by module init */ - current->flags |= PF_USED_ASYNC; - /* schedule for execution */ queue_work_node(node, system_unbound_wq, &entry->work); diff --git a/kernel/module.c b/kernel/module.c index 706911dc94d24..407cd7f72c3ae 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3519,12 +3519,6 @@ static noinline int do_init_module(struct module *mod) } freeinit->module_init = mod->init_layout.base; - /* - * We want to find out whether @mod uses async during init. Clear - * PF_USED_ASYNC. async_schedule*() will set it. - */ - current->flags &= ~PF_USED_ASYNC; - do_mod_ctors(mod); /* Start the module */ if (mod->init != NULL) @@ -3547,22 +3541,13 @@ static noinline int do_init_module(struct module *mod) /* * We need to finish all async code before the module init sequence - * is done. This has potential to deadlock. For example, a newly - * detected block device can trigger request_module() of the - * default iosched from async probing task. Once userland helper - * reaches here, async_synchronize_full() will wait on the async - * task waiting on request_module() and deadlock. - * - * This deadlock is avoided by perfomring async_synchronize_full() - * iff module init queued any async jobs. This isn't a full - * solution as it will deadlock the same if module loading from - * async jobs nests more than once; however, due to the various - * constraints, this hack seems to be the best option for now. - * Please refer to the following thread for details. + * is done. This has potential to deadlock if synchronous module + * loading is requested from async (which is not allowed!). * - * http://thread.gmane.org/gmane.linux.kernel/1420814 + * See commit 0fdff3ec6d87 ("async, kmod: warn on synchronous + * request_module() from async workers") for more details. */ - if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC)) + if (!mod->async_probe_requested) async_synchronize_full(); ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base + diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 6bd22b13d8d9d..2c724802b9f45 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1868,6 +1868,11 @@ static int *tgid_map; #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]; @@ -2083,7 +2088,11 @@ static int trace_save_cmdline(struct task_struct *tsk) * 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; @@ -4927,9 +4936,11 @@ tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, char 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); } @@ -4954,10 +4965,12 @@ static int tracing_resize_saved_cmdlines(unsigned int val) return -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; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 30fa1b40c390a..2c94a3719fe13 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1385,9 +1385,21 @@ static void free_pcppages_bulk(struct zone *zone, int count, /* * Ensure proper count is passed which otherwise would stuck in the * below while (list_empty(list)) loop. + * + * RHEL-85453: count should never be negative, but if it is, we will + * risk getting ourselves in the same predicament described above, + * and the clamping below will not be of any use to us, unfortunately. + * Upstream has indirectly addressed this condition when commit + * 44042b449872 ("mm/page_alloc: allow high-order pages to be stored + * on the per-cpu lists") changed the invariant for the outer while + * loop, preventing it from being executed when count <= 0. + * We do the same here, but we also include a warn_on assertion for + * allowing us to capture a coredump on the rare occasions where + * count would become less than zero. */ count = min(pcp->count, count); - while (count) { + WARN_ON_ONCE(unlikely(count < 0)); + while (count > 0) { struct list_head *list; /* diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 8a9badcebb39a..cf9705476b12e 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -658,7 +658,7 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key) memset(&key->ipv4, 0, sizeof(key->ipv4)); } } else if (eth_p_mpls(key->eth.type)) { - u8 label_count = 1; + size_t label_count = 1; memset(&key->mpls, 0, sizeof(key->mpls)); skb_set_inner_network_header(skb, skb->mac_len); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 6aa49ed62c5bf..0c973726b4026 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -781,15 +781,12 @@ static u32 qdisc_alloc_handle(struct net_device *dev) void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len) { - bool qdisc_is_offloaded = sch->flags & TCQ_F_OFFLOADED; const struct Qdisc_class_ops *cops; unsigned long cl; u32 parentid; bool notify; int drops; - if (n == 0 && len == 0) - return; drops = max_t(int, n, 0); rcu_read_lock(); while ((parentid = sch->parent)) { @@ -798,17 +795,8 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len) if (sch->flags & TCQ_F_NOPARENT) break; - /* Notify parent qdisc only if child qdisc becomes empty. - * - * If child was empty even before update then backlog - * counter is screwed and we skip notification because - * parent class is already passive. - * - * If the original child was offloaded then it is allowed - * to be seem as empty, so the parent is notified anyway. - */ - notify = !sch->q.qlen && !WARN_ON_ONCE(!n && - !qdisc_is_offloaded); + /* Notify parent qdisc only if child qdisc becomes empty. */ + notify = !sch->q.qlen; /* TODO: perform the search on a per txq basis */ sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid)); if (sch == NULL) { @@ -817,6 +805,9 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len) } cops = sch->ops->cl_ops; if (notify && cops->qlen_notify) { + /* Note that qlen_notify must be idempotent as it may get called + * multiple times. + */ cl = cops->find(sch, parentid); cops->qlen_notify(sch, cl); } diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 9c4dc97052705..bf057aa3557e8 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1342,6 +1342,8 @@ static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg) { struct cbq_class *cl = (struct cbq_class *)arg; + if (!cl->next_alive) + return; cbq_deactivate_class(cl); } diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index d7a4874543de5..5f2e068157456 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -95,10 +95,7 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) &q->stats, qdisc_pkt_len, codel_get_enqueue_time, drop_func, dequeue_func); - /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, - * or HTB crashes. Defer it for next round. - */ - if (q->stats.drop_count && sch->q.qlen) { + if (q->stats.drop_count) { qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); q->stats.drop_count = 0; q->stats.drop_len = 0; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 89b2ee29e0695..f6e00efe046a3 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -109,6 +109,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, return -ENOBUFS; gnet_stats_basic_sync_init(&cl->bstats); + INIT_LIST_HEAD(&cl->alist); cl->common.classid = classid; cl->quantum = quantum; cl->qdisc = qdisc_create_dflt(sch->dev_queue, @@ -231,7 +232,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg) { struct drr_class *cl = (struct drr_class *)arg; - list_del(&cl->alist); + list_del_init(&cl->alist); } static int drr_dump_class(struct Qdisc *sch, unsigned long arg, @@ -392,7 +393,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch) if (unlikely(skb == NULL)) goto out; if (cl->qdisc->q.qlen == 0) - list_del(&cl->alist); + list_del_init(&cl->alist); bstats_update(&cl->bstats, skb); qdisc_bstats_update(sch, skb); @@ -433,7 +434,7 @@ static void drr_reset_qdisc(struct Qdisc *sch) for (i = 0; i < q->clhash.hashsize; i++) { hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { if (cl->qdisc->q.qlen) - list_del(&cl->alist); + list_del_init(&cl->alist); qdisc_reset(cl->qdisc); } } diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c index 0520d8cfe580e..fbf78afe87bbd 100644 --- a/net/sched/sch_ets.c +++ b/net/sched/sch_ets.c @@ -649,23 +649,24 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, sch_tree_lock(sch); - q->nbands = nbands; + for (i = nbands; i < oldbands; i++) { + if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) + list_del_init(&q->classes[i].alist); + qdisc_purge_queue(q->classes[i].qdisc); + } + + WRITE_ONCE(q->nbands, nbands); for (i = nstrict; i < q->nstrict; i++) { if (q->classes[i].qdisc->q.qlen) { list_add_tail(&q->classes[i].alist, &q->active); q->classes[i].deficit = quanta[i]; } } - for (i = q->nbands; i < oldbands; i++) { - if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) - list_del_init(&q->classes[i].alist); - qdisc_tree_flush_backlog(q->classes[i].qdisc); - } - q->nstrict = nstrict; + WRITE_ONCE(q->nstrict, nstrict); memcpy(q->prio2band, priomap, sizeof(priomap)); for (i = 0; i < q->nbands; i++) - q->classes[i].quantum = quanta[i]; + WRITE_ONCE(q->classes[i].quantum, quanta[i]); for (i = oldbands; i < q->nbands; i++) { q->classes[i].qdisc = queues[i]; @@ -679,7 +680,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, for (i = q->nbands; i < oldbands; i++) { qdisc_put(q->classes[i].qdisc); q->classes[i].qdisc = NULL; - q->classes[i].quantum = 0; + WRITE_ONCE(q->classes[i].quantum, 0); q->classes[i].deficit = 0; gnet_stats_basic_sync_init(&q->classes[i].bstats); memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats)); @@ -736,6 +737,7 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb) struct ets_sched *q = qdisc_priv(sch); struct nlattr *opts; struct nlattr *nest; + u8 nbands, nstrict; int band; int prio; int err; @@ -748,21 +750,22 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb) if (!opts) goto nla_err; - if (nla_put_u8(skb, TCA_ETS_NBANDS, q->nbands)) + nbands = READ_ONCE(q->nbands); + if (nla_put_u8(skb, TCA_ETS_NBANDS, nbands)) goto nla_err; - if (q->nstrict && - nla_put_u8(skb, TCA_ETS_NSTRICT, q->nstrict)) + nstrict = READ_ONCE(q->nstrict); + if (nstrict && nla_put_u8(skb, TCA_ETS_NSTRICT, nstrict)) goto nla_err; - if (q->nbands > q->nstrict) { + if (nbands > nstrict) { nest = nla_nest_start(skb, TCA_ETS_QUANTA); if (!nest) goto nla_err; - for (band = q->nstrict; band < q->nbands; band++) { + for (band = nstrict; band < nbands; band++) { if (nla_put_u32(skb, TCA_ETS_QUANTA_BAND, - q->classes[band].quantum)) + READ_ONCE(q->classes[band].quantum))) goto nla_err; } @@ -774,7 +777,8 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb) goto nla_err; for (prio = 0; prio <= TC_PRIO_MAX; prio++) { - if (nla_put_u8(skb, TCA_ETS_PRIOMAP_BAND, q->prio2band[prio])) + if (nla_put_u8(skb, TCA_ETS_PRIOMAP_BAND, + READ_ONCE(q->prio2band[prio]))) goto nla_err; } diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 47bb80fc68277..cfda5d4d4cad0 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -318,10 +318,8 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) } qdisc_bstats_update(sch, skb); flow->deficit -= qdisc_pkt_len(skb); - /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, - * or HTB crashes. Defer it for next round. - */ - if (q->cstats.drop_count && sch->q.qlen) { + + if (q->cstats.drop_count) { qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len); q->cstats.drop_count = 0; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index e6b966a3138a5..61b91de8065f0 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -967,6 +967,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (cl != NULL) { int old_flags; + int len = 0; if (parentid) { if (cl->cl_parent && @@ -997,9 +998,13 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (usc != NULL) hfsc_change_usc(cl, usc, cur_time); + if (cl->qdisc->q.qlen != 0) + len = qdisc_peek_len(cl->qdisc); + /* Check queue length again since some qdisc implementations + * (e.g., netem/codel) might empty the queue during the peek + * operation. + */ if (cl->qdisc->q.qlen != 0) { - int len = qdisc_peek_len(cl->qdisc); - if (cl->cl_flags & HFSC_RSC) { if (old_flags & HFSC_RSC) update_ed(cl, len); @@ -1642,10 +1647,16 @@ hfsc_dequeue(struct Qdisc *sch) if (cl->qdisc->q.qlen != 0) { /* update ed */ next_len = qdisc_peek_len(cl->qdisc); - if (realtime) - update_ed(cl, next_len); - else - update_d(cl, next_len); + /* Check queue length again since some qdisc implementations + * (e.g., netem/codel) might empty the queue during the peek + * operation. + */ + if (cl->qdisc->q.qlen != 0) { + if (realtime) + update_ed(cl, next_len); + else + update_d(cl, next_len); + } } else { /* the class becomes passive */ eltree_remove(cl); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index c712696c9e17b..cc98035e2d170 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -353,7 +353,8 @@ static void htb_add_to_wait_tree(struct htb_sched *q, */ static inline void htb_next_rb_node(struct rb_node **n) { - *n = rb_next(*n); + if (*n) + *n = rb_next(*n); } /** @@ -614,8 +615,8 @@ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) */ static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) { - WARN_ON(!cl->prio_activity); - + if (!cl->prio_activity) + return; htb_deactivate_prios(q, cl); cl->prio_activity = 0; } @@ -1753,8 +1754,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg, if (cl->parent) cl->parent->children--; - if (cl->prio_activity) - htb_deactivate(q, cl); + htb_deactivate(q, cl); if (cl->cmode != HTB_CAN_SEND) htb_safe_rb_erase(&cl->pq_node, @@ -1970,8 +1970,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* turn parent into inner node */ qdisc_purge_queue(parent->leaf.q); parent_qdisc = parent->leaf.q; - if (parent->prio_activity) - htb_deactivate(q, parent); + htb_deactivate(q, parent); /* remove from evt list because of level change */ if (parent->cmode != HTB_CAN_SEND) { diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 0660200decc20..28b8edfdf2405 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -352,7 +352,7 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) struct qfq_aggregate *agg = cl->agg; - list_del(&cl->alist); /* remove from RR queue of the aggregate */ + list_del_init(&cl->alist); /* remove from RR queue of the aggregate */ if (list_empty(&agg->active)) /* agg is now inactive */ qfq_deactivate_agg(q, agg); } @@ -485,6 +485,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, gnet_stats_basic_sync_init(&cl->bstats); cl->common.classid = classid; cl->deficit = lmax; + INIT_LIST_HEAD(&cl->alist); cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid, NULL); @@ -997,7 +998,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg, cl->deficit -= (int) len; if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ - list_del(&cl->alist); + list_del_init(&cl->alist); else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { cl->deficit += agg->lmax; list_move_tail(&cl->alist, &agg->active); @@ -1430,6 +1431,8 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) struct qfq_sched *q = qdisc_priv(sch); struct qfq_class *cl = (struct qfq_class *)arg; + if (list_empty(&cl->alist)) + return; qfq_deactivate_class(q, cl); } diff --git a/net/sctp/input.c b/net/sctp/input.c index cab795448ca3a..04cfd6577b857 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -129,7 +129,7 @@ int sctp_rcv(struct sk_buff *skb) * it's better to just linearize it otherwise crc computing * takes longer. */ - if ((!is_gso && skb_linearize(skb)) || + if (((!is_gso || skb_cloned(skb)) && skb_linearize(skb)) || !pskb_may_pull(skb, sizeof(struct sctphdr))) goto discard_it; diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index fa5443d374f8e..6f7d22b5f3fa8 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -400,6 +400,8 @@ EXPORT_SYMBOL_GPL(vsock_enqueue_accept); static bool vsock_use_local_transport(unsigned int remote_cid) { + lockdep_assert_held(&vsock_register_mutex); + if (!transport_local) return false; @@ -457,6 +459,8 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) remote_flags = vsk->remote_addr.svm_flags; + mutex_lock(&vsock_register_mutex); + switch (sk->sk_type) { case SOCK_DGRAM: new_transport = transport_dgram; @@ -471,12 +475,15 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) new_transport = transport_h2g; break; default: - return -ESOCKTNOSUPPORT; + ret = -ESOCKTNOSUPPORT; + goto err; } if (vsk->transport) { - if (vsk->transport == new_transport) - return 0; + if (vsk->transport == new_transport) { + ret = 0; + goto err; + } /* transport->release() must be called with sock lock acquired. * This path can only be taken during vsock_stream_connect(), @@ -491,8 +498,16 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) /* We increase the module refcnt to prevent the transport unloading * while there are open sockets assigned to it. */ - if (!new_transport || !try_module_get(new_transport->module)) - return -ENODEV; + if (!new_transport || !try_module_get(new_transport->module)) { + ret = -ENODEV; + goto err; + } + + /* It's safe to release the mutex after a successful try_module_get(). + * Whichever transport `new_transport` points at, it won't go away until + * the last module_put() below or in vsock_deassign_transport(). + */ + mutex_unlock(&vsock_register_mutex); ret = new_transport->init(vsk, psk); if (ret) { @@ -503,6 +518,9 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) vsk->transport = new_transport; return 0; +err: + mutex_unlock(&vsock_register_mutex); + return ret; } EXPORT_SYMBOL_GPL(vsock_assign_transport);