]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow/bitmap: support adding bitmap via sysfs.
authorNeilBrown <neilb@suse.de>
Fri, 23 Dec 2011 03:10:41 +0000 (14:10 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 23 Dec 2011 03:10:41 +0000 (14:10 +1100)
Adding a bitmap via ioctl can only add it at a fixed location.
That location is not suitable for 4K-block devices.

So allow setting the bitmap location via sysfs if kernel supports it
and aim to always use 4K alignments.

Signed-off-by: NeilBrown <neilb@suse.de>
Grow.c
mdadm.h
super0.c
super1.c
sysfs.c

diff --git a/Grow.c b/Grow.c
index 388c2ce972fa00f1ee7671def6ce694f425b8eac..b2c136023aacc23144cf2f2ebd2a1efb288958da 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -375,12 +375,18 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
                return 1;
        }
        if (strcmp(file, "internal") == 0) {
+               int rv;
                int d;
+               int offset_setable = 0;
+               struct mdinfo *mdi;
                if (st->ss->add_internal_bitmap == NULL) {
                        fprintf(stderr, Name ": Internal bitmaps not supported "
                                "with %s metadata\n", st->ss->name);
                        return 1;
                }
+               mdi = sysfs_read(fd, -1, GET_BITMAP_LOCATION);
+               if (mdi)
+                       offset_setable = 1;
                for (d=0; d< st->max_devs; d++) {
                        mdu_disk_info_t disk;
                        char *dv;
@@ -401,11 +407,13 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
                                        if (st->ss->add_internal_bitmap(
                                                    st,
                                                    &chunk, delay, write_behind,
-                                                   bitmapsize, 0, major)
+                                                   bitmapsize, offset_setable,
+                                                   major)
                                                )
                                                st->ss->write_bitmap(st, fd2);
                                        else {
-                                               fprintf(stderr, Name ": failed to create internal bitmap - chunksize problem.\n");
+                                               fprintf(stderr, Name ": failed "
+                               "to create internal bitmap - chunksize problem.\n");
                                                close(fd2);
                                                return 1;
                                        }
@@ -413,8 +421,16 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
                                close(fd2);
                        }
                }
