Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 346098
b: refs/heads/master
c: cdfda63
h: refs/heads/master
v: v3
  • Loading branch information
Philipp Reisner committed Nov 8, 2012
1 parent a743734 commit 3dac420
Show file tree
Hide file tree
Showing 13 changed files with 322 additions and 91 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2fcb8f307f6014de9e771799d9ec0f050802c0ac
refs/heads/master: cdfda633d235028e9b27381dedb65416409e8729
75 changes: 58 additions & 17 deletions trunk/drivers/block/drbd/drbd_actlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,44 @@ struct drbd_atodb_wait {

static int w_al_write_transaction(struct drbd_work *, int);

void *drbd_md_get_buffer(struct drbd_conf *mdev)
{
int r;

wait_event(mdev->misc_wait,
(r = atomic_cmpxchg(&mdev->md_io_in_use, 0, 1)) == 0 ||
mdev->state.disk <= D_FAILED);

return r ? NULL : page_address(mdev->md_io_page);
}

void drbd_md_put_buffer(struct drbd_conf *mdev)
{
if (atomic_dec_and_test(&mdev->md_io_in_use))
wake_up(&mdev->misc_wait);
}

static bool md_io_allowed(struct drbd_conf *mdev)
{
enum drbd_disk_state ds = mdev->state.disk;
return ds >= D_NEGOTIATING || ds == D_ATTACHING;
}

void wait_until_done_or_disk_failure(struct drbd_conf *mdev, unsigned int *done)
{
wait_event(mdev->misc_wait, *done || !md_io_allowed(mdev));
}

static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
struct drbd_backing_dev *bdev,
struct page *page, sector_t sector,
int rw, int size)
{
struct bio *bio;
struct drbd_md_io md_io;
int err;

md_io.mdev = mdev;
init_completion(&md_io.event);
md_io.error = 0;
mdev->md_io.done = 0;
mdev->md_io.error = -ENODEV;

if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
rw |= REQ_FUA | REQ_FLUSH;
Expand All @@ -137,17 +163,25 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
err = -EIO;
if (bio_add_page(bio, page, size, 0) != size)
goto out;
bio->bi_private = &md_io;
bio->bi_private = &mdev->md_io;
bio->bi_end_io = drbd_md_io_complete;
bio->bi_rw = rw;

if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* Corresponding put_ldev in drbd_md_io_complete() */
dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n");
err = -ENODEV;
goto out;
}

bio_get(bio); /* one bio_put() is in the completion handler */
atomic_inc(&mdev->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */
if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
bio_endio(bio, -EIO);
else
submit_bio(rw, bio);
wait_for_completion(&md_io.event);
wait_until_done_or_disk_failure(mdev, &mdev->md_io.done);
if (bio_flagged(bio, BIO_UPTODATE))
err = md_io.error;
err = mdev->md_io.error;

out:
bio_put(bio);
Expand All @@ -160,7 +194,7 @@ int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
int err;
struct page *iop = mdev->md_io_page;

D_ASSERT(mutex_is_locked(&mdev->md_io_mutex));
D_ASSERT(atomic_read(&mdev->md_io_in_use) == 1);

BUG_ON(!bdev->md_bdev);

Expand Down Expand Up @@ -344,8 +378,14 @@ w_al_write_transaction(struct drbd_work *w, int unused)
return 0;
}

mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
buffer = page_address(mdev->md_io_page);
buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */
if (!buffer) {
dev_err(DEV, "disk failed while waiting for md_io buffer\n");
aw->err = -EIO;
complete(&((struct update_al_work *)w)->event);
put_ldev(mdev);
return 1;
}

memset(buffer, 0, sizeof(*buffer));
buffer->magic = cpu_to_be32(DRBD_AL_MAGIC);
Expand Down Expand Up @@ -415,7 +455,7 @@ w_al_write_transaction(struct drbd_work *w, int unused)
mdev->al_tr_number++;
}

mutex_unlock(&mdev->md_io_mutex);
drbd_md_put_buffer(mdev);
complete(&((struct update_al_work *)w)->event);
put_ldev(mdev);

Expand Down Expand Up @@ -506,8 +546,9 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
/* lock out all other meta data io for now,
* and make sure the page is mapped.
*/
mutex_lock(&mdev->md_io_mutex);
b = page_address(mdev->md_io_page);
b = drbd_md_get_buffer(mdev);
if (!b)
return 0;

/* Always use the full ringbuffer space for now.
* possible optimization: read in all of it,
Expand All @@ -528,7 +569,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)

/* IO error */
if (rv == -1) {
mutex_unlock(&mdev->md_io_mutex);
drbd_md_put_buffer(mdev);
return 0;
}

Expand Down Expand Up @@ -558,7 +599,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
if (!found_valid) {
if (found_initialized != mx)
dev_warn(DEV, "No usable activity log found.\n");
mutex_unlock(&mdev->md_io_mutex);
drbd_md_put_buffer(mdev);
return 1;
}

Expand All @@ -573,7 +614,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
if (!expect(rv != 0))
goto cancel;
if (rv == -1) {
mutex_unlock(&mdev->md_io_mutex);
drbd_md_put_buffer(mdev);
return 0;
}

Expand Down Expand Up @@ -643,7 +684,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
mdev->al_tr_pos = (to + 1) % (MD_AL_SECTORS*512/MD_BLOCK_SIZE);

/* ok, we are done with it */
mutex_unlock(&mdev->md_io_mutex);
drbd_md_put_buffer(mdev);

dev_info(DEV, "Found %d transactions (%d active extents) in activity log.\n",
transactions, active_extents);
Expand Down
115 changes: 85 additions & 30 deletions trunk/drivers/block/drbd/drbd_bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -918,13 +918,22 @@ void drbd_bm_clear_all(struct drbd_conf *mdev)
struct bm_aio_ctx {
struct drbd_conf *mdev;
atomic_t in_flight;
struct completion done;
unsigned int done;
unsigned flags;
#define BM_AIO_COPY_PAGES 1
#define BM_AIO_WRITE_HINTED 2
int error;
struct kref kref;
};

static void bm_aio_ctx_destroy(struct kref *kref)
{
struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref);

put_ldev(ctx->mdev);
kfree(ctx);
}

/* bv_page may be a copy, or may be the original */
static void bm_async_io_complete(struct bio *bio, int error)
{
Expand Down Expand Up @@ -968,13 +977,16 @@ static void bm_async_io_complete(struct bio *bio, int error)

bio_put(bio);

if (atomic_dec_and_test(&ctx->in_flight))
complete(&ctx->done);
if (atomic_dec_and_test(&ctx->in_flight)) {
ctx->done = 1;
wake_up(&mdev->misc_wait);
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
}
}

static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local)
{
struct bio *bio = bio_alloc_drbd(GFP_KERNEL);
struct bio *bio = bio_alloc_drbd(GFP_NOIO);
struct drbd_conf *mdev = ctx->mdev;
struct drbd_bitmap *b = mdev->bitmap;
struct page *page;
Expand Down Expand Up @@ -1032,12 +1044,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
*/
static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
{
struct bm_aio_ctx ctx = {
.mdev = mdev,
.in_flight = ATOMIC_INIT(1),
.done = COMPLETION_INITIALIZER_ONSTACK(ctx.done),
.flags = flags,
};
struct bm_aio_ctx *ctx;
struct drbd_bitmap *b = mdev->bitmap;
int num_pages, i, count = 0;
unsigned long now;
Expand All @@ -1052,7 +1059,27 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
* For lazy writeout, we don't care for ongoing changes to the bitmap,
* as we submit copies of pages anyways.
*/
if (!ctx.flags)

ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO);
if (!ctx)
return -ENOMEM;

*ctx = (struct bm_aio_ctx) {
.mdev = mdev,
.in_flight = ATOMIC_INIT(1),
.done = 0,
.flags = flags,
.error = 0,
.kref = { ATOMIC_INIT(2) },
};

if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
err = -ENODEV;
goto out;
}

if (!ctx->flags)
WARN_ON(!(BM_LOCKED_MASK & b->bm_flags));

num_pages = b->bm_number_of_pages;
Expand Down Expand Up @@ -1081,32 +1108,40 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
continue;
}
}
atomic_inc(&ctx.in_flight);
bm_page_io_async(&ctx, i, rw);
atomic_inc(&ctx->in_flight);
bm_page_io_async(ctx, i, rw);
++count;
cond_resched();
}

/*
* We initialize ctx.in_flight to one to make sure bm_async_io_complete
* will not complete() early, and decrement / test it here. If there
* We initialize ctx->in_flight to one to make sure bm_async_io_complete
* will not set ctx->done early, and decrement / test it here. If there
* are still some bios in flight, we need to wait for them here.
* If all IO is done already (or nothing had been submitted), there is
* no need to wait. Still, we need to put the kref associated with the
* "in_flight reached zero, all done" event.
*/
if (!atomic_dec_and_test(&ctx.in_flight))
wait_for_completion(&ctx.done);
if (!atomic_dec_and_test(&ctx->in_flight))
wait_until_done_or_disk_failure(mdev, &ctx->done);
else
kref_put(&ctx->kref, &bm_aio_ctx_destroy);

/* summary for global bitmap IO */
if (flags == 0)
dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n",
rw == WRITE ? "WRITE" : "READ",
count, jiffies - now);
rw == WRITE ? "WRITE" : "READ",
count, jiffies - now);

if (ctx.error) {
if (ctx->error) {
dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
drbd_chk_io_error(mdev, 1, true);
err = -EIO; /* ctx.error ? */
err = -EIO; /* ctx->error ? */
}

if (atomic_read(&ctx->in_flight))
err = -EIO; /* Disk failed during IO... */

now = jiffies;
if (rw == WRITE) {
drbd_md_flush(mdev);
Expand All @@ -1121,6 +1156,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);

out:
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
return err;
}

Expand Down Expand Up @@ -1177,28 +1214,46 @@ int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local)
*/
int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local)
{
struct bm_aio_ctx ctx = {
struct bm_aio_ctx *ctx;
int err;

if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) {
dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx);
return 0;
}

ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO);
if (!ctx)
return -ENOMEM;

*ctx = (struct bm_aio_ctx) {
.mdev = mdev,
.in_flight = ATOMIC_INIT(1),
.done = COMPLETION_INITIALIZER_ONSTACK(ctx.done),
.done = 0,
.flags = BM_AIO_COPY_PAGES,
.error = 0,
.kref = { ATOMIC_INIT(2) },
};

if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) {
dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx);
return 0;
if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
err = -ENODEV;
goto out;
}

bm_page_io_async(&ctx, idx, WRITE_SYNC);
wait_for_completion(&ctx.done);
bm_page_io_async(ctx, idx, WRITE_SYNC);
wait_until_done_or_disk_failure(mdev, &ctx->done);

if (ctx.error)
if (ctx->error)
drbd_chk_io_error(mdev, 1, true);
/* that should force detach, so the in memory bitmap will be
* gone in a moment as well. */

mdev->bm_writ_cnt++;
return ctx.error;
err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error;
out:
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
return err;
}

/* NOTE
Expand Down
Loading

0 comments on commit 3dac420

Please sign in to comment.