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

for 13 driver core, sysfs, and debugfs fixes.
diff --git a/Documentation/kref.txt b/Documentation/kref.txt
new file mode 100644
index 0000000..42fe284
--- /dev/null
+++ b/Documentation/kref.txt
@@ -0,0 +1,216 @@
+
+krefs allow you to add reference counters to your objects.  If you
+have objects that are used in multiple places and passed around, and
+you don't have refcounts, your code is almost certainly broken.  If
+you want refcounts, krefs are the way to go.
+
+To use a kref, add one to your data structures like:
+
+struct my_data
+{
+	.
+	.
+	struct kref refcount;
+	.
+	.
+};
+
+The kref can occur anywhere within the data structure.
+
+You must initialize the kref after you allocate it.  To do this, call
+kref_init as so:
+
+     struct my_data *data;
+
+     data = kmalloc(sizeof(*data), GFP_KERNEL);
+     if (!data)
+            return -ENOMEM;
+     kref_init(&data->refcount);
+
+This sets the refcount in the kref to 1.
+
+Once you have an initialized kref, you must follow the following
+rules:
+
+1) If you make a non-temporary copy of a pointer, especially if
+   it can be passed to another thread of execution, you must
+   increment the refcount with kref_get() before passing it off:
+       kref_get(&data->refcount);
+   If you already have a valid pointer to a kref-ed structure (the
+   refcount cannot go to zero) you may do this without a lock.
+
+2) When you are done with a pointer, you must call kref_put():
+       kref_put(&data->refcount, data_release);
+   If this is the last reference to the pointer, the release
+   routine will be called.  If the code never tries to get
+   a valid pointer to a kref-ed structure without already
+   holding a valid pointer, it is safe to do this without
+   a lock.
+
+3) If the code attempts to gain a reference to a kref-ed structure
+   without already holding a valid pointer, it must serialize access
+   where a kref_put() cannot occur during the kref_get(), and the
+   structure must remain valid during the kref_get().
+
+For example, if you allocate some data and then pass it to another
+thread to process:
+
+void data_release(struct kref *ref)
+{
+	struct my_data *data = container_of(ref, struct my_data, refcount);
+	kfree(data);
+}
+
+void more_data_handling(void *cb_data)
+{
+	struct my_data *data = cb_data;
+	.
+	. do stuff with data here
+	.
+	kref_put(data, data_release);
+}
+
+int my_data_handler(void)
+{
+	int rv = 0;
+	struct my_data *data;
+	struct task_struct *task;
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	kref_init(&data->refcount);
+
+	kref_get(&data->refcount);
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+	        kref_put(&data->refcount, data_release);
+		goto out;
+	}
+
+	.
+	. do stuff with data here
+	.
+ out:
+	kref_put(&data->refcount, data_release);
+	return rv;
+}
+
+This way, it doesn't matter what order the two threads handle the
+data, the kref_put() handles knowing when the data is not referenced
+any more and releasing it.  The kref_get() does not require a lock,
+since we already have a valid pointer that we own a refcount for.  The
+put needs no lock because nothing tries to get the data without
+already holding a pointer.
+
+Note that the "before" in rule 1 is very important.  You should never
+do something like:
+
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+		goto out;
+	} else
+		/* BAD BAD BAD - get is after the handoff */
+		kref_get(&data->refcount);
+
+Don't assume you know what you are doing and use the above construct.
+First of all, you may not know what you are doing.  Second, you may
+know what you are doing (there are some situations where locking is
+involved where the above may be legal) but someone else who doesn't
+know what they are doing may change the code or copy the code.  It's
+bad style.  Don't do it.
+
+There are some situations where you can optimize the gets and puts.
+For instance, if you are done with an object and enqueuing it for
+something else or passing it off to something else, there is no reason
+to do a get then a put:
+
+	/* Silly extra get and put */
+	kref_get(&obj->ref);
+	enqueue(obj);
+	kref_put(&obj->ref, obj_cleanup);
+
+Just do the enqueue.  A comment about this is always welcome:
+
+	enqueue(obj);
+	/* We are done with obj, so we pass our refcount off
+	   to the queue.  DON'T TOUCH obj AFTER HERE! */
+
+The last rule (rule 3) is the nastiest one to handle.  Say, for
+instance, you have a list of items that are each kref-ed, and you wish
+to get the first one.  You can't just pull the first item off the list
+and kref_get() it.  That violates rule 3 because you are not already
+holding a valid pointer.  You must add locks or semaphores.  For
+instance:
+
+static DECLARE_MUTEX(sem);
+static LIST_HEAD(q);
+struct my_data
+{
+	struct kref      refcount;
+	struct list_head link;
+};
+
+static struct my_data *get_entry()
+{
+	struct my_data *entry = NULL;
+	down(&sem);
+	if (!list_empty(&q)) {
+		entry = container_of(q.next, struct my_q_entry, link);
+		kref_get(&entry->refcount);
+	}
+	up(&sem);
+	return entry;
+}
+
+static void release_entry(struct kref *ref)
+{
+	struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+	list_del(&entry->link);
+	kfree(entry);
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	kref_put(&entry->refcount, release_entry);
+	up(&sem);
+}
+
+The kref_put() return value is useful if you do not want to hold the
+lock during the whole release operation.  Say you didn't want to call
+kfree() with the lock held in the example above (since it is kind of
+pointless to do so).  You could use kref_put() as follows:
+
+static void release_entry(struct kref *ref)
+{
+	/* All work is done after the return from kref_put(). */
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	if (kref_put(&entry->refcount, release_entry)) {
+		list_del(&entry->link);
+		up(&sem);
+		kfree(entry);
+	} else
+		up(&sem);
+}
+
+This is really more useful if you have to call other routines as part
+of the free operations that could take a long time or might claim the
+same lock.  Note that doing everything in the release routine is still
+preferred as it is a little neater.
+
+
+Corey Minyard <minyard@acm.org>
+
+A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
+presentation on krefs, which can be found at:
+  http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+and:
+  http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 6bf650f..d2a2f8f 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -430,6 +430,7 @@
 		sysfs_create_link(&class_dev->kobj,
 				  &class_dev->dev->kobj, "device");
 
+	kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
  register_done:
 	if (error && parent)
 		class_put(parent);
@@ -461,6 +462,7 @@
 		sysfs_remove_link(&class_dev->kobj, "device");
 	class_device_remove_attrs(class_dev);
 
+	kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
 	kobject_del(&class_dev->kobj);
 
 	if (parent)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 4e6cce8..a7cedd8 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -260,6 +260,8 @@
 	/* notify platform of device entry */
 	if (platform_notify)
 		platform_notify(dev);
+
+	kobject_hotplug(&dev->kobj, KOBJ_ADD);
  Done:
 	put_device(dev);
 	return error;
@@ -349,6 +351,7 @@
 		platform_notify_remove(dev);
 	bus_remove_device(dev);
 	device_pm_remove(dev);
+	kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
 	if (parent)
 		put_device(parent);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 26c9464..97fe13f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -102,6 +102,9 @@
 	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
 			"FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
+	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			"TIMEOUT=%i", loading_timeout))
+		return -ENOMEM;
 
 	envp[i] = NULL;
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 996cbb4..cd64539 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -341,6 +341,7 @@
 
 EXPORT_SYMBOL_GPL(platform_bus);
 EXPORT_SYMBOL_GPL(platform_bus_type);
+EXPORT_SYMBOL_GPL(platform_add_devices);
 EXPORT_SYMBOL_GPL(platform_device_register);
 EXPORT_SYMBOL_GPL(platform_device_register_simple);
 EXPORT_SYMBOL_GPL(platform_device_unregister);
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 4b12be8..376f8a0 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -4396,6 +4396,7 @@
         device_initialize(&fake_device);
         kobject_set_name(&fake_device.kobj, "etrax_usb");
         kobject_add(&fake_device.kobj);
+        kobject_hotplug(&fake_device.kobj, KOBJ_ADD);
         hc->bus->controller = &fake_device;
 	usb_register_bus(hc->bus);
 
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 31cff78..2cab98a 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -337,6 +337,7 @@
 	if ((err = kobject_add(&disk->kobj)))
 		return;
 	disk_sysfs_symlinks(disk);
+	kobject_hotplug(&disk->kobj, KOBJ_ADD);
 
 	/* No minors to use for partitions */
 	if (disk->minors == 1) {
@@ -441,5 +442,6 @@
 		sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
 		put_device(disk->driverfs_dev);
 	}
+	kobject_hotplug(&disk->kobj, KOBJ_REMOVE);
 	kobject_del(&disk->kobj);
 }
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 352f966..da25aeb 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -428,6 +428,41 @@
 
 
 /**
+ * sysfs_chmod_file - update the modified mode value on an object attribute.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @mode: file permissions.
+ *
+ */
+int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+{
+	struct dentry *dir = kobj->dentry;
+	struct dentry *victim;
+	struct sysfs_dirent *sd;
+	umode_t umode = (mode & S_IALLUGO) | S_IFREG;
+	int res = -ENOENT;
+
+	down(&dir->d_inode->i_sem);
+	victim = sysfs_get_dentry(dir, attr->name);
+	if (!IS_ERR(victim)) {
+		if (victim->d_inode &&
+		    (victim->d_parent->d_inode == dir->d_inode)) {
+			sd = victim->d_fsdata;
+			attr->mode = mode;
+			sd->s_mode = umode;
+			victim->d_inode->i_mode = umode;
+			dput(victim);
+			res = 0;
+		}
+	}
+	up(&dir->d_inode->i_sem);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(sysfs_chmod_file);
+
+
+/**
  *	sysfs_remove_file - remove an object attribute.
  *	@kobj:	object we're acting for.
  *	@attr:	attribute descriptor.
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index f7a7b86..a5fa6a6 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -17,6 +17,10 @@
 
 #include <linux/fs.h>
 
+#include <linux/types.h>
+
+struct file_operations;
+
 #if defined(CONFIG_DEBUG_FS)
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
 				   struct dentry *parent, void *data,
@@ -36,6 +40,9 @@
 				  struct dentry *parent, u32 *value);
 
 #else
+
+#include <linux/err.h>
+
 /* 
  * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled
  * so users have a chance to detect if there was a real error or not.  We don't
@@ -68,21 +75,21 @@
 
 static inline struct dentry *debugfs_create_u16(const char *name, mode_t mode,
 						struct dentry *parent,
-						u8 *value)
+						u16 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 						struct dentry *parent,
-						u8 *value)
+						u32 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 						 struct dentry *parent,
-						 u8 *value)
+						 u32 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 6f502ff..38b58b3 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -99,6 +99,9 @@
 extern int
 sysfs_update_file(struct kobject *, const struct attribute *);
 
+extern int
+sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
+
 extern void
 sysfs_remove_file(struct kobject *, const struct attribute *);
 
@@ -140,6 +143,10 @@
 {
 	return 0;
 }
+static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+{
+	return 0;
+}
 
 static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
 {
diff --git a/lib/kobject.c b/lib/kobject.c
index ff94919..5df8441 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -184,8 +184,6 @@
 		unlink(kobj);
 		if (parent)
 			kobject_put(parent);
-	} else {
-		kobject_hotplug(kobj, KOBJ_ADD);
 	}
 
 	return error;
@@ -207,7 +205,8 @@
 			printk("kobject_register failed for %s (%d)\n",
 			       kobject_name(kobj),error);
 			dump_stack();
-		}
+		} else
+			kobject_hotplug(kobj, KOBJ_ADD);
 	} else
 		error = -EINVAL;
 	return error;
@@ -301,7 +300,6 @@
 
 void kobject_del(struct kobject * kobj)
 {
-	kobject_hotplug(kobj, KOBJ_REMOVE);
 	sysfs_remove_dir(kobj);
 	unlink(kobj);
 }
@@ -314,6 +312,7 @@
 void kobject_unregister(struct kobject * kobj)
 {
 	pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
+	kobject_hotplug(kobj, KOBJ_REMOVE);
 	kobject_del(kobj);
 	kobject_put(kobj);
 }
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 567249b..f6a19d5 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -248,6 +248,7 @@
 	if (err)
 		goto out2;
 
+	kobject_hotplug(&p->kobj, KOBJ_ADD);
 	return 0;
  out2:
 	kobject_del(&p->kobj);
@@ -259,6 +260,7 @@
 {
 	pr_debug("br_sysfs_removeif\n");
 	sysfs_remove_link(&p->br->ifobj, p->dev->name);
+	kobject_hotplug(&p->kobj, KOBJ_REMOVE);
 	kobject_del(&p->kobj);
 }
 
diff --git a/scripts/ver_linux b/scripts/ver_linux
index bb195a1..a28c279 100755
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -87,7 +87,7 @@
 
 expr --v 2>&1 | awk 'NR==1{print "Sh-utils              ", $NF}'
 
-udevinfo -V | awk '{print "udev                  ", $3}'
+udevinfo -V 2>&1 | grep version | awk '{print "udev                  ", $3}'
 
 if [ -e /proc/modules ]; then
     X=`cat /proc/modules | sed -e "s/ .*$//"`