Re: [PATCH] driver core / ACPI: Avoid device removal locking problems

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Rafael,

On 08/26/2013 11:02 PM, Rafael J. Wysocki wrote:

> On Monday, August 26, 2013 04:43:26 PM Rafael J. Wysocki wrote:
>> On Monday, August 26, 2013 02:42:09 PM Rafael J. Wysocki wrote:
>>> On Monday, August 26, 2013 11:13:13 AM Gu Zheng wrote:
>>>> Hi Rafael,
> 
> [...]
> 
>>
>> OK, so the patch below is quick and dirty and overkill, but it should make the
>> splat go away at least.
> 
> And if this patch does make the splat go away for you, please also test the
> appended one (Tejun, thanks for the hint!).
> 
> I'll address the ACPI part differently later.

What about changing device_hotplug_lock and acpi_scan_lock to rwsem? like the
attached one(With a preliminary test, it also can make the splat go away).:)

Regards,
Gu

> 
[...]
> --
> 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/
> 


>From f1682ceaef4105f75f4d6a0bb8e77c8a5dde365b Mon Sep 17 00:00:00 2001
From: Gu Zheng <guz.fnst@xxxxxxxxxxxxxx>
Date: Tue, 27 Aug 2013 17:59:55 +0900
Subject: [PATCH] acpi: fix removal lock dep


Signed-off-by: Gu Zheng <guz.fnst@xxxxxxxxxxxxxx>
---
 drivers/acpi/scan.c    |   43 ++++++++++++++++++++++---------------------
 drivers/acpi/sysfs.c   |    7 +++++--
 drivers/base/core.c    |   45 ++++++++++++++++++++++++++++++++++++---------
 drivers/base/memory.c  |    5 +++--
 include/linux/device.h |    8 ++++++--
 5 files changed, 72 insertions(+), 36 deletions(-)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8a46c92..bb41760 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -36,7 +36,7 @@ bool acpi_force_hot_remove;
 static const char *dummy_hid = "device";
 
 static LIST_HEAD(acpi_bus_id_list);
-static DEFINE_MUTEX(acpi_scan_lock);
+static DECLARE_RWSEM(acpi_scan_rwsem);
 static LIST_HEAD(acpi_scan_handlers_list);
 DEFINE_MUTEX(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
@@ -49,13 +49,13 @@ struct acpi_device_bus_id{
 
 void acpi_scan_lock_acquire(void)
 {
-	mutex_lock(&acpi_scan_lock);
+	down_write(&acpi_scan_rwsem);
 }
 EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
 
 void acpi_scan_lock_release(void)
 {
-	mutex_unlock(&acpi_scan_lock);
+	up_write(&acpi_scan_rwsem);
 }
 EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
 
@@ -207,7 +207,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
 		return -EINVAL;
 	}
 
-	lock_device_hotplug();
+	device_hotplug_begin();
 
 	/*
 	 * Carry out two passes here and ignore errors in the first pass,
@@ -240,7 +240,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
 					    acpi_bus_online_companions, NULL,
 					    NULL, NULL);
 
-			unlock_device_hotplug();
+			device_hotplug_end();
 
 			put_device(&device->dev);
 			return -EBUSY;
@@ -252,7 +252,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
 
 	acpi_bus_trim(device);
 
-	unlock_device_hotplug();
+	device_hotplug_end();
 
 	/* Device node has been unregistered. */
 	put_device(&device->dev);
@@ -308,7 +308,7 @@ static void acpi_bus_device_eject(void *context)
 	struct acpi_scan_handler *handler;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
 
-	mutex_lock(&acpi_scan_lock);
+	acpi_scan_lock_acquire();
 
 	acpi_bus_get_device(handle, &device);
 	if (!device)
@@ -334,7 +334,7 @@ static void acpi_bus_device_eject(void *context)
 	}
 
  out:
-	mutex_unlock(&acpi_scan_lock);
+	acpi_scan_lock_release();
 	return;
 
  err_out:
@@ -349,8 +349,8 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
 	int error;
 
-	mutex_lock(&acpi_scan_lock);
-	lock_device_hotplug();
+	acpi_scan_lock_acquire();
+	device_hotplug_begin();
 
 	if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
 		acpi_bus_get_device(handle, &device);
@@ -376,9 +376,9 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
 		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
  out:
-	unlock_device_hotplug();
+	device_hotplug_end();
 	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
-	mutex_unlock(&acpi_scan_lock);
+	acpi_scan_lock_release();
 }
 
 static void acpi_scan_bus_check(void *context)
@@ -469,15 +469,14 @@ void acpi_bus_hot_remove_device(void *context)
 	acpi_handle handle = device->handle;
 	int error;
 
-	mutex_lock(&acpi_scan_lock);
+	acpi_scan_lock_acquire();
 
 	error = acpi_scan_hot_remove(device);
 	if (error && handle)
 		acpi_evaluate_hotplug_ost(handle, ej_event->event,
 					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
 					  NULL);
-
-	mutex_unlock(&acpi_scan_lock);
+	acpi_scan_lock_release();
 	kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
@@ -530,7 +529,8 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
 	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
 		return -ENODEV;
 
