Browse Source

[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>
Arnaldo Carvalho de Melo 19 years ago
parent
commit
6e2144b768
9 changed files with 56 additions and 48 deletions
  1. 15 1
      include/net/llc.h
  2. 0 1
      include/net/llc_conn.h
  3. 1 1
      net/802/p8022.c
  4. 1 1
      net/802/psnap.c
  5. 6 5
      net/llc/af_llc.c
  6. 1 0
      net/llc/llc_c_ac.c
  7. 2 26
      net/llc/llc_conn.c
  8. 23 11
      net/llc/llc_core.c
  9. 7 2
      net/llc/llc_input.c

+ 15 - 1
include/net/llc.h

@@ -17,6 +17,8 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#include <asm/atomic.h>
+
 struct net_device;
 struct packet_type;
 struct sk_buff;
@@ -44,6 +46,7 @@ struct llc_sap {
 	unsigned char	 state;
 	unsigned char	 p_bit;
 	unsigned char	 f_bit;
+	atomic_t         refcnt;
 	int		 (*rcv_func)(struct sk_buff *skb,
 				     struct net_device *dev,
 				     struct packet_type *pt,
@@ -81,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap,
 					       struct net_device *dev,
 					       struct packet_type *pt,
 					       struct net_device *orig_dev));
-extern void llc_sap_close(struct llc_sap *sap);
+static inline void llc_sap_hold(struct llc_sap *sap)
+{
+	atomic_inc(&sap->refcnt);
+}
+
+static inline void llc_sap_put(struct llc_sap *sap)
+{
+	extern void llc_sap_close(struct llc_sap *sap);
+
+	if (atomic_dec_and_test(&sap->refcnt))
+		llc_sap_close(sap);
+}
 
 extern struct llc_sap *llc_sap_find(unsigned char sap_value);
 

+ 0 - 1
include/net/llc_conn.h

@@ -115,5 +115,4 @@ extern void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk);
 
 extern u8 llc_data_accept_state(u8 state);
 extern void llc_build_offset_table(void);
-extern int llc_release_sockets(struct llc_sap *sap);
 #endif /* LLC_CONN_H */

+ 1 - 1
net/802/p8022.c

@@ -56,7 +56,7 @@ struct datalink_proto *register_8022_client(unsigned char type,
 
 void unregister_8022_client(struct datalink_proto *proto)
 {
-	llc_sap_close(proto->sap);
+	llc_sap_put(proto->sap);
 	kfree(proto);
 }
 

+ 1 - 1
net/802/psnap.c

@@ -106,7 +106,7 @@ module_init(snap_init);
 
 static void __exit snap_exit(void)
 {
-	llc_sap_close(snap_sap);
+	llc_sap_put(snap_sap);
 }
 
 module_exit(snap_exit);

+ 6 - 5
net/llc/af_llc.c

@@ -21,6 +21,7 @@
  * See the GNU General Public License for more details.
  */
 #include <linux/config.h>
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/rtnetlink.h>
@@ -188,10 +189,6 @@ static int llc_ui_release(struct socket *sock)
 	if (!sock_flag(sk, SOCK_ZAPPED))
 		llc_sap_remove_socket(llc->sap, sk);
 	release_sock(sk);
-	if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) {
-		llc_release_sockets(llc->sap);
-		llc_sap_close(llc->sap);
-	}
 	if (llc->dev)
 		dev_put(llc->dev);
 	sock_put(sk);
@@ -220,6 +217,7 @@ static int llc_ui_autoport(void)
 				llc_ui_sap_last_autoport = i + 2;
 				goto out;
 			}
+			llc_sap_put(sap);
 		}
 		llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
 		tries++;
@@ -310,6 +308,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
 		rc = -EBUSY; /* some other network layer is using the sap */
 		if (!sap)
 			goto out;
+		llc_sap_hold(sap);
 	} else {
 		struct llc_addr laddr, daddr;
 		struct sock *ask;
@@ -326,7 +325,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
 		ask = llc_lookup_established(sap, &daddr, &laddr);
 		if (ask) {
 			sock_put(ask);
-			goto out;
+			goto out_put;
 		}
 	}
 	llc->laddr.lsap = addr->sllc_sap;
@@ -336,6 +335,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
 	llc_sap_add_socket(sap, sk);
 	sock_reset_flag(sk, SOCK_ZAPPED);
 	rc = 0;
+out_put:
+	llc_sap_put(sap);
 out:
 	return rc;
 }

+ 1 - 0
net/llc/llc_c_ac.c

@@ -75,6 +75,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
 		llc->dev = skb->dev;
 		ev->ind_prim = LLC_CONN_PRIM;
 		rc = 0;
+		llc_sap_put(sap);
 	}
 	return rc;
 }

+ 2 - 26
net/llc/llc_conn.c

