2 linear.c : Multiple Devices driver for Linux
3 Copyright (C) 1994-96 Marc ZYNGIER
4 <zyngier@ufr-info-p7.ibp.fr> or
7 Linear mode management functions.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 You should have received a copy of the GNU General Public License
15 (for example /usr/src/linux/COPYING); if not, write to the Free
16 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <linux/module.h>
21 #include <linux/raid/md.h>
22 #include <linux/slab.h>
23 #include <linux/raid/linear.h>
25 #define MAJOR_NR MD_MAJOR
27 #define MD_PERSONALITY
30 * find which device holds a particular offset
32 static inline dev_info_t
*which_dev(mddev_t
*mddev
, sector_t sector
)
35 linear_conf_t
*conf
= mddev_to_conf(mddev
);
36 sector_t block
= sector
>> 1;
39 * sector_div(a,b) returns the remainer and sets a to a/b
41 block
>>= conf
->preshift
;
42 (void)sector_div(block
, conf
->hash_spacing
);
43 hash
= conf
->hash_table
[block
];
45 while ((sector
>>1) >= (hash
->size
+ hash
->offset
))
51 * linear_mergeable_bvec -- tell bio layer if two requests can be merged
53 * @bio: the buffer head that's been built up so far
54 * @biovec: the request that could be merged to it.
56 * Return amount of bytes we can take at this offset
58 static int linear_mergeable_bvec(request_queue_t
*q
, struct bio
*bio
, struct bio_vec
*biovec
)
60 mddev_t
*mddev
= q
->queuedata
;
62 unsigned long maxsectors
, bio_sectors
= bio
->bi_size
>> 9;
63 sector_t sector
= bio
->bi_sector
+ get_start_sect(bio
->bi_bdev
);
65 dev0
= which_dev(mddev
, sector
);
66 maxsectors
= (dev0
->size
<< 1) - (sector
- (dev0
->offset
<<1));
68 if (maxsectors
< bio_sectors
)
71 maxsectors
-= bio_sectors
;
73 if (maxsectors
<= (PAGE_SIZE
>> 9 ) && bio_sectors
== 0)
74 return biovec
->bv_len
;
75 /* The bytes available at this offset could be really big,
76 * so we cap at 2^31 to avoid overflow */
77 if (maxsectors
> (1 << (31-9)))
79 return maxsectors
<< 9;
82 static void linear_unplug(request_queue_t
*q
)
84 mddev_t
*mddev
= q
->queuedata
;
85 linear_conf_t
*conf
= mddev_to_conf(mddev
);
88 for (i
=0; i
< mddev
->raid_disks
; i
++) {
89 request_queue_t
*r_queue
= bdev_get_queue(conf
->disks
[i
].rdev
->bdev
);
90 if (r_queue
->unplug_fn
)
91 r_queue
->unplug_fn(r_queue
);
95 static int linear_issue_flush(request_queue_t
*q
, struct gendisk
*disk
,
96 sector_t
*error_sector
)
98 mddev_t
*mddev
= q
->queuedata
;
99 linear_conf_t
*conf
= mddev_to_conf(mddev
);
102 for (i
=0; i
< mddev
->raid_disks
&& ret
== 0; i
++) {
103 struct block_device
*bdev
= conf
->disks
[i
].rdev
->bdev
;
104 request_queue_t
*r_queue
= bdev_get_queue(bdev
);
106 if (!r_queue
->issue_flush_fn
)
109 ret
= r_queue
->issue_flush_fn(r_queue
, bdev
->bd_disk
, error_sector
);
114 static int linear_congested(void *data
, int bits
)
116 mddev_t
*mddev
= data
;
117 linear_conf_t
*conf
= mddev_to_conf(mddev
);
120 for (i
= 0; i
< mddev
->raid_disks
&& !ret
; i
++) {
121 request_queue_t
*q
= bdev_get_queue(conf
->disks
[i
].rdev
->bdev
);
122 ret
|= bdi_congested(&q
->backing_dev_info
, bits
);
127 static linear_conf_t
*linear_conf(mddev_t
*mddev
, int raid_disks
)
133 sector_t min_spacing
;
134 sector_t curr_offset
;
135 struct list_head
*tmp
;
137 conf
= kzalloc (sizeof (*conf
) + raid_disks
*sizeof(dev_info_t
),
142 mddev
->private = conf
;
145 conf
->array_size
= 0;
147 ITERATE_RDEV(mddev
,rdev
,tmp
) {
148 int j
= rdev
->raid_disk
;
149 dev_info_t
*disk
= conf
->disks
+ j
;
151 if (j
< 0 || j
> raid_disks
|| disk
->rdev
) {
152 printk("linear: disk numbering problem. Aborting!\n");
158 blk_queue_stack_limits(mddev
->queue
,
159 rdev
->bdev
->bd_disk
->queue
);
160 /* as we don't honour merge_bvec_fn, we must never risk
161 * violating it, so limit ->max_sector to one PAGE, as
162 * a one page request is never in violation.
164 if (rdev
->bdev
->bd_disk
->queue
->merge_bvec_fn
&&
165 mddev
->queue
->max_sectors
> (PAGE_SIZE
>>9))
166 blk_queue_max_sectors(mddev
->queue
, PAGE_SIZE
>>9);
168 disk
->size
= rdev
->size
;
169 conf
->array_size
+= rdev
->size
;
173 if (cnt
!= raid_disks
) {
174 printk("linear: not enough drives present. Aborting!\n");
178 min_spacing
= conf
->array_size
;
179 sector_div(min_spacing
, PAGE_SIZE
/sizeof(struct dev_info
*));
181 /* min_spacing is the minimum spacing that will fit the hash
182 * table in one PAGE. This may be much smaller than needed.
183 * We find the smallest non-terminal set of consecutive devices
184 * that is larger than min_spacing as use the size of that as
187 conf
->hash_spacing
= conf
->array_size
;
188 for (i
=0; i
< cnt
-1 ; i
++) {
191 for (j
=i
; i
<cnt
-1 && sz
< min_spacing
; j
++)
192 sz
+= conf
->disks
[j
].size
;
193 if (sz
>= min_spacing
&& sz
< conf
->hash_spacing
)
194 conf
->hash_spacing
= sz
;
197 /* hash_spacing may be too large for sector_div to work with,
198 * so we might need to pre-shift
201 if (sizeof(sector_t
) > sizeof(u32
)) {
202 sector_t space
= conf
->hash_spacing
;
203 while (space
> (sector_t
)(~(u32
)0)) {
209 * This code was restructured to work around a gcc-2.95.3 internal
210 * compiler error. Alter it with care.
217 sz
= conf
->array_size
>> conf
->preshift
;
218 sz
+= 1; /* force round-up */
219 base
= conf
->hash_spacing
>> conf
->preshift
;
220 round
= sector_div(sz
, base
);
221 nb_zone
= sz
+ (round
? 1 : 0);
223 BUG_ON(nb_zone
> PAGE_SIZE
/ sizeof(struct dev_info
*));
225 conf
->hash_table
= kmalloc (sizeof (struct dev_info
*) * nb_zone
,
227 if (!conf
->hash_table
)
231 * Here we generate the linear hash table
232 * First calculate the device offsets.
234 conf
->disks
[0].offset
= 0;
235 for (i
=1; i
<mddev
->raid_disks
; i
++)
236 conf
->disks
[i
].offset
=
237 conf
->disks
[i
-1].offset
+
238 conf
->disks
[i
-1].size
;
240 table
= conf
->hash_table
;
243 for (curr_offset
= 0;
244 curr_offset
< conf
->array_size
;
245 curr_offset
+= conf
->hash_spacing
) {
247 while (i
< mddev
->raid_disks
-1 &&
248 curr_offset
>= conf
->disks
[i
+1].offset
)
251 *table
++ = conf
->disks
+ i
;
254 if (conf
->preshift
) {
255 conf
->hash_spacing
>>= conf
->preshift
;
256 /* round hash_spacing up so that when we divide by it,
257 * we err on the side of "too-low", which is safest.
259 conf
->hash_spacing
++;
262 BUG_ON(table
- conf
->hash_table
> nb_zone
);
271 static int linear_run (mddev_t
*mddev
)
275 conf
= linear_conf(mddev
, mddev
->raid_disks
);
279 mddev
->private = conf
;
280 mddev
->array_size
= conf
->array_size
;
282 blk_queue_merge_bvec(mddev
->queue
, linear_mergeable_bvec
);
283 mddev
->queue
->unplug_fn
= linear_unplug
;
284 mddev
->queue
->issue_flush_fn
= linear_issue_flush
;
285 mddev
->queue
->backing_dev_info
.congested_fn
= linear_congested
;
286 mddev
->queue
->backing_dev_info
.congested_data
= mddev
;
290 static int linear_add(mddev_t
*mddev
, mdk_rdev_t
*rdev
)
292 /* Adding a drive to a linear array allows the array to grow.
293 * It is permitted if the new drive has a matching superblock
294 * already on it, with raid_disk equal to raid_disks.
295 * It is achieved by creating a new linear_private_data structure
296 * and swapping it in in-place of the current one.
297 * The current one is never freed until the array is stopped.
300 linear_conf_t
*newconf
;
302 if (rdev
->raid_disk
!= mddev
->raid_disks
)
305 newconf
= linear_conf(mddev
,mddev
->raid_disks
+1);
310 newconf
->prev
= mddev_to_conf(mddev
);
311 mddev
->private = newconf
;
313 mddev
->array_size
= newconf
->array_size
;
314 set_capacity(mddev
->gendisk
, mddev
->array_size
<< 1);
318 static int linear_stop (mddev_t
*mddev
)
320 linear_conf_t
*conf
= mddev_to_conf(mddev
);
322 blk_sync_queue(mddev
->queue
); /* the unplug fn references 'conf'*/
324 linear_conf_t
*t
= conf
->prev
;
325 kfree(conf
->hash_table
);
333 static int linear_make_request (request_queue_t
*q
, struct bio
*bio
)
335 const int rw
= bio_data_dir(bio
);
336 mddev_t
*mddev
= q
->queuedata
;
340 if (unlikely(bio_barrier(bio
))) {
341 bio_endio(bio
, bio
->bi_size
, -EOPNOTSUPP
);
345 disk_stat_inc(mddev
->gendisk
, ios
[rw
]);
346 disk_stat_add(mddev
->gendisk
, sectors
[rw
], bio_sectors(bio
));
348 tmp_dev
= which_dev(mddev
, bio
->bi_sector
);
349 block
= bio
->bi_sector
>> 1;
351 if (unlikely(block
>= (tmp_dev
->size
+ tmp_dev
->offset
)
352 || block
< tmp_dev
->offset
)) {
353 char b
[BDEVNAME_SIZE
];
355 printk("linear_make_request: Block %llu out of bounds on "
356 "dev %s size %llu offset %llu\n",
357 (unsigned long long)block
,
358 bdevname(tmp_dev
->rdev
->bdev
, b
),
359 (unsigned long long)tmp_dev
->size
,
360 (unsigned long long)tmp_dev
->offset
);
361 bio_io_error(bio
, bio
->bi_size
);
364 if (unlikely(bio
->bi_sector
+ (bio
->bi_size
>> 9) >
365 (tmp_dev
->offset
+ tmp_dev
->size
)<<1)) {
366 /* This bio crosses a device boundary, so we have to
370 bp
= bio_split(bio
, bio_split_pool
,
371 ((tmp_dev
->offset
+ tmp_dev
->size
)<<1) - bio
->bi_sector
);
372 if (linear_make_request(q
, &bp
->bio1
))
373 generic_make_request(&bp
->bio1
);
374 if (linear_make_request(q
, &bp
->bio2
))
375 generic_make_request(&bp
->bio2
);
376 bio_pair_release(bp
);
380 bio
->bi_bdev
= tmp_dev
->rdev
->bdev
;
381 bio
->bi_sector
= bio
->bi_sector
- (tmp_dev
->offset
<< 1) + tmp_dev
->rdev
->data_offset
;
386 static void linear_status (struct seq_file
*seq
, mddev_t
*mddev
)
392 linear_conf_t
*conf
= mddev_to_conf(mddev
);
395 seq_printf(seq
, " ");
396 for (j
= 0; j
< mddev
->raid_disks
; j
++)
398 char b
[BDEVNAME_SIZE
];
399 s
+= conf
->smallest_size
;
400 seq_printf(seq
, "[%s",
401 bdevname(conf
->hash_table
[j
][0].rdev
->bdev
,b
));
403 while (s
> conf
->hash_table
[j
][0].offset
+
404 conf
->hash_table
[j
][0].size
)
405 seq_printf(seq
, "/%s] ",
406 bdevname(conf
->hash_table
[j
][1].rdev
->bdev
,b
));
408 seq_printf(seq
, "] ");
410 seq_printf(seq
, "\n");
412 seq_printf(seq
, " %dk rounding", mddev
->chunk_size
/1024);
416 static struct mdk_personality linear_personality
=
419 .level
= LEVEL_LINEAR
,
420 .owner
= THIS_MODULE
,
421 .make_request
= linear_make_request
,
424 .status
= linear_status
,
425 .hot_add_disk
= linear_add
,
428 static int __init
linear_init (void)
430 return register_md_personality (&linear_personality
);
433 static void linear_exit (void)
435 unregister_md_personality (&linear_personality
);
439 module_init(linear_init
);
440 module_exit(linear_exit
);
441 MODULE_LICENSE("GPL");
442 MODULE_ALIAS("md-personality-1"); /* LINEAR - deprecated*/
443 MODULE_ALIAS("md-linear");
444 MODULE_ALIAS("md-level--1");