diff options
Diffstat (limited to 'drivers/net/xen-netback')
-rw-r--r-- | drivers/net/xen-netback/common.h | 1 | ||||
-rw-r--r-- | drivers/net/xen-netback/interface.c | 28 | ||||
-rw-r--r-- | drivers/net/xen-netback/netback.c | 94 | ||||
-rw-r--r-- | drivers/net/xen-netback/xenbus.c | 155 |
4 files changed, 203 insertions, 75 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index a1977430ddfb..5715318d6bab 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
@@ -184,6 +184,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
184 | unsigned long rx_ring_ref, unsigned int tx_evtchn, | 184 | unsigned long rx_ring_ref, unsigned int tx_evtchn, |
185 | unsigned int rx_evtchn); | 185 | unsigned int rx_evtchn); |
186 | void xenvif_disconnect(struct xenvif *vif); | 186 | void xenvif_disconnect(struct xenvif *vif); |
187 | void xenvif_free(struct xenvif *vif); | ||
187 | 188 | ||
188 | int xenvif_xenbus_init(void); | 189 | int xenvif_xenbus_init(void); |
189 | void xenvif_xenbus_fini(void); | 190 | void xenvif_xenbus_fini(void); |
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 625c6f49cfba..01bb854c7f62 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
@@ -353,6 +353,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, | |||
353 | } | 353 | } |
354 | 354 | ||
355 | netdev_dbg(dev, "Successfully created xenvif\n"); | 355 | netdev_dbg(dev, "Successfully created xenvif\n"); |
356 | |||
357 | __module_get(THIS_MODULE); | ||
358 | |||
356 | return vif; | 359 | return vif; |
357 | } | 360 | } |
358 | 361 | ||
@@ -366,8 +369,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
366 | if (vif->tx_irq) | 369 | if (vif->tx_irq) |
367 | return 0; | 370 | return 0; |
368 | 371 | ||
369 | __module_get(THIS_MODULE); | ||
370 | |||
371 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); | 372 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); |
372 | if (err < 0) | 373 | if (err < 0) |
373 | goto err; | 374 | goto err; |
@@ -406,7 +407,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
406 | 407 | ||
407 | init_waitqueue_head(&vif->wq); | 408 | init_waitqueue_head(&vif->wq); |
408 | vif->task = kthread_create(xenvif_kthread, | 409 | vif->task = kthread_create(xenvif_kthread, |
409 | (void *)vif, vif->dev->name); | 410 | (void *)vif, "%s", vif->dev->name); |
410 | if (IS_ERR(vif->task)) { | 411 | if (IS_ERR(vif->task)) { |
411 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); | 412 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); |
412 | err = PTR_ERR(vif->task); | 413 | err = PTR_ERR(vif->task); |
@@ -452,12 +453,6 @@ void xenvif_carrier_off(struct xenvif *vif) | |||
452 | 453 | ||
453 | void xenvif_disconnect(struct xenvif *vif) | 454 | void xenvif_disconnect(struct xenvif *vif) |
454 | { | 455 | { |
455 | /* Disconnect funtion might get called by generic framework | ||
456 | * even before vif connects, so we need to check if we really | ||
457 | * need to do a module_put. | ||
458 | */ | ||
459 | int need_module_put = 0; | ||
460 | |||
461 | if (netif_carrier_ok(vif->dev)) | 456 | if (netif_carrier_ok(vif->dev)) |
462 | xenvif_carrier_off(vif); | 457 | xenvif_carrier_off(vif); |
463 | 458 | ||
@@ -468,23 +463,22 @@ void xenvif_disconnect(struct xenvif *vif) | |||
468 | unbind_from_irqhandler(vif->tx_irq, vif); | 463 | unbind_from_irqhandler(vif->tx_irq, vif); |
469 | unbind_from_irqhandler(vif->rx_irq, vif); | 464 | unbind_from_irqhandler(vif->rx_irq, vif); |
470 | } | 465 | } |
471 | /* vif->irq is valid, we had a module_get in | 466 | vif->tx_irq = 0; |
472 | * xenvif_connect. | ||
473 | */ | ||
474 | need_module_put = 1; | ||
475 | } | 467 | } |
476 | 468 | ||
477 | if (vif->task) | 469 | if (vif->task) |
478 | kthread_stop(vif->task); | 470 | kthread_stop(vif->task); |
479 | 471 | ||
472 | xenvif_unmap_frontend_rings(vif); | ||
473 | } | ||
474 | |||
475 | void xenvif_free(struct xenvif *vif) | ||
476 | { | ||
480 | netif_napi_del(&vif->napi); | 477 | netif_napi_del(&vif->napi); |
481 | 478 | ||
482 | unregister_netdev(vif->dev); | 479 | unregister_netdev(vif->dev); |
483 | 480 | ||
484 | xenvif_unmap_frontend_rings(vif); | ||
485 | |||
486 | free_netdev(vif->dev); | 481 | free_netdev(vif->dev); |
487 | 482 | ||
488 | if (need_module_put) | 483 | module_put(THIS_MODULE); |
489 | module_put(THIS_MODULE); | ||
490 | } | 484 | } |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 956130c70036..f3e591c611de 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -212,6 +212,49 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head) | |||
212 | return false; | 212 | return false; |
213 | } | 213 | } |
214 | 214 | ||
215 | struct xenvif_count_slot_state { | ||
216 | unsigned long copy_off; | ||
217 | bool head; | ||
218 | }; | ||
219 | |||
220 | unsigned int xenvif_count_frag_slots(struct xenvif *vif, | ||
221 | unsigned long offset, unsigned long size, | ||
222 | struct xenvif_count_slot_state *state) | ||
223 | { | ||
224 | unsigned count = 0; | ||
225 | |||
226 | offset &= ~PAGE_MASK; | ||
227 | |||
228 | while (size > 0) { | ||
229 | unsigned long bytes; | ||
230 | |||
231 | bytes = PAGE_SIZE - offset; | ||
232 | |||
233 | if (bytes > size) | ||
234 | bytes = size; | ||
235 | |||
236 | if (start_new_rx_buffer(state->copy_off, bytes, state->head)) { | ||
237 | count++; | ||
238 | state->copy_off = 0; | ||
239 | } | ||
240 | |||
241 | if (state->copy_off + bytes > MAX_BUFFER_OFFSET) | ||
242 | bytes = MAX_BUFFER_OFFSET - state->copy_off; | ||
243 | |||
244 | state->copy_off += bytes; | ||
245 | |||
246 | offset += bytes; | ||
247 | size -= bytes; | ||
248 | |||
249 | if (offset == PAGE_SIZE) | ||
250 | offset = 0; | ||
251 | |||
252 | state->head = false; | ||
253 | } | ||
254 | |||
255 | return count; | ||
256 | } | ||
257 | |||
215 | /* | 258 | /* |
216 | * Figure out how many ring slots we're going to need to send @skb to | 259 | * Figure out how many ring slots we're going to need to send @skb to |
217 | * the guest. This function is essentially a dry run of | 260 | * the guest. This function is essentially a dry run of |
@@ -219,48 +262,39 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head) | |||
219 | */ | 262 | */ |
220 | unsigned int xenvif_count_skb_slots(struct xenvif *vif, struct sk_buff *skb) | 263 | unsigned int xenvif_count_skb_slots(struct xenvif *vif, struct sk_buff *skb) |
221 | { | 264 | { |
265 | struct xenvif_count_slot_state state; | ||
222 | unsigned int count; | 266 | unsigned int count; |
223 | int i, copy_off; | 267 | unsigned char *data; |
268 | unsigned i; | ||
224 | 269 | ||
225 | count = DIV_ROUND_UP(skb_headlen(skb), PAGE_SIZE); | 270 | state.head = true; |
271 | state.copy_off = 0; | ||
226 | 272 | ||
227 | copy_off = skb_headlen(skb) % PAGE_SIZE; | 273 | /* Slot for the first (partial) page of data. */ |
274 | count = 1; | ||
228 | 275 | ||
276 | /* Need a slot for the GSO prefix for GSO extra data? */ | ||
229 | if (skb_shinfo(skb)->gso_size) | 277 | if (skb_shinfo(skb)->gso_size) |
230 | count++; | 278 | count++; |
231 | 279 | ||
232 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 280 | data = skb->data; |
233 | unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]); | 281 | while (data < skb_tail_pointer(skb)) { |
234 | unsigned long offset = skb_shinfo(skb)->frags[i].page_offset; | 282 | unsigned long offset = offset_in_page(data); |
235 | unsigned long bytes; | 283 | unsigned long size = PAGE_SIZE - offset; |
236 | |||
237 | offset &= ~PAGE_MASK; | ||
238 | |||
239 | while (size > 0) { | ||
240 | BUG_ON(offset >= PAGE_SIZE); | ||
241 | BUG_ON(copy_off > MAX_BUFFER_OFFSET); | ||
242 | |||
243 | bytes = PAGE_SIZE - offset; | ||
244 | |||
245 | if (bytes > size) | ||
246 | bytes = size; | ||
247 | 284 | ||
248 | if (start_new_rx_buffer(copy_off, bytes, 0)) { | 285 | if (data + size > skb_tail_pointer(skb)) |
249 | count++; | 286 | size = skb_tail_pointer(skb) - data; |
250 | copy_off = 0; | ||
251 | } | ||
252 | 287 | ||
253 | if (copy_off + bytes > MAX_BUFFER_OFFSET) | 288 | count += xenvif_count_frag_slots(vif, offset, size, &state); |
254 | bytes = MAX_BUFFER_OFFSET - copy_off; | ||
255 | 289 | ||
256 | copy_off += bytes; | 290 | data += size; |
291 | } | ||
257 | 292 | ||
258 | offset += bytes; | 293 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
259 | size -= bytes; | 294 | unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]); |
295 | unsigned long offset = skb_shinfo(skb)->frags[i].page_offset; | ||
260 | 296 | ||
261 | if (offset == PAGE_SIZE) | 297 | count += xenvif_count_frag_slots(vif, offset, size, &state); |
262 | offset = 0; | ||
263 | } | ||
264 | } | 298 | } |
265 | return count; | 299 | return count; |
266 | } | 300 | } |
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 1fe48fe364ed..1b08d8798372 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c | |||
@@ -24,6 +24,12 @@ | |||
24 | struct backend_info { | 24 | struct backend_info { |
25 | struct xenbus_device *dev; | 25 | struct xenbus_device *dev; |
26 | struct xenvif *vif; | 26 | struct xenvif *vif; |
27 | |||
28 | /* This is the state that will be reflected in xenstore when any | ||
29 | * active hotplug script completes. | ||
30 | */ | ||
31 | enum xenbus_state state; | ||
32 | |||
27 | enum xenbus_state frontend_state; | 33 | enum xenbus_state frontend_state; |
28 | struct xenbus_watch hotplug_status_watch; | 34 | struct xenbus_watch hotplug_status_watch; |
29 | u8 have_hotplug_status_watch:1; | 35 | u8 have_hotplug_status_watch:1; |
@@ -33,16 +39,20 @@ static int connect_rings(struct backend_info *); | |||
33 | static void connect(struct backend_info *); | 39 | static void connect(struct backend_info *); |
34 | static void backend_create_xenvif(struct backend_info *be); | 40 | static void backend_create_xenvif(struct backend_info *be); |
35 | static void unregister_hotplug_status_watch(struct backend_info *be); | 41 | static void unregister_hotplug_status_watch(struct backend_info *be); |
42 | static void set_backend_state(struct backend_info *be, | ||
43 | enum xenbus_state state); | ||
36 | 44 | ||
37 | static int netback_remove(struct xenbus_device *dev) | 45 | static int netback_remove(struct xenbus_device *dev) |
38 | { | 46 | { |
39 | struct backend_info *be = dev_get_drvdata(&dev->dev); | 47 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
40 | 48 | ||
49 | set_backend_state(be, XenbusStateClosed); | ||
50 | |||
41 | unregister_hotplug_status_watch(be); | 51 | unregister_hotplug_status_watch(be); |
42 | if (be->vif) { | 52 | if (be->vif) { |
43 | kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); | 53 | kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); |
44 | xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); | 54 | xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); |
45 | xenvif_disconnect(be->vif); | 55 | xenvif_free(be->vif); |
46 | be->vif = NULL; | 56 | be->vif = NULL; |
47 | } | 57 | } |
48 | kfree(be); | 58 | kfree(be); |
@@ -136,6 +146,8 @@ static int netback_probe(struct xenbus_device *dev, | |||
136 | if (err) | 146 | if (err) |
137 | goto fail; | 147 | goto fail; |
138 | 148 | ||
149 | be->state = XenbusStateInitWait; | ||
150 | |||
139 | /* This kicks hotplug scripts, so do it immediately. */ | 151 | /* This kicks hotplug scripts, so do it immediately. */ |
140 | backend_create_xenvif(be); | 152 | backend_create_xenvif(be); |
141 | 153 | ||
@@ -208,15 +220,113 @@ static void backend_create_xenvif(struct backend_info *be) | |||
208 | kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); | 220 | kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); |
209 | } | 221 | } |
210 | 222 | ||
223 | static void backend_disconnect(struct backend_info *be) | ||
224 | { | ||
225 | if (be->vif) | ||
226 | xenvif_disconnect(be->vif); | ||
227 | } | ||
211 | 228 | ||
212 | static void disconnect_backend(struct xenbus_device *dev) | 229 | static void backend_connect(struct backend_info *be) |
213 | { | 230 | { |
214 | struct backend_info *be = dev_get_drvdata(&dev->dev); | 231 | if (be->vif) |
232 | connect(be); | ||
233 | } | ||
215 | 234 | ||
216 | if (be->vif) { | 235 | static inline void backend_switch_state(struct backend_info *be, |
217 | xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); | 236 | enum xenbus_state state) |
218 | xenvif_disconnect(be->vif); | 237 | { |
219 | be->vif = NULL; | 238 | struct xenbus_device *dev = be->dev; |
239 | |||
240 | pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state)); | ||
241 | be->state = state; | ||
242 | |||
243 | /* If we are waiting for a hotplug script then defer the | ||
244 | * actual xenbus state change. | ||
245 | */ | ||
246 | if (!be->have_hotplug_status_watch) | ||
247 | xenbus_switch_state(dev, state); | ||
248 | } | ||
249 | |||
250 | /* Handle backend state transitions: | ||
251 | * | ||
252 | * The backend state starts in InitWait and the following transitions are | ||
253 | * allowed. | ||
254 | * | ||
255 | * InitWait -> Connected | ||
256 | * | ||
257 | * ^ \ | | ||
258 | * | \ | | ||
259 | * | \ | | ||
260 | * | \ | | ||
261 | * | \ | | ||
262 | * | \ | | ||
263 | * | V V | ||
264 | * | ||
265 | * Closed <-> Closing | ||
266 | * | ||
267 | * The state argument specifies the eventual state of the backend and the | ||
268 | * function transitions to that state via the shortest path. | ||
269 | */ | ||
270 | static void set_backend_state(struct backend_info *be, | ||
271 | enum xenbus_state state) | ||
272 | { | ||
273 | while (be->state != state) { | ||
274 | switch (be->state) { | ||
275 | case XenbusStateClosed: | ||
276 | switch (state) { | ||
277 | case XenbusStateInitWait: | ||
278 | case XenbusStateConnected: | ||
279 | pr_info("%s: prepare for reconnect\n", | ||
280 | be->dev->nodename); | ||
281 | backend_switch_state(be, XenbusStateInitWait); | ||
282 | break; | ||
283 | case XenbusStateClosing: | ||
284 | backend_switch_state(be, XenbusStateClosing); | ||
285 | break; | ||
286 | default: | ||
287 | BUG(); | ||
288 | } | ||
289 | break; | ||
290 | case XenbusStateInitWait: | ||
291 | switch (state) { | ||
292 | case XenbusStateConnected: | ||
293 | backend_connect(be); | ||
294 | backend_switch_state(be, XenbusStateConnected); | ||
295 | break; | ||
296 | case XenbusStateClosing: | ||
297 | case XenbusStateClosed: | ||
298 | backend_switch_state(be, XenbusStateClosing); | ||
299 | break; | ||
300 | default: | ||
301 | BUG(); | ||
302 | } | ||
303 | break; | ||
304 | case XenbusStateConnected: | ||
305 | switch (state) { | ||
306 | case XenbusStateInitWait: | ||
307 | case XenbusStateClosing: | ||
308 | case XenbusStateClosed: | ||
309 | backend_disconnect(be); | ||
310 | backend_switch_state(be, XenbusStateClosing); | ||
311 | break; | ||
312 | default: | ||
313 | BUG(); | ||
314 | } | ||
315 | break; | ||
316 | case XenbusStateClosing: | ||
317 | switch (state) { | ||
318 | case XenbusStateInitWait: | ||
319 | case XenbusStateConnected: | ||
320 | case XenbusStateClosed: | ||
321 | backend_switch_state(be, XenbusStateClosed); | ||
322 | break; | ||
323 | default: | ||
324 | BUG(); | ||
325 | } | ||
326 | break; | ||
327 | default: | ||
328 | BUG(); | ||
329 | } | ||
220 | } | 330 | } |
221 | } | 331 | } |
222 | 332 | ||
@@ -228,42 +338,33 @@ static void frontend_changed(struct xenbus_device *dev, | |||
228 | { | 338 | { |
229 | struct backend_info *be = dev_get_drvdata(&dev->dev); | 339 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
230 | 340 | ||
231 | pr_debug("frontend state %s\n", xenbus_strstate(frontend_state)); | 341 | pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state)); |
232 | 342 | ||
233 | be->frontend_state = frontend_state; | 343 | be->frontend_state = frontend_state; |
234 | 344 | ||
235 | switch (frontend_state) { | 345 | switch (frontend_state) { |
236 | case XenbusStateInitialising: | 346 | case XenbusStateInitialising: |
237 | if (dev->state == XenbusStateClosed) { | 347 | set_backend_state(be, XenbusStateInitWait); |
238 | pr_info("%s: prepare for reconnect\n", dev->nodename); | ||
239 | xenbus_switch_state(dev, XenbusStateInitWait); | ||
240 | } | ||
241 | break; | 348 | break; |
242 | 349 | ||
243 | case XenbusStateInitialised: | 350 | case XenbusStateInitialised: |
244 | break; | 351 | break; |
245 | 352 | ||
246 | case XenbusStateConnected: | 353 | case XenbusStateConnected: |
247 | if (dev->state == XenbusStateConnected) | 354 | set_backend_state(be, XenbusStateConnected); |
248 | break; | ||
249 | backend_create_xenvif(be); | ||
250 | if (be->vif) | ||
251 | connect(be); | ||
252 | break; | 355 | break; |
253 | 356 | ||
254 | case XenbusStateClosing: | 357 | case XenbusStateClosing: |
255 | if (be->vif) | 358 | set_backend_state(be, XenbusStateClosing); |
256 | kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); | ||
257 | disconnect_backend(dev); | ||
258 | xenbus_switch_state(dev, XenbusStateClosing); | ||
259 | break; | 359 | break; |
260 | 360 | ||
261 | case XenbusStateClosed: | 361 | case XenbusStateClosed: |
262 | xenbus_switch_state(dev, XenbusStateClosed); | 362 | set_backend_state(be, XenbusStateClosed); |
263 | if (xenbus_dev_is_online(dev)) | 363 | if (xenbus_dev_is_online(dev)) |
264 | break; | 364 | break; |
265 | /* fall through if not online */ | 365 | /* fall through if not online */ |
266 | case XenbusStateUnknown: | 366 | case XenbusStateUnknown: |
367 | set_backend_state(be, XenbusStateClosed); | ||
267 | device_unregister(&dev->dev); | 368 | device_unregister(&dev->dev); |
268 | break; | 369 | break; |
269 | 370 | ||
@@ -356,7 +457,9 @@ static void hotplug_status_changed(struct xenbus_watch *watch, | |||
356 | if (IS_ERR(str)) | 457 | if (IS_ERR(str)) |
357 | return; | 458 | return; |
358 | if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) { | 459 | if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) { |
359 | xenbus_switch_state(be->dev, XenbusStateConnected); | 460 | /* Complete any pending state change */ |
461 | xenbus_switch_state(be->dev, be->state); | ||
462 | |||
360 | /* Not interested in this watch anymore. */ | 463 | /* Not interested in this watch anymore. */ |
361 | unregister_hotplug_status_watch(be); | 464 | unregister_hotplug_status_watch(be); |
362 | } | 465 | } |
@@ -386,12 +489,8 @@ static void connect(struct backend_info *be) | |||
386 | err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, | 489 | err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, |
387 | hotplug_status_changed, | 490 | hotplug_status_changed, |
388 | "%s/%s", dev->nodename, "hotplug-status"); | 491 | "%s/%s", dev->nodename, "hotplug-status"); |
389 | if (err) { | 492 | if (!err) |
390 | /* Switch now, since we can't do a watch. */ | ||
391 | xenbus_switch_state(dev, XenbusStateConnected); | ||
392 | } else { | ||
393 | be->have_hotplug_status_watch = 1; | 493 | be->have_hotplug_status_watch = 1; |
394 | } | ||
395 | 494 | ||
396 | netif_wake_queue(be->vif->dev); | 495 | netif_wake_queue(be->vif->dev); |
397 | } | 496 | } |