2 raid0.c : Multiple Devices driver for Linux
3 Copyright (C) 1994-96 Marc ZYNGIER
4 <zyngier@ufr-info-p7.ibp.fr> or
6 Copyright (C) 1999, 2000 Ingo Molnar, Red Hat
9 RAID-0 management functions.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 You should have received a copy of the GNU General Public License
17 (for example /usr/src/linux/COPYING); if not, write to the Free
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <linux/module.h>
22 #include <linux/raid/raid0.h>
24 #define MAJOR_NR MD_MAJOR
26 #define MD_PERSONALITY
28 static int create_strip_zones (mddev_t
*mddev
)
31 int current_offset
, curr_zone_offset
;
32 raid0_conf_t
*conf
= mddev_to_conf(mddev
);
33 mdk_rdev_t
*smallest
, *rdev1
, *rdev2
, *rdev
;
36 * The number of 'same size groups'
38 conf
->nr_strip_zones
= 0;
40 ITERATE_RDEV_ORDERED(mddev
,rdev1
,j1
) {
41 printk("raid0: looking at %s\n", partition_name(rdev1
->dev
));
43 ITERATE_RDEV_ORDERED(mddev
,rdev2
,j2
) {
44 printk("raid0: comparing %s(%ld) with %s(%ld)\n", partition_name(rdev1
->dev
), rdev1
->size
, partition_name(rdev2
->dev
), rdev2
->size
);
46 printk("raid0: END\n");
49 if (rdev2
->size
== rdev1
->size
)
52 * Not unique, dont count it as a new
55 printk("raid0: EQUAL\n");
59 printk("raid0: NOT EQUAL\n");
62 printk("raid0: ==> UNIQUE\n");
63 conf
->nr_strip_zones
++;
64 printk("raid0: %d zones\n", conf
->nr_strip_zones
);
67 printk("raid0: FINAL %d zones\n", conf
->nr_strip_zones
);
69 conf
->strip_zone
= vmalloc(sizeof(struct strip_zone
)*
70 conf
->nr_strip_zones
);
71 if (!conf
->strip_zone
)
75 conf
->smallest
= NULL
;
79 for (i
= 0; i
< conf
->nr_strip_zones
; i
++)
81 struct strip_zone
*zone
= conf
->strip_zone
+ i
;
83 printk("zone %d\n", i
);
84 zone
->dev_offset
= current_offset
;
88 ITERATE_RDEV_ORDERED(mddev
,rdev
,j
) {
90 printk(" checking %s ...", partition_name(rdev
->dev
));
91 if (rdev
->size
> current_offset
)
93 printk(" contained as device %d\n", c
);
96 if (!smallest
|| (rdev
->size
<smallest
->size
)) {
98 printk(" (%ld) is smallest!.\n", rdev
->size
);
105 zone
->size
= (smallest
->size
- current_offset
) * c
;
106 printk(" zone->nb_dev: %d, size: %d\n",zone
->nb_dev
,zone
->size
);
108 if (!conf
->smallest
|| (zone
->size
< conf
->smallest
->size
))
109 conf
->smallest
= zone
;
111 zone
->zone_offset
= curr_zone_offset
;
112 curr_zone_offset
+= zone
->size
;
114 current_offset
= smallest
->size
;
115 printk("current zone offset: %d\n", current_offset
);
121 static int raid0_run (mddev_t
*mddev
)
123 int cur
=0, i
=0, size
, zone0_size
, nb_zone
;
128 conf
= vmalloc(sizeof (raid0_conf_t
));
131 mddev
->private = (void *)conf
;
133 if (md_check_ordering(mddev
)) {
134 printk("raid0: disks are not ordered, aborting!\n");
138 if (create_strip_zones (mddev
))
141 printk("raid0 : md_size is %d blocks.\n", md_size
[mdidx(mddev
)]);
142 printk("raid0 : conf->smallest->size is %d blocks.\n", conf
->smallest
->size
);
143 nb_zone
= md_size
[mdidx(mddev
)]/conf
->smallest
->size
+
144 (md_size
[mdidx(mddev
)] % conf
->smallest
->size
? 1 : 0);
145 printk("raid0 : nb_zone is %d.\n", nb_zone
);
146 conf
->nr_zones
= nb_zone
;
148 printk("raid0 : Allocating %d bytes for hash.\n",
149 sizeof(struct raid0_hash
)*nb_zone
);
151 conf
->hash_table
= vmalloc (sizeof (struct raid0_hash
)*nb_zone
);
152 if (!conf
->hash_table
)
153 goto out_free_zone_conf
;
154 size
= conf
->strip_zone
[cur
].size
;
157 while (cur
< conf
->nr_strip_zones
) {
158 conf
->hash_table
[i
].zone0
= conf
->strip_zone
+ cur
;
161 * If we completely fill the slot
163 if (size
>= conf
->smallest
->size
) {
164 conf
->hash_table
[i
++].zone1
= NULL
;
165 size
-= conf
->smallest
->size
;
168 if (++cur
== conf
->nr_strip_zones
)
170 size
= conf
->strip_zone
[cur
].size
;
174 if (++cur
== conf
->nr_strip_zones
) {
176 * Last dev, set unit1 as NULL
178 conf
->hash_table
[i
].zone1
=NULL
;
183 * Here we use a 2nd dev to fill the slot
186 size
= conf
->strip_zone
[cur
].size
;
187 conf
->hash_table
[i
++].zone1
= conf
->strip_zone
+ cur
;
188 size
-= (conf
->smallest
->size
- zone0_size
);
193 vfree(conf
->strip_zone
);
194 conf
->strip_zone
= NULL
;
198 mddev
->private = NULL
;
204 static int raid0_stop (mddev_t
*mddev
)
206 raid0_conf_t
*conf
= mddev_to_conf(mddev
);
208 vfree (conf
->hash_table
);
209 conf
->hash_table
= NULL
;
210 vfree (conf
->strip_zone
);
211 conf
->strip_zone
= NULL
;
213 mddev
->private = NULL
;
220 * FIXME - We assume some things here :
221 * - requested buffers NEVER bigger than chunk size,
222 * - requested buffers NEVER cross stripes limits.
223 * Of course, those facts may not be valid anymore (and surely won't...)
224 * Hey guys, there's some work out there ;-)
226 static int raid0_make_request (request_queue_t
*q
, mddev_t
*mddev
,
227 int rw
, struct buffer_head
* bh
)
229 int blk_in_chunk
, chunksize_bits
, chunk
, chunk_size
;
230 raid0_conf_t
*conf
= mddev_to_conf(mddev
);
231 struct raid0_hash
*hash
;
232 struct strip_zone
*zone
;
236 chunk_size
= mddev
->param
.chunk_size
>> 10;
237 chunksize_bits
= ffz(~chunk_size
);
238 block
= bh
->b_rsector
>> 1;
239 hash
= conf
->hash_table
+ block
/ conf
->smallest
->size
;
242 if (chunk_size
< (block
% chunk_size
) + (bh
->b_size
>> 10))
251 if (block
>= (hash
->zone0
->size
+ hash
->zone0
->zone_offset
)) {
258 blk_in_chunk
= block
& (chunk_size
-1);
259 chunk
= (block
- zone
->zone_offset
) / (zone
->nb_dev
<< chunksize_bits
);
260 tmp_dev
= zone
->dev
[(block
>> chunksize_bits
) % zone
->nb_dev
];
261 rblock
= (chunk
<< chunksize_bits
) + blk_in_chunk
+ zone
->dev_offset
;
264 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
265 * is the only IO operation happening on this bh.
267 bh
->b_rdev
= tmp_dev
->dev
;
268 bh
->b_rsector
= rblock
<< 1;
271 * Let the main block layer submit the IO and resolve recursion:
276 printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size
, bh
->b_rsector
, bh
->b_size
>> 10);
279 printk("raid0_make_request bug: hash==NULL for block %ld\n", block
);
282 printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block
);
285 printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block
);
289 static int raid0_status (char *page
, mddev_t
*mddev
)
295 raid0_conf_t
*conf
= mddev_to_conf(mddev
);
297 sz
+= sprintf(page
+ sz
, " ");
298 for (j
= 0; j
< conf
->nr_zones
; j
++) {
299 sz
+= sprintf(page
+ sz
, "[z%d",
300 conf
->hash_table
[j
].zone0
- conf
->strip_zone
);
301 if (conf
->hash_table
[j
].zone1
)
302 sz
+= sprintf(page
+sz
, "/z%d] ",
303 conf
->hash_table
[j
].zone1
- conf
->strip_zone
);
305 sz
+= sprintf(page
+sz
, "] ");
308 sz
+= sprintf(page
+ sz
, "\n");
310 for (j
= 0; j
< conf
->nr_strip_zones
; j
++) {
311 sz
+= sprintf(page
+ sz
, " z%d=[", j
);
312 for (k
= 0; k
< conf
->strip_zone
[j
].nb_dev
; k
++)
313 sz
+= sprintf (page
+sz
, "%s/", partition_name(
314 conf
->strip_zone
[j
].dev
[k
]->dev
));
316 sz
+= sprintf (page
+sz
, "] zo=%d do=%d s=%d\n",
317 conf
->strip_zone
[j
].zone_offset
,
318 conf
->strip_zone
[j
].dev_offset
,
319 conf
->strip_zone
[j
].size
);
322 sz
+= sprintf(page
+ sz
, " %dk chunks", mddev
->param
.chunk_size
/1024);
326 static mdk_personality_t raid0_personality
=
329 make_request
: raid0_make_request
,
332 status
: raid0_status
,
337 void raid0_init (void)
339 register_md_personality (RAID0
, &raid0_personality
);
344 int init_module (void)
346 return (register_md_personality (RAID0
, &raid0_personality
));
349 void cleanup_module (void)
351 unregister_md_personality (RAID0
);