aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/linear.c
diff options
context:
space:
mode:
authorSandeep K Sinha <sandeepksinha@gmail.com>2009-06-16 02:55:26 -0400
committerNeilBrown <neilb@suse.de>2009-06-16 02:55:26 -0400
commit45d4582f219619e368ea91ea1189085e1c5f1969 (patch)
tree15c38d1090d67ecb600c395a5155f2630804d851 /drivers/md/linear.c
parent070ec55d07157a3041f92654135c3c6e2eaaf901 (diff)
md: Removal of hash table in linear raid
Get rid of sector_div and hash table for linear raid and replace with a linear search in which_dev. The hash table adds a lot of complexity for little if any gain. Ultimately a binary search will be used which will have smaller cache foot print, a similar number of memory access, and no divisions. Signed-off-by: Sandeep K Sinha <sandeepksinha@gmail.com> Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/linear.c')
-rw-r--r--drivers/md/linear.c93
1 files changed, 3 insertions, 90 deletions
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 31f8ec7131bd..92bcd3dd52cc 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -29,13 +29,8 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector)
29{ 29{
30 dev_info_t *hash; 30 dev_info_t *hash;
31 linear_conf_t *conf = mddev->private; 31 linear_conf_t *conf = mddev->private;
32 sector_t idx = sector >> conf->sector_shift;
33 32
34 /* 33 hash = conf->disks;
35 * sector_div(a,b) returns the remainer and sets a to a/b
36 */
37 (void)sector_div(idx, conf->spacing);
38 hash = conf->hash_table[idx];
39 34
40 while (sector >= hash->num_sectors + hash->start_sector) 35 while (sector >= hash->num_sectors + hash->start_sector)
41 hash++; 36 hash++;
@@ -114,11 +109,8 @@ static sector_t linear_size(mddev_t *mddev, sector_t sectors, int raid_disks)
114static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) 109static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
115{ 110{
116 linear_conf_t *conf; 111 linear_conf_t *conf;
117 dev_info_t **table;
118 mdk_rdev_t *rdev; 112 mdk_rdev_t *rdev;
119 int i, nb_zone, cnt; 113 int i, cnt;
120 sector_t min_sectors;
121 sector_t curr_sector;
122 114
123 conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), 115 conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t),
124 GFP_KERNEL); 116 GFP_KERNEL);
@@ -159,63 +151,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
159 goto out; 151 goto out;
160 } 152 }
161 153
162 min_sectors = conf->array_sectors;
163 sector_div(min_sectors, PAGE_SIZE/sizeof(struct dev_info *));
164 if (min_sectors == 0)
165 min_sectors = 1;
166
167 /* min_sectors is the minimum spacing that will fit the hash
168 * table in one PAGE. This may be much smaller than needed.
169 * We find the smallest non-terminal set of consecutive devices
170 * that is larger than min_sectors and use the size of that as
171 * the actual spacing
172 */
173 conf->spacing = conf->array_sectors;
174 for (i=0; i < cnt-1 ; i++) {
175 sector_t tmp = 0;
176 int j;
177 for (j = i; j < cnt - 1 && tmp < min_sectors; j++)
178 tmp += conf->disks[j].num_sectors;
179 if (tmp >= min_sectors && tmp < conf->spacing)
180 conf->spacing = tmp;
181 }
182
183 /* spacing may be too large for sector_div to work with,
184 * so we might need to pre-shift
185 */
186 conf->sector_shift = 0;
187 if (sizeof(sector_t) > sizeof(u32)) {
188 sector_t space = conf->spacing;
189 while (space > (sector_t)(~(u32)0)) {
190 space >>= 1;
191 conf->sector_shift++;
192 }
193 }
194 /* 154 /*
195 * This code was restructured to work around a gcc-2.95.3 internal 155 * Here we calculate the device offsets.
196 * compiler error. Alter it with care.
197 */
198 {
199 sector_t sz;
200 unsigned round;
201 unsigned long base;
202
203 sz = conf->array_sectors >> conf->sector_shift;
204 sz += 1; /* force round-up */
205 base = conf->spacing >> conf->sector_shift;
206 round = sector_div(sz, base);
207 nb_zone = sz + (round ? 1 : 0);
208 }
209 BUG_ON(nb_zone > PAGE_SIZE / sizeof(struct dev_info *));
210
211 conf->hash_table = kmalloc (sizeof (struct dev_info *) * nb_zone,
212 GFP_KERNEL);
213 if (!conf->hash_table)
214 goto out;
215
216 /*
217 * Here we generate the linear hash table
218 * First calculate the device offsets.
219 */ 156 */
220 conf->disks[0].start_sector = 0; 157 conf->disks[0].start_sector = 0;
221 for (i = 1; i < raid_disks; i++) 158 for (i = 1; i < raid_disks; i++)
@@ -223,29 +160,6 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
223 conf->disks[i-1].start_sector + 160 conf->disks[i-1].start_sector +
224 conf->disks[i-1].num_sectors; 161 conf->disks[i-1].num_sectors;
225 162
226 table = conf->hash_table;
227 i = 0;
228 for (curr_sector = 0;
229 curr_sector < conf->array_sectors;
230 curr_sector += conf->spacing) {
231
232 while (i < raid_disks-1 &&
233 curr_sector >= conf->disks[i+1].start_sector)
234 i++;
235
236 *table ++ = conf->disks + i;
237 }
238
239 if (conf->sector_shift) {
240 conf->spacing >>= conf->sector_shift;
241 /* round spacing up so that when we divide by it,
242 * we err on the side of "too-low", which is safest.
243 */
244 conf->spacing++;
245 }
246
247 BUG_ON(table - conf->hash_table > nb_zone);
248
249 return conf; 163 return conf;
250 164
251out: 165out:
@@ -309,7 +223,6 @@ static int linear_stop (mddev_t *mddev)
309 blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ 223 blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
310 do { 224 do {
311 linear_conf_t *t = conf->prev; 225 linear_conf_t *t = conf->prev;
312 kfree(conf->hash_table);
313 kfree(conf); 226 kfree(conf);
314 conf = t; 227 conf = t;
315 } while (conf); 228 } while (conf);