powerpc/perf/hv-24x7: Use per-cpu page buffer
authorsukadev@linux.vnet.ibm.com <sukadev@linux.vnet.ibm.com>
Wed, 10 Dec 2014 22:29:13 +0000 (14:29 -0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 12 Dec 2014 05:05:18 +0000 (16:05 +1100)
The 24x7 counters are continuously running and not updated on an
interrupt. So we record the event counts when stopping the event or
deleting it.

But to "read" a single counter in 24x7, we allocate a page and pass it
into the hypervisor (The HV returns the page full of counters from which
we extract the specific counter for this event).

We allocate a page using GFP_USER and when deleting the event, we end up
with the following warning because we are blocking in interrupt context.

  [  698.641709] BUG: scheduling while atomic: swapper/0/0/0x10010000

We could use GFP_ATOMIC but that could result in failures. Pre-allocate
a buffer so we don't have to allocate in interrupt context. Further as
Michael Ellerman suggested, use Per-CPU buffer so we only need to
allocate once per CPU.

Cc: stable@vger.kernel.org
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/perf/hv-24x7.c

index dba34088da2896187a390ee720af2a4a65bc3216..d073e0679a0c2539eb9755ebaf7117eeb65fda47 100644 (file)
@@ -217,11 +217,14 @@ static bool is_physical_domain(int domain)
                domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE;
 }
 
+DEFINE_PER_CPU(char, hv_24x7_reqb[4096]) __aligned(4096);
+DEFINE_PER_CPU(char, hv_24x7_resb[4096]) __aligned(4096);
+
 static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
                                         u16 lpar, u64 *res,
                                         bool success_expected)
 {
-       unsigned long ret = -ENOMEM;
+       unsigned long ret;
 
        /*
         * request_buffer and result_buffer are not required to be 4k aligned,
@@ -243,13 +246,11 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
        BUILD_BUG_ON(sizeof(*request_buffer) > 4096);
        BUILD_BUG_ON(sizeof(*result_buffer) > 4096);
 
-       request_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER);
-       if (!request_buffer)
-               goto out;
+       request_buffer = (void *)get_cpu_var(hv_24x7_reqb);
+       result_buffer = (void *)get_cpu_var(hv_24x7_resb);
 
-       result_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER);
-       if (!result_buffer)
-               goto out_free_request_buffer;
+       memset(request_buffer, 0, 4096);
+       memset(result_buffer, 0, 4096);
 
        *request_buffer = (struct reqb) {
                .buf = {
@@ -278,15 +279,11 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
                                domain, offset, ix, lpar, ret, ret,
                                result_buffer->buf.detailed_rc,
                                result_buffer->buf.failing_request_ix);
-               goto out_free_result_buffer;
+               goto out;
        }
 
        *res = be64_to_cpu(result_buffer->result);
 
-out_free_result_buffer:
-       kfree(result_buffer);
-out_free_request_buffer:
-       kfree(request_buffer);
 out:
        return ret;
 }