]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-hotplug-race.patch
Merge branch 'master' of git://git.ipfire.org/ipfire-2.x
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.arch / acpi-dock-fix-hotplug-race.patch
1 From: Shaohua Li <shaohua.li@intel.com>
2 Subject: fix hotplug race
3 Patch-mainline: submitted 2008-08-28
4 References: fate#304731,bnc#401740
5
6 hotplug notification handler and drivers' notification handler are all
7 running in one workqueue. Before hotplug removes an acpi device, the
8 device driver's notification handler is already be recorded to run just
9 after global notification handler. After hotplug notification handler
10 runs, acpica will notice a NULL notification handler and crash. This
11 patch runs hotplug in other workqueue and wait for all acpi notication
12 handlers finish. This is found in battery hotplug, but actually all
13 hotplug can be affected.
14
15 Signed-off-by: Zhang Rui <rui.zhang@intel.com>
16 Signed-off-by: Shaohua Li <shaohua.li@intel.com>
17 Signed-off-by: Holger Macht <hmacht@suse.de>
18 ---
19
20 ---
21 drivers/acpi/dock.c | 25 ++++++++++++++++++++++++-
22 drivers/acpi/osl.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
23 include/acpi/acpiosxf.h | 3 +++
24 3 files changed, 68 insertions(+), 6 deletions(-)
25
26 --- a/drivers/acpi/dock.c
27 +++ b/drivers/acpi/dock.c
28 @@ -748,6 +748,20 @@ static void dock_notify(acpi_handle hand
29 }
30 }
31
32 +struct dock_data {
33 + acpi_handle handle;
34 + unsigned long event;
35 + struct dock_station *ds;
36 +};
37 +
38 +static void acpi_dock_deferred_cb(void *context)
39 +{
40 + struct dock_data *data = (struct dock_data *)context;
41 +
42 + dock_notify(data->handle, data->event, data->ds);
43 + kfree(data);
44 +}
45 +
46 static int acpi_dock_notifier_call(struct notifier_block *this,
47 unsigned long event, void *data)
48 {
49 @@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struc
50 return 0;
51 list_for_each_entry(dock_station, &dock_stations, sibiling) {
52 if (dock_station->handle == handle) {
53 - dock_notify(handle, event, dock_station);
54 + struct dock_data *dock_data;
55 +
56 + dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
57 + if (!dock_data)
58 + return 0;
59 + dock_data->handle = handle;
60 + dock_data->event = event;
61 + dock_data->ds = dock_station;
62 + acpi_os_hotplug_execute(acpi_dock_deferred_cb,
63 + dock_data);
64 return 0 ;
65 }
66 }
67 --- a/drivers/acpi/osl.c
68 +++ b/drivers/acpi/osl.c
69 @@ -705,6 +705,22 @@ static void acpi_os_execute_deferred(str
70 return;
71 }
72
73 +static void acpi_os_execute_hp_deferred(struct work_struct *work)
74 +{
75 + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
76 + if (!dpc) {
77 + printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
78 + return;
79 + }
80 +
81 + acpi_os_wait_events_complete(NULL);
82 +
83 + dpc->function(dpc->context);
84 + kfree(dpc);
85 +
86 + return;
87 +}
88 +
89 /*******************************************************************************
90 *
91 * FUNCTION: acpi_os_execute
92 @@ -720,12 +736,13 @@ static void acpi_os_execute_deferred(str
93 *
94 ******************************************************************************/
95
96 -acpi_status acpi_os_execute(acpi_execute_type type,
97 - acpi_osd_exec_callback function, void *context)
98 +static acpi_status __acpi_os_execute(acpi_execute_type type,
99 + acpi_osd_exec_callback function, void *context, int hp)
100 {
101 acpi_status status = AE_OK;
102 struct acpi_os_dpc *dpc;
103 struct workqueue_struct *queue;
104 + int ret;
105 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
106 "Scheduling function [%p(%p)] for deferred execution.\n",
107 function, context));
108 @@ -749,9 +766,17 @@ acpi_status acpi_os_execute(acpi_execute
109 dpc->function = function;
110 dpc->context = context;
111
112 - INIT_WORK(&dpc->work, acpi_os_execute_deferred);
113 - queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
114 - if (!queue_work(queue, &dpc->work)) {
115 + if (!hp) {
116 + INIT_WORK(&dpc->work, acpi_os_execute_deferred);
117 + queue = (type == OSL_NOTIFY_HANDLER) ?
118 + kacpi_notify_wq : kacpid_wq;
119 + ret = queue_work(queue, &dpc->work);
120 + } else {
121 + INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
122 + ret = schedule_work(&dpc->work);
123 + }
124 +
125 + if (!ret) {
126 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
127 "Call to queue_work() failed.\n"));
128 status = AE_ERROR;
129 @@ -760,8 +785,19 @@ acpi_status acpi_os_execute(acpi_execute
130 return_ACPI_STATUS(status);
131 }
132
133 +acpi_status acpi_os_execute(acpi_execute_type type,
134 + acpi_osd_exec_callback function, void *context)
135 +{
136 + return __acpi_os_execute(type, function, context, 0);
137 +}
138 EXPORT_SYMBOL(acpi_os_execute);
139
140 +acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
141 + void *context)
142 +{
143 + return __acpi_os_execute(0, function, context, 1);
144 +}
145 +
146 void acpi_os_wait_events_complete(void *context)
147 {
148 flush_workqueue(kacpid_wq);
149 --- a/include/acpi/acpiosxf.h
150 +++ b/include/acpi/acpiosxf.h
151 @@ -193,6 +193,9 @@ acpi_status
152 acpi_os_execute(acpi_execute_type type,
153 acpi_osd_exec_callback function, void *context);
154
155 +acpi_status
156 +acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
157 +
158 void acpi_os_wait_events_complete(void *context);
159
160 void acpi_os_sleep(acpi_integer milliseconds);