diff options
author | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-09-22 03:43:05 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-09-22 03:43:05 -0400 |
commit | 6e2144b76840be09924de1626e2dcd7b315f75b3 (patch) | |
tree | 33044cb63f368270229e2b40aa2ad024325c7e8b | |
parent | 04e4223f44b89e50f275cb6b95a58ebe2c4909be (diff) |
[LLC]: Use refcounting with struct llc_sap
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
-rw-r--r-- | include/net/llc.h | 16 | ||||
-rw-r--r-- | include/net/llc_conn.h | 1 | ||||
-rw-r--r-- | net/802/p8022.c | 2 | ||||
-rw-r--r-- | net/802/psnap.c | 2 | ||||
-rw-r--r-- | net/llc/af_llc.c | 11 | ||||
-rw-r--r-- | net/llc/llc_c_ac.c | 1 | ||||
-rw-r--r-- | net/llc/llc_conn.c | 28 | ||||
-rw-r--r-- | net/llc/llc_core.c | 34 | ||||
-rw-r--r-- | net/llc/llc_input.c | 9 |
9 files changed, 56 insertions, 48 deletions
diff --git a/include/net/llc.h b/include/net/llc.h index 8b8e2be289b1..93e5b443a9a7 100644 --- a/include/net/llc.h +++ b/include/net/llc.h | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | 19 | ||
20 | #include <asm/atomic.h> | ||
21 | |||
20 | struct net_device; | 22 | struct net_device; |
21 | struct packet_type; | 23 | struct packet_type; |
22 | struct sk_buff; | 24 | struct sk_buff; |
@@ -44,6 +46,7 @@ struct llc_sap { | |||
44 | unsigned char state; | 46 | unsigned char state; |
45 | unsigned char p_bit; | 47 | unsigned char p_bit; |
46 | unsigned char f_bit; | 48 | unsigned char f_bit; |
49 | atomic_t refcnt; | ||
47 | int (*rcv_func)(struct sk_buff *skb, | 50 | int (*rcv_func)(struct sk_buff *skb, |
48 | struct net_device *dev, | 51 | struct net_device *dev, |
49 | struct packet_type *pt, | 52 | struct packet_type *pt, |
@@ -81,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap, | |||
81 | struct net_device *dev, | 84 | struct net_device *dev, |
82 | struct packet_type *pt, | 85 | struct packet_type *pt, |
83 | struct net_device *orig_dev)); | 86 | struct net_device *orig_dev)); |
84 | extern void llc_sap_close(struct llc_sap *sap); | 87 | static inline void llc_sap_hold(struct llc_sap *sap) |
88 | { | ||
89 | atomic_inc(&sap->refcnt); | ||
90 | } | ||
91 | |||
92 | static inline void llc_sap_put(struct llc_sap *sap) | ||
93 | { | ||
94 | extern void llc_sap_close(struct llc_sap *sap); | ||
95 | |||
96 | if (atomic_dec_and_test(&sap->refcnt)) | ||
97 | llc_sap_close(sap); | ||
98 | } | ||
85 | 99 | ||
86 | extern struct llc_sap *llc_sap_find(unsigned char sap_value); | 100 | extern struct llc_sap *llc_sap_find(unsigned char sap_value); |
87 | 101 | ||
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 8a8ff4810135..b2889218c76a 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h | |||
@@ -115,5 +115,4 @@ extern void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk); | |||
115 | 115 | ||
116 | extern u8 llc_data_accept_state(u8 state); | 116 | extern u8 llc_data_accept_state(u8 state); |
117 | extern void llc_build_offset_table(void); | 117 | extern void llc_build_offset_table(void); |
118 | extern int llc_release_sockets(struct llc_sap *sap); | ||
119 | #endif /* LLC_CONN_H */ | 118 | #endif /* LLC_CONN_H */ |
diff --git a/net/802/p8022.c b/net/802/p8022.c index b24817c63ca8..2530f35241cd 100644 --- a/net/802/p8022.c +++ b/net/802/p8022.c | |||
@@ -56,7 +56,7 @@ struct datalink_proto *register_8022_client(unsigned char type, | |||
56 | 56 | ||
57 | void unregister_8022_client(struct datalink_proto *proto) | 57 | void unregister_8022_client(struct datalink_proto *proto) |
58 | { | 58 | { |
59 | llc_sap_close(proto->sap); | 59 | llc_sap_put(proto->sap); |
60 | kfree(proto); | 60 | kfree(proto); |
61 | } | 61 | } |
62 | 62 | ||
diff --git a/net/802/psnap.c b/net/802/psnap.c index ab80b1fab53c..4d638944d933 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c | |||
@@ -106,7 +106,7 @@ module_init(snap_init); | |||
106 | 106 | ||
107 | static void __exit snap_exit(void) | 107 | static void __exit snap_exit(void) |
108 | { | 108 | { |
109 | llc_sap_close(snap_sap); | 109 | llc_sap_put(snap_sap); |
110 | } | 110 | } |
111 | 111 | ||
112 | module_exit(snap_exit); | 112 | module_exit(snap_exit); |
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index ad9aad807aa8..a75b8f2aab19 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
22 | */ | 22 | */ |
23 | #include <linux/config.h> | 23 | #include <linux/config.h> |
24 | #include <linux/compiler.h> | ||
24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
@@ -188,10 +189,6 @@ static int llc_ui_release(struct socket *sock) | |||
188 | if (!sock_flag(sk, SOCK_ZAPPED)) | 189 | if (!sock_flag(sk, SOCK_ZAPPED)) |
189 | llc_sap_remove_socket(llc->sap, sk); | 190 | llc_sap_remove_socket(llc->sap, sk); |
190 | release_sock(sk); | 191 | release_sock(sk); |
191 | if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) { | ||
192 | llc_release_sockets(llc->sap); | ||
193 | llc_sap_close(llc->sap); | ||
194 | } | ||
195 | if (llc->dev) | 192 | if (llc->dev) |
196 | dev_put(llc->dev); | 193 | dev_put(llc->dev); |
197 | sock_put(sk); | 194 | sock_put(sk); |
@@ -220,6 +217,7 @@ static int llc_ui_autoport(void) | |||
220 | llc_ui_sap_last_autoport = i + 2; | 217 | llc_ui_sap_last_autoport = i + 2; |
221 | goto out; | 218 | goto out; |
222 | } | 219 | } |
220 | llc_sap_put(sap); | ||
223 | } | 221 | } |
224 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; | 222 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; |
225 | tries++; | 223 | tries++; |
@@ -310,6 +308,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
310 | rc = -EBUSY; /* some other network layer is using the sap */ | 308 | rc = -EBUSY; /* some other network layer is using the sap */ |
311 | if (!sap) | 309 | if (!sap) |
312 | goto out; | 310 | goto out; |
311 | llc_sap_hold(sap); | ||
313 | } else { | 312 | } else { |
314 | struct llc_addr laddr, daddr; | 313 | struct llc_addr laddr, daddr; |
315 | struct sock *ask; | 314 | struct sock *ask; |
@@ -326,7 +325,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
326 | ask = llc_lookup_established(sap, &daddr, &laddr); | 325 | ask = llc_lookup_established(sap, &daddr, &laddr); |
327 | if (ask) { | 326 | if (ask) { |
328 | sock_put(ask); | 327 | sock_put(ask); |
329 | goto out; | 328 | goto out_put; |
330 | } | 329 | } |
331 | } | 330 | } |
332 | llc->laddr.lsap = addr->sllc_sap; | 331 | llc->laddr.lsap = addr->sllc_sap; |
@@ -336,6 +335,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
336 | llc_sap_add_socket(sap, sk); | 335 | llc_sap_add_socket(sap, sk); |
337 | sock_reset_flag(sk, SOCK_ZAPPED); | 336 | sock_reset_flag(sk, SOCK_ZAPPED); |
338 | rc = 0; | 337 | rc = 0; |
338 | out_put: | ||
339 | llc_sap_put(sap); | ||
339 | out: | 340 | out: |
340 | return rc; | 341 | return rc; |
341 | } | 342 | } |
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index c1e75103189a..05236c2cbb9e 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c | |||
@@ -75,6 +75,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) | |||
75 | llc->dev = skb->dev; | 75 | llc->dev = skb->dev; |
76 | ev->ind_prim = LLC_CONN_PRIM; | 76 | ev->ind_prim = LLC_CONN_PRIM; |
77 | rc = 0; | 77 | rc = 0; |
78 | llc_sap_put(sap); | ||
78 | } | 79 | } |
79 | return rc; | 80 | return rc; |
80 | } | 81 | } |
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 9f0e10e0978d..ab9e6d7e2875 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c | |||
@@ -633,6 +633,7 @@ static int llc_find_offset(int state, int ev_type) | |||
633 | */ | 633 | */ |
634 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) | 634 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) |
635 | { | 635 | { |
636 | llc_sap_hold(sap); | ||
636 | write_lock_bh(&sap->sk_list.lock); | 637 | write_lock_bh(&sap->sk_list.lock); |
637 | llc_sk(sk)->sap = sap; | 638 | llc_sk(sk)->sap = sap; |
638 | sk_add_node(sk, &sap->sk_list.list); | 639 | sk_add_node(sk, &sap->sk_list.list); |
@@ -652,6 +653,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) | |||
652 | write_lock_bh(&sap->sk_list.lock); | 653 | write_lock_bh(&sap->sk_list.lock); |
653 | sk_del_node_init(sk); | 654 | sk_del_node_init(sk); |
654 | write_unlock_bh(&sap->sk_list.lock); | 655 | write_unlock_bh(&sap->sk_list.lock); |
656 | llc_sap_put(sap); | ||
655 | } | 657 | } |
656 | 658 | ||
657 | /** | 659 | /** |
@@ -731,32 +733,6 @@ static atomic_t llc_sock_nr; | |||
731 | #endif | 733 | #endif |
732 | 734 | ||
733 | /** | 735 | /** |
734 | * llc_release_sockets - releases all sockets in a sap | ||
735 | * @sap: sap to release its sockets | ||
736 | * | ||
737 | * Releases all connections of a sap. Returns 0 if all actions complete | ||
738 | * successfully, nonzero otherwise | ||
739 | */ | ||
740 | int llc_release_sockets(struct llc_sap *sap) | ||
741 | { | ||
742 | int rc = 0; | ||
743 | struct sock *sk; | ||
744 | struct hlist_node *node; | ||
745 | |||
746 | write_lock_bh(&sap->sk_list.lock); | ||
747 | |||
748 | sk_for_each(sk, node, &sap->sk_list.list) { | ||
749 | llc_sk(sk)->state = LLC_CONN_STATE_TEMP; | ||
750 | |||
751 | if (llc_send_disc(sk)) | ||
752 | rc = 1; | ||
753 | } | ||
754 | |||
755 | write_unlock_bh(&sap->sk_list.lock); | ||
756 | return rc; | ||
757 | } | ||
758 | |||
759 | /** | ||
760 | * llc_backlog_rcv - Processes rx frames and expired timers. | 736 | * llc_backlog_rcv - Processes rx frames and expired timers. |
761 | * @sk: LLC sock (p8022 connection) | 737 | * @sk: LLC sock (p8022 connection) |
762 | * @skb: queued rx frame or event | 738 | * @skb: queued rx frame or event |
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 9727455bf0e7..9ccff1266b26 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c | |||
@@ -40,6 +40,7 @@ static struct llc_sap *llc_sap_alloc(void) | |||
40 | sap->state = LLC_SAP_STATE_ACTIVE; | 40 | sap->state = LLC_SAP_STATE_ACTIVE; |
41 | memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN); | 41 | memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN); |
42 | rwlock_init(&sap->sk_list.lock); | 42 | rwlock_init(&sap->sk_list.lock); |
43 | atomic_set(&sap->refcnt, 1); | ||
43 | } | 44 | } |
44 | return sap; | 45 | return sap; |
45 | } | 46 | } |
@@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void) | |||
52 | */ | 53 | */ |
53 | static void llc_add_sap(struct llc_sap *sap) | 54 | static void llc_add_sap(struct llc_sap *sap) |
54 | { | 55 | { |
55 | write_lock_bh(&llc_sap_list_lock); | ||
56 | list_add_tail(&sap->node, &llc_sap_list); | 56 | list_add_tail(&sap->node, &llc_sap_list); |
57 | write_unlock_bh(&llc_sap_list_lock); | ||
58 | } | 57 | } |
59 | 58 | ||
60 | /** | 59 | /** |
@@ -70,11 +69,25 @@ static void llc_del_sap(struct llc_sap *sap) | |||
70 | write_unlock_bh(&llc_sap_list_lock); | 69 | write_unlock_bh(&llc_sap_list_lock); |
71 | } | 70 | } |
72 | 71 | ||
72 | struct llc_sap *__llc_sap_find(unsigned char sap_value) | ||
73 | { | ||
74 | struct llc_sap* sap; | ||
75 | |||
76 | list_for_each_entry(sap, &llc_sap_list, node) | ||
77 | if (sap->laddr.lsap == sap_value) | ||
78 | goto out; | ||
79 | sap = NULL; | ||
80 | out: | ||
81 | return sap; | ||
82 | } | ||
83 | |||
73 | /** | 84 | /** |
74 | * llc_sap_find - searchs a SAP in station | 85 | * llc_sap_find - searchs a SAP in station |
75 | * @sap_value: sap to be found | 86 | * @sap_value: sap to be found |
76 | * | 87 | * |
77 | * Searchs for a sap in the sap list of the LLC's station upon the sap ID. | 88 | * Searchs for a sap in the sap list of the LLC's station upon the sap ID. |
89 | * If the sap is found it will be refcounted and the user will have to do | ||
90 | * a llc_sap_put after use. | ||
78 | * Returns the sap or %NULL if not found. | 91 | * Returns the sap or %NULL if not found. |
79 | */ | 92 | */ |
80 | struct llc_sap *llc_sap_find(unsigned char sap_value) | 93 | struct llc_sap *llc_sap_find(unsigned char sap_value) |
@@ -82,11 +95,9 @@ struct llc_sap *llc_sap_find(unsigned char sap_value) | |||
82 | struct llc_sap* sap; | 95 | struct llc_sap* sap; |
83 | 96 | ||
84 | read_lock_bh(&llc_sap_list_lock); | 97 | read_lock_bh(&llc_sap_list_lock); |
85 | list_for_each_entry(sap, &llc_sap_list, node) | 98 | sap = __llc_sap_find(sap_value); |
86 | if (sap->laddr.lsap == sap_value) | 99 | if (sap) |
87 | goto out; | 100 | llc_sap_hold(sap); |
88 | sap = NULL; | ||
89 | out: | ||
90 | read_unlock_bh(&llc_sap_list_lock); | 101 | read_unlock_bh(&llc_sap_list_lock); |
91 | return sap; | 102 | return sap; |
92 | } | 103 | } |
@@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap, | |||
106 | struct packet_type *pt, | 117 | struct packet_type *pt, |
107 | struct net_device *orig_dev)) | 118 | struct net_device *orig_dev)) |
108 | { | 119 | { |
109 | struct llc_sap *sap = llc_sap_find(lsap); | 120 | struct llc_sap *sap = NULL; |
110 | 121 | ||
111 | if (sap) { /* SAP already exists */ | 122 | write_lock_bh(&llc_sap_list_lock); |
112 | sap = NULL; | 123 | if (__llc_sap_find(lsap)) /* SAP already exists */ |
113 | goto out; | 124 | goto out; |
114 | } | ||
115 | sap = llc_sap_alloc(); | 125 | sap = llc_sap_alloc(); |
116 | if (!sap) | 126 | if (!sap) |
117 | goto out; | 127 | goto out; |
118 | sap->laddr.lsap = lsap; | 128 | sap->laddr.lsap = lsap; |
119 | sap->rcv_func = func; | 129 | sap->rcv_func = func; |
130 | llc_sap_hold(sap); | ||
120 | llc_add_sap(sap); | 131 | llc_add_sap(sap); |
121 | out: | 132 | out: |
133 | write_unlock_bh(&llc_sap_list_lock); | ||
122 | return sap; | 134 | return sap; |
123 | } | 135 | } |
124 | 136 | ||
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 60c1acac7c97..789eec426451 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c | |||
@@ -166,17 +166,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, | |||
166 | */ | 166 | */ |
167 | if (sap->rcv_func) { | 167 | if (sap->rcv_func) { |
168 | sap->rcv_func(skb, dev, pt, orig_dev); | 168 | sap->rcv_func(skb, dev, pt, orig_dev); |
169 | goto out; | 169 | goto out_put; |
170 | } | 170 | } |
171 | dest = llc_pdu_type(skb); | 171 | dest = llc_pdu_type(skb); |
172 | if (unlikely(!dest || !llc_type_handlers[dest - 1])) | 172 | if (unlikely(!dest || !llc_type_handlers[dest - 1])) |
173 | goto drop; | 173 | goto drop_put; |
174 | llc_type_handlers[dest - 1](sap, skb); | 174 | llc_type_handlers[dest - 1](sap, skb); |
175 | out_put: | ||
176 | llc_sap_put(sap); | ||
175 | out: | 177 | out: |
176 | return 0; | 178 | return 0; |
177 | drop: | 179 | drop: |
178 | kfree_skb(skb); | 180 | kfree_skb(skb); |
179 | goto out; | 181 | goto out; |
182 | drop_put: | ||
183 | kfree_skb(skb); | ||
184 | goto out_put; | ||
180 | handle_station: | 185 | handle_station: |
181 | if (!llc_station_handler) | 186 | if (!llc_station_handler) |
182 | goto drop; | 187 | goto drop; |