|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/mutex.h>
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/sysfs.h>
|
|
|
#include <linux/rcupdate.h>
|
|
|
|
|
|
#define MAX_SEQ_NR (INT_MAX - NR_CPUS)
|
|
@@ -924,6 +925,149 @@ static int padata_cpu_callback(struct notifier_block *nfb,
|
|
|
}
|
|
|
#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);
|
|
|
+ pentry = attr2pentry(attr);
|
|
|
+ if (pentry->show)
|
|
|
+ ret = pentry->show(pinst, attr, buf);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t padata_sysfs_store(struct kobject *kobj, struct attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ struct padata_instance *pinst;
|
|
|
+ struct padata_sysfs_entry *pentry;
|
|
|
+ ssize_t ret = -EIO;
|
|
|
+
|
|
|
+ pinst = kobj2pinst(kobj);
|
|
|
+ pentry = attr2pentry(attr);
|
|
|
+ if (pentry->show)
|
|
|
+ ret = pentry->store(pinst, attr, buf, count);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct sysfs_ops padata_sysfs_ops = {
|
|
|
+ .show = padata_sysfs_show,
|
|
|
+ .store = padata_sysfs_store,
|
|
|
+};
|
|
|
+
|
|
|
+static struct kobj_type padata_attr_type = {
|
|
|
+ .sysfs_ops = &padata_sysfs_ops,
|
|
|
+ .default_attrs = padata_default_attrs,
|
|
|
+ .release = padata_sysfs_release,
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* padata_alloc - Allocate and initialize padata instance.
|
|
|
* Use default cpumask(cpu_possible_mask)
|
|
@@ -989,6 +1133,7 @@ struct padata_instance *__padata_alloc(struct workqueue_struct *wq,
|
|
|
put_online_cpus();
|
|
|
|
|
|
BLOCKING_INIT_NOTIFIER_HEAD(&pinst->cpumask_change_notifier);
|
|
|
+ kobject_init(&pinst->kobj, &padata_attr_type);
|
|
|
mutex_init(&pinst->lock);
|
|
|
|
|
|
return pinst;
|
|
@@ -1011,14 +1156,6 @@ EXPORT_SYMBOL(__padata_alloc);
|
|
|
*/
|
|
|
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);
|
|
|
+ kobject_put(&pinst->kobj);
|
|
|
}
|
|
|
EXPORT_SYMBOL(padata_free);
|