lkml.org 
[lkml]   [2016]   [Jul]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip:smp/hotplug] profile: Convert to hotplug state machine
    Commit-ID:  e722d8daafb974b9ad1bbaf42f384a5ea5929f5f
    Gitweb: http://git.kernel.org/tip/e722d8daafb974b9ad1bbaf42f384a5ea5929f5f
    Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    AuthorDate: Wed, 13 Jul 2016 17:16:59 +0000
    Committer: Ingo Molnar <mingo@kernel.org>
    CommitDate: Fri, 15 Jul 2016 10:41:42 +0200

    profile: Convert to hotplug state machine

    Install the callbacks via the state machine and let the core invoke
    the callbacks on the already online CPUs. A lot of code is removed because
    the for-loop is used and create_hash_tables() is removed since its purpose
    is covered by the startup / teardown hooks.

    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Mel Gorman <mgorman@techsingularity.net>
    Cc: Michal Hocko <mhocko@suse.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Vlastimil Babka <vbabka@suse.cz>
    Cc: rt@linutronix.de
    Link: http://lkml.kernel.org/r/20160713153337.649867675@linutronix.de
    Signed-off-by: Ingo Molnar <mingo@kernel.org>
    ---
    include/linux/cpuhotplug.h | 1 +
    kernel/profile.c | 181 ++++++++++++++++-----------------------------
    2 files changed, 66 insertions(+), 116 deletions(-)

    diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
    index 15d46d2..ace5ad0 100644
    --- a/include/linux/cpuhotplug.h
    +++ b/include/linux/cpuhotplug.h
    @@ -16,6 +16,7 @@ enum cpuhp_state {
    CPUHP_X86_APB_DEAD,
    CPUHP_WORKQUEUE_PREP,
    CPUHP_HRTIMERS_PREPARE,
    + CPUHP_PROFILE_PREPARE,
    CPUHP_TIMERS_DEAD,
    CPUHP_NOTIFY_PREPARE,
    CPUHP_BRINGUP_CPU,
    diff --git a/kernel/profile.c b/kernel/profile.c
    index c2199e9..2dbccf2 100644
    --- a/kernel/profile.c
    +++ b/kernel/profile.c
    @@ -328,68 +328,57 @@ out:
    put_cpu();
    }

    -static int profile_cpu_callback(struct notifier_block *info,
    - unsigned long action, void *__cpu)
    +static int profile_dead_cpu(unsigned int cpu)
    {
    - int node, cpu = (unsigned long)__cpu;
    struct page *page;
    + int i;

    - switch (action) {
    - case CPU_UP_PREPARE:
    - case CPU_UP_PREPARE_FROZEN:
    - node = cpu_to_mem(cpu);
    - per_cpu(cpu_profile_flip, cpu) = 0;
    - if (!per_cpu(cpu_profile_hits, cpu)[1]) {
    - page = __alloc_pages_node(node,
    - GFP_KERNEL | __GFP_ZERO,
    - 0);
    - if (!page)
    - return notifier_from_errno(-ENOMEM);
    - per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
    - }
    - if (!per_cpu(cpu_profile_hits, cpu)[0]) {
    - page = __alloc_pages_node(node,
    - GFP_KERNEL | __GFP_ZERO,
    - 0);
    - if (!page)
    - goto out_free;
    - per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
    - }
    - break;
    -out_free:
    - page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
    - per_cpu(cpu_profile_hits, cpu)[1] = NULL;
    - __free_page(page);
    - return notifier_from_errno(-ENOMEM);
    - case CPU_ONLINE:
    - case CPU_ONLINE_FROZEN:
    - if (prof_cpu_mask != NULL)
    - cpumask_set_cpu(cpu, prof_cpu_mask);
    - break;
    - case CPU_UP_CANCELED:
    - case CPU_UP_CANCELED_FROZEN:
    - case CPU_DEAD:
    - case CPU_DEAD_FROZEN:
    - if (prof_cpu_mask != NULL)
    - cpumask_clear_cpu(cpu, prof_cpu_mask);
    - if (per_cpu(cpu_profile_hits, cpu)[0]) {
    - page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
    - per_cpu(cpu_profile_hits, cpu)[0] = NULL;
    + if (prof_cpu_mask != NULL)
    + cpumask_clear_cpu(cpu, prof_cpu_mask);
    +
    + for (i = 0; i < 2; i++) {
    + if (per_cpu(cpu_profile_hits, cpu)[i]) {
    + page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[i]);
    + per_cpu(cpu_profile_hits, cpu)[i] = NULL;
    __free_page(page);
    }
    - if (per_cpu(cpu_profile_hits, cpu)[1]) {
    - page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
    - per_cpu(cpu_profile_hits, cpu)[1] = NULL;
    - __free_page(page);
    + }
    + return 0;
    +}
    +
    +static int profile_prepare_cpu(unsigned int cpu)
    +{
    + int i, node = cpu_to_mem(cpu);
    + struct page *page;
    +
    + per_cpu(cpu_profile_flip, cpu) = 0;
    +
    + for (i = 0; i < 2; i++) {
    + if (per_cpu(cpu_profile_hits, cpu)[i])
    + continue;
    +
    + page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
    + if (!page) {
    + profile_dead_cpu(cpu);
    + return -ENOMEM;
    }
    - break;
    + per_cpu(cpu_profile_hits, cpu)[i] = page_address(page);
    +
    }
    - return NOTIFY_OK;
    + return 0;
    +}
    +
    +static int profile_online_cpu(unsigned int cpu)
    +{
    + if (prof_cpu_mask != NULL)
    + cpumask_set_cpu(cpu, prof_cpu_mask);
    +
    + return 0;
    }
    +
    #else /* !CONFIG_SMP */
    #define profile_flip_buffers() do { } while (0)
    #define profile_discard_flip_buffers() do { } while (0)
    -#define profile_cpu_callback NULL

    static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
    {
    @@ -531,83 +520,43 @@ static const struct file_operations proc_profile_operations = {
    .llseek = default_llseek,
    };

    -#ifdef CONFIG_SMP
    -static void profile_nop(void *unused)
    -{
    -}
    -
    -static int create_hash_tables(void)
    +int __ref create_proc_profile(void)
    {
    - int cpu;
    -
    - for_each_online_cpu(cpu) {
    - int node = cpu_to_mem(cpu);
    - struct page *page;
    -
    - page = __alloc_pages_node(node,
    - GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
    - 0);
    - if (!page)
    - goto out_cleanup;
    - per_cpu(cpu_profile_hits, cpu)[1]
    - = (struct profile_hit *)page_address(page);
    - page = __alloc_pages_node(node,
    - GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
    - 0);
    - if (!page)
    - goto out_cleanup;
    - per_cpu(cpu_profile_hits, cpu)[0]
    - = (struct profile_hit *)page_address(page);
    - }
    - return 0;
    -out_cleanup:
    - prof_on = 0;
    - smp_mb();
    - on_each_cpu(profile_nop, NULL, 1);
    - for_each_online_cpu(cpu) {
    - struct page *page;
    -
    - if (per_cpu(cpu_profile_hits, cpu)[0]) {
    - page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
    - per_cpu(cpu_profile_hits, cpu)[0] = NULL;
    - __free_page(page);
    - }
    - if (per_cpu(cpu_profile_hits, cpu)[1]) {
    - page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
    - per_cpu(cpu_profile_hits, cpu)[1] = NULL;
    - __free_page(page);
    - }
    - }
    - return -1;
    -}
    -#else
    -#define create_hash_tables() ({ 0; })
    + struct proc_dir_entry *entry;
    +#ifdef CONFIG_SMP
    + enum cpuhp_state online_state;
    #endif

    -int __ref create_proc_profile(void) /* false positive from hotcpu_notifier */
    -{
    - struct proc_dir_entry *entry;
    int err = 0;

    if (!prof_on)
    return 0;
    -
    - cpu_notifier_register_begin();
    -
    - if (create_hash_tables()) {
    - err = -ENOMEM;
    - goto out;
    - }
    -
    +#ifdef CONFIG_SMP
    + err = cpuhp_setup_state(CPUHP_PROFILE_PREPARE, "PROFILE_PREPARE",
    + profile_prepare_cpu, profile_dead_cpu);
    + if (err)
    + return err;
    +
    + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_PROFILE_ONLINE",
    + profile_online_cpu, NULL);
    + if (err < 0)
    + goto err_state_prep;
    + online_state = err;
    + err = 0;
    +#endif
    entry = proc_create("profile", S_IWUSR | S_IRUGO,
    NULL, &proc_profile_operations);
    if (!entry)
    - goto out;
    + goto err_state_onl;
    proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t));
    - __hotcpu_notifier(profile_cpu_callback, 0);

    -out:
    - cpu_notifier_register_done();
    + return err;
    +err_state_onl:
    +#ifdef CONFIG_SMP
    + cpuhp_remove_state(online_state);
    +err_state_prep:
    + cpuhp_remove_state(CPUHP_PROFILE_PREPARE);
    +#endif
    return err;
    }
    subsys_initcall(create_proc_profile);
    \
     
     \ /
      Last update: 2016-07-19 10:21    [W:4.032 / U:1.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site