powerpc/pseries: Protect against hogging the cpu while setting up the stats
authorNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Wed, 3 Jul 2019 17:04:01 +0000 (22:34 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 4 Jul 2019 12:27:25 +0000 (22:27 +1000)
When enabling or disabling the vcpu dispatch statistics, we do a lot of
work including allocating/deallocating memory across all possible cpus
for the DTL buffer. In order to guard against hogging the cpu for too
long, track the time we're taking and yield the processor if necessary.

Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/lppaca.h
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/setup.c

index f5195b4d9ffb3d09416e313864d622bf69d15e0c..d7952665945a2842e29820646bd93a3139b70e70 100644 (file)
@@ -201,7 +201,7 @@ extern rwlock_t dtl_access_lock;
 extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
 
 extern void register_dtl_buffer(int cpu);
-extern void alloc_dtl_buffers(void);
+extern void alloc_dtl_buffers(unsigned long *time_limit);
 extern long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity);
 
 #endif /* CONFIG_PPC_BOOK3S */
index ec5a7893f71b54d2935063718445c5710cbab76c..ae7040f5956425de4dba5bc02640f9f59147e97d 100644 (file)
@@ -75,7 +75,7 @@ static u8 dtl_mask = DTL_LOG_PREEMPT;
 static u8 dtl_mask;
 #endif
 
-void alloc_dtl_buffers(void)
+void alloc_dtl_buffers(unsigned long *time_limit)
 {
        int cpu;
        struct paca_struct *pp;
@@ -99,6 +99,11 @@ void alloc_dtl_buffers(void)
                pp->dispatch_log = dtl;
                pp->dispatch_log_end = dtl + N_DISPATCH_LOG;
                pp->dtl_curr = dtl;
+
+               if (time_limit && time_after(jiffies, *time_limit)) {
+                       cond_resched();
+                       *time_limit = jiffies + HZ;
+               }
        }
 }
 
@@ -168,7 +173,7 @@ static int vcpudispatch_stats_freq = 50;
 static __be32 *vcpu_associativity, *pcpu_associativity;
 
 
-static void free_dtl_buffers(void)
+static void free_dtl_buffers(unsigned long *time_limit)
 {
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        int cpu;
@@ -183,6 +188,11 @@ static void free_dtl_buffers(void)
                pp->dispatch_log = 0;
                pp->dispatch_log_end = 0;
                pp->dtl_curr = 0;
+
+               if (time_limit && time_after(jiffies, *time_limit)) {
+                       cond_resched();
+                       *time_limit = jiffies + HZ;
+               }
        }
 #endif
 }
@@ -442,7 +452,7 @@ static void reset_global_dtl_mask(void)
                lppaca_of(cpu).dtl_enable_mask = dtl_mask;
 }
 
-static int dtl_worker_enable(void)
+static int dtl_worker_enable(unsigned long *time_limit)
 {
        int rc = 0, state;
 
@@ -454,13 +464,13 @@ static int dtl_worker_enable(void)
        set_global_dtl_mask(DTL_LOG_ALL);
 
        /* Setup dtl buffers and register those */
-       alloc_dtl_buffers();
+       alloc_dtl_buffers(time_limit);
 
        state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powerpc/dtl:online",
                                        dtl_worker_online, dtl_worker_offline);
        if (state < 0) {
                pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n");
-               free_dtl_buffers();
+               free_dtl_buffers(time_limit);
                reset_global_dtl_mask();
                write_unlock(&dtl_access_lock);
                rc = -EINVAL;
@@ -472,10 +482,10 @@ out:
        return rc;
 }
 
-static void dtl_worker_disable(void)
+static void dtl_worker_disable(unsigned long *time_limit)
 {
        cpuhp_remove_state(dtl_worker_state);
-       free_dtl_buffers();
+       free_dtl_buffers(time_limit);
        reset_global_dtl_mask();
        write_unlock(&dtl_access_lock);
 }
@@ -483,6 +493,7 @@ static void dtl_worker_disable(void)
 static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
                size_t count, loff_t *ppos)
 {
+       unsigned long time_limit = jiffies + HZ;
        struct vcpu_dispatch_data *disp;
        int rc, cmd, cpu;
        char buf[16];
@@ -517,13 +528,13 @@ static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
                        disp->last_disp_cpu = -1;
                }
 
-               rc = dtl_worker_enable();
+               rc = dtl_worker_enable(&time_limit);
                if (rc) {
                        destroy_cpu_associativity();
                        goto out;
                }
        } else {
-               dtl_worker_disable();
+               dtl_worker_disable(&time_limit);
                destroy_cpu_associativity();
        }
 
index 9d106494cc2df5d57a849cae92f718112daf0f0f..cb418d2bb1acdc9623349c380033b2a9da90c16a 100644 (file)
@@ -285,7 +285,7 @@ static int alloc_dispatch_logs(void)
        if (!dtl_cache)
                return 0;
 
-       alloc_dtl_buffers();
+       alloc_dtl_buffers(0);
 
        /* Register the DTL for the current (boot) cpu */
        register_dtl_buffer(smp_processor_id());