aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-18 19:45:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-18 19:45:01 -0400
commit2e0c17d100c35e843dac1e99daf19b5e2b3fe168 (patch)
tree5bb58364fb453298819fe479cad95f5fcfeb8edf /net
parent7de4a9a73563e5f6f3c153015fadee433a443241 (diff)
parent22001a13d09d82772e831dcdac0553994a4bac5d (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (39 commits) gigaset: fix build failure bridge: Make first arg to deliver_clone const. bridge br_multicast: Don't refer to BR_INPUT_SKB_CB(skb)->mrouters_only without IGMP snooping. route: Fix caught BUG_ON during rt_secret_rebuild_oneshot() bridge br_multicast: Fix skb leakage in error path. bridge br_multicast: Fix handling of Max Response Code in IGMPv3 message. NET: netpoll, fix potential NULL ptr dereference tipc: fix lockdep warning on address assignment l2tp: Fix UDP socket reference count bugs in the pppol2tp driver smsc95xx: wait for PHY to complete reset during init l2tp: Fix oops in pppol2tp_xmit smsc75xx: SMSC LAN75xx USB gigabit ethernet adapter driver ne: Do not use slashes in irq name string NET: ksz884x, fix lock imbalance gigaset: correct range checking off by one error bridge: Fix br_forward crash in promiscuous mode bridge: Move NULL mdb check into br_mdb_ip_get ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe net-2.6 [Bug-Fix][dccp]: fix oops caused after failed initialisation myri: remove dead code ...
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_forward.c18
-rw-r--r--net/bridge/br_input.c4
-rw-r--r--net/bridge/br_multicast.c18
-rw-r--r--net/bridge/br_private.h10
-rw-r--r--net/core/netpoll.c4
-rw-r--r--net/dccp/ipv4.c8
-rw-r--r--net/dccp/ipv6.c8
-rw-r--r--net/dccp/proto.c16
-rw-r--r--net/ipv4/route.c16
-rw-r--r--net/phonet/pn_dev.c3
-rw-r--r--net/phonet/pn_netlink.c3
-rw-r--r--net/tipc/ref.c26
13 files changed, 79 insertions, 57 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index eb7062d2e9e5..90a9024e5c1e 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -40,7 +40,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
40 goto out; 40 goto out;
41 41
42 mdst = br_mdb_get(br, skb); 42 mdst = br_mdb_get(br, skb);
43 if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) 43 if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
44 br_multicast_deliver(mdst, skb); 44 br_multicast_deliver(mdst, skb);
45 else 45 else
46 br_flood_deliver(br, skb); 46 br_flood_deliver(br, skb);
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index d61e6f741125..8dbec83e50ca 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -19,6 +19,11 @@
19#include <linux/netfilter_bridge.h> 19#include <linux/netfilter_bridge.h>
20#include "br_private.h" 20#include "br_private.h"
21 21
22static int deliver_clone(const struct net_bridge_port *prev,
23 struct sk_buff *skb,
24 void (*__packet_hook)(const struct net_bridge_port *p,
25 struct sk_buff *skb));
26
22/* Don't forward packets to originating port or forwarding diasabled */ 27/* Don't forward packets to originating port or forwarding diasabled */
23static inline int should_deliver(const struct net_bridge_port *p, 28static inline int should_deliver(const struct net_bridge_port *p,
24 const struct sk_buff *skb) 29 const struct sk_buff *skb)
@@ -94,17 +99,22 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
94} 99}
95 100
96/* called with rcu_read_lock */ 101/* called with rcu_read_lock */
97void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) 102void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
98{ 103{
99 if (should_deliver(to, skb)) { 104 if (should_deliver(to, skb)) {
100 __br_forward(to, skb); 105 if (skb0)
106 deliver_clone(to, skb, __br_forward);
107 else
108 __br_forward(to, skb);
101 return; 109 return;
102 } 110 }
103 111
104 kfree_skb(skb); 112 if (!skb0)
113 kfree_skb(skb);
105} 114}
106 115
107static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb, 116static int deliver_clone(const struct net_bridge_port *prev,
117 struct sk_buff *skb,
108 void (*__packet_hook)(const struct net_bridge_port *p, 118 void (*__packet_hook)(const struct net_bridge_port *p,
109 struct sk_buff *skb)) 119 struct sk_buff *skb))
110{ 120{
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 53b39851d87d..d74d570fc848 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -70,7 +70,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
70 70
71 if (is_multicast_ether_addr(dest)) { 71 if (is_multicast_ether_addr(dest)) {
72 mdst = br_mdb_get(br, skb); 72 mdst = br_mdb_get(br, skb);
73 if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) { 73 if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
74 if ((mdst && !hlist_unhashed(&mdst->mglist)) || 74 if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
75 br_multicast_is_router(br)) 75 br_multicast_is_router(br))
76 skb2 = skb; 76 skb2 = skb;
@@ -90,7 +90,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
90 90
91 if (skb) { 91 if (skb) {
92 if (dst) 92 if (dst)
93 br_forward(dst->dst, skb); 93 br_forward(dst->dst, skb, skb2);
94 else 94 else
95 br_flood_forward(br, skb, skb2); 95 br_flood_forward(br, skb, skb2);
96 } 96 }
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index fd96a8dc97f4..6980625537ca 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -49,22 +49,23 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(
49static struct net_bridge_mdb_entry *br_mdb_ip_get( 49static struct net_bridge_mdb_entry *br_mdb_ip_get(
50 struct net_bridge_mdb_htable *mdb, __be32 dst) 50 struct net_bridge_mdb_htable *mdb, __be32 dst)
51{ 51{
52 if (!mdb)
53 return NULL;
54
52 return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst)); 55 return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));
53} 56}
54 57
55struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, 58struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
56 struct sk_buff *skb) 59 struct sk_buff *skb)
57{ 60{
58 struct net_bridge_mdb_htable *mdb = br->mdb; 61 if (br->multicast_disabled)
59
60 if (!mdb || br->multicast_disabled)
61 return NULL; 62 return NULL;
62 63
63 switch (skb->protocol) { 64 switch (skb->protocol) {
64 case htons(ETH_P_IP): 65 case htons(ETH_P_IP):
65 if (BR_INPUT_SKB_CB(skb)->igmp) 66 if (BR_INPUT_SKB_CB(skb)->igmp)
66 break; 67 break;
67 return br_mdb_ip_get(mdb, ip_hdr(skb)->daddr); 68 return br_mdb_ip_get(br->mdb, ip_hdr(skb)->daddr);
68 } 69 }
69 70
70 return NULL; 71 return NULL;
@@ -851,8 +852,8 @@ static int br_multicast_query(struct net_bridge *br,
851 if (ih3->nsrcs) 852 if (ih3->nsrcs)
852 goto out; 853 goto out;
853 854
854 max_delay = ih3->code ? 1 : 855 max_delay = ih3->code ?
855 IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE); 856 IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
856 } 857 }
857 858
858 if (!group) 859 if (!group)
@@ -990,7 +991,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
990 991
991 err = pskb_trim_rcsum(skb2, len); 992 err = pskb_trim_rcsum(skb2, len);
992 if (err) 993 if (err)
993 return err; 994 goto err_out;
994 } 995 }
995 996
996 len -= ip_hdrlen(skb2); 997 len -= ip_hdrlen(skb2);
@@ -1012,7 +1013,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1012 case CHECKSUM_NONE: 1013 case CHECKSUM_NONE:
1013 skb2->csum = 0; 1014 skb2->csum = 0;
1014 if (skb_checksum_complete(skb2)) 1015 if (skb_checksum_complete(skb2))
1015 return -EINVAL; 1016 goto out;
1016 } 1017 }
1017 1018
1018 err = 0; 1019 err = 0;
@@ -1039,6 +1040,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1039 1040
1040out: 1041out:
1041 __skb_push(skb2, offset); 1042 __skb_push(skb2, offset);
1043err_out:
1042 if (skb2 != skb) 1044 if (skb2 != skb)
1043 kfree_skb(skb2); 1045 kfree_skb(skb2);
1044 return err; 1046 return err;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index fef0384e3c0b..846d7d1e2075 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -206,12 +206,20 @@ struct net_bridge
206 206
207struct br_input_skb_cb { 207struct br_input_skb_cb {
208 struct net_device *brdev; 208 struct net_device *brdev;
209#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
209 int igmp; 210 int igmp;
210 int mrouters_only; 211 int mrouters_only;
212#endif
211}; 213};
212 214
213#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb) 215#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
214 216
217#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
218# define BR_INPUT_SKB_CB_MROUTERS_ONLY(__skb) (BR_INPUT_SKB_CB(__skb)->mrouters_only)
219#else
220# define BR_INPUT_SKB_CB_MROUTERS_ONLY(__skb) (0)
221#endif
222
215extern struct notifier_block br_device_notifier; 223extern struct notifier_block br_device_notifier;
216extern const u8 br_group_address[ETH_ALEN]; 224extern const u8 br_group_address[ETH_ALEN];
217 225
@@ -252,7 +260,7 @@ extern void br_deliver(const struct net_bridge_port *to,
252 struct sk_buff *skb); 260 struct sk_buff *skb);
253extern int br_dev_queue_push_xmit(struct sk_buff *skb); 261extern int br_dev_queue_push_xmit(struct sk_buff *skb);
254extern void br_forward(const struct net_bridge_port *to, 262extern void br_forward(const struct net_bridge_port *to,
255 struct sk_buff *skb); 263 struct sk_buff *skb, struct sk_buff *skb0);
256extern int br_forward_finish(struct sk_buff *skb); 264extern int br_forward_finish(struct sk_buff *skb);
257extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb); 265extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
258extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, 266extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 7aa697253765..d4ec38fa64e6 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -735,7 +735,7 @@ int netpoll_setup(struct netpoll *np)
735 npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL); 735 npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
736 if (!npinfo) { 736 if (!npinfo) {
737 err = -ENOMEM; 737 err = -ENOMEM;
738 goto release; 738 goto put;
739 } 739 }
740 740
741 npinfo->rx_flags = 0; 741 npinfo->rx_flags = 0;
@@ -845,7 +845,7 @@ int netpoll_setup(struct netpoll *np)
845 845
846 kfree(npinfo); 846 kfree(npinfo);
847 } 847 }
848 848put:
849 dev_put(ndev); 849 dev_put(ndev);
850 return err; 850 return err;
851} 851}
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index b195c4feaa0a..4071eaf2b361 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -998,11 +998,11 @@ static struct inet_protosw dccp_v4_protosw = {
998 998
999static int __net_init dccp_v4_init_net(struct net *net) 999static int __net_init dccp_v4_init_net(struct net *net)
1000{ 1000{
1001 int err; 1001 if (dccp_hashinfo.bhash == NULL)
1002 return -ESOCKTNOSUPPORT;
1002 1003
1003 err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, 1004 return inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET,
1004 SOCK_DCCP, IPPROTO_DCCP, net); 1005 SOCK_DCCP, IPPROTO_DCCP, net);
1005 return err;
1006} 1006}
1007 1007
1008static void __net_exit dccp_v4_exit_net(struct net *net) 1008static void __net_exit dccp_v4_exit_net(struct net *net)
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 1aec6349e858..af3394df63b7 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1191,11 +1191,11 @@ static struct inet_protosw dccp_v6_protosw = {
1191 1191
1192static int __net_init dccp_v6_init_net(struct net *net) 1192static int __net_init dccp_v6_init_net(struct net *net)
1193{ 1193{
1194 int err; 1194 if (dccp_hashinfo.bhash == NULL)
1195 return -ESOCKTNOSUPPORT;
1195 1196
1196 err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, 1197 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1197 SOCK_DCCP, IPPROTO_DCCP, net); 1198 SOCK_DCCP, IPPROTO_DCCP, net);
1198 return err;
1199} 1199}
1200 1200
1201static void __net_exit dccp_v6_exit_net(struct net *net) 1201static void __net_exit dccp_v6_exit_net(struct net *net)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 0ef7061920c0..aa4cef374fd0 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1036,7 +1036,7 @@ static int __init dccp_init(void)
1036 FIELD_SIZEOF(struct sk_buff, cb)); 1036 FIELD_SIZEOF(struct sk_buff, cb));
1037 rc = percpu_counter_init(&dccp_orphan_count, 0); 1037 rc = percpu_counter_init(&dccp_orphan_count, 0);
1038 if (rc) 1038 if (rc)
1039 goto out; 1039 goto out_fail;
1040 rc = -ENOBUFS; 1040 rc = -ENOBUFS;
1041 inet_hashinfo_init(&dccp_hashinfo); 1041 inet_hashinfo_init(&dccp_hashinfo);
1042 dccp_hashinfo.bind_bucket_cachep = 1042 dccp_hashinfo.bind_bucket_cachep =
@@ -1125,8 +1125,9 @@ static int __init dccp_init(void)
1125 goto out_sysctl_exit; 1125 goto out_sysctl_exit;
1126 1126
1127 dccp_timestamping_init(); 1127 dccp_timestamping_init();
1128out: 1128
1129 return rc; 1129 return 0;
1130
1130out_sysctl_exit: 1131out_sysctl_exit:
1131 dccp_sysctl_exit(); 1132 dccp_sysctl_exit();
1132out_ackvec_exit: 1133out_ackvec_exit:
@@ -1135,18 +1136,19 @@ out_free_dccp_mib:
1135 dccp_mib_exit(); 1136 dccp_mib_exit();
1136out_free_dccp_bhash: 1137out_free_dccp_bhash:
1137 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); 1138 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
1138 dccp_hashinfo.bhash = NULL;
1139out_free_dccp_locks: 1139out_free_dccp_locks:
1140 inet_ehash_locks_free(&dccp_hashinfo); 1140 inet_ehash_locks_free(&dccp_hashinfo);
1141out_free_dccp_ehash: 1141out_free_dccp_ehash:
1142 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order); 1142 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
1143 dccp_hashinfo.ehash = NULL;
1144out_free_bind_bucket_cachep: 1143out_free_bind_bucket_cachep:
1145 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 1144 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
1146 dccp_hashinfo.bind_bucket_cachep = NULL;
1147out_free_percpu: 1145out_free_percpu:
1148 percpu_counter_destroy(&dccp_orphan_count); 1146 percpu_counter_destroy(&dccp_orphan_count);
1149 goto out; 1147out_fail:
1148 dccp_hashinfo.bhash = NULL;
1149 dccp_hashinfo.ehash = NULL;
1150 dccp_hashinfo.bind_bucket_cachep = NULL;
1151 return rc;
1150} 1152}
1151 1153
1152static void __exit dccp_fini(void) 1154static void __exit dccp_fini(void)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index d9b40248b97f..a770df2493d2 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -932,10 +932,8 @@ static void rt_secret_rebuild_oneshot(struct net *net)
932{ 932{
933 del_timer_sync(&net->ipv4.rt_secret_timer); 933 del_timer_sync(&net->ipv4.rt_secret_timer);
934 rt_cache_invalidate(net); 934 rt_cache_invalidate(net);
935 if (ip_rt_secret_interval) { 935 if (ip_rt_secret_interval)
936 net->ipv4.rt_secret_timer.expires += ip_rt_secret_interval; 936 mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval);
937 add_timer(&net->ipv4.rt_secret_timer);
938 }
939} 937}
940 938
941static void rt_emergency_hash_rebuild(struct net *net) 939static void rt_emergency_hash_rebuild(struct net *net)
@@ -3103,22 +3101,20 @@ static void rt_secret_reschedule(int old)
3103 rtnl_lock(); 3101 rtnl_lock();
3104 for_each_net(net) { 3102 for_each_net(net) {
3105 int deleted = del_timer_sync(&net->ipv4.rt_secret_timer); 3103 int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
3104 long time;
3106 3105
3107 if (!new) 3106 if (!new)
3108 continue; 3107 continue;
3109 3108
3110 if (deleted) { 3109 if (deleted) {
3111 long time = net->ipv4.rt_secret_timer.expires - jiffies; 3110 time = net->ipv4.rt_secret_timer.expires - jiffies;
3112 3111
3113 if (time <= 0 || (time += diff) <= 0) 3112 if (time <= 0 || (time += diff) <= 0)
3114 time = 0; 3113 time = 0;
3115
3116 net->ipv4.rt_secret_timer.expires = time;
3117 } else 3114 } else
3118 net->ipv4.rt_secret_timer.expires = new; 3115 time = new;
3119 3116
3120 net->ipv4.rt_secret_timer.expires += jiffies; 3117 mod_timer(&net->ipv4.rt_secret_timer, jiffies + time);
3121 add_timer(&net->ipv4.rt_secret_timer);
3122 } 3118 }
3123 rtnl_unlock(); 3119 rtnl_unlock();
3124} 3120}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index c597cc53a6fb..5c6ae0c701c0 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -107,8 +107,7 @@ static void phonet_device_destroy(struct net_device *dev)
107 if (pnd) { 107 if (pnd) {
108 u8 addr; 108 u8 addr;
109 109
110 for (addr = find_first_bit(pnd->addrs, 64); addr < 64; 110 for_each_set_bit(addr, pnd->addrs, 64)
111 addr = find_next_bit(pnd->addrs, 64, 1+addr))
112 phonet_address_notify(RTM_DELADDR, dev, addr); 111 phonet_address_notify(RTM_DELADDR, dev, addr);
113 kfree(pnd); 112 kfree(pnd);
114 } 113 }
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 2e6c7eb8e76a..fe2e7088ee07 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -141,8 +141,7 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
141 continue; 141 continue;
142 142
143 addr_idx = 0; 143 addr_idx = 0;
144 for (addr = find_first_bit(pnd->addrs, 64); addr < 64; 144 for_each_set_bit(addr, pnd->addrs, 64) {
145 addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
146 if (addr_idx++ < addr_start_idx) 145 if (addr_idx++ < addr_start_idx)
147 continue; 146 continue;
148 147
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 414fc34b8bea..8dea66500cf5 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -153,11 +153,11 @@ void tipc_ref_table_stop(void)
153 153
154u32 tipc_ref_acquire(void *object, spinlock_t **lock) 154u32 tipc_ref_acquire(void *object, spinlock_t **lock)
155{ 155{
156 struct reference *entry;
157 u32 index; 156 u32 index;
158 u32 index_mask; 157 u32 index_mask;
159 u32 next_plus_upper; 158 u32 next_plus_upper;
160 u32 ref; 159 u32 ref;
160 struct reference *entry = NULL;
161 161
162 if (!object) { 162 if (!object) {
163 err("Attempt to acquire reference to non-existent object\n"); 163 err("Attempt to acquire reference to non-existent object\n");
@@ -175,30 +175,36 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
175 index = tipc_ref_table.first_free; 175 index = tipc_ref_table.first_free;
176 entry = &(tipc_ref_table.entries[index]); 176 entry = &(tipc_ref_table.entries[index]);
177 index_mask = tipc_ref_table.index_mask; 177 index_mask = tipc_ref_table.index_mask;
178 /* take lock in case a previous user of entry still holds it */
179 spin_lock_bh(&entry->lock);
180 next_plus_upper = entry->ref; 178 next_plus_upper = entry->ref;
181 tipc_ref_table.first_free = next_plus_upper & index_mask; 179 tipc_ref_table.first_free = next_plus_upper & index_mask;
182 ref = (next_plus_upper & ~index_mask) + index; 180 ref = (next_plus_upper & ~index_mask) + index;
183 entry->ref = ref;
184 entry->object = object;
185 *lock = &entry->lock;
186 } 181 }
187 else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { 182 else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
188 index = tipc_ref_table.init_point++; 183 index = tipc_ref_table.init_point++;
189 entry = &(tipc_ref_table.entries[index]); 184 entry = &(tipc_ref_table.entries[index]);
190 spin_lock_init(&entry->lock); 185 spin_lock_init(&entry->lock);
191 spin_lock_bh(&entry->lock);
192 ref = tipc_ref_table.start_mask + index; 186 ref = tipc_ref_table.start_mask + index;
193 entry->ref = ref;
194 entry->object = object;
195 *lock = &entry->lock;
196 } 187 }
197 else { 188 else {
198 ref = 0; 189 ref = 0;
199 } 190 }
200 write_unlock_bh(&ref_table_lock); 191 write_unlock_bh(&ref_table_lock);
201 192
193 /*
194 * Grab the lock so no one else can modify this entry
195 * While we assign its ref value & object pointer
196 */
197 if (entry) {
198 spin_lock_bh(&entry->lock);
199 entry->ref = ref;
200 entry->object = object;
201 *lock = &entry->lock;
202 /*
203 * keep it locked, the caller is responsible
204 * for unlocking this when they're done with it
205 */
206 }
207
202 return ref; 208 return ref;
203} 209}
204 210