]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: NeilBrown <neilb@suse.de> |
2 | Subject: [PATCH] md: 'array_size' sysfs attribute | |
3 | References: bnc#498358 | |
4 | ||
5 | Allow userspace to set the size of the array according to the following | |
6 | semantics: | |
7 | ||
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 | |
16 | ||
17 | To avoid kabi break we store the user-specified size in ->queue->end_sector | |
18 | which is otherwise unused by md devices. | |
19 | ||
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> | |
24 | --- | |
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(-) | |
30 | ||
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; | |
35 | mddev->raid_disks++; | |
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); | |
40 | return 0; | |
41 | } | |
42 | ||
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) | |
46 | kfree(new); | |
47 | return NULL; | |
48 | } | |
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); | |
52 | ||
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); | |
55 | } | |
56 | ||
57 | +static int strict_blocks_to_sectors(const char *buf, sector_t *sectors) | |
58 | +{ | |
59 | + unsigned long long blocks; | |
60 | + sector_t new; | |
61 | + | |
62 | + if (strict_strtoull(buf, 10, &blocks) < 0) | |
63 | + return -EINVAL; | |
64 | + | |
65 | + if (blocks & 1ULL << (8 * sizeof(blocks) - 1)) | |
66 | + return -EINVAL; /* sector conversion overflow */ | |
67 | + | |
68 | + new = blocks * 2; | |
69 | + if (new != blocks * 2) | |
70 | + return -EINVAL; /* unsigned long long to sector_t overflow */ | |
71 | + | |
72 | + *sectors = new; | |
73 | + return 0; | |
74 | +} | |
75 | + | |
76 | static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) | |
77 | { | |
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); | |
82 | ||
83 | +static ssize_t | |
84 | +array_size_show(mddev_t *mddev, char *page) | |
85 | +{ | |
86 | + if (mddev->queue->end_sector) | |
87 | + return sprintf(page, "%llu\n", | |
88 | + (unsigned long long)mddev->queue->end_sector/2); | |
89 | + else | |
90 | + return sprintf(page, "default\n"); | |
91 | +} | |
92 | + | |
93 | +static ssize_t | |
94 | +array_size_store(mddev_t *mddev, const char *buf, size_t len) | |
95 | +{ | |
96 | + sector_t sectors; | |
97 | + | |
98 | + if (strncmp(buf, "default", 7) == 0) { | |
99 | + sectors = mddev->array_sectors; | |
100 | + | |
101 | + mddev->queue->end_sector = 0; | |
102 | + } else { | |
103 | + if (strict_blocks_to_sectors(buf, §ors) < 0) | |
104 | + return -EINVAL; | |
105 | + if (sectors < 2) | |
106 | + return -EINVAL; | |
107 | + if (mddev->pers && mddev->array_sectors < sectors) | |
108 | + return -E2BIG; | |
109 | + | |
110 | + mddev->queue->end_sector = sectors; | |
111 | + } | |
112 | + | |
113 | + set_capacity(mddev->gendisk, sectors); | |
114 | + if (mddev->pers) { | |
115 | + struct block_device *bdev = bdget_disk(mddev->gendisk, 0); | |
116 | + | |
117 | + if (bdev) { | |
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); | |
122 | + bdput(bdev); | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + return len; | |
127 | +} | |
128 | + | |
129 | +static struct md_sysfs_entry md_array_size = | |
130 | +__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show, | |
131 | + array_size_store); | |
132 | ||
133 | static struct attribute *md_default_attrs[] = { | |
134 | &md_level.attr, | |
135 | @@ -3410,6 +3479,7 @@ static struct attribute *md_default_attr | |
136 | &md_safe_delay.attr, | |
137 | &md_array_state.attr, | |
138 | &md_reshape_position.attr, | |
139 | + &md_array_size.attr, | |
140 | NULL, | |
141 | }; | |
142 | ||
143 | @@ -3721,7 +3791,15 @@ static int do_md_run(mddev_t * mddev) | |
144 | err = mddev->pers->run(mddev); | |
145 | if (err) | |
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) { | |
150 | + printk(KERN_ERR | |
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); | |
154 | + err = -EINVAL; | |
155 | + mddev->pers->stop(mddev); | |
156 | + } else if (mddev->pers->sync_request) { | |
157 | err = bitmap_create(mddev); | |
158 | if (err) { | |
159 | printk(KERN_ERR "%s: failed to create bitmap (%d)\n", | |
160 | @@ -3764,7 +3842,10 @@ static int do_md_run(mddev_t * mddev) | |
161 | if (mddev->flags) | |
162 | md_update_sb(mddev, 0); | |
163 | ||
164 | - set_capacity(disk, mddev->array_sectors); | |
165 | + if (mddev->queue->end_sector) | |
166 | + set_capacity(disk, mddev->queue->end_sector); | |
167 | + else | |
168 | + set_capacity(disk, mddev->array_sectors); | |
169 | ||
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, | |
175 | * worth it. | |
176 | */ | |
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); | |
191 | + } | |
192 | } | |
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); | |
204 | mddev->changed = 1; | |
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; | |
216 | ||
217 | bdev = bdget_disk(conf->mddev->gendisk, 0); | |
218 | - if (bdev) { | |
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); |