diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2010-05-12 11:08:26 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 08:35:58 -0400 |
commit | 11b58e73a3a3d1bbb582370d59f9b2c4d0136b42 (patch) | |
tree | 9ca5b48e368da91f6cc1888440b6ea9ffe9a7e3f /drivers/block/drbd/drbd_main.c | |
parent | 2a80699f807885d501f08a7006f6a56c1c937a6e (diff) |
drbd: factored tl_restart() out of tl_clear().
If IO was frozen for a temporal network outage, resend the
content of the transfer-log into the newly established connection.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_main.c')
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 116 |
1 files changed, 79 insertions, 37 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a86e6f1ff7f4..a8a0341fce53 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -333,59 +333,94 @@ bail: | |||
333 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); | 333 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); |
334 | } | 334 | } |
335 | 335 | ||
336 | |||
337 | /** | 336 | /** |
338 | * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL | 337 | * _tl_restart() - Walks the transfer log, and applies an action to all requests |
339 | * @mdev: DRBD device. | 338 | * @mdev: DRBD device. |
339 | * @what: The action/event to perform with all request objects | ||
340 | * | 340 | * |
341 | * This is called after the connection to the peer was lost. The storage covered | 341 | * @what might be one of connection_lost_while_pending, resend, fail_frozen_disk_io, |
342 | * by the requests on the transfer gets marked as our of sync. Called from the | 342 | * restart_frozen_disk_io. |
343 | * receiver thread and the worker thread. | ||
344 | */ | 343 | */ |
345 | void tl_clear(struct drbd_conf *mdev) | 344 | static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) |
346 | { | 345 | { |
347 | struct drbd_tl_epoch *b, *tmp; | 346 | struct drbd_tl_epoch *b, *tmp, **pn; |
348 | struct list_head *le, *tle; | 347 | struct list_head *le, *tle; |
349 | struct drbd_request *r; | 348 | struct drbd_request *req; |
350 | int new_initial_bnr = net_random(); | 349 | int rv, n_writes, n_reads; |
351 | |||
352 | spin_lock_irq(&mdev->req_lock); | ||
353 | 350 | ||
354 | b = mdev->oldest_tle; | 351 | b = mdev->oldest_tle; |
352 | pn = &mdev->oldest_tle; | ||
355 | while (b) { | 353 | while (b) { |
354 | n_writes = 0; | ||
355 | n_reads = 0; | ||
356 | list_for_each_safe(le, tle, &b->requests) { | 356 | list_for_each_safe(le, tle, &b->requests) { |
357 | r = list_entry(le, struct drbd_request, tl_requests); | 357 | req = list_entry(le, struct drbd_request, tl_requests); |
358 | /* It would be nice to complete outside of spinlock. | 358 | rv = _req_mod(req, what); |
359 | * But this is easier for now. */ | 359 | |
360 | _req_mod(r, connection_lost_while_pending); | 360 | n_writes += (rv & MR_WRITE) >> MR_WRITE_SHIFT; |
361 | n_reads += (rv & MR_READ) >> MR_READ_SHIFT; | ||
361 | } | 362 | } |
362 | tmp = b->next; | 363 | tmp = b->next; |
363 | 364 | ||
364 | /* there could still be requests on that ring list, | 365 | if (n_writes + n_reads) { |
365 | * in case local io is still pending */ | 366 | if (what == resend) { |
366 | list_del(&b->requests); | 367 | b->n_writes = n_writes; |
367 | 368 | if (b->w.cb == NULL) { | |
368 | /* dec_ap_pending corresponding to queue_barrier. | 369 | b->w.cb = w_send_barrier; |
369 | * the newest barrier may not have been queued yet, | 370 | inc_ap_pending(mdev); |
370 | * in which case w.cb is still NULL. */ | 371 | set_bit(CREATE_BARRIER, &mdev->flags); |
371 | if (b->w.cb != NULL) | 372 | } |
372 | dec_ap_pending(mdev); | 373 | |
373 | 374 | drbd_queue_work(&mdev->data.work, &b->w); | |
374 | if (b == mdev->newest_tle) { | 375 | } |
375 | /* recycle, but reinit! */ | 376 | pn = &b->next; |
376 | D_ASSERT(tmp == NULL); | 377 | } else { |
377 | INIT_LIST_HEAD(&b->requests); | 378 | /* there could still be requests on that ring list, |
378 | INIT_LIST_HEAD(&b->w.list); | 379 | * in case local io is still pending */ |
379 | b->w.cb = NULL; | 380 | list_del(&b->requests); |
380 | b->br_number = new_initial_bnr; | 381 | |
381 | b->n_writes = 0; | 382 | /* dec_ap_pending corresponding to queue_barrier. |
382 | 383 | * the newest barrier may not have been queued yet, | |
383 | mdev->oldest_tle = b; | 384 | * in which case w.cb is still NULL. */ |
384 | break; | 385 | if (b->w.cb != NULL) |
386 | dec_ap_pending(mdev); | ||
387 | |||
388 | if (b == mdev->newest_tle) { | ||
389 | /* recycle, but reinit! */ | ||
390 | D_ASSERT(tmp == NULL); | ||
391 | INIT_LIST_HEAD(&b->requests); | ||
392 | INIT_LIST_HEAD(&b->w.list); | ||
393 | b->w.cb = NULL; | ||
394 | b->br_number = net_random(); | ||
395 | b->n_writes = 0; | ||
396 | |||
397 | *pn = b; | ||
398 | break; | ||
399 | } | ||
400 | *pn = tmp; | ||
401 | kfree(b); | ||
385 | } | 402 | } |
386 | kfree(b); | ||
387 | b = tmp; | 403 | b = tmp; |
388 | } | 404 | } |
405 | } | ||
406 | |||
407 | |||
408 | /** | ||
409 | * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL | ||
410 | * @mdev: DRBD device. | ||
411 | * | ||
412 | * This is called after the connection to the peer was lost. The storage covered | ||
413 | * by the requests on the transfer gets marked as our of sync. Called from the | ||
414 | * receiver thread and the worker thread. | ||
415 | */ | ||
416 | void tl_clear(struct drbd_conf *mdev) | ||
417 | { | ||
418 | struct list_head *le, *tle; | ||
419 | struct drbd_request *r; | ||
420 | |||
421 | spin_lock_irq(&mdev->req_lock); | ||
422 | |||
423 | _tl_restart(mdev, connection_lost_while_pending); | ||
389 | 424 | ||
390 | /* we expect this list to be empty. */ | 425 | /* we expect this list to be empty. */ |
391 | D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); | 426 | D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); |
@@ -406,6 +441,13 @@ void tl_clear(struct drbd_conf *mdev) | |||
406 | spin_unlock_irq(&mdev->req_lock); | 441 | spin_unlock_irq(&mdev->req_lock); |
407 | } | 442 | } |
408 | 443 | ||
444 | void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) | ||
445 | { | ||
446 | spin_lock_irq(&mdev->req_lock); | ||
447 | _tl_restart(mdev, what); | ||
448 | spin_unlock_irq(&mdev->req_lock); | ||
449 | } | ||
450 | |||
409 | /** | 451 | /** |
410 | * cl_wide_st_chg() - TRUE if the state change is a cluster wide one | 452 | * cl_wide_st_chg() - TRUE if the state change is a cluster wide one |
411 | * @mdev: DRBD device. | 453 | * @mdev: DRBD device. |