From: Wen Congyang Date: Thu, 13 Sep 2012 00:58:16 +0000 (+1000) Subject: acpi_memhotplug.c: don't allow to eject the memory device if it is being used X-Git-Tag: next-20120917~4^2~266 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=bc52194a4ad46bfb7ac8c9241990206a8652be96;p=karo-tx-linux.git acpi_memhotplug.c: don't allow to eject the memory device if it is being used We eject the memory device even if it is in use. It is very dangerous, and it will cause the kernel to panic. Signed-off-by: Wen Congyang Cc: Len Brown Cc: "Brown, Len" Cc: Yasuaki ISIMATU Cc: David Rientjes Cc: Konrad Rzeszutek Wilk Signed-off-by: Andrew Morton --- diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 8f529731c8ba..b4f68ca60e0c 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -78,6 +78,7 @@ struct acpi_memory_info { unsigned short caching; /* memory cache attribute */ unsigned short write_protect; /* memory read/write attribute */ unsigned int enabled:1; + unsigned int failed:1; }; struct acpi_memory_device { @@ -257,9 +258,23 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) node = memory_add_physaddr_to_nid(info->start_addr); result = add_memory(node, info->start_addr, info->length); - if (result) + + /* + * If the memory block has been used by the kernel, add_memory() + * returns -EEXIST. If add_memory() returns the other error, it + * means that this memory block is not used by the kernel. + */ + if (result && result != -EEXIST) { + info->failed = 1; continue; - info->enabled = 1; + } + + if (!result) + info->enabled = 1; + /* + * Add num_enable even if add_memory() returns -EEXIST, so the + * device is bound to this driver. + */ num_enabled++; } if (!num_enabled) { @@ -323,11 +338,20 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) * Note: Assume that this function returns zero on success */ list_for_each_entry_safe(info, n, &mem_device->res_list, list) { - if (info->enabled) { - result = remove_memory(info->start_addr, info->length); - if (result) - return result; - } + if (info->failed) + /* The kernel does not use this memory block */ + continue; + + if (!info->enabled) + /* + * The kernel uses this memory block, but it may be not + * managed by us. + */ + return -EBUSY; + + result = remove_memory(info->start_addr, info->length); + if (result) + return result; list_del(&info->list); kfree(info); }