diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-07-15 11:19:02 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:57:58 -0500 |
commit | 1b7ab15b11716d075b3dca34cf41e8d7aba3cba2 (patch) | |
tree | 3aaa51da655ed15215d5ad1367cf4f0140bc4d89 | |
parent | 9b743da96c8640dbfc864cb5d79c51547c3fadb4 (diff) |
drbd: Fixed w_restart_disk_io() to handle non active AL-extents
Since we now apply the AL in user space onto the bitmap, the AL
is not active for the requests we want to reply.
For that a al_write_transaction() that might be called from
worker context became necessary.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_actlog.c | 70 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 4 |
2 files changed, 45 insertions, 29 deletions
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index da8ffd54fc18..5731d6019518 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c | |||
@@ -112,7 +112,7 @@ struct drbd_atodb_wait { | |||
112 | }; | 112 | }; |
113 | 113 | ||
114 | 114 | ||
115 | static int w_al_write_transaction(struct drbd_work *, int); | 115 | static int al_write_transaction(struct drbd_conf *mdev); |
116 | 116 | ||
117 | void *drbd_md_get_buffer(struct drbd_conf *mdev) | 117 | void *drbd_md_get_buffer(struct drbd_conf *mdev) |
118 | { | 118 | { |
@@ -272,18 +272,13 @@ void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i) | |||
272 | /* Double check: it may have been committed by someone else, | 272 | /* Double check: it may have been committed by someone else, |
273 | * while we have been waiting for the lock. */ | 273 | * while we have been waiting for the lock. */ |
274 | if (mdev->act_log->pending_changes) { | 274 | if (mdev->act_log->pending_changes) { |
275 | struct update_al_work al_work; | 275 | int err; |
276 | init_completion(&al_work.event); | 276 | err = al_write_transaction(mdev); |
277 | al_work.w.cb = w_al_write_transaction; | ||
278 | al_work.w.mdev = mdev; | ||
279 | drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); | ||
280 | wait_for_completion(&al_work.event); | ||
281 | |||
282 | mdev->al_writ_cnt++; | 277 | mdev->al_writ_cnt++; |
283 | 278 | ||
284 | spin_lock_irq(&mdev->al_lock); | 279 | spin_lock_irq(&mdev->al_lock); |
285 | /* FIXME | 280 | /* FIXME |
286 | if (al_work.err) | 281 | if (err) |
287 | we need an "lc_cancel" here; | 282 | we need an "lc_cancel" here; |
288 | */ | 283 | */ |
289 | lc_committed(mdev->act_log); | 284 | lc_committed(mdev->act_log); |
@@ -348,23 +343,20 @@ static unsigned int rs_extent_to_bm_page(unsigned int rs_enr) | |||
348 | } | 343 | } |
349 | 344 | ||
350 | static int | 345 | static int |
351 | w_al_write_transaction(struct drbd_work *w, int unused) | 346 | _al_write_transaction(struct drbd_conf *mdev) |
352 | { | 347 | { |
353 | struct update_al_work *aw = container_of(w, struct update_al_work, w); | ||
354 | struct drbd_conf *mdev = w->mdev; | ||
355 | struct al_transaction_on_disk *buffer; | 348 | struct al_transaction_on_disk *buffer; |
356 | struct lc_element *e; | 349 | struct lc_element *e; |
357 | sector_t sector; | 350 | sector_t sector; |
358 | int i, mx; | 351 | int i, mx; |
359 | unsigned extent_nr; | 352 | unsigned extent_nr; |
360 | unsigned crc = 0; | 353 | unsigned crc = 0; |
354 | int err = 0; | ||
361 | 355 | ||
362 | if (!get_ldev(mdev)) { | 356 | if (!get_ldev(mdev)) { |
363 | dev_err(DEV, "disk is %s, cannot start al transaction\n", | 357 | dev_err(DEV, "disk is %s, cannot start al transaction\n", |
364 | drbd_disk_str(mdev->state.disk)); | 358 | drbd_disk_str(mdev->state.disk)); |
365 | aw->err = -EIO; | 359 | return -EIO; |
366 | complete(&((struct update_al_work *)w)->event); | ||
367 | return 0; | ||
368 | } | 360 | } |
369 | 361 | ||
370 | /* The bitmap write may have failed, causing a state change. */ | 362 | /* The bitmap write may have failed, causing a state change. */ |
@@ -372,19 +364,15 @@ w_al_write_transaction(struct drbd_work *w, int unused) | |||
372 | dev_err(DEV, | 364 | dev_err(DEV, |
373 | "disk is %s, cannot write al transaction\n", | 365 | "disk is %s, cannot write al transaction\n", |
374 | drbd_disk_str(mdev->state.disk)); | 366 | drbd_disk_str(mdev->state.disk)); |
375 | aw->err = -EIO; | ||
376 | complete(&((struct update_al_work *)w)->event); | ||
377 | put_ldev(mdev); | 367 | put_ldev(mdev); |
378 | return 0; | 368 | return -EIO; |
379 | } | 369 | } |
380 | 370 | ||
381 | buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */ | 371 | buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */ |
382 | if (!buffer) { | 372 | if (!buffer) { |
383 | dev_err(DEV, "disk failed while waiting for md_io buffer\n"); | 373 | dev_err(DEV, "disk failed while waiting for md_io buffer\n"); |
384 | aw->err = -EIO; | ||
385 | complete(&((struct update_al_work *)w)->event); | ||
386 | put_ldev(mdev); | 374 | put_ldev(mdev); |
387 | return 1; | 375 | return -ENODEV; |
388 | } | 376 | } |
389 | 377 | ||
390 | memset(buffer, 0, sizeof(*buffer)); | 378 | memset(buffer, 0, sizeof(*buffer)); |
@@ -444,10 +432,10 @@ w_al_write_transaction(struct drbd_work *w, int unused) | |||
444 | buffer->crc32c = cpu_to_be32(crc); | 432 | buffer->crc32c = cpu_to_be32(crc); |
445 | 433 | ||
446 | if (drbd_bm_write_hinted(mdev)) | 434 | if (drbd_bm_write_hinted(mdev)) |
447 | aw->err = -EIO; | 435 | err = -EIO; |
448 | /* drbd_chk_io_error done already */ | 436 | /* drbd_chk_io_error done already */ |
449 | else if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { | 437 | else if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { |
450 | aw->err = -EIO; | 438 | err = -EIO; |
451 | drbd_chk_io_error(mdev, 1, true); | 439 | drbd_chk_io_error(mdev, 1, true); |
452 | } else { | 440 | } else { |
453 | /* advance ringbuffer position and transaction counter */ | 441 | /* advance ringbuffer position and transaction counter */ |
@@ -456,10 +444,42 @@ w_al_write_transaction(struct drbd_work *w, int unused) | |||
456 | } | 444 | } |
457 | 445 | ||
458 | drbd_md_put_buffer(mdev); | 446 | drbd_md_put_buffer(mdev); |
459 | complete(&((struct update_al_work *)w)->event); | ||
460 | put_ldev(mdev); | 447 | put_ldev(mdev); |
461 | 448 | ||
462 | return 0; | 449 | return err; |
450 | } | ||
451 | |||
452 | |||
453 | static int w_al_write_transaction(struct drbd_work *w, int unused) | ||
454 | { | ||
455 | struct update_al_work *aw = container_of(w, struct update_al_work, w); | ||
456 | struct drbd_conf *mdev = w->mdev; | ||
457 | int err; | ||
458 | |||
459 | err = _al_write_transaction(mdev); | ||
460 | aw->err = err; | ||
461 | complete(&aw->event); | ||
462 | |||
463 | return err != -EIO ? err : 0; | ||
464 | } | ||
465 | |||
466 | /* Calls from worker context (see w_restart_disk_io()) need to write the | ||
467 | transaction directly. Others came through generic_make_request(), | ||
468 | those need to delegate it to the worker. */ | ||
469 | static int al_write_transaction(struct drbd_conf *mdev) | ||
470 | { | ||
471 | struct update_al_work al_work; | ||
472 | |||
473 | if (current == mdev->tconn->worker.task) | ||
474 | return _al_write_transaction(mdev); | ||
475 | |||
476 | init_completion(&al_work.event); | ||
477 | al_work.w.cb = w_al_write_transaction; | ||
478 | al_work.w.mdev = mdev; | ||
479 | drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); | ||
480 | wait_for_completion(&al_work.event); | ||
481 | |||
482 | return al_work.err; | ||
463 | } | 483 | } |
464 | 484 | ||
465 | static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext) | 485 | static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext) |
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 9ee9b9fab7a8..c57e47c0a1f5 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -1333,10 +1333,6 @@ int w_restart_disk_io(struct drbd_work *w, int cancel) | |||
1333 | 1333 | ||
1334 | if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG) | 1334 | if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG) |
1335 | drbd_al_begin_io(mdev, &req->i); | 1335 | drbd_al_begin_io(mdev, &req->i); |
1336 | /* Calling drbd_al_begin_io() out of the worker might deadlocks | ||
1337 | theoretically. Practically it can not deadlock, since this is | ||
1338 | only used when unfreezing IOs. All the extents of the requests | ||
1339 | that made it into the TL are already active */ | ||
1340 | 1336 | ||
1341 | drbd_req_make_private_bio(req, req->master_bio); | 1337 | drbd_req_make_private_bio(req, req->master_bio); |
1342 | req->private_bio->bi_bdev = mdev->ldev->backing_bdev; | 1338 | req->private_bio->bi_bdev = mdev->ldev->backing_bdev; |