[PATCH v2 2/3] acpi,memory-hotplug: introduce a mutex lock to protect the list in acpi_memory_device

From: wency
Date: Fri Oct 19 2012 - 05:58:39 EST


From: Wen Congyang <wency@xxxxxxxxxxxxxx>

The memory device can be removed by 2 ways:
1. send eject request by SCI
2. echo 1 >/sys/bus/pci/devices/PNP0C80:XX/eject

This 2 events may happen at the same time, so we may touch
acpi_memory_device.res_list at the same time. This patch
introduce a lock to protect this list.

CC: David Rientjes <rientjes@xxxxxxxxxx>
CC: Jiang Liu <liuj97@xxxxxxxxx>
CC: Len Brown <len.brown@xxxxxxxxx>
CC: Christoph Lameter <cl@xxxxxxxxx>
Cc: Minchan Kim <minchan.kim@xxxxxxxxx>
CC: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
CC: KOSAKI Motohiro <kosaki.motohiro@xxxxxxxxxxxxxx>
CC: Yasuaki Ishimatsu <isimatu.yasuaki@xxxxxxxxxxxxxx>
Signed-off-by: Wen Congyang <wency@xxxxxxxxxxxxxx>
---
drivers/acpi/acpi_memhotplug.c | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 1e90e8f..8ff2976 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -83,7 +83,8 @@ struct acpi_memory_info {
struct acpi_memory_device {
struct acpi_device * device;
unsigned int state; /* State of the memory device */
- struct list_head res_list;
+ struct mutex lock;
+ struct list_head res_list; /* protected by lock */
};

static int acpi_hotmem_initialized;
@@ -101,19 +102,23 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
(address64.resource_type != ACPI_MEMORY_RANGE))
return AE_OK;

+ mutex_lock(&mem_device->lock);
list_for_each_entry(info, &mem_device->res_list, list) {
/* Can we combine the resource range information? */
if ((info->caching == address64.info.mem.caching) &&
(info->write_protect == address64.info.mem.write_protect) &&
(info->start_addr + info->length == address64.minimum)) {
info->length += address64.address_length;
+ mutex_unlock(&mem_device->lock);
return AE_OK;
}
}

new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
- if (!new)
+ if (!new) {
+ mutex_unlock(&mem_device->lock);
return AE_ERROR;
+ }

INIT_LIST_HEAD(&new->list);
new->caching = address64.info.mem.caching;
@@ -121,6 +126,7 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
new->start_addr = address64.minimum;
new->length = address64.address_length;
list_add_tail(&new->list, &mem_device->res_list);
+ mutex_unlock(&mem_device->lock);

return AE_OK;
}
@@ -138,9 +144,11 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
acpi_memory_get_resource, mem_device);
if (ACPI_FAILURE(status)) {
+ mutex_lock(&mem_device->lock);
list_for_each_entry_safe(info, n, &mem_device->res_list, list)
kfree(info);
INIT_LIST_HEAD(&mem_device->res_list);
+ mutex_unlock(&mem_device->lock);
return -EINVAL;
}

@@ -236,6 +244,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
* We don't have memory-hot-add rollback function,now.
* (i.e. memory-hot-remove function)
*/
+ mutex_lock(&mem_device->lock);
list_for_each_entry(info, &mem_device->res_list, list) {
if (info->enabled) { /* just sanity check...*/
num_enabled++;
@@ -256,6 +265,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
info->enabled = 1;
num_enabled++;
}
+ mutex_unlock(&mem_device->lock);
if (!num_enabled) {
printk(KERN_ERR PREFIX "add_memory failed\n");
mem_device->state = MEMORY_INVALID_STATE;
@@ -316,6 +326,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
* Ask the VM to offline this memory range.
* Note: Assume that this function returns zero on success
*/
+ mutex_lock(&mem_device->lock);
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
if (info->enabled) {
result = remove_memory(info->start_addr, info->length);
@@ -324,6 +335,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
}
kfree(info);
}
+ mutex_unlock(&mem_device->lock);

/* Power-off and eject the device */
result = acpi_memory_powerdown_device(mem_device);
@@ -438,6 +450,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
mem_device->device = device;
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
+ mutex_init(&mem_device->lock);
device->driver_data = mem_device;

/* Get the range from the _CRS */
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/