Эх сурвалжийг харах

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6:
  Driver core: proper prototype for drivers/base/init.c:driver_init()
  kobject: kobject_uevent() returns manageable value
  kref refcnt and false positives
Linus Torvalds 18 жил өмнө
parent
commit
28cb5ccd30

+ 2 - 2
drivers/acpi/ibm_acpi.c

@@ -352,7 +352,7 @@ static char *next_cmd(char **cmds)
 	return start;
 	return start;
 }
 }
 
 
-static int driver_init(void)
+static int ibm_acpi_driver_init(void)
 {
 {
 	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
 	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
 	printk(IBM_INFO "%s\n", IBM_URL);
 	printk(IBM_INFO "%s\n", IBM_URL);
@@ -1605,7 +1605,7 @@ static int fan_write(char *buf)
 static struct ibm_struct ibms[] = {
 static struct ibm_struct ibms[] = {
 	{
 	{
 	 .name = "driver",
 	 .name = "driver",
-	 .init = driver_init,
+	 .init = ibm_acpi_driver_init,
 	 .read = driver_read,
 	 .read = driver_read,
 	 },
 	 },
 	{
 	{

+ 2 - 0
include/linux/device.h

@@ -433,6 +433,8 @@ static inline int device_is_registered(struct device *dev)
 	return dev->is_registered;
 	return dev->is_registered;
 }
 }
 
 
+void driver_init(void);
+
 /*
 /*
  * High level routines for use by the bus drivers
  * High level routines for use by the bus drivers
  */
  */

+ 6 - 5
include/linux/kobject.h

@@ -265,8 +265,8 @@ extern int __must_check subsys_create_file(struct subsystem * ,
 					struct subsys_attribute *);
 					struct subsys_attribute *);
 
 
 #if defined(CONFIG_HOTPLUG)
 #if defined(CONFIG_HOTPLUG)
-void kobject_uevent(struct kobject *kobj, enum kobject_action action);
-void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
+int kobject_uevent(struct kobject *kobj, enum kobject_action action);
+int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			char *envp[]);
 			char *envp[]);
 
 
 int add_uevent_var(char **envp, int num_envp, int *cur_index,
 int add_uevent_var(char **envp, int num_envp, int *cur_index,
@@ -274,11 +274,12 @@ int add_uevent_var(char **envp, int num_envp, int *cur_index,
 			const char *format, ...)
 			const char *format, ...)
 	__attribute__((format (printf, 7, 8)));
 	__attribute__((format (printf, 7, 8)));
 #else
 #else
-static inline void kobject_uevent(struct kobject *kobj, enum kobject_action action) { }
-static inline void kobject_uevent_env(struct kobject *kobj,
+static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
+{ return 0; }
+static inline int kobject_uevent_env(struct kobject *kobj,
 				      enum kobject_action action,
 				      enum kobject_action action,
 				      char *envp[])
 				      char *envp[])
-{ }
+{ return 0; }
 
 
 static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
 static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
 				      char *buffer, int buffer_size, int *cur_len, 
 				      char *buffer, int buffer_size, int *cur_len, 

+ 1 - 1
init/main.c

@@ -53,6 +53,7 @@
 #include <linux/utsrelease.h>
 #include <linux/utsrelease.h>
 #include <linux/pid_namespace.h>
 #include <linux/pid_namespace.h>
 #include <linux/compile.h>
 #include <linux/compile.h>
+#include <linux/device.h>
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/bugs.h>
 #include <asm/bugs.h>
@@ -94,7 +95,6 @@ extern void pidmap_init(void);
 extern void prio_tree_init(void);
 extern void prio_tree_init(void);
 extern void radix_tree_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
 extern void free_initmem(void);
-extern void driver_init(void);
 extern void prepare_namespace(void);
 extern void prepare_namespace(void);
 #ifdef	CONFIG_ACPI
 #ifdef	CONFIG_ACPI
 extern void acpi_early_init(void);
 extern void acpi_early_init(void);

+ 30 - 14
lib/kobject_uevent.c

@@ -63,8 +63,11 @@ static char *action_to_string(enum kobject_action action)
  * @action: action that is happening (usually KOBJ_MOVE)
  * @action: action that is happening (usually KOBJ_MOVE)
  * @kobj: struct kobject that the action is happening to
  * @kobj: struct kobject that the action is happening to
  * @envp_ext: pointer to environmental data
  * @envp_ext: pointer to environmental data
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
  */
  */
-void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
+int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			char *envp_ext[])
 			char *envp_ext[])
 {
 {
 	char **envp;
 	char **envp;
@@ -79,14 +82,16 @@ void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 	u64 seq;
 	u64 seq;
 	char *seq_buff;
 	char *seq_buff;
 	int i = 0;
 	int i = 0;
-	int retval;
+	int retval = 0;
 	int j;
 	int j;
 
 
 	pr_debug("%s\n", __FUNCTION__);
 	pr_debug("%s\n", __FUNCTION__);
 
 
 	action_string = action_to_string(action);
 	action_string = action_to_string(action);
-	if (!action_string)
-		return;
+	if (!action_string) {
+		pr_debug("kobject attempted to send uevent without action_string!\n");
+		return -EINVAL;
+	}
 
 
 	/* search the kset we belong to */
 	/* search the kset we belong to */
 	top_kobj = kobj;
 	top_kobj = kobj;
@@ -95,31 +100,39 @@ void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			top_kobj = top_kobj->parent;
 			top_kobj = top_kobj->parent;
 		} while (!top_kobj->kset && top_kobj->parent);
 		} while (!top_kobj->kset && top_kobj->parent);
 	}
 	}
