Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d435d862 authored by Akinobu Mita's avatar Akinobu Mita Committed by Linus Torvalds
Browse files

cpu hotplug: mce: fix cpu hotplug error handling



- Clear kobject in percpu device_mce before calling sysdev_register() with

  Because mce_create_device() may fail and it leaves kobject filled with
  junk. It will be the problem when mce_create_device() will be called
  next time.

- Fix error handling in mce_create_device()

  Error handling should not do sysdev_remove_file() with not yet added
  attributes.

- Don't register hotcpu notifier when mce_create_device() returns error

- Do mce_create_device() in CPU_UP_PREPARE instead of CPU_ONLINE

Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Cc: Gautham R Shenoy <ego@in.ibm.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Andi Kleen <ak@suse.de>
Cc: Jan Beulich <jbeulich@novell.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 881a841f
Loading
Loading
Loading
Loading
+29 −10
Original line number Diff line number Diff line
@@ -802,16 +802,29 @@ static __cpuinit int mce_create_device(unsigned int cpu)
	if (!mce_available(&cpu_data[cpu]))
		return -EIO;

	memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
	per_cpu(device_mce,cpu).id = cpu;
	per_cpu(device_mce,cpu).cls = &mce_sysclass;

	err = sysdev_register(&per_cpu(device_mce,cpu));
	if (err)
		return err;

	if (!err) {
		for (i = 0; mce_attributes[i]; i++)
			sysdev_create_file(&per_cpu(device_mce,cpu),
	for (i = 0; mce_attributes[i]; i++) {
		err = sysdev_create_file(&per_cpu(device_mce,cpu),
					 mce_attributes[i]);
		if (err)
			goto error;
	}

	return 0;
error:
	while (i--) {
		sysdev_remove_file(&per_cpu(device_mce,cpu),
				   mce_attributes[i]);
	}
	sysdev_unregister(&per_cpu(device_mce,cpu));

	return err;
}

@@ -823,7 +836,6 @@ static void mce_remove_device(unsigned int cpu)
		sysdev_remove_file(&per_cpu(device_mce,cpu),
			mce_attributes[i]);
	sysdev_unregister(&per_cpu(device_mce,cpu));
	memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
}

/* Get notified when a cpu comes on/off. Be hotplug friendly. */
@@ -831,18 +843,21 @@ static int
mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
	unsigned int cpu = (unsigned long)hcpu;
	int err = 0;

	switch (action) {
	case CPU_ONLINE:
	case CPU_ONLINE_FROZEN:
		mce_create_device(cpu);
	case CPU_UP_PREPARE:
	case CPU_UP_PREPARE_FROZEN:
		err = mce_create_device(cpu);
		break;
	case CPU_UP_CANCELED:
	case CPU_UP_CANCELED_FROZEN:
	case CPU_DEAD:
	case CPU_DEAD_FROZEN:
		mce_remove_device(cpu);
		break;
	}
	return NOTIFY_OK;
	return err ? NOTIFY_BAD : NOTIFY_OK;
}

static struct notifier_block mce_cpu_notifier = {
@@ -857,9 +872,13 @@ static __init int mce_init_device(void)
	if (!mce_available(&boot_cpu_data))
		return -EIO;
	err = sysdev_class_register(&mce_sysclass);
	if (err)
		return err;

	for_each_online_cpu(i) {
		mce_create_device(i);
		err = mce_create_device(i);
		if (err)
			return err;
	}

	register_hotcpu_notifier(&mce_cpu_notifier);