summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2004-08-24 22:45:48 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-08-24 22:45:48 -0700
commitf75bdb62b88f893e24f67be1831e55f15eb79f25 (patch)
tree4ae13cb5f650e966b77ed3b2d3fe59a92bf39f87
parent32a8ed459490371bb9e5973bae5c502f94dd8034 (diff)
parent764dfe0b8c158293b2905f5a1fe213bd91d4e3f0 (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.txt74
-rw-r--r--drivers/base/class.c9
-rw-r--r--drivers/char/tty_io.c22
-rw-r--r--drivers/scsi/sd.c12
-rw-r--r--drivers/scsi/sr.c12
-rw-r--r--drivers/usb/core/config.c7
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/core/urb.c4
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/host/ehci-mem.c4
-rw-r--r--drivers/usb/serial/usb-serial.c130
-rw-r--r--include/linux/device.h1
-rw-r--r--include/linux/kobject.h5
-rw-r--r--include/linux/kref.h9
-rw-r--r--lib/Makefile5
-rw-r--r--lib/kobject.c57
-rw-r--r--lib/kref.c29
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);