-               array.state |= (1<<MD_SB_BITMAP_PRESENT);
-               if (ioctl(fd, SET_ARRAY_INFO, &array)!= 0) {
+               if (offset_setable) {
+                       st->ss->getinfo_super(st, mdi, NULL);
+                       sysfs_init(mdi, fd, -1);
+                       rv = sysfs_set_num(mdi, NULL, "bitmap/location",
+                                          mdi->bitmap_offset);
+               } else {
+                       array.state |= (1<<MD_SB_BITMAP_PRESENT);
+                       rv = ioctl(fd, SET_ARRAY_INFO, &array);
+               }
+               if (rv < 0) {
                        if (errno == EBUSY)
                                fprintf(stderr, Name
                                        ": Cannot add bitmap while array is"
diff --git a/mdadm.h b/mdadm.h
index 4f3533f8d650ac9c6e848ec91757e2ae0081b73f..3bcd0526111e878d6885b7f14bb3820964fde768 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -211,6 +211,7 @@ struct mdinfo {
                unsigned long long recovery_start; /* per-device rebuild position */
                #define MaxSector  (~0ULL) /* resync/recovery complete position */
        };
+       unsigned long           bitmap_offset;  /* 0 == none, 1 == a file */
        unsigned long           safe_mode_delay; /* ms delay to mark clean */
        int                     new_level, delta_disks, new_layout, new_chunk;
        int                     errors;
@@ -448,11 +449,13 @@ enum sysfs_read_flags {
        GET_DISKS       = (1 << 7),
        GET_DEGRADED    = (1 << 8),
        GET_SAFEMODE    = (1 << 9),
-       GET_DEVS        = (1 << 10), /* gets role, major, minor */
-       GET_OFFSET      = (1 << 11),
-       GET_SIZE        = (1 << 12),
-       GET_STATE       = (1 << 13),
-       GET_ERROR       = (1 << 14),
+       GET_BITMAP_LOCATION = (1 << 10),
+
+       GET_DEVS        = (1 << 20), /* gets role, major, minor */
+       GET_OFFSET      = (1 << 21),
+       GET_SIZE        = (1 << 22),
+       GET_STATE       = (1 << 23),
+       GET_ERROR       = (1 << 24),
 };
 
 /* If fd >= 0, get the array it is open on,
index f3d0c07cc74750363c9a1b353d1a0f3a39b83053..dab85db8d2d514560147956cdd77fa2994da928b 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -360,6 +360,9 @@ static void getinfo_super0(struct supertype *st, struct mdinfo *info, char *map)
        info->array.state = sb->state;
        info->component_size = sb->size*2;
 
+       if (sb->state & (1<<MD_SB_BITMAP_PRESENT))
+               info->bitmap_offset = 8;
+
        info->disk.state = sb->this_disk.state;
        info->disk.major = sb->this_disk.major;
        info->disk.minor = sb->this_disk.minor;
index 3582f0c883acf67d6361bcbe5b2c54671426f43d..867aa58c0cf7875ce1d8526f19e54eafd7411710 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -578,6 +578,8 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
 
        info->data_offset = __le64_to_cpu(sb->data_offset);
        info->component_size = __le64_to_cpu(sb->size);
+       if (sb->feature_map & __le32_to_cpu(MD_FEATURE_BITMAP_OFFSET))
+               info->bitmap_offset = __le32_to_cpu(sb->bitmap_offset);
 
        info->disk.major = 0;
        info->disk.minor = 0;
@@ -1384,7 +1386,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
        return 0;
 
  no_bitmap:
-       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ~1);
+       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map)
+                                          & ~MD_FEATURE_BITMAP_OFFSET);
        return 0;
 }
 
@@ -1486,12 +1489,10 @@ add_internal_bitmap1(struct supertype *st,
                     int may_change, int major)
 {
        /*
-        * If not may_change, then this is a 'Grow', and the bitmap
-        * must fit after the superblock.
-        * If may_change, then this is create, and we can put the bitmap
-        * before the superblock if we like, or may move the start.
-        * If !may_change, the bitmap MUST live at offset of 1K, until
-        * we get a sysfs interface.
+        * If not may_change, then this is a 'Grow' without sysfs support for
+        * bitmaps, and the bitmap must fit after the superblock at 1K offset.
+        * If may_change, then this is create or a Grow with sysfs syupport,
+        * and we can put the bitmap wherever we like.
         *
         * size is in sectors,  chunk is in bytes !!!
         */
@@ -1502,16 +1503,20 @@ add_internal_bitmap1(struct supertype *st,
        long offset;
        unsigned long long chunk = *chunkp;
        int room = 0;
+       int creating = 0;
        struct mdp_superblock_1 *sb = st->sb;
        bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
        int uuid[4];
 
+       if (__le64_to_cpu(sb->data_size) == 0)
+               /* Must be creating the array, else data_size would be non-zero */
+               creating = 1;
        switch(st->minor_version) {
        case 0:
                /* either 3K after the superblock (when hot-add),
                 * or some amount of space before.
                 */
-               if (may_change) {
+               if (creating) {
                        /* We are creating array, so we *know* how much room has
                         * been left.
                         */
@@ -1521,8 +1526,8 @@ add_internal_bitmap1(struct supertype *st,
                        room = __le64_to_cpu(sb->super_offset)
                                - __le64_to_cpu(sb->data_offset)
                                - __le64_to_cpu(sb->data_size);
-                       /* remove '1 ||' when we can set offset via sysfs */
-                       if (1 || (room < 3*2 &&
+
+                       if (!may_change || (room < 3*2 &&
                                  __le32_to_cpu(sb->max_dev) <= 384)) {
                                room = 3*2;
                                offset = 1*2;
@@ -1533,17 +1538,17 @@ add_internal_bitmap1(struct supertype *st,
                break;
        case 1:
        case 2: /* between superblock and data */
-               if (may_change) {
+               if (creating) {
                        offset = 4*2;
                        room = choose_bm_space(__le64_to_cpu(sb->size));
                } else {
                        room = __le64_to_cpu(sb->data_offset)
                                - __le64_to_cpu(sb->super_offset);
-                       if (1 || __le32_to_cpu(sb->max_dev) <= 384) {
-                               room -= 2;
+                       if (!may_change) {
+                               room -= 2; /* Leave 1K for superblock */
                                offset = 2;
                        } else {
-                               room -= 4*2;
+                               room -= 4*2; /* leave 4K for superblock */
                                offset = 4*2;
                        }
                }
@@ -1588,7 +1593,8 @@ add_internal_bitmap1(struct supertype *st,
 
        sb->bitmap_offset = __cpu_to_le32(offset);
 
-       sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
+       sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map)
+                                       | MD_FEATURE_BITMAP_OFFSET);
        memset(bms, 0, sizeof(*bms));
        bms->magic = __cpu_to_le32(BITMAP_MAGIC);
        bms->version = __cpu_to_le32(major);
@@ -1603,7 +1609,6 @@ add_internal_bitmap1(struct supertype *st,
        return 1;
 }
 
-
 static void locate_bitmap1(struct supertype *st, int fd)
 {
        unsigned long long offset;
diff --git a/sysfs.c b/sysfs.c
index d923f7fbdd6e2f38271e610497477e858b3993dd..e32ececa3faff026008beeb7208feb6095538a59 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -217,6 +217,19 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                msec = (msec * 1000) / scale;
                sra->safe_mode_delay = msec;
        }
+       if (options & GET_BITMAP_LOCATION) {
+               strcpy(base, "bitmap/location");
+               if (load_sys(fname, buf))
+                       goto abort;
+               if (strncmp(buf, "file", 4) == 0)
+                       sra->bitmap_offset = 1;
+               else if (strncmp(buf, "none", 4) == 0)
+                       sra->bitmap_offset = 0;
+               else if (buf[0] == '+')
+                       sra->bitmap_offset = strtoul(buf+1, NULL, 10);
+               else
+                       goto abort;
+       }
 
        if (! (options & GET_DEVS))
                return sra;