Patch "s390/cpum_sf: Check for SDBT and SDB consistency" has been added to the 4.4-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_sf: Check for SDBT and SDB consistency

to the 4.4-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_sf-check-for-sdbt-and-sdb-consistency.patch
and it can be found in the queue-4.4 subdirectory.

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



commit 7f0f616b10607cff76d9c413ef46f6dce4c888c2
Author: Thomas Richter <tmricht@xxxxxxxxxxxxx>
Date:   Fri Nov 22 16:43:15 2019 +0100

    s390/cpum_sf: Check for SDBT and SDB consistency
    
    [ Upstream commit 247f265fa502e7b17a0cb0cc330e055a36aafce4 ]
    
    Each SBDT is located at a 4KB page and contains 512 entries.
    Each entry of a SDBT points to a SDB, a 4KB page containing
    sampled data. The last entry is a link to another SDBT page.
    
    When an event is created the function sequence executed is:
    
      __hw_perf_event_init()
      +--> allocate_buffers()
           +--> realloc_sampling_buffers()
                +---> alloc_sample_data_block()
    
    Both functions realloc_sampling_buffers() and
    alloc_sample_data_block() allocate pages and the allocation
    can fail. This is handled correctly and all allocated
    pages are freed and error -ENOMEM is returned to the
    top calling function. Finally the event is not created.
    
    Once the event has been created, the amount of initially
    allocated SDBT and SDB can be too low. This is detected
    during measurement interrupt handling, where the amount
    of lost samples is calculated. If the number of lost samples
    is too high considering sampling frequency and already allocated
    SBDs, the number of SDBs is enlarged during the next execution
    of cpumsf_pmu_enable().
    
    If more SBDs need to be allocated, functions
    
           realloc_sampling_buffers()
           +---> alloc-sample_data_block()
    
    are called to allocate more pages. Page allocation may fail
    and the returned error is ignored. A SDBT and SDB setup
    already exists.
    
    However the modified SDBTs and SDBs might end up in a situation
    where the first entry of an SDBT does not point to an SDB,
    but another SDBT, basicly an SBDT without payload.
    This can not be handled by the interrupt handler, where an SDBT
    must have at least one entry pointing to an SBD.
    
    Add a check to avoid SDBTs with out payload (SDBs) when enlarging
    the buffer setup.
    
    Signed-off-by: Thomas Richter <tmricht@xxxxxxxxxxxxx>
    Signed-off-by: Vasily Gorbik <gor@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
index 874762a51c54..7490c52b2715 100644
--- a/arch/s390/kernel/perf_cpum_sf.c
+++ b/arch/s390/kernel/perf_cpum_sf.c
@@ -185,7 +185,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
 				   unsigned long num_sdb, gfp_t gfp_flags)
 {
 	int i, rc;
-	unsigned long *new, *tail;
+	unsigned long *new, *tail, *tail_prev = NULL;
 
 	if (!sfb->sdbt || !sfb->tail)
 		return -EINVAL;
@@ -224,6 +224,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
 			sfb->num_sdbt++;
 			/* Link current page to tail of chain */
 			*tail = (unsigned long)(void *) new + 1;
+			tail_prev = tail;
 			tail = new;
 		}
 
@@ -233,10 +234,22 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
 		 * issue, a new realloc call (if required) might succeed.
 		 */
 		rc = alloc_sample_data_block(tail, gfp_flags);
-		if (rc)
+		if (rc) {
+			/* Undo last SDBT. An SDBT with no SDB at its first
+			 * entry but with an SDBT entry instead can not be
+			 * handled by the interrupt handler code.
+			 * Avoid this situation.
+			 */
+			if (tail_prev) {
+				sfb->num_sdbt--;
+				free_page((unsigned long) new);
+				tail = tail_prev;
+			}
 			break;
+		}
 		sfb->num_sdb++;
 		tail++;
+		tail_prev = new = NULL;	/* Allocated at least one SBD */
 	}
 
 	/* Link sampling buffer to its origin */



[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