1 From: NeilBrown <neilb@suse.de>
2 Subject: [PATCH] md: 'array_size' sysfs attribute
5 Allow userspace to set the size of the array according to the following
8 1/ size must be <= to the size stored in mddev->array_size
9 a) If size is set before the array is running, do_md_run will fail
10 if size is greater than the default size
11 b) A reshape attempt that reduces the default size to less than the set
12 array size should be blocked
13 2/ once userspace sets the size the kernel will not change it
14 3/ writing 'default' to this attribute returns control of the size to the
15 kernel and reverts to the size reported by the personality
17 To avoid kabi break we store the user-specified size in ->queue->end_sector
18 which is otherwise unused by md devices.
20 (based on a patch which was)
21 Signed-off-by: Dan Williams <dan.j.williams@intel.com>
22 Signed-off-by: NeilBrown <neilb@suse.de>
23 Acked-by: NeilBrown <neilb@suse.de>
25 drivers/md/linear.c | 3 +
26 drivers/md/md.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++--
27 drivers/md/raid1.c | 14 ++++----
28 drivers/md/raid5.c | 9 +++--
29 4 files changed, 99 insertions(+), 12 deletions(-)
31 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/linear.c
32 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/linear.c
33 @@ -295,7 +295,8 @@ static int linear_add(mddev_t *mddev, md
34 mddev->private = newconf;
36 mddev->array_sectors = newconf->array_sectors;
37 - set_capacity(mddev->gendisk, mddev->array_sectors);
38 + if (mddev->queue->end_sector == 0)
39 + set_capacity(mddev->gendisk, mddev->array_sectors);
43 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c
44 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c
45 @@ -287,6 +287,7 @@ static mddev_t * mddev_find(dev_t unit)
49 + new->queue->end_sector = 0;
50 /* Can be unlocked because the queue is new: no concurrency */
51 queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue);
53 @@ -2136,6 +2137,25 @@ rdev_size_show(mdk_rdev_t *rdev, char *p
54 return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
57 +static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
59 + unsigned long long blocks;
62 + if (strict_strtoull(buf, 10, &blocks) < 0)
65 + if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
66 + return -EINVAL; /* sector conversion overflow */
69 + if (new != blocks * 2)
70 + return -EINVAL; /* unsigned long long to sector_t overflow */
76 static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
78 /* check if two start/length pairs overlap */
79 @@ -3397,6 +3417,55 @@ static struct md_sysfs_entry md_reshape_
80 __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
81 reshape_position_store);
84 +array_size_show(mddev_t *mddev, char *page)
86 + if (mddev->queue->end_sector)
87 + return sprintf(page, "%llu\n",
88 + (unsigned long long)mddev->queue->end_sector/2);
90 + return sprintf(page, "default\n");
94 +array_size_store(mddev_t *mddev, const char *buf, size_t len)
98 + if (strncmp(buf, "default", 7) == 0) {
99 + sectors = mddev->array_sectors;
101 + mddev->queue->end_sector = 0;
103 + if (strict_blocks_to_sectors(buf, §ors) < 0)
107 + if (mddev->pers && mddev->array_sectors < sectors)
110 + mddev->queue->end_sector = sectors;
113 + set_capacity(mddev->gendisk, sectors);
115 + struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
118 + mutex_lock(&bdev->bd_inode->i_mutex);
119 + i_size_write(bdev->bd_inode,
120 + (loff_t)sectors << 9);
121 + mutex_unlock(&bdev->bd_inode->i_mutex);
129 +static struct md_sysfs_entry md_array_size =
130 +__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show,
133 static struct attribute *md_default_attrs[] = {
135 @@ -3410,6 +3479,7 @@ static struct attribute *md_default_attr
137 &md_array_state.attr,
138 &md_reshape_position.attr,
139 + &md_array_size.attr,
143 @@ -3721,7 +3791,15 @@ static int do_md_run(mddev_t * mddev)
144 err = mddev->pers->run(mddev);
146 printk(KERN_ERR "md: pers->run() failed ...\n");
147 - else if (mddev->pers->sync_request) {
148 + else if (mddev->queue->end_sector &&
149 + mddev->queue->end_sector > mddev->array_sectors) {
151 + "md: invalid array_size %llu > default size %llu\n",
152 + (unsigned long long)mddev->queue->end_sector / 2,
153 + (unsigned long long)mddev->array_sectors / 2);
155 + mddev->pers->stop(mddev);
156 + } else if (mddev->pers->sync_request) {
157 err = bitmap_create(mddev);
159 printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
160 @@ -3764,7 +3842,10 @@ static int do_md_run(mddev_t * mddev)
162 md_update_sb(mddev, 0);
164 - set_capacity(disk, mddev->array_sectors);
165 + if (mddev->queue->end_sector)
166 + set_capacity(disk, mddev->queue->end_sector);
168 + set_capacity(disk, mddev->array_sectors);
170 /* If we call blk_queue_make_request here, it will
171 * re-initialise max_sectors etc which may have been
172 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid1.c
173 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid1.c
174 @@ -2108,12 +2108,14 @@ static int raid1_resize(mddev_t *mddev,
177 mddev->array_sectors = sectors;
178 - set_capacity(mddev->gendisk, mddev->array_sectors);
179 - mddev->changed = 1;
180 - if (mddev->array_sectors / 2 > mddev->size &&
181 - mddev->recovery_cp == MaxSector) {
182 - mddev->recovery_cp = mddev->size << 1;
183 - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
184 + if (mddev->queue->end_sector == 0) {
185 + set_capacity(mddev->gendisk, mddev->array_sectors);
186 + mddev->changed = 1;
187 + if (mddev->array_sectors / 2 > mddev->size &&
188 + mddev->recovery_cp == MaxSector) {
189 + mddev->recovery_cp = mddev->size << 1;
190 + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
193 mddev->size = mddev->array_sectors / 2;
194 mddev->resync_max_sectors = sectors;
195 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c
196 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c
197 @@ -4650,7 +4650,8 @@ static int raid5_resize(mddev_t *mddev,
198 sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
199 mddev->array_sectors = sectors * (mddev->raid_disks
200 - conf->max_degraded);
201 - set_capacity(mddev->gendisk, mddev->array_sectors);
202 + if (mddev->queue->end_sector == 0)
203 + set_capacity(mddev->gendisk, mddev->array_sectors);
205 if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
206 mddev->recovery_cp = mddev->size << 1;
207 @@ -4788,11 +4789,13 @@ static void end_reshape(raid5_conf_t *co
208 if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
209 conf->mddev->array_sectors = 2 * conf->mddev->size *
210 (conf->raid_disks - conf->max_degraded);
211 - set_capacity(conf->mddev->gendisk, conf->mddev->array_sectors);
212 + if (conf->mddev->queue->end_sector == 0)
213 + set_capacity(conf->mddev->gendisk,
214 + conf->mddev->array_sectors);
215 conf->mddev->changed = 1;
217 bdev = bdget_disk(conf->mddev->gendisk, 0);
219 + if (bdev && conf->mddev->queue->end_sector == 0) {
220 mutex_lock(&bdev->bd_inode->i_mutex);
221 i_size_write(bdev->bd_inode,
222 (loff_t)conf->mddev->array_sectors << 9);