put_online_cpus();} /* Replace the internal control structure with a new one. */static void padata_replace(struct padata_instance *pinst, struct parallel_data *pd_new){ struct parallel_data *pd_old = pinst->pd; int notification_mask = 0; pinst->flags |= PADATA_RESET; rcu_assign_pointer(pinst->pd, pd_new); synchronize_rcu(); if (!cpumask_equal(pd_old->cpumask.pcpu, pd_new->cpumask.pcpu)) notification_mask |= PADATA_CPU_PARALLEL; if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu)) notification_mask |= PADATA_CPU_SERIAL; padata_flush_queues(pd_old); padata_free_pd(pd_old); if (notification_mask) blocking_notifier_call_chain(&pinst->cpumask_change_notifier, notification_mask, &pd_new->cpumask); pinst->flags &= ~PADATA_RESET;} /** * padata_register_cpumask_notifier - Registers a notifier that will be called * if either pcpu or cbcpu or both cpumasks change. * * @pinst: A poineter to padata instance * @nblock: A pointer to notifier block. */int padata_register_cpumask_notifier(struct padata_instance *pinst, struct notifier_block *nblock){ return blocking_notifier_chain_register(&pinst->cpumask_change_notifier, nblock);}EXPORT_SYMBOL(padata_register_cpumask_notifier); /** * padata_unregister_cpumask_notifier - Unregisters cpumask notifier * registered earlier using padata_register_cpumask_notifier * * @pinst: A pointer to data instance. * @nlock: A pointer to notifier block. */int padata_unregister_cpumask_notifier(struct padata_instance *pinst, struct notifier_block *nblock){ return blocking_notifier_chain_unregister( &pinst->cpumask_change_notifier, nblock);}EXPORT_SYMBOL(padata_unregister_cpumask_notifier); /* If cpumask contains no active cpu, we mark the instance as invalid. */static bool padata_validate_cpumask(struct padata_instance *pinst, const struct cpumask *cpumask){ if (!cpumask_intersects(cpumask, cpu_online_mask)) { pinst->flags |= PADATA_INVALID; return false; } pinst->flags &= ~PADATA_INVALID; return true;} static int __padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask, cpumask_var_t cbcpumask){ int valid; struct parallel_data *pd; valid = padata_validate_cpumask(pinst, pcpumask); if (!valid) { __padata_stop(pinst); goto out_replace; } valid = padata_validate_cpumask(pinst, cbcpumask); if (!valid) __padata_stop(pinst); out_replace: pd = padata_alloc_pd(pinst, pcpumask, cbcpumask); if (!pd) return -ENOMEM; cpumask_copy(pinst->cpumask.pcpu, pcpumask); cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); padata_replace(pinst, pd); if (valid) __padata_start(pinst); return 0;} /** * padata_set_cpumasks - Set both parallel and serial cpumasks. The first * one is used by parallel workers and the second one * by the wokers doing serialization. * * @pinst: padata instance * @pcpumask: the cpumask to use for parallel workers * @cbcpumask: the cpumsak to use for serial workers */int padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask, cpumask_var_t cbcpumask){ int err; mutex_lock(&pinst->lock); get_online_cpus(); err = __padata_set_cpumasks(pinst, pcpumask, cbcpumask); put_online_cpus(); mutex_unlock(&pinst->lock); return err; }EXPORT_SYMBOL(padata_set_cpumasks); /** * padata_set_cpumask: Sets specified by @cpumask_type cpumask to the value * equivalent to @cpumask. * * @pinst: padata instance * @cpumask_type: PADATA_CPU_SERIAL or PADATA_CPU_PARALLEL corresponding * to parallel and serial cpumasks respectively. * @cpumask: the cpumask to use */int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type, cpumask_var_t cpumask){ struct cpumask *serial_mask, *parallel_mask; int err = -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); switch (cpumask_type) { case PADATA_CPU_PARALLEL: serial_mask = pinst->cpumask.cbcpu; parallel_mask = cpumask; break; case PADATA_CPU_SERIAL: parallel_mask = pinst->cpumask.pcpu; serial_mask = cpumask; break; default: goto out; } err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask); out: put_online_cpus(); mutex_unlock(&pinst->lock); return err;}EXPORT_SYMBOL(padata_set_cpumask); static int __padata_add_cpu(struct padata_instance *pinst, int cpu){ struct parallel_data *pd; if (cpumask_test_cpu(cpu, cpu_online_mask)) { pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu, pinst->cpumask.cbcpu); if (!pd) return -ENOMEM; padata_replace(pinst, pd); if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) __padata_start(pinst); } return 0;} /** * padata_add_cpu - add a cpu to one or both(parallel and serial) * padata cpumasks. * * @pinst: padata instance * @cpu: cpu to add * @mask: bitmask of flags specifying to which cpumask @cpu shuld be added. * The @mask may be any combination of the following flags: * PADATA_CPU_SERIAL - serial cpumask * PADATA_CPU_PARALLEL - parallel cpumask */ int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask){ int err; if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL))) return -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); if (mask & PADATA_CPU_SERIAL) cpumask_set_cpu(cpu, pinst->cpumask.cbcpu); if (mask & PADATA_CPU_PARALLEL) cpumask_set_cpu(cpu, pinst->cpumask.pcpu); err = __padata_add_cpu(pinst, cpu); put_online_cpus(); mutex_unlock(&pinst->lock); return err;}EXPORT_SYMBOL(padata_add_cpu); static int __padata_remove_cpu(struct padata_instance *pinst, int cpu){ struct parallel_data *pd = NULL; if (cpumask_test_cpu(cpu, cpu_online_mask)) { if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) __padata_stop(pinst); pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu, pinst->cpumask.cbcpu); if (!pd) return -ENOMEM; padata_replace(pinst, pd); cpumask_clear_cpu(cpu, pd->cpumask.cbcpu); cpumask_clear_cpu(cpu, pd->cpumask.pcpu); } return 0;} /** * padata_remove_cpu - remove a cpu from the one or both(serial and parallel) * padata cpumasks. * * @pinst: padata instance * @cpu: cpu to remove * @mask: bitmask specifying from which cpumask @cpu should be removed * The @mask may be any combination of the following flags: * PADATA_CPU_SERIAL - serial cpumask * PADATA_CPU_PARALLEL - parallel cpumask */int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask){ int err; if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL))) return -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); if (mask & PADATA_CPU_SERIAL) cpumask_clear_cpu(cpu, pinst->cpumask.cbcpu); if (mask & PADATA_CPU_PARALLEL) cpumask_clear_cpu(cpu, pinst->cpumask.pcpu); err = __padata_remove_cpu(pinst, cpu); put_online_cpus(); mutex_unlock(&pinst->lock); return err;}EXPORT_SYMBOL(padata_remove_cpu); /** * padata_start - start the parallel processing * * @pinst: padata instance to start */int padata_start(struct padata_instance *pinst){ int err = 0; mutex_lock(&pinst->lock); if (pinst->flags & PADATA_INVALID) err =-EINVAL; __padata_start(pinst); mutex_unlock(&pinst->lock); return err;}EXPORT_SYMBOL(padata_start); /** * padata_stop - stop the parallel processing * * @pinst: padata instance to stop */void padata_stop(struct padata_instance *pinst){ mutex_lock(&pinst->lock); __padata_stop(pinst); mutex_unlock(&pinst->lock);}EXPORT_SYMBOL(padata_stop); #ifdef CONFIG_HOTPLUG_CPU static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu){ return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || cpumask_test_cpu(cpu, pinst->cpumask.cbcpu);} static int padata_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu){ int err; struct padata_instance *pinst; int cpu = (unsigned long)hcpu; pinst = container_of(nfb, struct padata_instance, cpu_notifier); switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); err = __padata_add_cpu(pinst, cpu); mutex_unlock(&pinst->lock); if (err) return notifier_from_errno(err); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); err = __padata_remove_cpu(pinst, cpu); mutex_unlock(&pinst->lock); if (err) return notifier_from_errno(err); break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); __padata_remove_cpu(pinst, cpu); mutex_unlock(&pinst->lock); case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); __padata_add_cpu(pinst, cpu); mutex_unlock(&pinst->lock); } return NOTIFY_OK;}#endif static void __padata_free(struct padata_instance *pinst){#ifdef CONFIG_HOTPLUG_CPU unregister_hotcpu_notifier(&pinst->cpu_notifier);#endif padata_stop(pinst); padata_free_pd(pinst->pd); free_cpumask_var(pinst->cpumask.pcpu); free_cpumask_var(pinst->cpumask.cbcpu); kfree(pinst);} #define kobj2pinst(_kobj) \ container_of(_kobj, struct padata_instance, kobj)#define attr2pentry(_attr) \ container_of(_attr, struct padata_sysfs_entry, attr) static void padata_sysfs_release(struct kobject *kobj){ struct padata_instance *pinst = kobj2pinst(kobj); __padata_free(pinst);} struct padata_sysfs_entry { struct attribute attr; ssize_t (*show)(struct padata_instance *, struct attribute *, char *); ssize_t (*store)(struct padata_instance *, struct attribute *, const char *, size_t);}; static ssize_t show_cpumask(struct padata_instance *pinst, struct attribute *attr, char *buf){ struct cpumask *cpumask; ssize_t len; mutex_lock(&pinst->lock); if (!strcmp(attr->name, "serial_cpumask")) cpumask = pinst->cpumask.cbcpu; else cpumask = pinst->cpumask.pcpu; len = bitmap_scnprintf(buf, PAGE_SIZE, cpumask_bits(cpumask), nr_cpu_ids); if (PAGE_SIZE - len < 2) len = -EINVAL; else len += sprintf(buf + len, "\n"); mutex_unlock(&pinst->lock); return len;} static ssize_t store_cpumask(struct padata_instance *pinst, struct attribute *attr, const char *buf, size_t count){ cpumask_var_t new_cpumask; ssize_t ret; int mask_type; if (!alloc_cpumask_var(&new_cpumask, GFP_KERNEL)) return -ENOMEM; ret = bitmap_parse(buf, count, cpumask_bits(new_cpumask), nr_cpumask_bits); if (ret < 0) goto out; mask_type = !strcmp(attr->name, "serial_cpumask") ? PADATA_CPU_SERIAL : PADATA_CPU_PARALLEL; ret = padata_set_cpumask(pinst, mask_type, new_cpumask); if (!ret) ret = count; out: free_cpumask_var(new_cpumask); return ret;} #define PADATA_ATTR_RW(_name, _show_name, _store_name) \ static struct padata_sysfs_entry _name##_attr = \ __ATTR(_name, 0644, _show_name, _store_name)#define PADATA_ATTR_RO(_name, _show_name) \ static struct padata_sysfs_entry _name##_attr = \ __ATTR(_name, 0400, _show_name, NULL) PADATA_ATTR_RW(serial_cpumask, show_cpumask, store_cpumask);PADATA_ATTR_RW(parallel_cpumask, show_cpumask, store_cpumask); /* * Padata sysfs provides the following objects: * serial_cpumask [RW] - cpumask for serial workers * parallel_cpumask [RW] - cpumask for parallel workers */static struct attribute *padata_default_attrs[] = { &serial_cpumask_attr.attr, ¶llel_cpumask_attr.attr, NULL,}; static ssize_t padata_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf){ struct padata_instance *pinst; struct padata_sysfs_entry *pentry; ssize_t ret = -EIO; pinst = kobj2pinst(kobj);Lines 501–1000 of 1124. Previous lines Load more
put_online_cpus(); } /* Replace the internal control structure with a new one. */ static void padata_replace(struct padata_instance *pinst, struct parallel_data *pd_new) { struct parallel_data *pd_old = pinst->pd; int notification_mask = 0; pinst->flags |= PADATA_RESET; rcu_assign_pointer(pinst->pd, pd_new); synchronize_rcu(); if (!cpumask_equal(pd_old->cpumask.pcpu, pd_new->cpumask.pcpu)) notification_mask |= PADATA_CPU_PARALLEL; if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu)) notification_mask |= PADATA_CPU_SERIAL; padata_flush_queues(pd_old); padata_free_pd(pd_old); if (notification_mask) blocking_notifier_call_chain(&pinst->cpumask_change_notifier, notification_mask, &pd_new->cpumask); pinst->flags &= ~PADATA_RESET; } /** * padata_register_cpumask_notifier - Registers a notifier that will be called * if either pcpu or cbcpu or both cpumasks change. * * @pinst: A poineter to padata instance * @nblock: A pointer to notifier block. */ int padata_register_cpumask_notifier(struct padata_instance *pinst, struct notifier_block *nblock) { return blocking_notifier_chain_register(&pinst->cpumask_change_notifier, nblock); } EXPORT_SYMBOL(padata_register_cpumask_notifier); /** * padata_unregister_cpumask_notifier - Unregisters cpumask notifier * registered earlier using padata_register_cpumask_notifier * * @pinst: A pointer to data instance. * @nlock: A pointer to notifier block. */ int padata_unregister_cpumask_notifier(struct padata_instance *pinst, struct notifier_block *nblock) { return blocking_notifier_chain_unregister( &pinst->cpumask_change_notifier, nblock); } EXPORT_SYMBOL(padata_unregister_cpumask_notifier); /* If cpumask contains no active cpu, we mark the instance as invalid. */ static bool padata_validate_cpumask(struct padata_instance *pinst, const struct cpumask *cpumask) { if (!cpumask_intersects(cpumask, cpu_online_mask)) { pinst->flags |= PADATA_INVALID; return false; } pinst->flags &= ~PADATA_INVALID; return true; } static int __padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask, cpumask_var_t cbcpumask) { int valid; struct parallel_data *pd; valid = padata_validate_cpumask(pinst, pcpumask); if (!valid) { __padata_stop(pinst); goto out_replace; } valid = padata_validate_cpumask(pinst, cbcpumask); if (!valid) __padata_stop(pinst); out_replace: pd = padata_alloc_pd(pinst, pcpumask, cbcpumask); if (!pd) return -ENOMEM; cpumask_copy(pinst->cpumask.pcpu, pcpumask); cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); padata_replace(pinst, pd); if (valid) __padata_start(pinst); return 0; } /** * padata_set_cpumasks - Set both parallel and serial cpumasks. The first * one is used by parallel workers and the second one * by the wokers doing serialization. * * @pinst: padata instance * @pcpumask: the cpumask to use for parallel workers * @cbcpumask: the cpumsak to use for serial workers */ int padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask, cpumask_var_t cbcpumask) { int err; mutex_lock(&pinst->lock); get_online_cpus(); err = __padata_set_cpumasks(pinst, pcpumask, cbcpumask); put_online_cpus(); mutex_unlock(&pinst->lock); return err; } EXPORT_SYMBOL(padata_set_cpumasks); /** * padata_set_cpumask: Sets specified by @cpumask_type cpumask to the value * equivalent to @cpumask. * * @pinst: padata instance * @cpumask_type: PADATA_CPU_SERIAL or PADATA_CPU_PARALLEL corresponding * to parallel and serial cpumasks respectively. * @cpumask: the cpumask to use */ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type, cpumask_var_t cpumask) { struct cpumask *serial_mask, *parallel_mask; int err = -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); switch (cpumask_type) { case PADATA_CPU_PARALLEL: serial_mask = pinst->cpumask.cbcpu; parallel_mask = cpumask; break; case PADATA_CPU_SERIAL: parallel_mask = pinst->cpumask.pcpu; serial_mask = cpumask; break; default: goto out; } err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask); out: put_online_cpus(); mutex_unlock(&pinst->lock); return err; } EXPORT_SYMBOL(padata_set_cpumask); static int __padata_add_cpu(struct padata_instance *pinst, int cpu) { struct parallel_data *pd; if (cpumask_test_cpu(cpu, cpu_online_mask)) { pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu, pinst->cpumask.cbcpu); if (!pd) return -ENOMEM; padata_replace(pinst, pd); if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) __padata_start(pinst); } return 0; } /** * padata_add_cpu - add a cpu to one or both(parallel and serial) * padata cpumasks. * * @pinst: padata instance * @cpu: cpu to add * @mask: bitmask of flags specifying to which cpumask @cpu shuld be added. * The @mask may be any combination of the following flags: * PADATA_CPU_SERIAL - serial cpumask * PADATA_CPU_PARALLEL - parallel cpumask */ int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask) { int err; if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL))) return -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); if (mask & PADATA_CPU_SERIAL) cpumask_set_cpu(cpu, pinst->cpumask.cbcpu); if (mask & PADATA_CPU_PARALLEL) cpumask_set_cpu(cpu, pinst->cpumask.pcpu); err = __padata_add_cpu(pinst, cpu); put_online_cpus(); mutex_unlock(&pinst->lock); return err; } EXPORT_SYMBOL(padata_add_cpu); static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) { struct parallel_data *pd = NULL; if (cpumask_test_cpu(cpu, cpu_online_mask)) { if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) __padata_stop(pinst); pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu, pinst->cpumask.cbcpu); if (!pd) return -ENOMEM; padata_replace(pinst, pd); cpumask_clear_cpu(cpu, pd->cpumask.cbcpu); cpumask_clear_cpu(cpu, pd->cpumask.pcpu); } return 0; } /** * padata_remove_cpu - remove a cpu from the one or both(serial and parallel) * padata cpumasks. * * @pinst: padata instance * @cpu: cpu to remove * @mask: bitmask specifying from which cpumask @cpu should be removed * The @mask may be any combination of the following flags: * PADATA_CPU_SERIAL - serial cpumask * PADATA_CPU_PARALLEL - parallel cpumask */ int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask) { int err; if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL))) return -EINVAL; mutex_lock(&pinst->lock); get_online_cpus(); if (mask & PADATA_CPU_SERIAL) cpumask_clear_cpu(cpu, pinst->cpumask.cbcpu); if (mask & PADATA_CPU_PARALLEL) cpumask_clear_cpu(cpu, pinst->cpumask.pcpu); err = __padata_remove_cpu(pinst, cpu); put_online_cpus(); mutex_unlock(&pinst->lock); return err; } EXPORT_SYMBOL(padata_remove_cpu); /** * padata_start - start the parallel processing * * @pinst: padata instance to start */ int padata_start(struct padata_instance *pinst) { int err = 0; mutex_lock(&pinst->lock); if (pinst->flags & PADATA_INVALID) err =-EINVAL; __padata_start(pinst); mutex_unlock(&pinst->lock); return err; } EXPORT_SYMBOL(padata_start); /** * padata_stop - stop the parallel processing * * @pinst: padata instance to stop */ void padata_stop(struct padata_instance *pinst) { mutex_lock(&pinst->lock); __padata_stop(pinst); mutex_unlock(&pinst->lock); } EXPORT_SYMBOL(padata_stop); #ifdef CONFIG_HOTPLUG_CPU static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) { return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || cpumask_test_cpu(cpu, pinst->cpumask.cbcpu); } static int padata_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { int err; struct padata_instance *pinst; int cpu = (unsigned long)hcpu; pinst = container_of(nfb, struct padata_instance, cpu_notifier); switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); err = __padata_add_cpu(pinst, cpu); mutex_unlock(&pinst->lock); if (err) return notifier_from_errno(err); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); err = __padata_remove_cpu(pinst, cpu); mutex_unlock(&pinst->lock); if (err) return notifier_from_errno(err); break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); __padata_remove_cpu(pinst, cpu); mutex_unlock(&pinst->lock); case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: if (!pinst_has_cpu(pinst, cpu)) break; mutex_lock(&pinst->lock); __padata_add_cpu(pinst, cpu); mutex_unlock(&pinst->lock); } return NOTIFY_OK; } #endif static void __padata_free(struct padata_instance *pinst) { #ifdef CONFIG_HOTPLUG_CPU unregister_hotcpu_notifier(&pinst->cpu_notifier); #endif padata_stop(pinst); padata_free_pd(pinst->pd); free_cpumask_var(pinst->cpumask.pcpu); free_cpumask_var(pinst->cpumask.cbcpu); kfree(pinst); } #define kobj2pinst(_kobj) \ container_of(_kobj, struct padata_instance, kobj) #define attr2pentry(_attr) \ container_of(_attr, struct padata_sysfs_entry, attr) static void padata_sysfs_release(struct kobject *kobj) { struct padata_instance *pinst = kobj2pinst(kobj); __padata_free(pinst); } struct padata_sysfs_entry { struct attribute attr; ssize_t (*show)(struct padata_instance *, struct attribute *, char *); ssize_t (*store)(struct padata_instance *, struct attribute *, const char *, size_t); }; static ssize_t show_cpumask(struct padata_instance *pinst, struct attribute *attr, char *buf) { struct cpumask *cpumask; ssize_t len; mutex_lock(&pinst->lock); if (!strcmp(attr->name, "serial_cpumask")) cpumask = pinst->cpumask.cbcpu; else cpumask = pinst->cpumask.pcpu; len = bitmap_scnprintf(buf, PAGE_SIZE, cpumask_bits(cpumask), nr_cpu_ids); if (PAGE_SIZE - len < 2) len = -EINVAL; else len += sprintf(buf + len, "\n"); mutex_unlock(&pinst->lock); return len; } static ssize_t store_cpumask(struct padata_instance *pinst, struct attribute *attr, const char *buf, size_t count) { cpumask_var_t new_cpumask; ssize_t ret; int mask_type; if (!alloc_cpumask_var(&new_cpumask, GFP_KERNEL)) return -ENOMEM; ret = bitmap_parse(buf, count, cpumask_bits(new_cpumask), nr_cpumask_bits); if (ret < 0) goto out; mask_type = !strcmp(attr->name, "serial_cpumask") ? PADATA_CPU_SERIAL : PADATA_CPU_PARALLEL; ret = padata_set_cpumask(pinst, mask_type, new_cpumask); if (!ret) ret = count; out: free_cpumask_var(new_cpumask); return ret; } #define PADATA_ATTR_RW(_name, _show_name, _store_name) \ static struct padata_sysfs_entry _name##_attr = \ __ATTR(_name, 0644, _show_name, _store_name) #define PADATA_ATTR_RO(_name, _show_name) \ static struct padata_sysfs_entry _name##_attr = \ __ATTR(_name, 0400, _show_name, NULL) PADATA_ATTR_RW(serial_cpumask, show_cpumask, store_cpumask); PADATA_ATTR_RW(parallel_cpumask, show_cpumask, store_cpumask); /* * Padata sysfs provides the following objects: * serial_cpumask [RW] - cpumask for serial workers * parallel_cpumask [RW] - cpumask for parallel workers */ static struct attribute *padata_default_attrs[] = { &serial_cpumask_attr.attr, ¶llel_cpumask_attr.attr, NULL, }; static ssize_t padata_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct padata_instance *pinst; struct padata_sysfs_entry *pentry; ssize_t ret = -EIO; pinst = kobj2pinst(kobj);