diff options
author | Jan Kiszka <jan.kiszka@web.de> | 2010-02-08 13:12:27 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-17 03:01:28 +0300 |
commit | 0159d5491fef4acadd116a989b671e1cd350382f (patch) | |
tree | 2cc7d1567c18a6629ea641922880ece36ad765de /drivers/isdn/capi/capi.c | |
parent | e95ac143868752ad30d93068a6fc0b39cf3a1bf4 (diff) | |
download | linux-0159d5491fef4acadd116a989b671e1cd350382f.tar.xz |
CAPI: Use kref on capiminor
Install a reference counter for capiminor objects. Acquire it when
obtaining a capiminor from the array during capinc_tty_open, drop it
when closing the tty again. Another reference is held for the hook-up
with capincci.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/capi/capi.c')
-rw-r--r-- | drivers/isdn/capi/capi.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index b1de0cbea69e..732cdb585b2d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -83,6 +83,8 @@ struct datahandle_queue { }; struct capiminor { + struct kref kref; + struct capincci *nccip; unsigned int minor; struct dentry *capifs_dentry; @@ -223,6 +225,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) return NULL; } + kref_init(&mp->kref); + mp->ap = ap; mp->ncci = ncci; mp->msgid = 0; @@ -265,18 +269,11 @@ err_out1: return NULL; } -static void capiminor_free(struct capiminor *mp) +static void capiminor_destroy(struct kref *kref) { - unsigned long flags; - - tty_unregister_device(capinc_tty_driver, mp->minor); - - write_lock_irqsave(&capiminors_lock, flags); - capiminors[mp->minor] = NULL; - write_unlock_irqrestore(&capiminors_lock, flags); + struct capiminor *mp = container_of(kref, struct capiminor, kref); kfree_skb(mp->ttyskb); - mp->ttyskb = NULL; skb_queue_purge(&mp->inqueue); skb_queue_purge(&mp->outqueue); capiminor_del_all_ack(mp); @@ -289,11 +286,31 @@ static struct capiminor *capiminor_get(unsigned int minor) read_lock(&capiminors_lock); mp = capiminors[minor]; + if (mp) + kref_get(&mp->kref); read_unlock(&capiminors_lock); return mp; } +static inline void capiminor_put(struct capiminor *mp) +{ + kref_put(&mp->kref, capiminor_destroy); +} + +static void capiminor_free(struct capiminor *mp) +{ + unsigned long flags; + + tty_unregister_device(capinc_tty_driver, mp->minor); + + write_lock_irqsave(&capiminors_lock, flags); + capiminors[mp->minor] = NULL; + write_unlock_irqrestore(&capiminors_lock, flags); + + capiminor_put(mp); +} + /* -------- struct capincci ----------------------------------------- */ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) @@ -1029,6 +1046,8 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file) #endif if (mp->nccip == NULL) capiminor_free(mp); + + capiminor_put(mp); } #ifdef _DEBUG_REFCOUNT |