Commit f75bdb62 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/driver-2.6
parents 32a8ed45 764dfe0b
......@@ -6,19 +6,20 @@ Definition
struct bus_type {
char * name;
rwlock_t lock;
atomic_t refcount;
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
......@@ -169,8 +137,8 @@ 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);
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
......
......@@ -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",
......
......@@ -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);
}
}
/**
......
......@@ -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;
......
......@@ -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;
......
......@@ -106,7 +106,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
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);
......
......@@ -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);
}
......
......@@ -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);
}
/**
......
......@@ -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,
......
......@@ -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);
}
/*-------------------------------------------------------------------------*/
......
......@@ -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 @@ static void serial_break (struct tty_struct *tty, int break_state)
;
}
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");
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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_ */
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment