s390/pai: Fix multiple concurrent event installation
authorThomas Richter <tmricht@linux.ibm.com>
Wed, 15 Jun 2022 12:02:07 +0000 (14:02 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Thu, 23 Jun 2022 15:24:00 +0000 (17:24 +0200)
Two different events such as pai_crypto/KM_AES_128/ and
pai_crypto/KM_AES_192/ can be installed multiple times on the same CPU
and the events are executed concurrently:

  # perf stat -e pai_crypto/KM_AES_128/  -C0 -a -- sleep 5 &
  # sleep 2
  # perf stat -e pai_crypto/KM_AES_192/ -C0 -a -- true

This results in the first event being installed two times with two seconds
delay. The kernel does install the second event after the first
event has been deleted and re-added, as can be seen in the traces:

 13:48:47.600350  paicrypt_start event 0x1007 (event KM_AES_128)
 13:48:49.599359  paicrypt_stop event 0x1007  (event KM_AES_128)
 13:48:49.599198  paicrypt_start event 0x1007
 13:48:49.599199  paicrypt_start event 0x1008
 13:48:49.599921  paicrypt_event_destroy event 0x1008
 13:48:52.601507  paicrypt_event_destroy event 0x1007

This is caused by functions event_sched_in() and event_sched_out() which
call the PMU's add() and start() functions on schedule_in and the PMU's
stop() and del() functions on schedule_out. This is correct for events
attached to processes.  The pai_crypto events are system-wide events
and not attached to processes.

Since the kernel common code can not be changed easily, fix this issue
and do not reset the event count value to zero each time the event is
added and started. Instead use a flag and zero the event count value
only when called immediately after the event has been initialized.
Therefore only the first invocation of the the event's add() function
initializes the event count value to zero. The following invocations
of the event's add() function leave the current event count value
untouched.

Fixes: 39d62336f5c1 ("s390/pai: add support for cryptography counters")
Reported-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/kernel/perf_pai_crypto.c

index 188c6cf09c7a2bea97590e76bbe4ef9bd8af2dd7..b38b4ae01589b20d58fa91d78b05844977f2f5e1 100644 (file)
@@ -209,6 +209,12 @@ static int paicrypt_event_init(struct perf_event *event)
        if (rc)
                return rc;
 
+       /* Event initialization sets last_tag to 0. When later on the events
+        * are deleted and re-added, do not reset the event count value to zero.
+        * Events are added, deleted and re-added when 2 or more events
+        * are active at the same time.
+        */
+       event->hw.last_tag = 0;
        cpump->event = event;
        event->destroy = paicrypt_event_destroy;
 
@@ -243,9 +249,12 @@ static void paicrypt_start(struct perf_event *event, int flags)
 {
        u64 sum;
 
-       sum = paicrypt_getall(event);           /* Get current value */
-       local64_set(&event->hw.prev_count, sum);
-       local64_set(&event->count, 0);
+       if (!event->hw.last_tag) {
+               event->hw.last_tag = 1;
+               sum = paicrypt_getall(event);           /* Get current value */
+               local64_set(&event->count, 0);
+               local64_set(&event->hw.prev_count, sum);
+       }
 }
 
 static int paicrypt_add(struct perf_event *event, int flags)