]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
md/bitmap: add new 'space' attribute for bitmaps.
authorNeilBrown <neilb@suse.de>
Tue, 24 Apr 2012 00:57:53 +0000 (10:57 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 24 Apr 2012 00:57:53 +0000 (10:57 +1000)
If we are to allow bitmaps to be resized when the array is resized,
we need to know how much space there is.

So create an attribute to store this information and set appropriate
defaults.

It can be set more precisely via sysfs, or future metadata extensions
may allow it to be recorded.

Signed-off-by: NeilBrown <neilb@suse.de>
drivers/md/bitmap.c
drivers/md/md.c
drivers/md/md.h

index 8de7c450e3a7e7e4b3542e18265f951f3d05bcd9..d735e7439ea00384946d7fa8e0cd48f61174db44 100644 (file)
@@ -1935,6 +1935,44 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
 static struct md_sysfs_entry bitmap_location =
 __ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
 
+/* 'bitmap/space' is the space available at 'location' for the
+ * bitmap.  This allows the kernel to know when it is safe to
+ * resize the bitmap to match a resized array.
+ */
+static ssize_t
+space_show(struct mddev *mddev, char *page)
+{
+       return sprintf(page, "%lu\n", mddev->bitmap_info.space);
+}
+
+static ssize_t
+space_store(struct mddev *mddev, const char *buf, size_t len)
+{
+       unsigned long sectors;
+       int rv;
+
+       rv = kstrtoul(buf, 10, &sectors);
+       if (rv)
+               return rv;
+
+       if (sectors == 0)
+               return -EINVAL;
+
+       if (mddev->bitmap &&
+           sectors  < ((mddev->bitmap->file_pages - 1) * PAGE_SIZE
+                       + mddev->bitmap->last_page_size + 511) >> 9)
+               return -EFBIG; /* Bitmap is too big for this small space */
+
+       /* could make sure it isn't too big, but that isn't really
+        * needed - user-space should be careful.
+        */
+       mddev->bitmap_info.space = sectors;
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_space =
+__ATTR(space, S_IRUGO|S_IWUSR, space_show, space_store);
+
 static ssize_t
 timeout_show(struct mddev *mddev, char *page)
 {
@@ -2110,6 +2148,7 @@ __ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
 
 static struct attribute *md_bitmap_attrs[] = {
        &bitmap_location.attr,
+       &bitmap_space.attr,
        &bitmap_timeout.attr,
        &bitmap_backlog.attr,
        &bitmap_chunksize.attr,
index d677d9dbcd6f9a4da978c943216bb3a8a6ca5af3..9e17f437f798c65a90f8490c94d85389864f894a 100644 (file)
@@ -1197,7 +1197,10 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
                mddev->dev_sectors = ((sector_t)sb->size) * 2;
                mddev->events = ev1;
                mddev->bitmap_info.offset = 0;
+               mddev->bitmap_info.space = 0;
+               /* bitmap can use 60 K after the 4K superblocks */
                mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+               mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
                mddev->reshape_backwards = 0;
 
                if (mddev->minor_version >= 91) {
@@ -1234,9 +1237,12 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
                mddev->max_disks = MD_SB_DISKS;
 
                if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
-                   mddev->bitmap_info.file == NULL)
+                   mddev->bitmap_info.file == NULL) {
                        mddev->bitmap_info.offset =
                                mddev->bitmap_info.default_offset;
+                       mddev->bitmap_info.space =
+                               mddev->bitmap_info.space;
+               }
 
        } else if (mddev->pers == NULL) {
                /* Insist on good event counter while assembling, except
@@ -1677,7 +1683,12 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
                mddev->dev_sectors = le64_to_cpu(sb->size);
                mddev->events = ev1;
                mddev->bitmap_info.offset = 0;
+               mddev->bitmap_info.space = 0;
+               /* Default location for bitmap is 1K after superblock
+                * using 3K - total of 4K
+                */
                mddev->bitmap_info.default_offset = 1024 >> 9;
+               mddev->bitmap_info.default_space = (4096-1024) >> 9;
                mddev->reshape_backwards = 0;
 
                mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
@@ -1686,9 +1697,23 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
                mddev->max_disks =  (4096-256)/2;
 
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
-                   mddev->bitmap_info.file == NULL )
+                   mddev->bitmap_info.file == NULL) {
                        mddev->bitmap_info.offset =
                                (__s32)le32_to_cpu(sb->bitmap_offset);
+                       /* Metadata doesn't record how much space is available.
+                        * For 1.0, we assume we can use up to the superblock
+                        * if before, else to 4K beyond superblock.
+                        * For others, assume no change is possible.
+                        */
+                       if (mddev->minor_version > 0)
+                               mddev->bitmap_info.space = 0;
+                       else if (mddev->bitmap_info.offset > 0)
+                               mddev->bitmap_info.space =
+                                       8 - mddev->bitmap_info.offset;
+                       else
+                               mddev->bitmap_info.space =
+                                       -mddev->bitmap_info.offset;
+               }
 
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
                        mddev->reshape_position = le64_to_cpu(sb->reshape_position);
@@ -5280,6 +5305,7 @@ static void md_clean(struct mddev *mddev)
        mddev->merge_check_needed = 0;
        mddev->bitmap_info.offset = 0;
        mddev->bitmap_info.default_offset = 0;
+       mddev->bitmap_info.default_space = 0;
        mddev->bitmap_info.chunksize = 0;
        mddev->bitmap_info.daemon_sleep = 0;
        mddev->bitmap_info.max_write_behind = 0;
@@ -6076,6 +6102,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
        mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+       mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
        mddev->bitmap_info.offset = 0;
 
        mddev->reshape_position = MaxSector;
@@ -6258,6 +6285,8 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
                                return -EINVAL;
                        mddev->bitmap_info.offset =
                                mddev->bitmap_info.default_offset;
+                       mddev->bitmap_info.space =
+                               mddev->bitmap_info.default_space;
                        mddev->pers->quiesce(mddev, 1);
                        rv = bitmap_create(mddev);
                        if (!rv)
index 360937389e640644254532a60e35ef68bb5a2437..7b4a3c318cae437ecb2041c33b2bdcee2c66bf15 100644 (file)
@@ -393,10 +393,13 @@ struct mddev {
                                                 * For external metadata, offset
                                                 * from start of device. 
                                                 */
+               unsigned long           space; /* space available at this offset */
                loff_t                  default_offset; /* this is the offset to use when
                                                         * hot-adding a bitmap.  It should
                                                         * eventually be settable by sysfs.
                                                         */
+               unsigned long           default_space; /* space available at
+                                                       * default offset */
                struct mutex            mutex;
                unsigned long           chunksize;
                unsigned long           daemon_sleep; /* how many jiffies between updates? */