aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2013-12-10 23:45:41 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-11 00:17:42 -0500
commit37cb0620073cb64101d9307931c135c70b2e3f04 (patch)
tree302cb1bf079ddf1b09dd79cb965d55566d2b75a5 /net/tipc
parentef72a7e02a28adfd9d5d0d1de81c0b75f3823aa5 (diff)
tipc: remove TIPC usage of field af_packet_priv in struct net_device
TIPC is currently using the field 'af_packet_priv' in struct net_device as a handle to find the bearer instance associated to the given network device. But, by doing so it is blocking other networking cleanups, such as the one discussed here: http://patchwork.ozlabs.org/patch/178044/ This commit removes this usage from TIPC. Instead, we introduce a new field, 'tipc_ptr', to the net_device structure, to serve this purpose. When TIPC bearer is enabled, the bearer object is associated to 'tipc_ptr'. When a TIPC packet arrives in the recv_msg() upcall from a networking device, the bearer object can now be obtained from 'tipc_ptr'. When a bearer is disabled, the bearer object is detached from its underlying network device by setting 'tipc_ptr' to NULL. Additionally, an RCU lock is used to protect the new pointer. Henceforth, the existing tipc_net_lock is used in write mode to serialize write accesses to this pointer, while the new RCU lock is applied on the read side to ensure that the pointer is 100% valid within its wrapped area for all readers. Signed-off-by: Ying Xue <ying.xue@windriver.com> Cc: Patrick McHardy <kaber@trash.net> Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bearer.h2
-rw-r--r--net/tipc/eth_media.c55
-rw-r--r--net/tipc/ib_media.c54
3 files changed, 65 insertions, 46 deletions
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index e50266aa4d10..91b8d8b92373 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -105,6 +105,7 @@ struct tipc_media {
105 105
106/** 106/**
107 * struct tipc_bearer - Generic TIPC bearer structure 107 * struct tipc_bearer - Generic TIPC bearer structure
108 * @dev: ptr to associated network device
108 * @usr_handle: pointer to additional media-specific information about bearer 109 * @usr_handle: pointer to additional media-specific information about bearer
109 * @mtu: max packet size bearer can support 110 * @mtu: max packet size bearer can support
110 * @lock: spinlock for controlling access to bearer 111 * @lock: spinlock for controlling access to bearer
@@ -127,6 +128,7 @@ struct tipc_media {
127 * care of initializing all other fields. 128 * care of initializing all other fields.
128 */ 129 */
129struct tipc_bearer { 130struct tipc_bearer {
131 struct net_device *dev;
130 void *usr_handle; /* initalized by media */ 132 void *usr_handle; /* initalized by media */
131 u32 mtu; /* initalized by media */ 133 u32 mtu; /* initalized by media */
132 struct tipc_media_addr addr; /* initalized by media */ 134 struct tipc_media_addr addr; /* initalized by media */
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 37fb145476ec..c5f685dee15b 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -63,6 +63,9 @@ static int eth_started;
63 63
64static int recv_notification(struct notifier_block *nb, unsigned long evt, 64static int recv_notification(struct notifier_block *nb, unsigned long evt,
65 void *dv); 65 void *dv);
66static int recv_msg(struct sk_buff *buf, struct net_device *dev,
67 struct packet_type *pt, struct net_device *orig_dev);
68
66/* 69/*
67 * Network device notifier info 70 * Network device notifier info
68 */ 71 */
@@ -71,6 +74,11 @@ static struct notifier_block notifier = {
71 .priority = 0 74 .priority = 0
72}; 75};
73 76
77static struct packet_type tipc_packet_type __read_mostly = {
78 .type = __constant_htons(ETH_P_TIPC),
79 .func = recv_msg,
80};
81
74/** 82/**
75 * eth_media_addr_set - initialize Ethernet media address structure 83 * eth_media_addr_set - initialize Ethernet media address structure
76 * 84 *
@@ -128,20 +136,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
128static int recv_msg(struct sk_buff *buf, struct net_device *dev, 136static int recv_msg(struct sk_buff *buf, struct net_device *dev,
129 struct packet_type *pt, struct net_device *orig_dev) 137 struct packet_type *pt, struct net_device *orig_dev)
130{ 138{
131 struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; 139 struct tipc_bearer *b_ptr;
132 140
133 if (!net_eq(dev_net(dev), &init_net)) { 141 if (!net_eq(dev_net(dev), &init_net)) {
134 kfree_skb(buf); 142 kfree_skb(buf);
135 return NET_RX_DROP; 143 return NET_RX_DROP;
136 } 144 }
137 145
138 if (likely(eb_ptr->bearer)) { 146 rcu_read_lock();
147 b_ptr = rcu_dereference(dev->tipc_ptr);
148 if (likely(b_ptr)) {
139 if (likely(buf->pkt_type <= PACKET_BROADCAST)) { 149 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
140 buf->next = NULL; 150 buf->next = NULL;
141 tipc_recv_msg(buf, eb_ptr->bearer); 151 tipc_recv_msg(buf, b_ptr);
152 rcu_read_unlock();
142 return NET_RX_SUCCESS; 153 return NET_RX_SUCCESS;
143 } 154 }
144 } 155 }
156 rcu_read_unlock();
157
145 kfree_skb(buf); 158 kfree_skb(buf);
146 return NET_RX_DROP; 159 return NET_RX_DROP;
147} 160}
@@ -151,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
151 */ 164 */
152static void setup_media(struct work_struct *work) 165static void setup_media(struct work_struct *work)
153{ 166{
154 struct eth_media *eb_ptr = 167 dev_add_pack(&tipc_packet_type);
155 container_of(work, struct eth_media, setup);
156
157 dev_add_pack(&eb_ptr->tipc_packet_type);
158} 168}
159 169
160/** 170/**
@@ -183,15 +193,11 @@ static int enable_media(struct tipc_bearer *tb_ptr)
183 193
184 /* Create Ethernet bearer for device */ 194 /* Create Ethernet bearer for device */
185 eb_ptr->dev = dev; 195 eb_ptr->dev = dev;
186 eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
187 eb_ptr->tipc_packet_type.dev = dev;
188 eb_ptr->tipc_packet_type.func = recv_msg;
189 eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
190 INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
191 INIT_WORK(&eb_ptr->setup, setup_media); 196 INIT_WORK(&eb_ptr->setup, setup_media);
192 schedule_work(&eb_ptr->setup); 197 schedule_work(&eb_ptr->setup);
193 198
194 /* Associate TIPC bearer with Ethernet bearer */ 199 /* Associate TIPC bearer with Ethernet bearer */
200 tb_ptr->dev = dev;
195 eb_ptr->bearer = tb_ptr; 201 eb_ptr->bearer = tb_ptr;
196 tb_ptr->usr_handle = (void *)eb_ptr; 202 tb_ptr->usr_handle = (void *)eb_ptr;
197 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); 203 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
@@ -200,6 +206,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
200 tb_ptr->bcast_addr.broadcast = 1; 206 tb_ptr->bcast_addr.broadcast = 1;
201 tb_ptr->mtu = dev->mtu; 207 tb_ptr->mtu = dev->mtu;
202 eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); 208 eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
209 rcu_assign_pointer(dev->tipc_ptr, tb_ptr);
203 return 0; 210 return 0;
204} 211}
205 212
@@ -213,7 +220,7 @@ static void cleanup_media(struct work_struct *work)
213 struct eth_media *eb_ptr = 220 struct eth_media *eb_ptr =
214 container_of(work, struct eth_media, cleanup); 221 container_of(work, struct eth_media, cleanup);
215 222
216 dev_remove_pack(&eb_ptr->tipc_packet_type); 223 dev_remove_pack(&tipc_packet_type);
217 dev_put(eb_ptr->dev); 224 dev_put(eb_ptr->dev);
218 eb_ptr->dev = NULL; 225 eb_ptr->dev = NULL;
219} 226}
@@ -232,6 +239,7 @@ static void disable_media(struct tipc_bearer *tb_ptr)
232 eb_ptr->bearer = NULL; 239 eb_ptr->bearer = NULL;
233 INIT_WORK(&eb_ptr->cleanup, cleanup_media); 240 INIT_WORK(&eb_ptr->cleanup, cleanup_media);
234 schedule_work(&eb_ptr->cleanup); 241 schedule_work(&eb_ptr->cleanup);
242 RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL);
235} 243}
236 244
237/** 245/**
@@ -243,21 +251,20 @@ static void disable_media(struct tipc_bearer *tb_ptr)
243static int recv_notification(struct notifier_block *nb, unsigned long evt, 251static int recv_notification(struct notifier_block *nb, unsigned long evt,
244 void *ptr) 252 void *ptr)
245{ 253{
254 struct tipc_bearer *b_ptr;
246 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 255 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
247 struct eth_media *eb_ptr = &eth_media_array[0];
248 struct eth_media *stop = &eth_media_array[MAX_ETH_MEDIA];
249 256
250 if (!net_eq(dev_net(dev), &init_net)) 257 if (!net_eq(dev_net(dev), &init_net))
251 return NOTIFY_DONE; 258 return NOTIFY_DONE;
252 259
253 while ((eb_ptr->dev != dev)) { 260 rcu_read_lock();
254 if (++eb_ptr == stop) 261 b_ptr = rcu_dereference(dev->tipc_ptr);
255 return NOTIFY_DONE; /* couldn't find device */ 262 if (!b_ptr) {
256 } 263 rcu_read_unlock();
257 if (!eb_ptr->bearer)
258 return NOTIFY_DONE; /* bearer had been disabled */ 264 return NOTIFY_DONE; /* bearer had been disabled */
265 }
259 266
260 eb_ptr->bearer->mtu = dev->mtu; 267 b_ptr->mtu = dev->mtu;
261 268
262 switch (evt) { 269 switch (evt) {
263 case NETDEV_CHANGE: 270 case NETDEV_CHANGE:
@@ -266,13 +273,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
266 case NETDEV_DOWN: 273 case NETDEV_DOWN:
267 case NETDEV_CHANGEMTU: 274 case NETDEV_CHANGEMTU:
268 case NETDEV_CHANGEADDR: 275 case NETDEV_CHANGEADDR:
269 tipc_reset_bearer(eb_ptr->bearer); 276 tipc_reset_bearer(b_ptr);
270 break; 277 break;
271 case NETDEV_UNREGISTER: 278 case NETDEV_UNREGISTER:
272 case NETDEV_CHANGENAME: 279 case NETDEV_CHANGENAME:
273 tipc_disable_bearer(eb_ptr->bearer->name); 280 tipc_disable_bearer(b_ptr->name);
274 break; 281 break;
275 } 282 }
283 rcu_read_unlock();
284
276 return NOTIFY_OK; 285 return NOTIFY_OK;
277} 286}
278 287
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index 48e1c07842e6..9fdf03cd672b 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -62,6 +62,13 @@ struct ib_media {
62 62
63static struct ib_media ib_media_array[MAX_IB_MEDIA]; 63static struct ib_media ib_media_array[MAX_IB_MEDIA];
64static int ib_started; 64static int ib_started;
65static int recv_msg(struct sk_buff *buf, struct net_device *dev,
66 struct packet_type *pt, struct net_device *orig_dev);
67
68static struct packet_type tipc_packet_type __read_mostly = {
69 .type = __constant_htons(ETH_P_TIPC),
70 .func = recv_msg,
71};
65 72
66/** 73/**
67 * ib_media_addr_set - initialize Infiniband media address structure 74 * ib_media_addr_set - initialize Infiniband media address structure
@@ -120,20 +127,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
120static int recv_msg(struct sk_buff *buf, struct net_device *dev, 127static int recv_msg(struct sk_buff *buf, struct net_device *dev,
121 struct packet_type *pt, struct net_device *orig_dev) 128 struct packet_type *pt, struct net_device *orig_dev)
122{ 129{
123 struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; 130 struct tipc_bearer *b_ptr;
124 131
125 if (!net_eq(dev_net(dev), &init_net)) { 132 if (!net_eq(dev_net(dev), &init_net)) {
126 kfree_skb(buf); 133 kfree_skb(buf);
127 return NET_RX_DROP; 134 return NET_RX_DROP;
128 } 135 }
129 136
130 if (likely(ib_ptr->bearer)) { 137 rcu_read_lock();
138 b_ptr = rcu_dereference(dev->tipc_ptr);
139 if (likely(b_ptr)) {
131 if (likely(buf->pkt_type <= PACKET_BROADCAST)) { 140 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
132 buf->next = NULL; 141 buf->next = NULL;
133 tipc_recv_msg(buf, ib_ptr->bearer); 142 tipc_recv_msg(buf, b_ptr);
143 rcu_read_unlock();
134 return NET_RX_SUCCESS; 144 return NET_RX_SUCCESS;
135 } 145 }
136 } 146 }
147 rcu_read_unlock();
148
137 kfree_skb(buf); 149 kfree_skb(buf);
138 return NET_RX_DROP; 150 return NET_RX_DROP;
139} 151}
@@ -143,10 +155,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
143 */ 155 */
144static void setup_media(struct work_struct *work) 156static void setup_media(struct work_struct *work)
145{ 157{
146 struct ib_media *ib_ptr = 158 dev_add_pack(&tipc_packet_type);
147 container_of(work, struct ib_media, setup);
148
149 dev_add_pack(&ib_ptr->tipc_packet_type);
150} 159}
151 160
152/** 161/**
@@ -175,15 +184,11 @@ static int enable_media(struct tipc_bearer *tb_ptr)
175 184
176 /* Create InfiniBand bearer for device */ 185 /* Create InfiniBand bearer for device */
177 ib_ptr->dev = dev; 186 ib_ptr->dev = dev;
178 ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
179 ib_ptr->tipc_packet_type.dev = dev;
180 ib_ptr->tipc_packet_type.func = recv_msg;
181 ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr;
182 INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list));
183 INIT_WORK(&ib_ptr->setup, setup_media); 187 INIT_WORK(&ib_ptr->setup, setup_media);
184 schedule_work(&ib_ptr->setup); 188 schedule_work(&ib_ptr->setup);
185 189
186 /* Associate TIPC bearer with InfiniBand bearer */ 190 /* Associate TIPC bearer with InfiniBand bearer */
191 tb_ptr->dev = dev;
187 ib_ptr->bearer = tb_ptr; 192 ib_ptr->bearer = tb_ptr;
188 tb_ptr->usr_handle = (void *)ib_ptr; 193 tb_ptr->usr_handle = (void *)ib_ptr;
189 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); 194 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
@@ -192,6 +197,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
192 tb_ptr->bcast_addr.broadcast = 1; 197 tb_ptr->bcast_addr.broadcast = 1;
193 tb_ptr->mtu = dev->mtu; 198 tb_ptr->mtu = dev->mtu;
194 ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); 199 ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
200 rcu_assign_pointer(dev->tipc_ptr, tb_ptr);
195 return 0; 201 return 0;
196} 202}
197 203
@@ -205,7 +211,7 @@ static void cleanup_bearer(struct work_struct *work)
205 struct ib_media *ib_ptr = 211 struct ib_media *ib_ptr =
206 container_of(work, struct ib_media, cleanup); 212 container_of(work, struct ib_media, cleanup);
207 213
208 dev_remove_pack(&ib_ptr->tipc_packet_type); 214 dev_remove_pack(&tipc_packet_type);
209 dev_put(ib_ptr->dev); 215 dev_put(ib_ptr->dev);
210 ib_ptr->dev = NULL; 216 ib_ptr->dev = NULL;
211} 217}
@@ -224,6 +230,7 @@ static void disable_media(struct tipc_bearer *tb_ptr)
224 ib_ptr->bearer = NULL; 230 ib_ptr->bearer = NULL;
225 INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); 231 INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
226 schedule_work(&ib_ptr->cleanup); 232 schedule_work(&ib_ptr->cleanup);
233 RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL);
227} 234}
228 235
229/** 236/**
@@ -235,21 +242,20 @@ static void disable_media(struct tipc_bearer *tb_ptr)
235static int recv_notification(struct notifier_block *nb, unsigned long evt, 242static int recv_notification(struct notifier_block *nb, unsigned long evt,
236 void *ptr) 243 void *ptr)
237{ 244{
245 struct tipc_bearer *b_ptr;
238 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 246 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
239 struct ib_media *ib_ptr = &ib_media_array[0];
240 struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA];
241 247
242 if (!net_eq(dev_net(dev), &init_net)) 248 if (!net_eq(dev_net(dev), &init_net))
243 return NOTIFY_DONE; 249 return NOTIFY_DONE;
244 250
245 while ((ib_ptr->dev != dev)) { 251 rcu_read_lock();
246 if (++ib_ptr == stop) 252 b_ptr = rcu_dereference(dev->tipc_ptr);
247 return NOTIFY_DONE; /* couldn't find device */ 253 if (!b_ptr) {
248 } 254 rcu_read_unlock();
249 if (!ib_ptr->bearer)
250 return NOTIFY_DONE; /* bearer had been disabled */ 255 return NOTIFY_DONE; /* bearer had been disabled */
256 }
251 257
252 ib_ptr->bearer->mtu = dev->mtu; 258 b_ptr->mtu = dev->mtu;
253 259
254 switch (evt) { 260 switch (evt) {
255 case NETDEV_CHANGE: 261 case NETDEV_CHANGE:
@@ -258,13 +264,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
258 case NETDEV_DOWN: 264 case NETDEV_DOWN:
259 case NETDEV_CHANGEMTU: 265 case NETDEV_CHANGEMTU:
260 case NETDEV_CHANGEADDR: 266 case NETDEV_CHANGEADDR:
261 tipc_reset_bearer(ib_ptr->bearer); 267 tipc_reset_bearer(b_ptr);
262 break; 268 break;
263 case NETDEV_UNREGISTER: 269 case NETDEV_UNREGISTER:
264 case NETDEV_CHANGENAME: 270 case NETDEV_CHANGENAME:
265 tipc_disable_bearer(ib_ptr->bearer->name); 271 tipc_disable_bearer(b_ptr->name);
266 break; 272 break;
267 } 273 }
274 rcu_read_unlock();
275
268 return NOTIFY_OK; 276 return NOTIFY_OK;
269} 277}
270 278