aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRuss Gorby <russ.gorby@intel.com>2011-06-16 17:20:13 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-01 18:34:50 -0400
commit6ab8fba7fcb012a42d686abd33555b2215071415 (patch)
treee30be9d556f7179ad606cb473e9003c9dea7b4a2 /drivers
parentbcd5abe28f40cc6a935d3339cde27976f6be3f1a (diff)
tty: n_gsm: Added refcount usage to gsm_mux and gsm_dlci structs
The gsm_mux is created/destroyed when ldisc is opened/closed but clients of the MUX channel devices (gsmttyN) may access this structure as long as the TTYs are open. For the open, the ldisc open is guaranteed to preceed the TTY open, but the close has no such guaranteed ordering. As a result, the gsm_mux can be freed in the ldisc close before being accessed by one of the TTY clients. This can happen if the ldisc is removed while there are open, active MUX channels. A similar situation exists for DLCI-0, it is basically a resource shared by MUX and DLCI , and should not be freed while they can be accessed To avoid this, gsm_mux and dlcis now have a reference counter ldisc open takes a reference on the mux and all the dlcis gsmtty_open takes a reference on the mux, dlci0 and its specific dlci. Dropping the last reference initiates the actual free. Signed-off-by: Russ Gorby <russ.gorby@intel.com> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/n_gsm.c111
1 files changed, 91 insertions, 20 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 9a13e510dae..a38114b01fe 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -133,6 +133,7 @@ struct gsm_dlci {
133#define DLCI_OPENING 1 /* Sending SABM not seen UA */ 133#define DLCI_OPENING 1 /* Sending SABM not seen UA */
134#define DLCI_OPEN 2 /* SABM/UA complete */ 134#define DLCI_OPEN 2 /* SABM/UA complete */
135#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ 135#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */
136 struct kref ref; /* freed from port or mux close */
136 struct mutex mutex; 137 struct mutex mutex;
137 138
138 /* Link layer */ 139 /* Link layer */
@@ -194,6 +195,7 @@ struct gsm_mux {
194 struct tty_struct *tty; /* The tty our ldisc is bound to */ 195 struct tty_struct *tty; /* The tty our ldisc is bound to */
195 spinlock_t lock; 196 spinlock_t lock;
196 unsigned int num; 197 unsigned int num;
198 struct kref ref;
197 199
198 /* Events on the GSM channel */ 200 /* Events on the GSM channel */
199 wait_queue_head_t event; 201 wait_queue_head_t event;
@@ -1606,6 +1608,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
1606 if (dlci == NULL) 1608 if (dlci == NULL)
1607 return NULL; 1609 return NULL;
1608 spin_lock_init(&dlci->lock); 1610 spin_lock_init(&dlci->lock);
1611 kref_init(&dlci->ref);
1609 mutex_init(&dlci->mutex); 1612 mutex_init(&dlci->mutex);
1610 dlci->fifo = &dlci->_fifo; 1613 dlci->fifo = &dlci->_fifo;
1611 if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { 1614 if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
@@ -1632,26 +1635,52 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
1632} 1635}
1633 1636
1634/** 1637/**
1635 * gsm_dlci_free - release DLCI 1638 * gsm_dlci_free - free DLCI
1639 * @dlci: DLCI to free
1640 *
1641 * Free up a DLCI.
1642 *
1643 * Can sleep.
1644 */
1645static void gsm_dlci_free(struct kref *ref)
1646{
1647 struct gsm_dlci *dlci = container_of(ref, struct gsm_dlci, ref);
1648
1649 del_timer_sync(&dlci->t1);
1650 dlci->gsm->dlci[dlci->addr] = NULL;
1651 kfifo_free(dlci->fifo);
1652 while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
1653 kfree_skb(dlci->skb);
1654 kfree(dlci);
1655}
1656
1657static inline void dlci_get(struct gsm_dlci *dlci)
1658{
1659 kref_get(&dlci->ref);
1660}
1661
1662static inline void dlci_put(struct gsm_dlci *dlci)
1663{
1664 kref_put(&dlci->ref, gsm_dlci_free);
1665}
1666
1667/**
1668 * gsm_dlci_release - release DLCI
1636 * @dlci: DLCI to destroy 1669 * @dlci: DLCI to destroy
1637 * 1670 *
1638 * Free up a DLCI. Currently to keep the lifetime rules sane we only 1671 * Release a DLCI. Actual free is deferred until either
1639 * clean up DLCI objects when the MUX closes rather than as the port 1672 * mux is closed or tty is closed - whichever is last.
1640 * is closed down on both the tty and mux levels.
1641 * 1673 *
1642 * Can sleep. 1674 * Can sleep.
1643 */ 1675 */
1644static void gsm_dlci_free(struct gsm_dlci *dlci) 1676static void gsm_dlci_release(struct gsm_dlci *dlci)
1645{ 1677{
1646 struct tty_struct *tty = tty_port_tty_get(&dlci->port); 1678 struct tty_struct *tty = tty_port_tty_get(&dlci->port);
1647 if (tty) { 1679 if (tty) {
1648 tty_vhangup(tty); 1680 tty_vhangup(tty);
1649 tty_kref_put(tty); 1681 tty_kref_put(tty);
1650 } 1682 }
1651 del_timer_sync(&dlci->t1); 1683 dlci_put(dlci);
1652 dlci->gsm->dlci[dlci->addr] = NULL;
1653 kfifo_free(dlci->fifo);
1654 kfree(dlci);
1655} 1684}
1656 1685
1657/* 1686/*
@@ -1989,7 +2018,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
1989 /* Free up any link layer users */ 2018 /* Free up any link layer users */
1990 for (i = 0; i < NUM_DLCI; i++) 2019 for (i = 0; i < NUM_DLCI; i++)
1991 if (gsm->dlci[i]) 2020 if (gsm->dlci[i])
1992 gsm_dlci_free(gsm->dlci[i]); 2021 gsm_dlci_release(gsm->dlci[i]);
1993 /* Now wipe the queues */ 2022 /* Now wipe the queues */
1994 for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) { 2023 for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
1995 gsm->tx_head = txq->next; 2024 gsm->tx_head = txq->next;
@@ -2050,8 +2079,7 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux);
2050 * gsm_free_mux - free up a mux 2079 * gsm_free_mux - free up a mux
2051 * @mux: mux to free 2080 * @mux: mux to free
2052 * 2081 *
2053 * Dispose of allocated resources for a dead mux. No refcounting 2082 * Dispose of allocated resources for a dead mux
2054 * at present so the mux must be truly dead.
2055 */ 2083 */
2056void gsm_free_mux(struct gsm_mux *gsm) 2084void gsm_free_mux(struct gsm_mux *gsm)
2057{ 2085{
@@ -2062,6 +2090,28 @@ void gsm_free_mux(struct gsm_mux *gsm)
2062EXPORT_SYMBOL_GPL(gsm_free_mux); 2090EXPORT_SYMBOL_GPL(gsm_free_mux);
2063 2091
2064/** 2092/**
2093 * gsm_free_muxr - free up a mux
2094 * @mux: mux to free
2095 *
2096 * Dispose of allocated resources for a dead mux
2097 */
2098static void gsm_free_muxr(struct kref *ref)
2099{
2100 struct gsm_mux *gsm = container_of(ref, struct gsm_mux, ref);
2101 gsm_free_mux(gsm);
2102}
2103
2104static inline void mux_get(struct gsm_mux *gsm)
2105{
2106 kref_get(&gsm->ref);
2107}
2108
2109static inline void mux_put(struct gsm_mux *gsm)
2110{
2111 kref_put(&gsm->ref, gsm_free_muxr);
2112}
2113
2114/**
2065 * gsm_alloc_mux - allocate a mux 2115 * gsm_alloc_mux - allocate a mux
2066 * 2116 *
2067 * Creates a new mux ready for activation. 2117 * Creates a new mux ready for activation.
@@ -2084,6 +2134,7 @@ struct gsm_mux *gsm_alloc_mux(void)
2084 return NULL; 2134 return NULL;
2085 } 2135 }
2086 spin_lock_init(&gsm->lock); 2136 spin_lock_init(&gsm->lock);
2137 kref_init(&gsm->ref);
2087 2138
2088 gsm->t1 = T1; 2139 gsm->t1 = T1;
2089 gsm->t2 = T2; 2140 gsm->t2 = T2;
@@ -2255,7 +2306,7 @@ static void gsmld_close(struct tty_struct *tty)
2255 2306
2256 gsmld_flush_buffer(tty); 2307 gsmld_flush_buffer(tty);
2257 /* Do other clean up here */ 2308 /* Do other clean up here */
2258 gsm_free_mux(gsm); 2309 mux_put(gsm);
2259} 2310}
2260 2311
2261/** 2312/**
@@ -2554,12 +2605,22 @@ static void net_free(struct kref *ref)
2554 } 2605 }
2555} 2606}
2556 2607
2608static inline void muxnet_get(struct gsm_mux_net *mux_net)
2609{
2610 kref_get(&mux_net->ref);
2611}
2612
2613static inline void muxnet_put(struct gsm_mux_net *mux_net)
2614{
2615 kref_put(&mux_net->ref, net_free);
2616}
2617
2557static int gsm_mux_net_start_xmit(struct sk_buff *skb, 2618static int gsm_mux_net_start_xmit(struct sk_buff *skb,
2558 struct net_device *net) 2619 struct net_device *net)
2559{ 2620{
2560 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); 2621 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
2561 struct gsm_dlci *dlci = mux_net->dlci; 2622 struct gsm_dlci *dlci = mux_net->dlci;
2562 kref_get(&mux_net->ref); 2623 muxnet_get(mux_net);
2563 2624
2564 skb_queue_head(&dlci->skb_list, skb); 2625 skb_queue_head(&dlci->skb_list, skb);
2565 STATS(net).tx_packets++; 2626 STATS(net).tx_packets++;
@@ -2567,7 +2628,7 @@ static int gsm_mux_net_start_xmit(struct sk_buff *skb,
2567 gsm_dlci_data_kick(dlci); 2628 gsm_dlci_data_kick(dlci);
2568 /* And tell the kernel when the last transmit started. */ 2629 /* And tell the kernel when the last transmit started. */
2569 net->trans_start = jiffies; 2630 net->trans_start = jiffies;
2570 kref_put(&mux_net->ref, net_free); 2631 muxnet_put(mux_net);
2571 return NETDEV_TX_OK; 2632 return NETDEV_TX_OK;
2572} 2633}
2573 2634
@@ -2587,14 +2648,14 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
2587 struct net_device *net = dlci->net; 2648 struct net_device *net = dlci->net;
2588 struct sk_buff *skb; 2649 struct sk_buff *skb;
2589 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); 2650 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
2590 kref_get(&mux_net->ref); 2651 muxnet_get(mux_net);
2591 2652
2592 /* Allocate an sk_buff */ 2653 /* Allocate an sk_buff */
2593 skb = dev_alloc_skb(size + NET_IP_ALIGN); 2654 skb = dev_alloc_skb(size + NET_IP_ALIGN);
2594 if (!skb) { 2655 if (!skb) {
2595 /* We got no receive buffer. */ 2656 /* We got no receive buffer. */
2596 STATS(net).rx_dropped++; 2657 STATS(net).rx_dropped++;
2597 kref_put(&mux_net->ref, net_free); 2658 muxnet_put(mux_net);
2598 return; 2659 return;
2599 } 2660 }
2600 skb_reserve(skb, NET_IP_ALIGN); 2661 skb_reserve(skb, NET_IP_ALIGN);
@@ -2609,7 +2670,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
2609 /* update out statistics */ 2670 /* update out statistics */
2610 STATS(net).rx_packets++; 2671 STATS(net).rx_packets++;
2611 STATS(net).rx_bytes += size; 2672 STATS(net).rx_bytes += size;
2612 kref_put(&mux_net->ref, net_free); 2673 muxnet_put(mux_net);
2613 return; 2674 return;
2614} 2675}
2615 2676
@@ -2652,7 +2713,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci)
2652 if (!dlci->net) 2713 if (!dlci->net)
2653 return; 2714 return;
2654 mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); 2715 mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net);
2655 kref_put(&mux_net->ref, net_free); 2716 muxnet_put(mux_net);
2656} 2717}
2657 2718
2658 2719
@@ -2814,6 +2875,9 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
2814 port = &dlci->port; 2875 port = &dlci->port;
2815 port->count++; 2876 port->count++;
2816 tty->driver_data = dlci; 2877 tty->driver_data = dlci;
2878 dlci_get(dlci);
2879 dlci_get(dlci->gsm->dlci[0]);
2880 mux_get(dlci->gsm);
2817 tty_port_tty_set(port, tty); 2881 tty_port_tty_set(port, tty);
2818 2882
2819 dlci->modem_rx = 0; 2883 dlci->modem_rx = 0;
@@ -2829,16 +2893,23 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
2829static void gsmtty_close(struct tty_struct *tty, struct file *filp) 2893static void gsmtty_close(struct tty_struct *tty, struct file *filp)
2830{ 2894{
2831 struct gsm_dlci *dlci = tty->driver_data; 2895 struct gsm_dlci *dlci = tty->driver_data;
2896 struct gsm_mux *gsm;
2897
2832 if (dlci == NULL) 2898 if (dlci == NULL)
2833 return; 2899 return;
2834 mutex_lock(&dlci->mutex); 2900 mutex_lock(&dlci->mutex);
2835 gsm_destroy_network(dlci); 2901 gsm_destroy_network(dlci);
2836 mutex_unlock(&dlci->mutex); 2902 mutex_unlock(&dlci->mutex);
2903 gsm = dlci->gsm;
2837 if (tty_port_close_start(&dlci->port, tty, filp) == 0) 2904 if (tty_port_close_start(&dlci->port, tty, filp) == 0)
2838 return; 2905 goto out;
2839 gsm_dlci_begin_close(dlci); 2906 gsm_dlci_begin_close(dlci);
2840 tty_port_close_end(&dlci->port, tty); 2907 tty_port_close_end(&dlci->port, tty);
2841 tty_port_tty_set(&dlci->port, NULL); 2908 tty_port_tty_set(&dlci->port, NULL);
2909out:
2910 dlci_put(dlci);
2911 dlci_put(gsm->dlci[0]);
2912 mux_put(gsm);
2842} 2913}
2843 2914
2844static void gsmtty_hangup(struct tty_struct *tty) 2915static void gsmtty_hangup(struct tty_struct *tty)