Bug Fix: 2.6.6 ACPI modules couldn't unload properly

From: Sau Dan Lee
Date: Wed May 12 2004 - 07:13:50 EST



Dan> I've enabled ACPI and boot with "acpi=force". I loaded the
Dan> ACPI modules "processor", "ac", "battery" and "button". When
Dan> I unload any of these modules, I get an oops. Unloading of
Dan> these modules didn't occur in 2.6.5 and 2.6.2.

The bug is due to the removal of procfs entries that are non-empty
directories. This leads to a failed assertion in the procfs code,
which dumps an oops message. (Would this leak to kernel memory leak?)
(Why this doesn't happen in 2.6.5 and 2.6.2 is still mysterious to
me.)

The fix is to remove all entries created by the corresponding ACPI
modules before removing a directory in /proc.

Here is the patch, against kernel 2.6.6:


--- linux-2.6.6/drivers/acpi/ac.c 2004/05/12 09:51:05 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/ac.c 2004/05/12 09:53:33 1.2
@@ -178,20 +178,23 @@
}


static int
acpi_ac_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_ac_remove_fs");

if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_AC_FILE_STATE,
+ acpi_device_dir(device));
+
remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
acpi_device_dir(device) = NULL;
}

return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Model
--- linux-2.6.6/drivers/acpi/battery.c 2004/05/12 09:55:49 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/battery.c 2004/05/12 09:58:08 1.2
@@ -672,20 +672,27 @@
}


static int
acpi_battery_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_battery_remove_fs");

if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BATTERY_FILE_INFO,
+ acpi_device_dir(device));
+
remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
acpi_device_dir(device) = NULL;
}

return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Interface
--- linux-2.6.6/drivers/acpi/button.c 2004/05/12 08:02:46 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/button.c 2004/05/12 09:47:30 1.2
@@ -234,20 +234,30 @@
static int
acpi_button_remove_fs (
struct acpi_device *device)
{
struct acpi_button *button = NULL;

ACPI_FUNCTION_TRACE("acpi_button_remove_fs");

button = acpi_driver_data(device);
if (acpi_device_dir(device)) {
+ if (button->type == ACPI_BUTTON_TYPE_LID)
+ remove_proc_entry(ACPI_BUTTON_FILE_STATE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BUTTON_FILE_INFO,
+ acpi_device_dir(device));
+
+ remove_proc_entry(acpi_device_bid(device),
+ acpi_device_dir(device)->parent);
+
+
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP,
acpi_button_dir);
--- linux-2.6.6/drivers/acpi/ec.c 2004/05/12 10:07:39 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/ec.c 2004/05/12 10:08:36 1.2
@@ -541,20 +541,26 @@
return_VALUE(0);
}


static int
acpi_ec_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_ec_remove_fs");

+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */

static int
acpi_ec_add (
--- linux-2.6.6/drivers/acpi/fan.c 2004/05/12 10:09:09 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/fan.c 2004/05/12 10:09:54 1.2
@@ -178,20 +178,22 @@
}


static int
acpi_fan_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_fan_remove_fs");

if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_FAN_FILE_STATE,
+ acpi_device_dir(device));
remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
acpi_device_dir(device) = NULL;
}

return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Interface
--- linux-2.6.6/drivers/acpi/power.c 2004/05/12 10:10:15 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/power.c 2004/05/12 10:10:59 1.2
@@ -475,20 +475,22 @@
}


static int
acpi_power_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_power_remove_fs");

if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_POWER_FILE_STATUS,
+ acpi_device_dir(device));
remove_proc_entry(acpi_device_bid(device), acpi_power_dir);
acpi_device_dir(device) = NULL;
}

return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Interface
--- linux-2.6.6/drivers/acpi/thermal.c 2004/05/12 10:13:01 1.1
+++ linux-2.6.6-acpi-procfs-patch/drivers/acpi/thermal.c 2004/05/12 10:13:36 1.2
@@ -1132,20 +1132,30 @@
}


static int
acpi_thermal_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");

if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_STATE,
+ acpi_device_dir(device));
remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
acpi_device_dir(device) = NULL;
}

return_VALUE(0);
}


/* --------------------------------------------------------------------------
Driver Interface




--
Sau Dan LEE ???(Big5) ~{@nJX6X~}(HZ)

E-mail: danlee@xxxxxxxxxxxxxxxxxxxxxxxxxx
Home page: http://www.informatik.uni-freiburg.de/~danlee

-
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/