@@ -633,6 +633,7 @@ static int llc_find_offset(int state, int ev_type)
  */
 void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
 {
+	llc_sap_hold(sap);
 	write_lock_bh(&sap->sk_list.lock);
 	llc_sk(sk)->sap = sap;
 	sk_add_node(sk, &sap->sk_list.list);
@@ -652,6 +653,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
 	write_lock_bh(&sap->sk_list.lock);
 	sk_del_node_init(sk);
 	write_unlock_bh(&sap->sk_list.lock);
+	llc_sap_put(sap);
 }
 
 /**
@@ -730,32 +732,6 @@ drop:
 static atomic_t llc_sock_nr;
 #endif
 
-/**
- *	llc_release_sockets - releases all sockets in a sap
- *	@sap: sap to release its sockets
- *
- *	Releases all connections of a sap. Returns 0 if all actions complete
- *	successfully, nonzero otherwise
- */
-int llc_release_sockets(struct llc_sap *sap)
-{
-	int rc = 0;
-	struct sock *sk;
-	struct hlist_node *node;
-
-	write_lock_bh(&sap->sk_list.lock);
-
-	sk_for_each(sk, node, &sap->sk_list.list) {
-		llc_sk(sk)->state = LLC_CONN_STATE_TEMP;
-
-		if (llc_send_disc(sk))
-			rc = 1;
-	}
-
-	write_unlock_bh(&sap->sk_list.lock);
-	return rc;
-}
-
 /**
  *	llc_backlog_rcv - Processes rx frames and expired timers.
  *	@sk: LLC sock (p8022 connection)

+ 23 - 11
net/llc/llc_core.c

@@ -40,6 +40,7 @@ static struct llc_sap *llc_sap_alloc(void)
 		sap->state = LLC_SAP_STATE_ACTIVE;
 		memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
 		rwlock_init(&sap->sk_list.lock);
+		atomic_set(&sap->refcnt, 1);
 	}
 	return sap;
 }
@@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void)
  */
 static void llc_add_sap(struct llc_sap *sap)
 {
-	write_lock_bh(&llc_sap_list_lock);
 	list_add_tail(&sap->node, &llc_sap_list);
-	write_unlock_bh(&llc_sap_list_lock);
 }
 
 /**
@@ -70,11 +69,25 @@ static void llc_del_sap(struct llc_sap *sap)
 	write_unlock_bh(&llc_sap_list_lock);
 }
 
+struct llc_sap *__llc_sap_find(unsigned char sap_value)
+{
+	struct llc_sap* sap;
+
+	list_for_each_entry(sap, &llc_sap_list, node)
+		if (sap->laddr.lsap == sap_value)
+			goto out;
+	sap = NULL;
+out:
+	return sap;
+}
+
 /**
  *	llc_sap_find - searchs a SAP in station
  *	@sap_value: sap to be found
  *
  *	Searchs for a sap in the sap list of the LLC's station upon the sap ID.
+ *	If the sap is found it will be refcounted and the user will have to do
+ *	a llc_sap_put after use.
  *	Returns the sap or %NULL if not found.
  */
 struct llc_sap *llc_sap_find(unsigned char sap_value)
@@ -82,11 +95,9 @@ struct llc_sap *llc_sap_find(unsigned char sap_value)
 	struct llc_sap* sap;
 
 	read_lock_bh(&llc_sap_list_lock);
-	list_for_each_entry(sap, &llc_sap_list, node)
-		if (sap->laddr.lsap == sap_value)
-			goto out;
-	sap = NULL;
-out:
+	sap = __llc_sap_find(sap_value);
+	if (sap)
+		llc_sap_hold(sap);
 	read_unlock_bh(&llc_sap_list_lock);
 	return sap;
 }
@@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
 					 struct packet_type *pt,
 					 struct net_device *orig_dev))
 {
-	struct llc_sap *sap = llc_sap_find(lsap);
+	struct llc_sap *sap = NULL;
 
-	if (sap) { /* SAP already exists */
-		sap = NULL;
+	write_lock_bh(&llc_sap_list_lock);
+	if (__llc_sap_find(lsap)) /* SAP already exists */
 		goto out;
-	}
 	sap = llc_sap_alloc();
 	if (!sap)
 		goto out;
 	sap->laddr.lsap = lsap;
 	sap->rcv_func	= func;
+	llc_sap_hold(sap);
 	llc_add_sap(sap);
 out:
+	write_unlock_bh(&llc_sap_list_lock);
 	return sap;
 }
 

+ 7 - 2
net/llc/llc_input.c

@@ -166,17 +166,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 	 */
 	if (sap->rcv_func) {
 		sap->rcv_func(skb, dev, pt, orig_dev);
-		goto out;
+		goto out_put;
 	}
 	dest = llc_pdu_type(skb);
 	if (unlikely(!dest || !llc_type_handlers[dest - 1]))
-		goto drop;
+		goto drop_put;
 	llc_type_handlers[dest - 1](sap, skb);
+out_put:
+	llc_sap_put(sap);
 out:
 	return 0;
 drop:
 	kfree_skb(skb);
 	goto out;
+drop_put:
+	kfree_skb(skb);
+	goto out_put;
 handle_station:
 	if (!llc_station_handler)
 		goto drop;