-	if (!top_kobj->kset)
-		return;
+	if (!top_kobj->kset) {
+		pr_debug("kobject attempted to send uevent without kset!\n");
+		return -EINVAL;
+	}
 
 
 	kset = top_kobj->kset;
 	kset = top_kobj->kset;
 	uevent_ops = kset->uevent_ops;
 	uevent_ops = kset->uevent_ops;
 
 
 	/*  skip the event, if the filter returns zero. */
 	/*  skip the event, if the filter returns zero. */
 	if (uevent_ops && uevent_ops->filter)
 	if (uevent_ops && uevent_ops->filter)
-		if (!uevent_ops->filter(kset, kobj))
-			return;
+		if (!uevent_ops->filter(kset, kobj)) {
+			pr_debug("kobject filter function caused the event to drop!\n");
+			return 0;
+		}
 
 
 	/* environment index */
 	/* environment index */
 	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
 	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
 	if (!envp)
 	if (!envp)
-		return;
+		return -ENOMEM;
 
 
 	/* environment values */
 	/* environment values */
 	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
 	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-	if (!buffer)
+	if (!buffer) {
+		retval = -ENOMEM;
 		goto exit;
 		goto exit;
+	}
 
 
 	/* complete object path */
 	/* complete object path */
 	devpath = kobject_get_path(kobj, GFP_KERNEL);
 	devpath = kobject_get_path(kobj, GFP_KERNEL);
-	if (!devpath)
+	if (!devpath) {
+		retval = -ENOENT;
 		goto exit;
 		goto exit;
+	}
 
 
 	/* originating subsystem */
 	/* originating subsystem */
 	if (uevent_ops && uevent_ops->name)
 	if (uevent_ops && uevent_ops->name)
@@ -204,7 +217,7 @@ exit:
 	kfree(devpath);
 	kfree(devpath);
 	kfree(buffer);
 	kfree(buffer);
 	kfree(envp);
 	kfree(envp);
-	return;
+	return retval;
 }
 }
 
 
 EXPORT_SYMBOL_GPL(kobject_uevent_env);
 EXPORT_SYMBOL_GPL(kobject_uevent_env);
@@ -214,10 +227,13 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env);
  *
  *
  * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
  * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
  * @kobj: struct kobject that the action is happening to
  * @kobj: struct kobject that the action is happening to
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
  */
  */
-void kobject_uevent(struct kobject *kobj, enum kobject_action action)
+int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 {
 {
-	kobject_uevent_env(kobj, action, NULL);
+	return kobject_uevent_env(kobj, action, NULL);
 }
 }
 
 
 EXPORT_SYMBOL_GPL(kobject_uevent);
 EXPORT_SYMBOL_GPL(kobject_uevent);

+ 1 - 6
lib/kref.c

@@ -52,12 +52,7 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
 	WARN_ON(release == NULL);
 	WARN_ON(release == NULL);
 	WARN_ON(release == (void (*)(struct kref *))kfree);
 	WARN_ON(release == (void (*)(struct kref *))kfree);
 
 
-	/*
-	 * if current count is one, we are the last user and can release object
-	 * right now, avoiding an atomic operation on 'refcount'
-	 */
-	if ((atomic_read(&kref->refcount) == 1) ||
-	    (atomic_dec_and_test(&kref->refcount))) {
+	if (atomic_dec_and_test(&kref->refcount)) {
 		release(kref);
 		release(kref);
 		return 1;
 		return 1;
 	}
 	}