drbd: fix al-to-on-disk-bitmap for 4k logical_block_size
authorLars Ellenberg <lars.ellenberg@linbit.com>
Thu, 4 Mar 2010 14:52:30 +0000 (15:52 +0100)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 11 Mar 2010 15:33:46 +0000 (16:33 +0100)
Up to now, applying the in-core activity-log to the on-disk
bitmap did not care for logical_block_size.

On logical_block_size != 512 byte, this very likely results
in misalligned block access and spurious "io errors".

We now simply always submit aligned whole 4k blocks, fixing this
for logical block sizes of 512, 1024, 2048 and 4096.

For even larger logical block sizes, this won't work.
But I'm not aware of devices with such properties being available.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_actlog.c

index 17956ff6a08dea7b4de01e707553de42ca60bd22..43e57f395fd601eff1c44b19021d4d58a93dbc83 100644 (file)
@@ -536,7 +536,9 @@ static void atodb_endio(struct bio *bio, int error)
        put_ldev(mdev);
 }
 
+/* sector to word */
 #define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+
 /* activity log to on disk bitmap -- prepare bio unless that sector
  * is already covered by previously prepared bios */
 static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
@@ -546,13 +548,20 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
 {
        struct bio *bio;
        struct page *page;
-       sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
-                                     + mdev->ldev->md.bm_offset;
+       sector_t on_disk_sector;
        unsigned int page_offset = PAGE_SIZE;
        int offset;
        int i = 0;
        int err = -ENOMEM;
 
+       /* We always write aligned, full 4k blocks,
+        * so we can ignore the logical_block_size (for now) */
+       enr &= ~7U;
+       on_disk_sector = enr + mdev->ldev->md.md_offset
+                            + mdev->ldev->md.bm_offset;
+
+       D_ASSERT(!(on_disk_sector & 7U));
+
        /* Check if that enr is already covered by an already created bio.
         * Caution, bios[] is not NULL terminated,
         * but only initialized to all NULL.
@@ -588,7 +597,7 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
 
        offset = S2W(enr);
        drbd_bm_get_lel(mdev, offset,
-                       min_t(size_t, S2W(1), drbd_bm_words(mdev) - offset),
+                       min_t(size_t, S2W(8), drbd_bm_words(mdev) - offset),
                        kmap(page) + page_offset);
        kunmap(page);
 
@@ -597,7 +606,7 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
        bio->bi_bdev = mdev->ldev->md_bdev;
        bio->bi_sector = on_disk_sector;
 
-       if (bio_add_page(bio, page, MD_SECTOR_SIZE, page_offset) != MD_SECTOR_SIZE)
+       if (bio_add_page(bio, page, 4096, page_offset) != 4096)
                goto out_put_page;
 
        atomic_inc(&wc->count);