Steffen Klassertpadata: Fix cpu hotplug961209014 years agoHistory
1124 lines · 27.2 KB · C
RawDownload
	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,	&parallel_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