-	mutex_lock(&acpi_scan_lock);
+	if (!down_write_trylock(&acpi_scan_rwsem))
+		return -EBUSY;
 
 	if (acpi_device->flags.eject_pending) {
 		/* ACPI eject notification event. */
@@ -560,7 +560,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
 	ret = count;
 
  out:
-	mutex_unlock(&acpi_scan_lock);
+	up_write(&acpi_scan_rwsem);
 	return ret;
 
  err_out:
@@ -1858,11 +1858,12 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
 	if (!!hotplug->enabled == !!val)
 		return;
 
-	mutex_lock(&acpi_scan_lock);
+	acpi_scan_lock_acquire();
 
 	hotplug->enabled = val;
 
-	mutex_unlock(&acpi_scan_lock);
+	acpi_scan_lock_release();
+
 }
 
 static void acpi_scan_init_hotplug(acpi_handle handle, int type)
@@ -2141,7 +2142,7 @@ int __init acpi_scan_init(void)
 	acpi_memory_hotplug_init();
 	acpi_dock_init();
 
-	mutex_lock(&acpi_scan_lock);
+	acpi_scan_lock_acquire();
 	/*
 	 * Enumerate devices in the ACPI namespace.
 	 */
@@ -2164,6 +2165,6 @@ int __init acpi_scan_init(void)
 	acpi_pci_root_hp_init();
 
  out:
-	mutex_unlock(&acpi_scan_lock);
+	acpi_scan_lock_release();
 	return result;
 }
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 05306a5..6d8b54f 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -796,9 +796,12 @@ static ssize_t force_remove_store(struct kobject *kobj,
 	if (ret < 0)
 		return ret;
 
-	lock_device_hotplug();
+	if (!write_lock_device_hotplug())
+		return -EBUSY;
+
 	acpi_force_hot_remove = val;
-	unlock_device_hotplug();
+
+	write_unlock_device_hotplug();
 	return size;
 }
 
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8856d74..83c0f46 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -408,9 +408,13 @@ static ssize_t show_online(struct device *dev, struct device_attribute *attr,
 {
 	bool val;
 
-	lock_device_hotplug();
+	if (!read_lock_device_hotplug()) {
+		msleep(10);
+		return restart_syscall();
+	}
+
 	val = !dev->offline;
-	unlock_device_hotplug();
+	read_unlock_device_hotplug();
 	return sprintf(buf, "%u\n", val);
 }
 
@@ -424,9 +428,12 @@ static ssize_t store_online(struct device *dev, struct device_attribute *attr,
 	if (ret < 0)
 		return ret;
 
-	lock_device_hotplug();
+	if (!write_lock_device_hotplug()) {
+		msleep(10);
+		return restart_syscall();
+	}
 	ret = val ? device_online(dev) : device_offline(dev);
-	unlock_device_hotplug();
+	write_unlock_device_hotplug();
 	return ret < 0 ? ret : count;
 }
 
@@ -1479,16 +1486,36 @@ EXPORT_SYMBOL_GPL(put_device);
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
 
-static DEFINE_MUTEX(device_hotplug_lock);
+static DECLARE_RWSEM(device_hotplug_rwsem);
+
+bool __must_check read_lock_device_hotplug(void)
+{
+	return down_read_trylock(&device_hotplug_rwsem);
+}
+
+void read_unlock_device_hotplug(void)
+{
+	up_read(&device_hotplug_rwsem);
+}
+
+bool __must_check write_lock_device_hotplug(void)
+{
+	return down_write_trylock(&device_hotplug_rwsem);
+}
+
+void write_unlock_device_hotplug(void)
+{
+	up_write(&device_hotplug_rwsem);
+}
 
-void lock_device_hotplug(void)
+void device_hotplug_begin(void)
 {
-	mutex_lock(&device_hotplug_lock);
+	down_write(&device_hotplug_rwsem);
 }
 
-void unlock_device_hotplug(void)
+void device_hotplug_end(void)
 {
-	mutex_unlock(&device_hotplug_lock);
+	up_write(&device_hotplug_rwsem);
 }
 
 static int device_check_offline(struct device *dev, void *not_used)
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 2b7813e..71991b9 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -351,7 +351,8 @@ store_mem_state(struct device *dev,
 
 	mem = container_of(dev, struct memory_block, dev);
 
-	lock_device_hotplug();
+	if (!write_lock_device_hotplug())
+		return -EBUSY;
 
 	if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
 		offline = false;
@@ -373,7 +374,7 @@ store_mem_state(struct device *dev,
 	if (!ret)
 		dev->offline = offline;
 
-	unlock_device_hotplug();
+	write_unlock_device_hotplug();
 
 	if (ret)
 		return ret;
diff --git a/include/linux/device.h b/include/linux/device.h
index 22b546a..08581f4 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -893,8 +893,12 @@ static inline bool device_supports_offline(struct device *dev)
 	return dev->bus && dev->bus->offline && dev->bus->online;
 }
 
-extern void lock_device_hotplug(void);
-extern void unlock_device_hotplug(void);
+extern bool read_lock_device_hotplug(void);
+extern void read_unlock_device_hotplug(void);
+extern bool write_lock_device_hotplug(void);
+extern void write_unlock_device_hotplug(void);
+extern void device_hotplug_begin(void);
+extern void device_hotplug_end(void);
 extern int device_offline(struct device *dev);
 extern int device_online(struct device *dev);
 /*
-- 
1.7.1


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux