bk://kernel.bkbits.net/gregkh/linux/driver-2.6 kay.sievers@vrfy.org[gregkh]|ChangeSet|20050318003354|02391 kay.sievers # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/03/17 16:33:54-08:00 kay.sievers@vrfy.org # [PATCH] add TIMEOUT to firmware_class hotplug event # # On Tue, 2005-03-15 at 09:25 +0100, Hannes Reinecke wrote: # > The current implementation of the firmware class breaks a fundamental # > assumption in udevd: that the physical device can be initialised fully # > prior to executing the next event for that device. # # Here we add a TIMEOUT value to the hotplug environment of the firmware # requesting event. I will adapt udevd not to wait for anything else, if # it finds a TIMEOUT key. # # Signed-off-by: Kay Sievers # Signed-off-by: Greg Kroah-Hartman # # drivers/base/firmware_class.c # 2005/03/16 18:22:37-08:00 kay.sievers@vrfy.org +3 -0 # add TIMEOUT to firmware_class hotplug event # # ChangeSet # 2005/03/17 15:38:05-08:00 ecashin@coraid.com # [PATCH] aoe 12/12: send outgoing packets in order # # I can't use list.h, since sk_buff doesn't have a list_head but instead # has two struct sk_buff pointers, and I want to avoid any extra memory # allocation. # # send outgoing packets in order # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoecmd.c # 2005/03/10 09:20:04-08:00 ecashin@coraid.com +17 -9 # aoe 12/12: send outgoing packets in order # # drivers/block/aoe/aoeblk.c # 2005/03/10 09:20:04-08:00 ecashin@coraid.com +2 -2 # aoe 12/12: send outgoing packets in order # # drivers/block/aoe/aoe.h # 2005/03/10 09:20:04-08:00 ecashin@coraid.com +2 -1 # aoe 12/12: send outgoing packets in order # # ChangeSet # 2005/03/17 15:24:31-08:00 ecashin@coraid.com # [PATCH] aoe 11/12: add support for disk statistics # # add support for disk statistics # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoecmd.c # 2005/03/10 09:20:02-08:00 ecashin@coraid.com +14 -0 # aoe 11/12: add support for disk statistics # # drivers/block/aoe/aoeblk.c # 2005/03/10 09:20:02-08:00 ecashin@coraid.com +1 -0 # aoe 11/12: add support for disk statistics # # drivers/block/aoe/aoe.h # 2005/03/10 09:20:02-08:00 ecashin@coraid.com +1 -0 # aoe 11/12: add support for disk statistics # # ChangeSet # 2005/03/17 15:24:12-08:00 ecashin@coraid.com # [PATCH] aoe 9/12: add note about the need for # # add note about the need for deadlock-free sk_buff allocation # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # Documentation/aoe/todo.txt # 2005/03/10 09:19:57-08:00 ecashin@coraid.com +14 -0 # aoe 9/12: add note about the need for # # Documentation/aoe/todo.txt # 2005/03/10 09:19:57-08:00 ecashin@coraid.com +0 -0 # BitKeeper file /home/greg/linux/BK/driver-2.6/Documentation/aoe/todo.txt # # ChangeSet # 2005/03/17 15:23:51-08:00 ecashin@coraid.com # [PATCH] aoe 8/12: document env var for specifying number # # document env var for specifying number of partitions per dev # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # Documentation/aoe/mkshelf.sh # 2005/03/10 09:19:56-08:00 ecashin@coraid.com +1 -0 # aoe 8/12: document env var for specifying number # # Documentation/aoe/mkdevs.sh # 2005/03/10 09:19:56-08:00 ecashin@coraid.com +1 -0 # aoe 8/12: document env var for specifying number # # ChangeSet # 2005/03/17 15:23:25-08:00 ecashin@coraid.com # [PATCH] aoe 7/12: support configuration of AOE_PARTITIONS # # support configuration of AOE_PARTITIONS from Kconfig # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoe.h # 2005/03/10 09:19:54-08:00 ecashin@coraid.com +3 -2 # aoe 7/12: support configuration of AOE_PARTITIONS # # drivers/block/Kconfig # 2005/03/10 09:19:54-08:00 ecashin@coraid.com +15 -0 # aoe 7/12: support configuration of AOE_PARTITIONS # # ChangeSet # 2005/03/17 15:23:00-08:00 ecashin@coraid.com # [PATCH] aoe 6/12: Alexey Dobriyan sparse cleanup # # Alexey Dobriyan sparse cleanup # # Signed-off-by: Alexey Dobriyan # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoenet.c # 2005/03/10 09:19:27-08:00 ecashin@coraid.com +4 -4 # aoe 6/12: Alexey Dobriyan sparse cleanup # # drivers/block/aoe/aoecmd.c # 2005/03/10 09:19:27-08:00 ecashin@coraid.com +23 -29 # aoe 6/12: Alexey Dobriyan sparse cleanup # # drivers/block/aoe/aoe.h # 2005/03/10 09:19:27-08:00 ecashin@coraid.com +5 -5 # aoe 6/12: Alexey Dobriyan sparse cleanup # # ChangeSet # 2005/03/17 15:21:48-08:00 ecashin@coraid.com # [PATCH] aoe 5/12: don't try to free null bufpool # # don't try to free null bufpool # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoedev.c # 2005/03/10 09:19:25-08:00 ecashin@coraid.com +2 -1 # aoe 5/12: don't try to free null bufpool # # ChangeSet # 2005/03/17 15:21:30-08:00 ecashin@coraid.com # [PATCH] aoe 4/12: handle distros that have a udev rules # # handle distros that have a udev rules file instead of dir # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # Documentation/aoe/udev-install.sh # 2005/03/10 09:19:18-08:00 ecashin@coraid.com +5 -1 # aoe 4/12: handle distros that have a udev rules # # ChangeSet # 2005/03/17 15:21:12-08:00 ecashin@coraid.com # [PATCH] aoe 3/12: update driver version to 6 # # update driver version to 6 # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoe.h # 2005/03/10 09:19:14-08:00 ecashin@coraid.com +1 -1 # aoe 3/12: update driver version to 6 # # ChangeSet # 2005/03/17 15:20:51-08:00 ecashin@coraid.com # [PATCH] aoe 2/12: allow multiple aoe devices with same MAC # # allow multiple aoe devices with same MAC addr # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoedev.c # 2005/03/10 09:19:11-08:00 ecashin@coraid.com +2 -3 # aoe 2/12: allow multiple aoe devices with same MAC # # drivers/block/aoe/aoecmd.c # 2005/03/10 09:19:11-08:00 ecashin@coraid.com +5 -4 # aoe 2/12: allow multiple aoe devices with same MAC # # drivers/block/aoe/aoe.h # 2005/03/10 09:19:11-08:00 ecashin@coraid.com +1 -1 # aoe 2/12: allow multiple aoe devices with same MAC # # ChangeSet # 2005/03/17 15:20:32-08:00 ecashin@coraid.com # [PATCH] aoe 1/12: remove too-low cap on minor number # # remove too-low cap on minor number # # Signed-off-by: Ed L. Cashin # Signed-off-by: Greg Kroah-Hartman # # drivers/block/aoe/aoecmd.c # 2005/03/10 09:19:04-08:00 ecashin@coraid.com +5 -4 # aoe 1/12: remove too-low cap on minor number # # drivers/block/aoe/aoe.h # 2005/03/10 09:19:04-08:00 ecashin@coraid.com +5 -0 # aoe 1/12: remove too-low cap on minor number # # ChangeSet # 2005/03/16 23:22:27-08:00 gregkh@suse.de # [PATCH] kref: add link to original documentation to the kref documentation. # # Signed-off-by: Greg Kroah-Hartman # # Documentation/kref.txt # 2005/03/16 23:21:28-08:00 gregkh@suse.de +6 -1 # kref: add link to original documentation to the kref documentation. # # ChangeSet # 2005/03/16 23:22:04-08:00 minyard@acm.org # [PATCH] kref: add documentation # # Add some documentation for krefs. # # Signed-off-by: Corey Minyard # Signed-off-by: Greg Kroah-Hartman # # Documentation/kref.txt # 2005/03/16 16:00:00-08:00 minyard@acm.org +211 -0 # kref: add documentation # # Documentation/kref.txt # 2005/03/16 16:00:00-08:00 minyard@acm.org +0 -0 # BitKeeper file /home/greg/linux/BK/driver-2.6/Documentation/kref.txt # # ChangeSet # 2005/03/15 15:10:13-08:00 gregkh@suse.de # [PATCH] USB: move the usb hcd code to use the new class code. # # This moves a kref into the main hcd structure, which detaches it from # the class device structure. # # Signed-off-by: Greg Kroah-Hartman # # include/linux/usb.h # 2005/03/15 14:44:25-08:00 gregkh@suse.de +2 -3 # USB: move the usb hcd code to use the new class code. # # drivers/usb/host/ohci-dbg.c # 2005/03/15 14:44:25-08:00 gregkh@suse.de +5 -5 # USB: move the usb hcd code to use the new class code. # # drivers/usb/host/ehci-dbg.c # 2005/03/15 14:44:25-08:00 gregkh@suse.de +5 -5 # USB: move the usb hcd code to use the new class code. # # drivers/usb/core/hcd.c # 2005/03/15 14:50:06-08:00 gregkh@suse.de +27 -34 # USB: move the usb hcd code to use the new class code. # # ChangeSet # 2005/03/15 14:26:30-08:00 gregkh@suse.de # [PATCH] INPUT: move to use the new class code, instead of class_simple # # Signed-off-by: Greg Kroah-Hartman # # include/linux/input.h # 2005/03/15 08:54:28-08:00 gregkh@suse.de +1 -1 # INPUT: move to use the new class code, instead of class_simple # # drivers/input/tsdev.c # 2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -4 # INPUT: move to use the new class code, instead of class_simple # # drivers/input/mousedev.c # 2005/03/15 08:54:28-08:00 gregkh@suse.de +9 -7 # INPUT: move to use the new class code, instead of class_simple # # drivers/input/joydev.c # 2005/03/15 08:54:28-08:00 gregkh@suse.de +4 -4 # INPUT: move to use the new class code, instead of class_simple # # drivers/input/input.c # 2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -5 # INPUT: move to use the new class code, instead of class_simple # # drivers/input/evdev.c # 2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -4 # INPUT: move to use the new class code, instead of class_simple # # ChangeSet # 2005/03/15 14:23:15-08:00 gregkh@suse.de # [PATCH] tty: move to use the new class code, instead of class_simple # # Signed-off-by: Greg Kroah-Hartman # # drivers/char/tty_io.c # 2005/03/15 08:54:22-08:00 gregkh@suse.de +8 -8 # tty: move to use the new class code, instead of class_simple # # ChangeSet # 2005/03/15 11:54:21-08:00 gregkh@suse.de # [PATCH] CLASS: move a "simple" class logic into the class core. # # One step on improving the class api so that it can not be used incorrectly. # This also fixes the module owner issue with the dev files that happened when # the devt logic moved to the class core. # # Based on a patch originally written by Kay Sievers # # Signed-off-by: Greg Kroah-Hartman # # include/linux/device.h # 2005/03/15 08:52:00-08:00 gregkh@suse.de +8 -0 # CLASS: move a "simple" class logic into the class core. # # drivers/base/class.c # 2005/03/15 08:52:00-08:00 gregkh@suse.de +133 -10 # CLASS: move a "simple" class logic into the class core. # diff -Nru a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh --- a/Documentation/aoe/mkdevs.sh 2005-03-20 16:42:13 -08:00 +++ b/Documentation/aoe/mkdevs.sh 2005-03-20 16:42:13 -08:00 @@ -5,6 +5,7 @@ if test "$#" != "1"; then echo "Usage: sh `basename $0` {dir}" 1>&2 + echo " n_partitions=16 sh `basename $0` {dir}" 1>&2 exit 1 fi dir=$1 diff -Nru a/Documentation/aoe/mkshelf.sh b/Documentation/aoe/mkshelf.sh --- a/Documentation/aoe/mkshelf.sh 2005-03-20 16:42:13 -08:00 +++ b/Documentation/aoe/mkshelf.sh 2005-03-20 16:42:13 -08:00 @@ -2,6 +2,7 @@ if test "$#" != "2"; then echo "Usage: sh `basename $0` {dir} {shelfaddress}" 1>&2 + echo " n_partitions=16 sh `basename $0` {dir} {shelfaddress}" 1>&2 exit 1 fi n_partitions=${n_partitions:-16} diff -Nru a/Documentation/aoe/todo.txt b/Documentation/aoe/todo.txt --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/Documentation/aoe/todo.txt 2005-03-20 16:42:13 -08:00 @@ -0,0 +1,14 @@ +There is a potential for deadlock when allocating a struct sk_buff for +data that needs to be written out to aoe storage. If the data is +being written from a dirty page in order to free that page, and if +there are no other pages available, then deadlock may occur when a +free page is needed for the sk_buff allocation. This situation has +not been observed, but it would be nice to eliminate any potential for +deadlock under memory pressure. + +Because ATA over Ethernet is not fragmented by the kernel's IP code, +the destructore member of the struct sk_buff is available to the aoe +driver. By using a mempool for allocating all but the first few +sk_buffs, and by registering a destructor, we should be able to +efficiently allocate sk_buffs without introducing any potential for +deadlock. diff -Nru a/Documentation/aoe/udev-install.sh b/Documentation/aoe/udev-install.sh --- a/Documentation/aoe/udev-install.sh 2005-03-20 16:42:13 -08:00 +++ b/Documentation/aoe/udev-install.sh 2005-03-20 16:42:13 -08:00 @@ -23,4 +23,8 @@ # /etc/udev/rules.d # rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`" -test "$rules_d" && sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules" +if test -z "$rules_d" || test ! -d "$rules_d"; then + echo "$me Error: cannot find udev rules directory" 1>&2 + exit 1 +fi +sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules" diff -Nru a/Documentation/kref.txt b/Documentation/kref.txt --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/Documentation/kref.txt 2005-03-20 16:42:13 -08:00 @@ -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 + +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 -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/base/class.c 2005-03-20 16:42:13 -08:00 @@ -16,6 +16,7 @@ #include #include #include +#include #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) @@ -162,6 +163,51 @@ subsystem_unregister(&cls->subsys); } +static void class_create_release(struct class *cls) +{ + kfree(cls); +} + +static void class_device_create_release(struct class_device *class_dev) +{ + kfree(class_dev); +} + +struct class *class_create(struct module *owner, char *name) +{ + struct class *cls; + int retval; + + cls = kmalloc(sizeof(struct class), GFP_KERNEL); + if (!cls) { + retval = -ENOMEM; + goto error; + } + memset(cls, 0x00, sizeof(struct class)); + + cls->name = name; + cls->owner = owner; + cls->class_release = class_create_release; + cls->release = class_device_create_release; + + retval = class_register(cls); + if (retval) + goto error; + + return cls; + +error: + kfree(cls); + return ERR_PTR(retval); +} + +void class_destroy(struct class *cls) +{ + if ((cls == NULL) || (IS_ERR(cls))) + return; + + class_unregister(cls); +} /* Class Device Stuff */ @@ -375,7 +421,6 @@ { return print_dev_t(buf, class_dev->devt); } -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); void class_device_initialize(struct class_device *class_dev) { @@ -412,7 +457,31 @@ if ((error = kobject_add(&class_dev->kobj))) goto register_done; - /* now take care of our own registration */ + /* add the needed attributes to this device */ + if (MAJOR(class_dev->devt)) { + struct class_device_attribute *attr; + attr = kmalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + error = -ENOMEM; + kobject_del(&class_dev->kobj); + goto register_done; + } + memset(attr, sizeof(*attr), 0x00); + attr->attr.name = "dev"; + attr->attr.mode = S_IRUGO; + attr->attr.owner = parent->owner; + attr->show = show_dev; + attr->store = NULL; + class_device_create_file(class_dev, attr); + class_dev->devt_attr = attr; + } + + class_device_add_attrs(class_dev); + if (class_dev->dev) + sysfs_create_link(&class_dev->kobj, + &class_dev->dev->kobj, "device"); + + /* notify any interfaces this device is now here */ if (parent) { down(&parent->sem); list_add_tail(&class_dev->node, &parent->children); @@ -422,14 +491,6 @@ up(&parent->sem); } - if (MAJOR(class_dev->devt)) - class_device_create_file(class_dev, &class_device_attr_dev); - - class_device_add_attrs(class_dev); - if (class_dev->dev) - sysfs_create_link(&class_dev->kobj, - &class_dev->dev->kobj, "device"); - register_done: if (error && parent) class_put(parent); @@ -443,6 +504,41 @@ return class_device_add(class_dev); } +struct class_device *class_device_create(struct class *cls, dev_t devt, + struct device *device, char *fmt, ...) +{ + va_list args; + struct class_device *class_dev = NULL; + int retval = -ENODEV; + + if (cls == NULL || IS_ERR(cls)) + goto error; + + class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); + if (!class_dev) { + retval = -ENOMEM; + goto error; + } + memset(class_dev, 0x00, sizeof(struct class_device)); + + class_dev->devt = devt; + class_dev->dev = device; + class_dev->class = cls; + + va_start(args, fmt); + vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); + va_end(args); + retval = class_device_register(class_dev); + if (retval) + goto error; + + return class_dev; + +error: + kfree(class_dev); + return ERR_PTR(retval); +} + void class_device_del(struct class_device *class_dev) { struct class * parent = class_dev->class; @@ -459,6 +555,11 @@ if (class_dev->dev) sysfs_remove_link(&class_dev->kobj, "device"); + if (class_dev->devt_attr) { + class_device_remove_file(class_dev, class_dev->devt_attr); + kfree(class_dev->devt_attr); + class_dev->devt_attr = NULL; + } class_device_remove_attrs(class_dev); kobject_del(&class_dev->kobj); @@ -475,6 +576,24 @@ class_device_put(class_dev); } +void class_device_destroy(struct class *cls, dev_t devt) +{ + struct class_device *class_dev = NULL; + struct class_device *class_dev_tmp; + + down(&cls->sem); + list_for_each_entry(class_dev_tmp, &cls->children, node) { + if (class_dev_tmp->devt == devt) { + class_dev = class_dev_tmp; + break; + } + } + up(&cls->sem); + + if (class_dev) + class_device_unregister(class_dev); +} + int class_device_rename(struct class_device *class_dev, char *new_name) { int error = 0; @@ -574,6 +693,8 @@ EXPORT_SYMBOL_GPL(class_unregister); EXPORT_SYMBOL_GPL(class_get); EXPORT_SYMBOL_GPL(class_put); +EXPORT_SYMBOL_GPL(class_create); +EXPORT_SYMBOL_GPL(class_destroy); EXPORT_SYMBOL_GPL(class_device_register); EXPORT_SYMBOL_GPL(class_device_unregister); @@ -582,6 +703,8 @@ EXPORT_SYMBOL_GPL(class_device_del); EXPORT_SYMBOL_GPL(class_device_get); EXPORT_SYMBOL_GPL(class_device_put); +EXPORT_SYMBOL_GPL(class_device_create); +EXPORT_SYMBOL_GPL(class_device_destroy); EXPORT_SYMBOL_GPL(class_device_create_file); EXPORT_SYMBOL_GPL(class_device_remove_file); EXPORT_SYMBOL_GPL(class_device_create_bin_file); diff -Nru a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c --- a/drivers/base/firmware_class.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/base/firmware_class.c 2005-03-20 16:42:13 -08:00 @@ -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 -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/Kconfig 2005-03-20 16:42:13 -08:00 @@ -506,4 +506,19 @@ This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config AOE_PARTITIONS + int "Partitions per AoE device" if ATA_OVER_ETH + default "16" + help + The default is to support 16 partitions per aoe device. Some + systems lack good support for devices with large minor + numbers. + + Such systems will be able to use more aoe disks when + AOE_PARTITIONS is set to one, but you won't be able to + partition the disks, and you must make sure your device + nodes are created to work with the value you select. + + If unsure, use 16. + endmenu diff -Nru a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h --- a/drivers/block/aoe/aoe.h 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/aoe/aoe.h 2005-03-20 16:42:13 -08:00 @@ -1,10 +1,16 @@ /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "5" +#define VERSION "6" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" -#ifndef AOE_PARTITIONS -#define AOE_PARTITIONS 16 + +/* set AOE_PARTITIONS to 1 to use whole-disks only + * default is 16, which is 15 partitions plus the whole disk + */ +#define AOE_PARTITIONS CONFIG_AOE_PARTITIONS +#if AOE_PARTITIONS < 1 +#error AOE_PARTITIONS less than one #endif + #define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor)) #define AOEMAJOR(sysminor) ((sysminor) / 10) #define AOEMINOR(sysminor) ((sysminor) % 10) @@ -34,13 +40,13 @@ struct aoe_hdr { unsigned char dst[6]; unsigned char src[6]; - unsigned char type[2]; + __be16 type; unsigned char verfl; unsigned char err; - unsigned char major[2]; + __be16 major; unsigned char minor; unsigned char cmd; - unsigned char tag[4]; + __be32 tag; }; struct aoe_atahdr { @@ -58,8 +64,8 @@ }; struct aoe_cfghdr { - unsigned char bufcnt[2]; - unsigned char fwver[2]; + __be16 bufcnt; + __be16 fwver; unsigned char res; unsigned char aoeccmd; unsigned char cslen[2]; @@ -85,6 +91,7 @@ struct buf { struct list_head bufs; + ulong start_time; /* for disk stats */ ulong flags; ulong nframesout; char *bufaddr; @@ -125,7 +132,8 @@ struct timer_list timer; spinlock_t lock; struct net_device *ifp; /* interface ed is attached to */ - struct sk_buff *skblist;/* packets needing to be sent */ + struct sk_buff *sendq_hd; /* packets needing to be sent, list head */ + struct sk_buff *sendq_tl; mempool_t *bufpool; /* for deadlock-free Buf allocation */ struct list_head bufq; /* queue of bios to work on */ struct buf *inprocess; /* the one we're currently working on */ @@ -151,7 +159,7 @@ int aoedev_init(void); void aoedev_exit(void); -struct aoedev *aoedev_bymac(unsigned char *); +struct aoedev *aoedev_by_aoeaddr(int maj, int min); void aoedev_downdev(struct aoedev *d); struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); int aoedev_busy(void); diff -Nru a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c --- a/drivers/block/aoe/aoeblk.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/aoe/aoeblk.c 2005-03-20 16:42:13 -08:00 @@ -125,6 +125,7 @@ } memset(buf, 0, sizeof(*buf)); INIT_LIST_HEAD(&buf->bufs); + buf->start_time = jiffies; buf->bio = bio; buf->resid = bio->bi_size; buf->sector = bio->bi_sector; @@ -146,8 +147,8 @@ list_add_tail(&buf->bufs, &d->bufq); aoecmd_work(d); - sl = d->skblist; - d->skblist = NULL; + sl = d->sendq_hd; + d->sendq_hd = d->sendq_tl = NULL; spin_unlock_irqrestore(&d->lock, flags); diff -Nru a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c --- a/drivers/block/aoe/aoecmd.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/aoe/aoecmd.c 2005-03-20 16:42:13 -08:00 @@ -90,19 +90,16 @@ static int aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) { - u16 type = __constant_cpu_to_be16(ETH_P_AOE); - u16 aoemajor = __cpu_to_be16(d->aoemajor); u32 host_tag = newtag(d); - u32 tag = __cpu_to_be32(host_tag); memcpy(h->src, d->ifp->dev_addr, sizeof h->src); memcpy(h->dst, d->addr, sizeof h->dst); - memcpy(h->type, &type, sizeof type); + h->type = __constant_cpu_to_be16(ETH_P_AOE); h->verfl = AOE_HVER; - memcpy(h->major, &aoemajor, sizeof aoemajor); + h->major = cpu_to_be16(d->aoemajor); h->minor = d->aoeminor; h->cmd = AOECMD_ATA; - memcpy(h->tag, &tag, sizeof tag); + h->tag = cpu_to_be32(host_tag); return host_tag; } @@ -181,8 +178,12 @@ skb = skb_prepare(d, f); if (skb) { - skb->next = d->skblist; - d->skblist = skb; + skb->next = NULL; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } } @@ -215,7 +216,6 @@ struct aoe_hdr *h; char buf[128]; u32 n; - u32 net_tag; n = newtag(d); @@ -227,13 +227,16 @@ h = (struct aoe_hdr *) f->data; f->tag = n; - net_tag = __cpu_to_be32(n); - memcpy(h->tag, &net_tag, sizeof net_tag); + h->tag = cpu_to_be32(n); skb = skb_prepare(d, f); if (skb) { - skb->next = d->skblist; - d->skblist = skb; + skb->next = NULL; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } } @@ -285,8 +288,8 @@ } } - sl = d->skblist; - d->skblist = NULL; + sl = d->sendq_hd; + d->sendq_hd = d->sendq_tl = NULL; if (sl) { n = d->rttavg <<= 1; if (n > MAXTIMER) @@ -308,16 +311,16 @@ u16 n; /* word 83: command set supported */ - n = __le16_to_cpu(*((u16 *) &id[83<<1])); + n = le16_to_cpup((__le16 *) &id[83<<1]); /* word 86: command set/feature enabled */ - n |= __le16_to_cpu(*((u16 *) &id[86<<1])); + n |= le16_to_cpup((__le16 *) &id[86<<1]); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = __le64_to_cpu(*((u64 *) &id[100<<1])); + ssize = le64_to_cpup((__le64 *) &id[100<<1]); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -328,12 +331,12 @@ d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = __le32_to_cpu(*((u32 *) &id[60<<1])); + ssize = le32_to_cpup((__le32 *) &id[60<<1]); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = __le16_to_cpu(*((u16 *) &id[54<<1])); - d->geo.heads = __le16_to_cpu(*((u16 *) &id[55<<1])); - d->geo.sectors = __le16_to_cpu(*((u16 *) &id[56<<1])); + d->geo.cylinders = le16_to_cpup((__le16 *) &id[54<<1]); + d->geo.heads = le16_to_cpup((__le16 *) &id[55<<1]); + d->geo.sectors = le16_to_cpup((__le16 *) &id[56<<1]); } d->ssize = ssize; d->geo.start = 0; @@ -380,29 +383,30 @@ register long n; ulong flags; char ebuf[128]; - + u16 aoemajor; + hin = (struct aoe_hdr *) skb->mac.raw; - d = aoedev_bymac(hin->src); + aoemajor = be16_to_cpu(hin->major); + d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " "for unknown device %d.%d\n", - __be16_to_cpu(*((u16 *) hin->major)), - hin->minor); + aoemajor, hin->minor); aoechr_error(ebuf); return; } spin_lock_irqsave(&d->lock, flags); - f = getframe(d, __be32_to_cpu(*((u32 *) hin->tag))); + f = getframe(d, be32_to_cpu(hin->tag)); if (f == NULL) { spin_unlock_irqrestore(&d->lock, flags); snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - __be16_to_cpu(*((u16 *) hin->major)), + be16_to_cpu(hin->major), hin->minor, - __be32_to_cpu(*((u32 *) hin->tag)), + be32_to_cpu(hin->tag), jiffies); aoechr_error(ebuf); return; @@ -452,7 +456,7 @@ printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " "outbound ata command %2.2Xh for %d.%d\n", ahout->cmdstat, - __be16_to_cpu(*((u16 *) hin->major)), + be16_to_cpu(hin->major), hin->minor); } } @@ -460,6 +464,20 @@ if (buf) { buf->nframesout -= 1; if (buf->nframesout == 0 && buf->resid == 0) { + unsigned long duration = jiffies - buf->start_time; + unsigned long n_sect = buf->bio->bi_size >> 9; + struct gendisk *disk = d->gd; + + if (bio_data_dir(buf->bio) == WRITE) { + disk_stat_inc(disk, writes); + disk_stat_add(disk, write_ticks, duration); + disk_stat_add(disk, write_sectors, n_sect); + } else { + disk_stat_inc(disk, reads); + disk_stat_add(disk, read_ticks, duration); + disk_stat_add(disk, read_sectors, n_sect); + } + disk_stat_add(disk, io_ticks, duration); n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; bio_endio(buf->bio, buf->bio->bi_size, n); mempool_free(buf, d->bufpool); @@ -471,8 +489,8 @@ aoecmd_work(d); - sl = d->skblist; - d->skblist = NULL; + sl = d->sendq_hd; + d->sendq_hd = d->sendq_tl = NULL; spin_unlock_irqrestore(&d->lock, flags); @@ -486,8 +504,6 @@ struct aoe_cfghdr *ch; struct sk_buff *skb, *sl; struct net_device *ifp; - u16 aoe_type = __constant_cpu_to_be16(ETH_P_AOE); - u16 net_aoemajor = __cpu_to_be16(aoemajor); sl = NULL; @@ -507,9 +523,9 @@ memset(h->dst, 0xff, sizeof h->dst); memcpy(h->src, ifp->dev_addr, sizeof h->src); - memcpy(h->type, &aoe_type, sizeof aoe_type); + h->type = __constant_cpu_to_be16(ETH_P_AOE); h->verfl = AOE_HVER; - memcpy(h->major, &net_aoemajor, sizeof net_aoemajor); + h->major = cpu_to_be16(aoemajor); h->minor = aoeminor; h->cmd = AOECMD_CFG; @@ -523,7 +539,7 @@ /* * Since we only call this in one place (and it only prepares one frame) - * we just return the skb. Usually we'd chain it up to the d->skblist. + * we just return the skb. Usually we'd chain it up to the aoedev sendq. */ static struct sk_buff * aoecmd_ata_id(struct aoedev *d) @@ -575,9 +591,10 @@ struct aoedev *d; struct aoe_hdr *h; struct aoe_cfghdr *ch; - ulong flags, bufcnt, sysminor, aoemajor; + ulong flags, sysminor, aoemajor; + u16 bufcnt; struct sk_buff *sl; - enum { MAXFRAMES = 8, MAXSYSMINOR = 255 }; + enum { MAXFRAMES = 8 }; h = (struct aoe_hdr *) skb->mac.raw; ch = (struct aoe_cfghdr *) (h+1); @@ -586,7 +603,7 @@ * Enough people have their dip switches set backwards to * warrant a loud message for this special case. */ - aoemajor = __be16_to_cpu(*((u16 *) h->major)); + aoemajor = be16_to_cpu(h->major); if (aoemajor == 0xfff) { printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf " "address is all ones. Check shelf dip switches\n"); @@ -594,13 +611,14 @@ } sysminor = SYSMINOR(aoemajor, h->minor); - if (sysminor > MAXSYSMINOR) { - printk(KERN_INFO "aoe: aoecmd_cfg_rsp: sysminor %ld too " - "large\n", sysminor); + if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { + printk(KERN_INFO + "aoe: e%ld.%d: minor number too large\n", + aoemajor, (int) h->minor); return; } - bufcnt = __be16_to_cpu(*((u16 *) ch->bufcnt)); + bufcnt = be16_to_cpu(ch->bufcnt); if (bufcnt > MAXFRAMES) /* keep it reasonable */ bufcnt = MAXFRAMES; @@ -617,7 +635,7 @@ return; } - d->fw_ver = __be16_to_cpu(*((u16 *) ch->fwver)); + d->fw_ver = be16_to_cpu(ch->fwver); /* we get here only if the device is new */ sl = aoecmd_ata_id(d); diff -Nru a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c --- a/drivers/block/aoe/aoedev.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/aoe/aoedev.c 2005-03-20 16:42:13 -08:00 @@ -13,7 +13,7 @@ static spinlock_t devlist_lock; struct aoedev * -aoedev_bymac(unsigned char *macaddr) +aoedev_by_aoeaddr(int maj, int min) { struct aoedev *d; ulong flags; @@ -21,7 +21,7 @@ spin_lock_irqsave(&devlist_lock, flags); for (d=devlist; d; d=d->next) - if (!memcmp(d->addr, macaddr, 6)) + if (d->aoemajor == maj && d->aoeminor == min) break; spin_unlock_irqrestore(&devlist_lock, flags); @@ -125,7 +125,6 @@ d->ifp = ifp; if (d->sysminor != sysminor - || memcmp(d->addr, addr, sizeof d->addr) || (d->flags & DEVFL_UP) == 0) { aoedev_downdev(d); /* flushes outstanding frames */ memcpy(d->addr, addr, sizeof d->addr); @@ -147,7 +146,8 @@ put_disk(d->gd); } kfree(d->frames); - mempool_destroy(d->bufpool); + if (d->bufpool) + mempool_destroy(d->bufpool); kfree(d); } diff -Nru a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c --- a/drivers/block/aoe/aoenet.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/block/aoe/aoenet.c 2005-03-20 16:42:13 -08:00 @@ -69,7 +69,7 @@ u64 mac_addr(char addr[6]) { - u64 n = 0; + __be64 n = 0; char *p = (char *) &n; memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */ @@ -108,7 +108,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt) { struct aoe_hdr *h; - ulong n; + u32 n; skb = skb_check(skb); if (!skb) @@ -121,7 +121,7 @@ skb_push(skb, ETH_HLEN); /* (1) */ h = (struct aoe_hdr *) skb->mac.raw; - n = __be32_to_cpu(*((u32 *) h->tag)); + n = be32_to_cpu(h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -132,7 +132,7 @@ if (net_ratelimit()) printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; " "ecode=%d '%s'\n", - __be16_to_cpu(*((u16 *) h->major)), h->minor, + be16_to_cpu(h->major), h->minor, h->err, aoe_errlist[n]); goto exit; } diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/char/tty_io.c 2005-03-20 16:42:13 -08:00 @@ -2653,7 +2653,7 @@ tty->driver->write(tty, &ch, 1); } -static struct class_simple *tty_class; +static struct class *tty_class; /** * tty_register_device - register a tty device @@ -2686,7 +2686,7 @@ pty_line_name(driver, index, name); else tty_line_name(driver, index, name); - class_simple_device_add(tty_class, dev, device, name); + class_device_create(tty_class, dev, device, name); } /** @@ -2700,7 +2700,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index); + class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2917,7 +2917,7 @@ static int __init tty_class_init(void) { - tty_class = class_simple_create(THIS_MODULE, "tty"); + tty_class = class_create(THIS_MODULE, "tty"); if (IS_ERR(tty_class)) return PTR_ERR(tty_class); return 0; @@ -2946,14 +2946,14 @@ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); @@ -2961,7 +2961,7 @@ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -2970,7 +2970,7 @@ register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c --- a/drivers/input/evdev.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/input/evdev.c 2005-03-20 16:42:13 -08:00 @@ -431,9 +431,9 @@ devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->dev, "event%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), + dev->dev, "event%d", minor); return &evdev->handle; } @@ -443,7 +443,8 @@ struct evdev *evdev = handle->private; struct evdev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); devfs_remove("input/event%d", evdev->minor); evdev->exist = 0; diff -Nru a/drivers/input/input.c b/drivers/input/input.c --- a/drivers/input/input.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/input/input.c 2005-03-20 16:42:13 -08:00 @@ -702,13 +702,13 @@ static inline int input_proc_init(void) { return 0; } #endif -struct class_simple *input_class; +struct class *input_class; static int __init input_init(void) { int retval = -ENOMEM; - input_class = class_simple_create(THIS_MODULE, "input"); + input_class = class_create(THIS_MODULE, "input"); if (IS_ERR(input_class)) return PTR_ERR(input_class); input_proc_init(); @@ -718,7 +718,7 @@ remove_proc_entry("devices", proc_bus_input_dir); remove_proc_entry("handlers", proc_bus_input_dir); remove_proc_entry("input", proc_bus); - class_simple_destroy(input_class); + class_destroy(input_class); return retval; } @@ -728,7 +728,7 @@ remove_proc_entry("handlers", proc_bus_input_dir); remove_proc_entry("input", proc_bus); unregister_chrdev(INPUT_MAJOR, "input"); - class_simple_destroy(input_class); + class_destroy(input_class); } return retval; } @@ -741,7 +741,7 @@ devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); - class_simple_destroy(input_class); + class_destroy(input_class); } subsys_initcall(input_init); diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c --- a/drivers/input/joydev.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/input/joydev.c 2005-03-20 16:42:13 -08:00 @@ -452,9 +452,9 @@ devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->dev, "js%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + dev->dev, "js%d", minor); return &joydev->handle; } @@ -464,7 +464,7 @@ struct joydev *joydev = handle->private; struct joydev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); + class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); devfs_remove("input/js%d", joydev->minor); joydev->exist = 0; diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c --- a/drivers/input/mousedev.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/input/mousedev.c 2005-03-20 16:42:13 -08:00 @@ -642,9 +642,9 @@ devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->dev, "mouse%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + dev->dev, "mouse%d", minor); return &mousedev->handle; } @@ -654,7 +654,8 @@ struct mousedev *mousedev = handle->private; struct mousedev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); devfs_remove("input/mouse%d", mousedev->minor); mousedev->exist = 0; @@ -730,8 +731,8 @@ devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); - class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), - NULL, "mice"); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX if (!(psaux_registered = !misc_register(&psaux_mouse))) @@ -750,7 +751,8 @@ misc_deregister(&psaux_mouse); #endif devfs_remove("input/mice"); - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); } diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c --- a/drivers/input/tsdev.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/input/tsdev.c 2005-03-20 16:42:13 -08:00 @@ -414,9 +414,9 @@ S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->dev, "ts%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), + dev->dev, "ts%d", minor); return &tsdev->handle; } @@ -426,7 +426,8 @@ struct tsdev *tsdev = handle->private; struct tsdev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); devfs_remove("input/ts%d", tsdev->minor); devfs_remove("input/tsraw%d", tsdev->minor); tsdev->exist = 0; diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/usb/core/hcd.c 2005-03-20 16:42:13 -08:00 @@ -648,50 +648,45 @@ /*-------------------------------------------------------------------------*/ /* exported only within usbcore */ -struct usb_bus *usb_bus_get (struct usb_bus *bus) +struct usb_bus *usb_bus_get(struct usb_bus *bus) { - struct class_device *tmp; + if (bus) + kref_get(&bus->kref); + return bus; +} - if (!bus) - return NULL; +static void usb_host_release(struct kref *kref) +{ + struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - tmp = class_device_get(&bus->class_dev); - if (tmp) - return to_usb_bus(tmp); - else - return NULL; + if (bus->release) + bus->release(bus); } /* exported only within usbcore */ -void usb_bus_put (struct usb_bus *bus) +void usb_bus_put(struct usb_bus *bus) { if (bus) - class_device_put(&bus->class_dev); + kref_put(&bus->kref, usb_host_release); } /*-------------------------------------------------------------------------*/ -static void usb_host_release(struct class_device *class_dev) -{ - struct usb_bus *bus = to_usb_bus(class_dev); - - if (bus->release) - bus->release(bus); -} - -static struct class usb_host_class = { - .name = "usb_host", - .release = &usb_host_release, -}; +static struct class *usb_host_class; int usb_host_init(void) { - return class_register(&usb_host_class); + int retval = 0; + + usb_host_class = class_create(THIS_MODULE, "usb_host"); + if (IS_ERR(usb_host_class)) + retval = PTR_ERR(usb_host_class); + return retval; } void usb_host_cleanup(void) { - class_unregister(&usb_host_class); + class_destroy(usb_host_class); } /** @@ -716,8 +711,7 @@ INIT_LIST_HEAD (&bus->bus_list); - class_device_initialize(&bus->class_dev); - bus->class_dev.class = &usb_host_class; + kref_init(&bus->kref); } EXPORT_SYMBOL (usb_bus_init); @@ -760,7 +754,6 @@ int usb_register_bus(struct usb_bus *bus) { int busnum; - int retval; down (&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); @@ -773,15 +766,15 @@ return -E2BIG; } - snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); - bus->class_dev.dev = bus->controller; - retval = class_device_add(&bus->class_dev); - if (retval) { + bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum); + if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); - return retval; + return PTR_ERR(bus->class_dev); } + class_set_devdata(bus->class_dev, bus); + /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); @@ -820,7 +813,7 @@ clear_bit (bus->busnum, busmap.busmap); - class_device_del(&bus->class_dev); + class_device_unregister(bus->class_dev); } EXPORT_SYMBOL (usb_deregister_bus); diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/usb/host/ehci-dbg.c 2005-03-20 16:42:13 -08:00 @@ -450,7 +450,7 @@ *buf = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -496,7 +496,7 @@ return 0; seen_count = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -633,7 +633,7 @@ static char fmt [] = "%*s\n"; static char label [] = ""; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -735,7 +735,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci) { - struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev; + struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; class_device_create_file(cldev, &class_device_attr_async); class_device_create_file(cldev, &class_device_attr_periodic); @@ -744,7 +744,7 @@ static inline void remove_debug_files (struct ehci_hcd *ehci) { - struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev; + struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; class_device_remove_file(cldev, &class_device_attr_async); class_device_remove_file(cldev, &class_device_attr_periodic); diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c 2005-03-20 16:42:13 -08:00 +++ b/drivers/usb/host/ohci-dbg.c 2005-03-20 16:42:13 -08:00 @@ -477,7 +477,7 @@ size_t temp; unsigned long flags; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); @@ -510,7 +510,7 @@ return 0; seen_count = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); next = buf; @@ -607,7 +607,7 @@ char *next; u32 rdata; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); regs = ohci->regs; @@ -678,7 +678,7 @@ static inline void create_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev; + struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_create_file(cldev, &class_device_attr_async); class_device_create_file(cldev, &class_device_attr_periodic); @@ -688,7 +688,7 @@ static inline void remove_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev; + struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_remove_file(cldev, &class_device_attr_async); class_device_remove_file(cldev, &class_device_attr_periodic); diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h 2005-03-20 16:42:13 -08:00 +++ b/include/linux/device.h 2005-03-20 16:42:13 -08:00 @@ -143,6 +143,7 @@ */ struct class { char * name; + struct module * owner; struct subsystem subsys; struct list_head children; @@ -185,6 +186,7 @@ struct kobject kobj; struct class * class; /* required */ dev_t devt; /* dev_t, creates the sysfs "dev" */ + struct class_device_attribute *devt_attr; struct device * dev; /* not necessary, but nice to have */ void * class_data; /* class-specific data */ @@ -244,6 +246,12 @@ extern int class_interface_register(struct class_interface *); extern void class_interface_unregister(struct class_interface *); + +extern struct class *class_create(struct module *owner, char *name); +extern void class_destroy(struct class *cls); +extern struct class_device *class_device_create(struct class *cls, dev_t devt, + struct device *device, char *fmt, ...); +extern void class_device_destroy(struct class *cls, dev_t devt); /* interface for class simple stuff */ extern struct class_simple *class_simple_create(struct module *owner, char *name); diff -Nru a/include/linux/input.h b/include/linux/input.h --- a/include/linux/input.h 2005-03-20 16:42:13 -08:00 +++ b/include/linux/input.h 2005-03-20 16:42:13 -08:00 @@ -1010,7 +1010,7 @@ dev->absbit[LONG(axis)] |= BIT(axis); } -extern struct class_simple *input_class; +extern struct class *input_class; #endif #endif diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h 2005-03-20 16:42:13 -08:00 +++ b/include/linux/usb.h 2005-03-20 16:42:13 -08:00 @@ -287,15 +287,14 @@ struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ - struct class_device class_dev; /* class device for this bus */ + struct class_device *class_dev; /* class device for this bus */ + struct kref kref; /* handles reference counting this bus */ void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */ #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif }; -#define to_usb_bus(d) container_of(d, struct usb_bus, class_dev) - /* -------------------------------------------------------------------------- */