Patch "s390/cpum_cf: Fix endless loop in CF_DIAG event stop" has been added to the 6.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    s390/cpum_cf: Fix endless loop in CF_DIAG event stop

to the 6.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     s390-cpum_cf-fix-endless-loop-in-cf_diag-event-stop.patch
and it can be found in the queue-6.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 1d8e14d92aeecfacd63fa2927efd7a14df3eb470
Author: Thomas Richter <tmricht@xxxxxxxxxxxxx>
Date:   Mon Jul 15 12:07:29 2024 +0200

    s390/cpum_cf: Fix endless loop in CF_DIAG event stop
    
    [ Upstream commit e6ce1f12d777f6ee22b20e10ae6a771e7e6f44f5 ]
    
    Event CF_DIAG reads out complete counter sets using stcctm
    instruction. This is done at event start time when the process
    starts execution and at event stop time when the process is
    removed from the CPU. During removal the difference of each
    counter in the counter sets is calculated and saved as raw data
    in the ring buffer. This works fine unless the number of counters
    in a counter set is zero. This may happen for the extended counter
    set. This set is machine specific and the size of the counter
    set can be zero even when extended counter set is authorized for
    read access.
    
    This case is not handled. cfdiag_diffctr() checks authorization
    of the extended counter set. If true the functions assumes
    the extended counter set has been saved in a data buffer. However
    this is not the case, cfdiag_getctrset() does not save a counter
    set with counter set size of zero. This mismatch causes an endless
    loop in the counter set readout during event stop handling.
    
    The calculation of the difference of the counters in each counter
    now verifies the size of the counter set is non-zero. A counter set
    with size zero is skipped.
    
    Fixes: a029a4eab39e ("s390/cpumf: Allow concurrent access for CPU Measurement Counter Facility")
    Signed-off-by: Thomas Richter <tmricht@xxxxxxxxxxxxx>
    Acked-by: Sumanth Korikkar <sumanthk@xxxxxxxxxxxxx>
    Acked-by: Heiko Carstens <hca@xxxxxxxxxxxxx>
    Cc: Heiko Carstens <hca@xxxxxxxxxxxxx>
    Cc: Vasily Gorbik <gor@xxxxxxxxxxxxx>
    Cc: Alexander Gordeev <agordeev@xxxxxxxxxxxxx>
    Signed-off-by: Vasily Gorbik <gor@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
index 1434642e9cba0..6968be98af117 100644
--- a/arch/s390/kernel/perf_cpum_cf.c
+++ b/arch/s390/kernel/perf_cpum_cf.c
@@ -556,25 +556,31 @@ static int cfdiag_diffctr(struct cpu_cf_events *cpuhw, unsigned long auth)
 	struct cf_trailer_entry *trailer_start, *trailer_stop;
 	struct cf_ctrset_entry *ctrstart, *ctrstop;
 	size_t offset = 0;
+	int i;
 
-	auth &= (1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1;
-	do {
+	for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
 		ctrstart = (struct cf_ctrset_entry *)(cpuhw->start + offset);
 		ctrstop = (struct cf_ctrset_entry *)(cpuhw->stop + offset);
 
+		/* Counter set not authorized */
+		if (!(auth & cpumf_ctr_ctl[i]))
+			continue;
+		/* Counter set size zero was not saved */
+		if (!cpum_cf_read_setsize(i))
+			continue;
+
 		if (memcmp(ctrstop, ctrstart, sizeof(*ctrstop))) {
 			pr_err_once("cpum_cf_diag counter set compare error "
 				    "in set %i\n", ctrstart->set);
 			return 0;
 		}
-		auth &= ~cpumf_ctr_ctl[ctrstart->set];
 		if (ctrstart->def == CF_DIAG_CTRSET_DEF) {
 			cfdiag_diffctrset((u64 *)(ctrstart + 1),
 					  (u64 *)(ctrstop + 1), ctrstart->ctr);
 			offset += ctrstart->ctr * sizeof(u64) +
 							sizeof(*ctrstart);
 		}
-	} while (ctrstart->def && auth);
+	}
 
 	/* Save time_stamp from start of event in stop's trailer */
 	trailer_start = (struct cf_trailer_entry *)(cpuhw->start + offset);




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux