md: support bitmap offset appropriate for external-metadata arrays.
NeilBrown [Mon, 14 Dec 2009 01:49:54 +0000 (12:49 +1100)]
For md arrays were metadata is managed externally, the kernel does not
know about a superblock so the superblock offset is 0.
If we want to have a write-intent-bitmap near the end of the
devices of such an array, we should support sector_t sized offset.
We need offset be possibly negative for when the bitmap is before
the metadata, so use loff_t instead.

Also add sanity check that bitmap does not overlap with data.

Signed-off-by: NeilBrown <neilb@suse.de>

drivers/md/bitmap.c
drivers/md/md.h

index b1bcd36..9588654 100644 (file)
@@ -212,7 +212,7 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
  */
 
 /* IO operations when bitmap is stored near all superblocks */
-static struct page *read_sb_page(mddev_t *mddev, long offset,
+static struct page *read_sb_page(mddev_t *mddev, loff_t offset,
                                 struct page *page,
                                 unsigned long index, int size)
 {
@@ -287,14 +287,22 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
 
        while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
                        int size = PAGE_SIZE;
-                       long offset = mddev->bitmap_info.offset;
+                       loff_t offset = mddev->bitmap_info.offset;
                        if (page->index == bitmap->file_pages-1)
                                size = roundup(bitmap->last_page_size,
                                               bdev_logical_block_size(rdev->bdev));
                        /* Just make sure we aren't corrupting data or
                         * metadata
                         */
-                       if (offset < 0) {
+                       if (mddev->external) {
+                               /* Bitmap could be anywhere. */
+                               if (rdev->sb_start + offset + (page->index *(PAGE_SIZE/512)) >
+                                   rdev->data_offset &&
+                                   rdev->sb_start + offset < 
+                                   rdev->data_offset + mddev->dev_sectors +
+                                   (PAGE_SIZE/512))
+                                       goto bad_alignment;
+                       } else if (offset < 0) {
                                /* DATA  BITMAP METADATA  */
                                if (offset
                                    + (long)(page->index * (PAGE_SIZE/512))
index 4b07e0a..df69295 100644 (file)
@@ -282,11 +282,13 @@ struct mddev_s
        struct bitmap                   *bitmap; /* the bitmap for the device */
        struct {
                struct file             *file; /* the bitmap file */
-               long                    offset; /* offset from superblock of
+               loff_t                  offset; /* offset from superblock of
                                                 * start of bitmap. May be
                                                 * negative, but not '0'
+                                                * For external metadata, offset
+                                                * from start of device. 
                                                 */
-               long                    default_offset; /* this is the offset to use when
+               loff_t                  default_offset; /* this is the offset to use when
                                                         * hot-adding a bitmap.  It should
                                                         * eventually be settable by sysfs.
                                                         */