aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/CodingStyle20
-rw-r--r--Documentation/HOWTO3
-rw-r--r--Documentation/driver-model/devres.txt2
-rw-r--r--Documentation/feature-removal-schedule.txt4
-rw-r--r--drivers/base/core.c168
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/power.h5
-rw-r--r--drivers/base/power/runtime.c85
-rw-r--r--drivers/base/power/sysfs.c66
-rw-r--r--drivers/pcmcia/ds.c40
-rw-r--r--drivers/usb/core/driver.c7
-rw-r--r--fs/debugfs/inode.c5
-rw-r--r--fs/sysfs/dir.c25
-rw-r--r--fs/sysfs/file.c9
-rw-r--r--fs/sysfs/inode.c2
-rw-r--r--fs/sysfs/mount.c10
-rw-r--r--fs/sysfs/symlink.c12
-rw-r--r--fs/sysfs/sysfs.h1
-rw-r--r--include/linux/device.h10
-rw-r--r--include/linux/kobject.h25
-rw-r--r--include/linux/pm.h11
-rw-r--r--kernel/power/Kconfig12
-rw-r--r--lib/kobject_uevent.c30
23 files changed, 253 insertions, 301 deletions
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index a667eb1fc26..7f1730f1a1a 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -633,12 +633,27 @@ covers RTL which is used frequently with assembly language in the kernel.
Kernel developers like to be seen as literate. Do mind the spelling
of kernel messages to make a good impression. Do not use crippled
-words like "dont" and use "do not" or "don't" instead.
+words like "dont"; use "do not" or "don't" instead. Make the messages
+concise, clear, and unambiguous.
Kernel messages do not have to be terminated with a period.
Printing numbers in parentheses (%d) adds no value and should be avoided.
+There are a number of driver model diagnostic macros in <linux/device.h>
+which you should use to make sure messages are matched to the right device
+and driver, and are tagged with the right level: dev_err(), dev_warn(),
+dev_info(), and so forth. For messages that aren't associated with a
+particular device, <linux/kernel.h> defines pr_debug() and pr_info().
+
+Coming up with good debugging messages can be quite a challenge; and once
+you have them, they can be a huge help for remote troubleshooting. Such
+messages should be compiled out when the DEBUG symbol is not defined (that
+is, by default they are not included). When you use dev_dbg() or pr_debug(),
+that's automatic. Many subsystems have Kconfig options to turn on -DDEBUG.
+A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the
+ones already enabled by DEBUG.
+
Chapter 14: Allocating memory
@@ -790,4 +805,5 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--
-Last updated on 2006-December-06.
+Last updated on 2007-July-13.
+
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 98e2701c746..f8cc3f8ed15 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -249,6 +249,9 @@ process is as follows:
release a new -rc kernel every week.
- Process continues until the kernel is considered "ready", the
process should last around 6 weeks.
+ - A list of known regressions present in each -rc release is
+ tracked at the following URI:
+ http://kernelnewbies.org/known_regressions
It is worth mentioning what Andrew Morton wrote on the linux-kernel
mailing list about kernel releases:
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 6c8d8f27db3..8569072fa38 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -207,7 +207,7 @@ responsibility. This is usually non-issue because bus ops and
resource allocations already do the job.
For an example of single-instance devres type, read pcim_iomap_table()
-in lib/iomap.c.
+in lib/devres.c.
All devres interface functions can be called without context if the
right gfp mask is given.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index d245c639c22..66c8b4b165c 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -26,9 +26,7 @@ Who: Hans Verkuil <hverkuil@xs4all.nl> and
---------------------------
-What: /sys/devices/.../power/state
- dev->power.power_state
- dpm_runtime_{suspend,resume)()
+What: dev->power.power_state
When: July 2007
Why: Broken design for runtime control over driver power states, confusing
driver-internal runtime power management with: mechanisms to support
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0455aa78fa1..3599ab2506d 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -24,6 +24,8 @@
#include "base.h"
#include "power/power.h"
+extern const char *kobject_actions[];
+
int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL;
@@ -303,10 +305,25 @@ out:
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- if (memcmp(buf, "add", 3) != 0)
- dev_err(dev, "uevent: unsupported action-string; this will "
- "be ignored in a future kernel version");
+ size_t len = count;
+ enum kobject_action action;
+
+ if (len && buf[len-1] == '\n')
+ len--;
+
+ for (action = 0; action < KOBJ_MAX; action++) {
+ if (strncmp(kobject_actions[action], buf, len) != 0)
+ continue;
+ if (kobject_actions[action][len] != '\0')
+ continue;
+ kobject_uevent(&dev->kobj, action);
+ goto out;
+ }
+
+ dev_err(dev, "uevent: unsupported action-string; this will "
+ "be ignored in a future kernel version\n");
kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
return count;
}
@@ -643,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
return 0;
}
+static int device_add_class_symlinks(struct device *dev)
+{
+ int error;
+
+ if (!dev->class)
+ return 0;
+ error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
+ "subsystem");
+ if (error)
+ goto out;
+ /*
+ * If this is not a "fake" compatible device, then create the
+ * symlink from the class to the device.
+ */
+ if (dev->kobj.parent != &dev->class->subsys.kobj) {
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error)
+ goto out_subsys;
+ }
+ /* only bus-device parents get a "device"-link */
+ if (dev->parent && dev->parent->bus) {
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
+#ifdef CONFIG_SYSFS_DEPRECATED
+ {
+ char * class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
+ kfree(class_name);
+ if (error)
+ goto out_device;
+ }
+#endif
+ }
+ return 0;
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+out_device:
+ if (dev->parent)
+ sysfs_remove_link(&dev->kobj, "device");
+#endif
+out_busid:
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+out_subsys:
+ sysfs_remove_link(&dev->kobj, "subsystem");
+out:
+ return error;
+}
+
+static void device_remove_class_symlinks(struct device *dev)
+{
+ if (!dev->class)
+ return;
+ if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+ char *class_name;
+
+ class_name = make_class_name(dev->class->name, &dev->kobj);
+ if (class_name) {
+ sysfs_remove_link(&dev->parent->kobj, class_name);
+ kfree(class_name);
+ }
+#endif
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+ sysfs_remove_link(&dev->kobj, "subsystem");
+}
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -657,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
int device_add(struct device *dev)
{
struct device *parent = NULL;
- char *class_name = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
@@ -697,27 +789,9 @@ int device_add(struct device *dev)
goto ueventattrError;
}
- if (dev->class) {
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
- "subsystem");
- /* If this is not a "fake" compatible device, then create the
- * symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kobj)
- sysfs_create_link(&dev->class->subsys.kobj,
- &dev->kobj, dev->bus_id);
- if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj,
- "device");
-#ifdef CONFIG_SYSFS_DEPRECATED
- class_name = make_class_name(dev->class->name,
- &dev->kobj);
- if (class_name)
- sysfs_create_link(&dev->parent->kobj,
- &dev->kobj, class_name);
-#endif
- }
- }
-
+ error = device_add_class_symlinks(dev);
+ if (error)
+ goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
@@ -744,7 +818,6 @@ int device_add(struct device *dev)
up(&dev->class->sem);
}
Done:
- kfree(class_name);
put_device(dev);
return error;
BusError:
@@ -755,6 +828,8 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
+ device_remove_class_symlinks(dev);
+ SymlinkError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
@@ -1139,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
{
char *old_class_name = NULL;
char *new_class_name = NULL;
- char *old_symlink_name = NULL;
+ char *old_device_name = NULL;
int error;
dev = get_device(dev);
@@ -1153,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif
- if (dev->class) {
- old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
- if (!old_symlink_name) {
- error = -ENOMEM;
- goto out_free_old_class;
- }
- strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+ old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ if (!old_device_name) {
+ error = -ENOMEM;
+ goto out;
}
-
+ strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name);
+ if (error) {
+ strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+ goto out;
+ }
#ifdef CONFIG_SYSFS_DEPRECATED
if (old_class_name) {
new_class_name = make_class_name(dev->class->name, &dev->kobj);
if (new_class_name) {
- sysfs_create_link(&dev->parent->kobj, &dev->kobj,
- new_class_name);
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, new_class_name);
+ if (error)
+ goto out;
sysfs_remove_link(&dev->parent->kobj, old_class_name);
}
}
#endif
if (dev->class) {
- sysfs_remove_link(&dev->class->subsys.kobj,
- old_symlink_name);
- sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
- dev->bus_id);
+ sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error) {
+ /* Uh... how to unravel this if restoring can fail? */
+ dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
+ __FUNCTION__, error);
+ }
}
+out:
put_device(dev);
kfree(new_class_name);
- kfree(old_symlink_name);
- out_free_old_class:
kfree(old_class_name);
+ kfree(old_device_name);
return error;
}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 91f230939c1..fff17800720 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
obj-y := shutdown.o
-obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM) += main.o suspend.o resume.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 2760f25b3ac..591a0dd5dee 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -62,11 +62,6 @@ extern int resume_device(struct device *);
*/
extern int suspend_device(struct device *, pm_message_t);
-
-/*
- * runtime.c
- */
-
#else /* CONFIG_PM */
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644
index df6174d8586..00000000000
--- a/drivers/base/power/runtime.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * drivers/base/power/runtime.c - Handling dynamic device power management.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- *
- */
-
-#include <linux/device.h>
-#include "power.h"
-
-
-static void runtime_resume(struct device * dev)
-{
- dev_dbg(dev, "resuming\n");
- if (!dev->power.power_state.event)
- return;
- if (!resume_device(dev))
- dev->power.power_state = PMSG_ON;
-}
-
-
-/**
- * dpm_runtime_resume - Power one device back on.
- * @dev: Device.
- *
- * Bring one device back to the on state by first powering it
- * on, then restoring state. We only operate on devices that aren't
- * already on.
- * FIXME: We need to handle devices that are in an unknown state.
- */
-
-void dpm_runtime_resume(struct device * dev)
-{
- mutex_lock(&dpm_mtx);
- runtime_resume(dev);
- mutex_unlock(&dpm_mtx);
-}
-EXPORT_SYMBOL(dpm_runtime_resume);
-
-
-/**
- * dpm_runtime_suspend - Put one device in low-power state.
- * @dev: Device.
- * @state: State to enter.
- */
-
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- mutex_lock(&dpm_mtx);
- if (dev->power.power_state.event == state.event)
- goto Done;
-
- if (dev->power.power_state.event)
- runtime_resume(dev);
-
- if (!(error = suspend_device(dev, state)))
- dev->power.power_state = state;
- Done:
- mutex_unlock(&dpm_mtx);
- return error;
-}
-EXPORT_SYMBOL(dpm_runtime_suspend);
-
-
-#if 0
-/**
- * dpm_set_power_state - Update power_state field.
- * @dev: Device.
- * @state: Power state device is in.
- *
- * This is an update mechanism for drivers to notify the core
- * what power state a device is in. Device probing code may not
- * always be able to tell, but we need accurate information to
- * work reliably.
- */
-void dpm_set_power_state(struct device * dev, pm_message_t state)
-{
- mutex_lock(&dpm_mtx);
- dev->power.power_state = state;
- mutex_unlock(&dpm_mtx);
-}
-#endif /* 0 */
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 2d47517dbe3..f2ed179cd69 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,69 +7,6 @@
#include "power.h"
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
-
-/**
- * state - Control current power state of device
- *
- * show() returns the current power state of the device. '0' indicates
- * the device is on. Other values (2) indicate the device is in some low
- * power state.
- *
- * store() sets the current power state, which is an integer valued
- * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
- * methods fail this operation; those methods couldn't be called.
- * Otherwise,
- *
- * - If the recorded dev->power.power_state.event matches the
- * target value, nothing is done.
- * - If the recorded event code is nonzero, the device is reactivated
- * by calling bus.resume() and/or class.resume().
- * - If the target value is nonzero, the device is suspended by
- * calling class.suspend() and/or bus.suspend() with event code
- * PM_EVENT_SUSPEND.
- *
- * This mechanism is DEPRECATED and should only be used for testing.
- */
-
-static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
-{
- if (dev->power.power_state.event)
- return sprintf(buf, "2\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
-{
- pm_message_t state;
- int error = -EINVAL;
-
- /* disallow incomplete suspend sequences */
- if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
- return error;
-
- state.event = PM_EVENT_SUSPEND;
- /* Older apps expected to write "3" here - confused with PCI D3 */
- if ((n == 1) && !strcmp(buf, "3"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "2"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "0")) {
- dpm_runtime_resume(dev);
- error = 0;
- }
-
- return error ? error : n;
-}
-
-static DEVICE_ATTR(state, 0644, state_show, state_store);
-
-
-#endif /* CONFIG_PM_SYSFS_DEPRECATED */
-
/*
* wakeup - Report/change current wakeup option for device
*
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
- &dev_attr_state.attr,
-#endif
&dev_attr_wakeup.attr,
NULL,
};
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 143c6efc478..a99607142fc 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1127,6 +1127,34 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
#endif
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_SUSPEND;
+ return rc;
+}
+
+static void runtime_resume(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_resume(dev);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_ON;
+}
+
/************************ per-device sysfs output ***************************/
#define pcmcia_device_attr(field, test, format) \
@@ -1173,9 +1201,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
return -EINVAL;
if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
- ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ ret = runtime_suspend(dev);
else if (p_dev->suspended && !strncmp(buf, "on", 2))
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return ret ? ret : count;
}
@@ -1312,10 +1340,10 @@ static int pcmcia_bus_suspend_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || p_dev->suspended)
return 0;
- return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ return runtime_suspend(dev);
}
static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
@@ -1323,10 +1351,10 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || !p_dev->suspended)
return 0;
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return 0;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 73c49362cd4..654857493a8 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -29,13 +29,6 @@
#include "hcd.h"
#include "usb.h"
-#define VERBOSE_DEBUG 0
-
-#if VERBOSE_DEBUG
-#define dev_vdbg dev_dbg
-#else
-#define dev_vdbg(dev, fmt, args...) do { } while (0)
-#endif
#ifdef CONFIG_HOTPLUG
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 1d533a2ec3a..11be8a325e2 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -345,11 +345,6 @@ void debugfs_remove(struct dentry *dentry)
switch (dentry->d_inode->i_mode & S_IFMT) {
case S_IFDIR:
ret = simple_rmdir(parent->d_inode, dentry);
- if (ret)
- printk(KERN_ERR
- "DebugFS rmdir on %s failed : "
- "directory not empty.\n",
- dentry->d_name.name);
break;
case S_IFLNK:
kfree(dentry->d_inode->i_private);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index aee966c44aa..048e6054c2f 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -361,20 +361,20 @@ static struct dentry_operations sysfs_dentry_ops = {
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
char *dup_name = NULL;
- struct sysfs_dirent *sd = NULL;
+ struct sysfs_dirent *sd;
if (type & SYSFS_COPY_NAME) {
name = dup_name = kstrdup(name, GFP_KERNEL);
if (!name)
- goto err_out;
+ return NULL;
}
sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
if (!sd)
- goto err_out;
+ goto err_out1;
if (sysfs_alloc_ino(&sd->s_ino))
- goto err_out;
+ goto err_out2;
atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_active, 0);
@@ -386,9 +386,10 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
return sd;
- err_out:
- kfree(dup_name);
+ err_out2:
kmem_cache_free(sysfs_dir_cachep, sd);
+ err_out1:
+ kfree(dup_name);
return NULL;
}
@@ -698,17 +699,19 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
/* link in */
sysfs_addrm_start(&acxt, parent_sd);
+
if (!sysfs_find_dirent(parent_sd, name)) {
sysfs_add_one(&acxt, sd);
sysfs_link_sibling(sd);
}
- if (sysfs_addrm_finish(&acxt)) {
- *p_sd = sd;
- return 0;
+
+ if (!sysfs_addrm_finish(&acxt)) {
+ sysfs_put(sd);
+ return -EEXIST;
}
- sysfs_put(sd);
- return -EEXIST;
+ *p_sd = sd;
+ return 0;
}
int sysfs_create_subdir(struct kobject *kobj, const char *name,
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index cc497994b2a..3e1cc062a74 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -410,11 +410,12 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
sysfs_link_sibling(sd);
}
- if (sysfs_addrm_finish(&acxt))
- return 0;
+ if (!sysfs_addrm_finish(&acxt)) {
+ sysfs_put(sd);
+ return -EEXIST;
+ }
- sysfs_put(sd);
- return -EEXIST;
+ return 0;
}
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 3756e152285..10d1b52899f 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -133,7 +133,7 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
*/
static struct lock_class_key sysfs_inode_imutex_key;
-void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
+static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
inode->i_blocks = 0;
inode->i_mapping->a_ops = &sysfs_aops;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 402cc356203..60714d075c2 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -43,19 +43,19 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_time_gran = 1;
sysfs_sb = sb;
- inode = new_inode(sysfs_sb);
+ /* get root inode, initialize and unlock it */
+ inode = sysfs_get_inode(&sysfs_root);
if (!inode) {
pr_debug("sysfs: could not get root inode\n");
return -ENOMEM;
}
- sysfs_init_inode(&sysfs_root, inode);
-
inode->i_op = &sysfs_dir_inode_operations;
inode->i_fop = &sysfs_dir_operations;
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
+ inc_nlink(inode); /* directory, account for "." */
+ unlock_new_inode(inode);
+ /* instantiate and link root dentry */
root = d_alloc_root(inode);
if (!root) {
pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 2f86e042229..4ce687f0b5d 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -86,7 +86,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
if (!sd)
goto out_put;
+
sd->s_elem.symlink.target_sd = target_sd;
+ target_sd = NULL; /* reference is now owned by the symlink */
sysfs_addrm_start(&acxt, parent_sd);
@@ -95,11 +97,13 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
sysfs_link_sibling(sd);
}
- if (sysfs_addrm_finish(&acxt))
- return 0;
+ if (!sysfs_addrm_finish(&acxt)) {
+ error = -EEXIST;
+ goto out_put;
+ }
+
+ return 0;
- error = -EEXIST;
- /* fall through */
out_put:
sysfs_put(target_sd);
sysfs_put(sd);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 6a37f2386a8..6b8c8d76d30 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -71,7 +71,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
extern void sysfs_delete_inode(struct inode *inode);
-extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode);
extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
diff --git a/include/linux/device.h b/include/linux/device.h
index be2debed70d..d9f0a57f5a2 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -572,6 +572,16 @@ dev_dbg(struct device * dev, const char * fmt, ...)
}
#endif
+#ifdef VERBOSE_DEBUG
+#define dev_vdbg dev_dbg
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+dev_vdbg(struct device * dev, const char * fmt, ...)
+{
+ return 0;
+}
+#endif
+
#define dev_err(dev, format, arg...) \
dev_printk(KERN_ERR , dev , format , ## arg)
#define dev_info(dev, format, arg...) \
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 06cbf41d32d..aa2fe22b1ba 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -36,15 +36,24 @@ extern char uevent_helper[];
/* counter to tag the uevent, read only except for the kobject core */
extern u64 uevent_seqnum;
-/* the actions here must match the proper string in lib/kobject_uevent.c */
-typedef int __bitwise kobject_action_t;
+/*
+ * The actions here must match the index to the string array
+ * in lib/kobject_uevent.c
+ *
+ * Do not add new actions here without checking with the driver-core
+ * maintainers. Action strings are not meant to express subsystem
+ * or device specific properties. In most cases you want to send a
+ * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
+ * specific variables added to the event environment.
+ */
enum kobject_action {
- KOBJ_ADD = (__force kobject_action_t) 0x01, /* exclusive to core */
- KOBJ_REMOVE = (__force kobject_action_t) 0x02, /* exclusive to core */
- KOBJ_CHANGE = (__force kobject_action_t) 0x03, /* device state change */
- KOBJ_OFFLINE = (__force kobject_action_t) 0x04, /* device offline */
- KOBJ_ONLINE = (__force kobject_action_t) 0x05, /* device online */
- KOBJ_MOVE = (__force kobject_action_t) 0x06, /* device move */
+ KOBJ_ADD,
+ KOBJ_REMOVE,
+ KOBJ_CHANGE,
+ KOBJ_MOVE,
+ KOBJ_ONLINE,
+ KOBJ_OFFLINE,
+ KOBJ_MAX
};
struct kobject {
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 273781c82e4..2735b7cadd2 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -284,8 +284,6 @@ extern int device_prepare_suspend(pm_message_t state);
#define device_may_wakeup(dev) \
(device_can_wakeup(dev) && (dev)->power.should_wakeup)
-extern int dpm_runtime_suspend(struct device *, pm_message_t);
-extern void dpm_runtime_resume(struct device *);
extern void __suspend_report_result(const char *function, void *fn, int ret);
#define suspend_report_result(fn, ret) \
@@ -317,15 +315,6 @@ static inline int device_suspend(pm_message_t state)
#define device_set_wakeup_enable(dev,val) do{}while(0)
#define device_may_wakeup(dev) (0)
-static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
- return 0;
-}
-
-static inline void dpm_runtime_resume(struct device * dev)
-{
-}
-
#define suspend_report_result(fn, ret) do { } while (0)
static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 495b7d4dd33..73328476761 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -65,18 +65,6 @@ config PM_TRACE
CAUTION: this option will cause your machine's real-time clock to be
set to an invalid time after a resume.
-config PM_SYSFS_DEPRECATED
- bool "Driver model /sys/devices/.../power/state files (DEPRECATED)"
- depends on PM && SYSFS
- default n
- help
- The driver model started out with a sysfs file intended to provide
- a userspace hook for device power management. This feature has never
- worked very well, except for limited testing purposes, and so it will
- be removed. It's not clear that a generic mechanism could really
- handle the wide variability of device power states; any replacements
- are likely to be bus or driver specific.
-
config SOFTWARE_SUSPEND
bool "Software Suspend (Hibernation)"
depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index bd5ecbbafab..6a80c784a8f 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -33,25 +33,15 @@ static DEFINE_SPINLOCK(sequence_lock);
static struct sock *uevent_sock;
#endif
-static char *action_to_string(enum kobject_action action)
-{
- switch (action) {
- case KOBJ_ADD:
- return "add";
- case KOBJ_REMOVE:
- return "remove";
- case KOBJ_CHANGE:
- return "change";
- case KOBJ_OFFLINE:
- return "offline";
- case KOBJ_ONLINE:
- return "online";
- case KOBJ_MOVE:
- return "move";
- default:
- return NULL;
- }
-}
+/* the strings here must match the enum in include/linux/kobject.h */
+const char *kobject_actions[] = {
+ "add",
+ "remove",
+ "change",
+ "move",
+ "online",
+ "offline",
+};
/**
* kobject_uevent_env - send an uevent with environmental data
@@ -83,7 +73,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
pr_debug("%s\n", __FUNCTION__);
- action_string = action_to_string(action);
+ action_string = kobject_actions[action];
if (!action_string) {
pr_debug("kobject attempted to send uevent without action_string!\n");
return -EINVAL;