diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2004-08-24 22:45:48 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-08-24 22:45:48 -0700 |
| commit | f75bdb62b88f893e24f67be1831e55f15eb79f25 (patch) | |
| tree | 4ae13cb5f650e966b77ed3b2d3fe59a92bf39f87 | |
| parent | 32a8ed459490371bb9e5973bae5c502f94dd8034 (diff) | |
| parent | 764dfe0b8c158293b2905f5a1fe213bd91d4e3f0 (diff) | |
Merge kroah.com:/home/greg/linux/BK/bleed-2.6
into kroah.com:/home/greg/linux/BK/driver-2.6
| -rw-r--r-- | Documentation/driver-model/bus.txt | 74 | ||||
| -rw-r--r-- | drivers/base/class.c | 9 | ||||
| -rw-r--r-- | drivers/char/tty_io.c | 22 | ||||
| -rw-r--r-- | drivers/scsi/sd.c | 12 | ||||
| -rw-r--r-- | drivers/scsi/sr.c | 12 | ||||
| -rw-r--r-- | drivers/usb/core/config.c | 7 | ||||
| -rw-r--r-- | drivers/usb/core/message.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/urb.c | 4 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 1 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-mem.c | 4 | ||||
| -rw-r--r-- | drivers/usb/serial/usb-serial.c | 130 | ||||
| -rw-r--r-- | include/linux/device.h | 1 | ||||
| -rw-r--r-- | include/linux/kobject.h | 5 | ||||
| -rw-r--r-- | include/linux/kref.h | 9 | ||||
| -rw-r--r-- | lib/Makefile | 5 | ||||
| -rw-r--r-- | lib/kobject.c | 57 | ||||
| -rw-r--r-- | lib/kref.c | 29 |
17 files changed, 185 insertions, 198 deletions
diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index 70685dde39c4..dd62c7b80b3f 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -5,20 +5,21 @@ Definition ~~~~~~~~~~ struct bus_type { - char * name; - rwlock_t lock; - atomic_t refcount; + char * name; - struct list_head node; - struct list_head devices; - struct list_head drivers; + struct subsystem subsys; + struct kset drivers; + struct kset devices; - struct driver_dir_entry dir; - struct driver_dir_entry device_dir; - struct driver_dir_entry driver_dir; + struct bus_attribute * bus_attrs; + struct device_attribute * dev_attrs; + struct driver_attribute * drv_attrs; - int (*match) (struct device * dev, struct device_driver * drv); - struct device (*add) (struct device * parent, char * bus_id); + int (*match)(struct device * dev, struct device_driver * drv); + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + int (*suspend)(struct device * dev, u32 state); + int (*resume)(struct device * dev); }; int bus_register(struct bus_type * bus); @@ -47,7 +48,7 @@ Registration When a bus driver is initialized, it calls bus_register. This initializes the rest of the fields in the bus object and inserts it into a global list of bus types. Once the bus object is registered, -the fields in it (e.g. the rwlock_t) are usable by the bus driver. +the fields in it are usable by the bus driver. Callbacks @@ -71,40 +72,6 @@ When a driver is registered with the bus, the bus's list of devices is iterated over, and the match callback is called for each device that does not have a driver associated with it. -add(): Adding a child device -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The add callback is available to notify the bus about a child device -at a particular location. - -The parent parameter is the parent device of the child to be added. If -parent == NULL, the bus should add the device as a child of a default -parent device or as a child of the root. This policy decision is up to -the bus driver. - -The format of the bus_id field should be consistent with the format of -the bus_id field of the rest of the devices on the bus. This requires -the caller to know the format. - -On return, the bus driver should return a pointer to the device that -was created. If the device was not created, the bus driver should -return an appropriate error code. Refer to include/linux/err.h for -helper functions to encode errors. Some sample code: - -struct device * pci_bus_add(struct device * parent, char * bus_id) -{ - ... - /* the device already exists */ - return ERR_PTR(-EEXIST); - ... -} - -The caller can check the return value using IS_ERR(): - - struct device * newdev = pci_bus_type.add(parent,bus_id); - if (IS_ERR(newdev)) { - ... - } Device and Driver Lists @@ -118,10 +85,11 @@ necessary. The LDM core provides helper functions for iterating over each list. -int bus_for_each_dev(struct bus_type * bus, void * data, - int (*callback)(struct device * dev, void * data)); -int bus_for_each_drv(struct bus_type * bus, void * data, - int (*callback)(struct device_driver * drv, void * data)); +int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, + int (*fn)(struct device *, void *)); + +int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); These helpers iterate over the respective list, and call the callback for each device or driver in the list. All list accesses are @@ -168,9 +136,9 @@ hierarchy: Exporting Attributes ~~~~~~~~~~~~~~~~~~~~ struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count); }; Bus drivers can export attributes using the BUS_ATTR macro that works diff --git a/drivers/base/class.c b/drivers/base/class.c index 2693bb5455f4..70be974509c3 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -349,14 +349,19 @@ void class_device_initialize(struct class_device *class_dev) int class_device_add(struct class_device *class_dev) { - struct class * parent; + struct class * parent = NULL; struct class_interface * class_intf; int error; class_dev = class_device_get(class_dev); - if (!class_dev || !strlen(class_dev->class_id)) + if (!class_dev) return -EINVAL; + if (!strlen(class_dev->class_id)) { + error = -EINVAL; + goto register_done; + } + parent = class_get(class_dev->class); pr_debug("CLASS: registering class device: ID = '%s'\n", diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4f6ff6188fb9..2b28688b36ea 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -763,6 +763,17 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t return tty_write(file, buf, count, ppos); } +static char ptychar[] = "pqrstuvwxyzabcde"; + +static inline void pty_line_name(struct tty_driver *driver, int index, char *p) +{ + int i = index + driver->name_base; + /* ->name is initialized to "ttyp", but "tty" is expected */ + sprintf(p, "%s%c%x", + driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, + ptychar[i >> 4 & 0xf], i & 0xf); +} + static inline void tty_line_name(struct tty_driver *driver, int index, char *p) { sprintf(p, "%s%d", driver->name, index + driver->name_base); @@ -2175,6 +2186,7 @@ static struct class_simple *tty_class; void tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { + char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; if (index >= driver->num) { @@ -2186,13 +2198,11 @@ void tty_register_device(struct tty_driver *driver, unsigned index, devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "%s%d", driver->devfs_name, index + driver->name_base); - /* we don't care about the ptys */ - /* how nice to hide this behind some crappy interface.. */ - if (driver->type != TTY_DRIVER_TYPE_PTY) { - char name[64]; + if (driver->type == TTY_DRIVER_TYPE_PTY) + pty_line_name(driver, index, name); + else tty_line_name(driver, index, name); - class_simple_device_add(tty_class, dev, device, name); - } + class_simple_device_add(tty_class, dev, device, name); } /** diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e2cc4aec3e17..d84dbfb24be2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -182,16 +182,14 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk) if (disk->private_data == NULL) goto out; sdkp = scsi_disk(disk); - if (!kref_get(&sdkp->kref)) - goto out_sdkp; + kref_get(&sdkp->kref); if (scsi_device_get(sdkp->device)) goto out_put; up(&sd_ref_sem); return sdkp; out_put: - kref_put(&sdkp->kref); - out_sdkp: + kref_put(&sdkp->kref, scsi_disk_release); sdkp = NULL; out: up(&sd_ref_sem); @@ -202,7 +200,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) { down(&sd_ref_sem); scsi_device_put(sdkp->device); - kref_put(&sdkp->kref); + kref_put(&sdkp->kref, scsi_disk_release); up(&sd_ref_sem); } @@ -1420,7 +1418,7 @@ static int sd_probe(struct device *dev) goto out; memset (sdkp, 0, sizeof(*sdkp)); - kref_init(&sdkp->kref, scsi_disk_release); + kref_init(&sdkp->kref); /* Note: We can accomodate 64 partitions, but the genhd code * assumes partitions allocate consecutive minors, which they don't. @@ -1522,7 +1520,7 @@ static int sd_remove(struct device *dev) del_gendisk(sdkp->disk); sd_shutdown(dev); down(&sd_ref_sem); - kref_put(&sdkp->kref); + kref_put(&sdkp->kref, scsi_disk_release); up(&sd_ref_sem); return 0; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b80aa283c921..ba2789d72633 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -140,15 +140,13 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) if (disk->private_data == NULL) goto out; cd = scsi_cd(disk); - if (!kref_get(&cd->kref)) - goto out_null; + kref_get(&cd->kref); if (scsi_device_get(cd->device)) goto out_put; goto out; out_put: - kref_put(&cd->kref); - out_null: + kref_put(&cd->kref, sr_kref_release); cd = NULL; out: up(&sr_ref_sem); @@ -159,7 +157,7 @@ static inline void scsi_cd_put(struct scsi_cd *cd) { down(&sr_ref_sem); scsi_device_put(cd->device); - kref_put(&cd->kref); + kref_put(&cd->kref, sr_kref_release); up(&sr_ref_sem); } @@ -576,7 +574,7 @@ static int sr_probe(struct device *dev) goto fail; memset(cd, 0, sizeof(*cd)); - kref_init(&cd->kref, sr_kref_release); + kref_init(&cd->kref); disk = alloc_disk(1); if (!disk) @@ -937,7 +935,7 @@ static int sr_remove(struct device *dev) del_gendisk(cd->disk); down(&sr_ref_sem); - kref_put(&cd->kref); + kref_put(&cd->kref, sr_kref_release); up(&sr_ref_sem); return 0; diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index ae7ec74052fb..33c51714f49c 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -106,7 +106,7 @@ skip_to_next_endpoint_or_interface_descriptor: return buffer - buffer0 + i; } -static void usb_release_interface_cache(struct kref *ref) +void usb_release_interface_cache(struct kref *ref) { struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); int j; @@ -356,7 +356,7 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, if (!intfc) return -ENOMEM; memset(intfc, 0, len); - kref_init(&intfc->ref, usb_release_interface_cache); + kref_init(&intfc->ref); } /* Skip over any Class Specific or Vendor Specific descriptors; @@ -422,7 +422,8 @@ void usb_destroy_configuration(struct usb_device *dev) for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) - kref_put(&cf->intf_cache[i]->ref); + kref_put(&cf->intf_cache[i]->ref, + usb_release_interface_cache); } } kfree(dev->config); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e0f9b3af9ba5..2768a6df862d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1196,7 +1196,7 @@ static void release_interface(struct device *dev) struct usb_interface_cache *intfc = altsetting_to_usb_interface_cache(intf->altsetting); - kref_put(&intfc->ref); + kref_put(&intfc->ref, usb_release_interface_cache); kfree(intf); } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 2defd6ab4ab0..3c14361bbeb3 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -39,7 +39,7 @@ void usb_init_urb(struct urb *urb) { if (urb) { memset(urb, 0, sizeof(*urb)); - kref_init(&urb->kref, urb_destroy); + kref_init(&urb->kref); spin_lock_init(&urb->lock); } } @@ -88,7 +88,7 @@ struct urb *usb_alloc_urb(int iso_packets, int mem_flags) void usb_free_urb(struct urb *urb) { if (urb) - kref_put(&urb->kref); + kref_put(&urb->kref, urb_destroy); } /** diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 7d978af3a0b0..f1dff4f4d5d6 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -10,6 +10,7 @@ extern int usb_unbind_interface (struct device *dev); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); +extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern void usb_enable_endpoint (struct usb_device *dev, diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 31f311d53b05..33d99d3ba6a3 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -114,7 +114,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) return qh; memset (qh, 0, sizeof *qh); - kref_init(&qh->kref, qh_destroy); + kref_init(&qh->kref); qh->ehci = ehci; qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); @@ -139,7 +139,7 @@ static inline struct ehci_qh *qh_get (struct ehci_qh *qh) static inline void qh_put (struct ehci_qh *qh) { - kref_put(&qh->kref); + kref_put(&qh->kref, qh_destroy); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2656807d7c18..0e59c134134c 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -421,6 +421,63 @@ static void return_serial (struct usb_serial *serial) return; } +static void destroy_serial(struct kref *kref) +{ + struct usb_serial *serial; + struct usb_serial_port *port; + int i; + + serial = to_usb_serial(kref); + + dbg ("%s - %s", __FUNCTION__, serial->type->name); + + serial->type->shutdown(serial); + + /* return the minor range that this device had */ + return_serial(serial); + + for (i = 0; i < serial->num_ports; ++i) + serial->port[i]->open_count = 0; + + /* the ports are cleaned up and released in port_release() */ + for (i = 0; i < serial->num_ports; ++i) + if (serial->port[i]->dev.parent != NULL) { + device_unregister(&serial->port[i]->dev); + serial->port[i] = NULL; + } + + /* If this is a "fake" port, we have to clean it up here, as it will + * not get cleaned up in port_release() as it was never registered with + * the driver core */ + if (serial->num_ports < serial->num_port_pointers) { + for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { + port = serial->port[i]; + if (!port) + continue; + if (port->read_urb) { + usb_unlink_urb(port->read_urb); + usb_free_urb(port->read_urb); + } + if (port->write_urb) { + usb_unlink_urb(port->write_urb); + usb_free_urb(port->write_urb); + } + if (port->interrupt_in_urb) { + usb_unlink_urb(port->interrupt_in_urb); + usb_free_urb(port->interrupt_in_urb); + } + kfree(port->bulk_in_buffer); + kfree(port->bulk_out_buffer); + kfree(port->interrupt_in_buffer); + } + } + + usb_put_dev(serial->dev); + + /* free up any memory that we allocated */ + kfree (serial); +} + /***************************************************************************** * Driver tty interface functions *****************************************************************************/ @@ -465,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) if (retval) { port->open_count = 0; module_put(serial->type->owner); - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } } bailout: @@ -496,7 +553,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) } module_put(port->serial->type->owner); - kref_put(&port->serial->kref); + kref_put(&port->serial->kref, destroy_serial); } static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -654,13 +711,6 @@ exit: ; } -static void serial_shutdown (struct usb_serial *serial) -{ - dbg ("%s", __FUNCTION__); - - serial->type->shutdown(serial); -} - static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { struct usb_serial *serial; @@ -694,7 +744,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int begin += length; length = 0; } - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } *eof = 1; done: @@ -763,62 +813,6 @@ void usb_serial_port_softint(void *private) wake_up_interruptible(&tty->write_wait); } -static void destroy_serial(struct kref *kref) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - int i; - - serial = to_usb_serial(kref); - - dbg ("%s - %s", __FUNCTION__, serial->type->name); - serial_shutdown (serial); - - /* return the minor range that this device had */ - return_serial(serial); - - for (i = 0; i < serial->num_ports; ++i) - serial->port[i]->open_count = 0; - - /* the ports are cleaned up and released in port_release() */ - for (i = 0; i < serial->num_ports; ++i) - if (serial->port[i]->dev.parent != NULL) { - device_unregister(&serial->port[i]->dev); - serial->port[i] = NULL; - } - - /* If this is a "fake" port, we have to clean it up here, as it will - * not get cleaned up in port_release() as it was never registered with - * the driver core */ - if (serial->num_ports < serial->num_port_pointers) { - for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { - port = serial->port[i]; - if (!port) - continue; - if (port->read_urb) { - usb_unlink_urb(port->read_urb); - usb_free_urb(port->read_urb); - } - if (port->write_urb) { - usb_unlink_urb(port->write_urb); - usb_free_urb(port->write_urb); - } - if (port->interrupt_in_urb) { - usb_unlink_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); - } - kfree(port->bulk_in_buffer); - kfree(port->bulk_out_buffer); - kfree(port->interrupt_in_buffer); - } - } - - usb_put_dev(serial->dev); - - /* free up any memory that we allocated */ - kfree (serial); -} - static void port_release(struct device *dev) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -859,7 +853,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, serial->interface = interface; serial->vendor = dev->descriptor.idVendor; serial->product = dev->descriptor.idProduct; - kref_init(&serial->kref, destroy_serial); + kref_init(&serial->kref); return serial; } @@ -1209,7 +1203,7 @@ void usb_serial_disconnect(struct usb_interface *interface) if (serial) { /* let the last holder of this object * cause it to be cleaned up */ - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } dev_info(dev, "device disconnected\n"); } diff --git a/include/linux/device.h b/include/linux/device.h index 49d3865aa27b..fd7e27c79467 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -59,7 +59,6 @@ struct bus_type { struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); - struct device * (*add) (struct device * parent, char * bus_id); int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); int (*suspend)(struct device * dev, u32 state); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 6360d225884c..4ec94fa8163f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -19,6 +19,7 @@ #include <linux/list.h> #include <linux/sysfs.h> #include <linux/rwsem.h> +#include <linux/kref.h> #include <asm/atomic.h> #define KOBJ_NAME_LEN 20 @@ -26,7 +27,7 @@ struct kobject { char * k_name; char name[KOBJ_NAME_LEN]; - atomic_t refcount; + struct kref kref; struct list_head entry; struct kobject * parent; struct kset * kset; @@ -58,6 +59,8 @@ extern void kobject_put(struct kobject *); extern void kobject_hotplug(const char *action, struct kobject *); +extern char * kobject_get_path(struct kset *, struct kobject *, int); + struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops; diff --git a/include/linux/kref.h b/include/linux/kref.h index 82284b7e730b..119c74eca194 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -18,15 +18,12 @@ #include <linux/types.h> #include <asm/atomic.h> - struct kref { atomic_t refcount; - void (*release)(struct kref *kref); }; -void kref_init(struct kref *kref, void (*release)(struct kref *)); -struct kref *kref_get(struct kref *kref); -void kref_put(struct kref *kref); - +void kref_init(struct kref *kref); +void kref_get(struct kref *kref); +void kref_put(struct kref *kref, void (*release) (struct kref *kref)); #endif /* _KREF_H_ */ diff --git a/lib/Makefile b/lib/Makefile index f80da4580059..b62c9ef212ed 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,12 +5,9 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ - kobject.o idr.o div64.o parser.o int_sqrt.o \ + kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \ bitmap.o extable.o -# hack for now till some static code uses krefs, then it can move up above... -obj-y += kref.o - lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o diff --git a/lib/kobject.c b/lib/kobject.c index 781f3e896695..a971b8e55e6b 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -58,14 +58,11 @@ static int create_dir(struct kobject * kobj) return error; } - static inline struct kobject * to_kobj(struct list_head * entry) { return container_of(entry,struct kobject,entry); } - -#ifdef CONFIG_HOTPLUG static int get_kobj_path_length(struct kset *kset, struct kobject *kobj) { int length = 1; @@ -98,6 +95,31 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, pr_debug("%s: path = '%s'\n",__FUNCTION__,path); } +/** + * kobject_get_path - generate and return the path associated with a given kobj + * and kset pair. The result must be freed by the caller with kfree(). + * + * @kset: kset in question, with which to build the path + * @kobj: kobject in question, with which to build the path + * @gfp_mask: the allocation type used to allocate the path + */ +char * kobject_get_path(struct kset *kset, struct kobject *kobj, int gfp_mask) +{ + char *path; + int len; + + len = get_kobj_path_length(kset, kobj); + path = kmalloc(len, gfp_mask); + if (!path) + return NULL; + memset(path, 0x00, len); + fill_kobj_path(kset, kobj, path, len); + + return path; +} + +#ifdef CONFIG_HOTPLUG + #define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define NUM_ENVP 32 /* number of env pointers */ static unsigned long sequence_num; @@ -112,7 +134,6 @@ static void kset_hotplug(const char *action, struct kset *kset, char *scratch; int i = 0; int retval; - int kobj_path_length; char *kobj_path = NULL; char *name = NULL; unsigned long seq; @@ -163,12 +184,9 @@ static void kset_hotplug(const char *action, struct kset *kset, envp [i++] = scratch; scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; - kobj_path_length = get_kobj_path_length (kset, kobj); - kobj_path = kmalloc (kobj_path_length, GFP_KERNEL); + kobj_path = kobject_get_path(kset, kobj, GFP_KERNEL); if (!kobj_path) goto exit; - memset (kobj_path, 0x00, kobj_path_length); - fill_kobj_path (kset, kobj, kobj_path, kobj_path_length); envp [i++] = scratch; scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1; @@ -225,10 +243,9 @@ void kobject_hotplug(const char *action, struct kobject *kobj) * kobject_init - initialize object. * @kobj: object in question. */ - void kobject_init(struct kobject * kobj) { - atomic_set(&kobj->refcount,1); + kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); kobj->kset = kset_get(kobj->kset); } @@ -325,7 +342,7 @@ int kobject_register(struct kobject * kobj) * @kobj: object. * @name: name. * - * If strlen(name) < KOBJ_NAME_LEN, then use a dynamically allocated + * If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated * string that @kobj->k_name points to. Otherwise, use the static * @kobj->name array. */ @@ -429,10 +446,8 @@ void kobject_unregister(struct kobject * kobj) struct kobject * kobject_get(struct kobject * kobj) { - if (kobj) { - WARN_ON(!atomic_read(&kobj->refcount)); - atomic_inc(&kobj->refcount); - } + if (kobj) + kref_get(&kobj->kref); return kobj; } @@ -459,17 +474,21 @@ void kobject_cleanup(struct kobject * kobj) kobject_put(parent); } +static void kobject_release(struct kref *kref) +{ + kobject_cleanup(container_of(kref, struct kobject, kref)); +} + /** * kobject_put - decrement refcount for object. * @kobj: object. * * Decrement the refcount, and if 0, call kobject_cleanup(). */ - void kobject_put(struct kobject * kobj) { - if (atomic_dec_and_test(&kobj->refcount)) - kobject_cleanup(kobj); + if (kobj) + kref_put(&kobj->kref, kobject_release); } @@ -626,7 +645,7 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a) } } - +EXPORT_SYMBOL(kobject_get_path); EXPORT_SYMBOL(kobject_init); EXPORT_SYMBOL(kobject_register); EXPORT_SYMBOL(kobject_unregister); diff --git a/lib/kref.c b/lib/kref.c index ee141adbf2e5..2218b7ae7db6 100644 --- a/lib/kref.c +++ b/lib/kref.c @@ -11,48 +11,45 @@ * */ -/* #define DEBUG */ - #include <linux/kref.h> #include <linux/module.h> /** * kref_init - initialize object. * @kref: object in question. - * @release: pointer to a function that will clean up the object - * when the last reference to the object is released. - * This pointer is required. */ -void kref_init(struct kref *kref, void (*release)(struct kref *kref)) +void kref_init(struct kref *kref) { - WARN_ON(release == NULL); atomic_set(&kref->refcount,1); - kref->release = release; } /** * kref_get - increment refcount for object. * @kref: object. */ -struct kref *kref_get(struct kref *kref) +void kref_get(struct kref *kref) { WARN_ON(!atomic_read(&kref->refcount)); atomic_inc(&kref->refcount); - return kref; } /** * kref_put - decrement refcount for object. * @kref: object. + * @release: pointer to the function that will clean up the object when the + * last reference to the object is released. + * This pointer is required, and it is not acceptable to pass kfree + * in as this function. * - * Decrement the refcount, and if 0, call kref->release(). + * Decrement the refcount, and if 0, call release(). */ -void kref_put(struct kref *kref) +void kref_put(struct kref *kref, void (*release) (struct kref *kref)) { - if (atomic_dec_and_test(&kref->refcount)) { - pr_debug("kref cleaning up\n"); - kref->release(kref); - } + WARN_ON(release == NULL); + WARN_ON(release == (void (*)(struct kref *))kfree); + + if (atomic_dec_and_test(&kref->refcount)) + release(kref); } EXPORT_SYMBOL(kref_init); |
