Import 2.3.18pre1
[davej-history.git] / drivers / block / raid0.c
blob2e95d34f89b8832295c41688219dc91f361ef841
2 /*
3 raid0.c : Multiple Devices driver for Linux
4 Copyright (C) 1994-96 Marc ZYNGIER
5 <zyngier@ufr-info-p7.ibp.fr> or
6 <maz@gloups.fdn.fr>
8 RAID-0 management functions.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
15 You should have received a copy of the GNU General Public License
16 (for example /usr/src/linux/COPYING); if not, write to the Free
17 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <linux/module.h>
21 #include <linux/md.h>
22 #include <linux/raid0.h>
23 #include <linux/vmalloc.h>
25 #define MAJOR_NR MD_MAJOR
26 #define MD_DRIVER
27 #define MD_PERSONALITY
29 static int create_strip_zones (int minor, struct md_dev *mddev)
31 int i, j, c=0;
32 int current_offset=0;
33 struct real_dev *smallest_by_zone;
34 struct raid0_data *data=(struct raid0_data *) mddev->private;
36 data->nr_strip_zones=1;
38 for (i=1; i<mddev->nb_dev; i++)
40 for (j=0; j<i; j++)
41 if (mddev->devices[i].size==mddev->devices[j].size)
43 c=1;
44 break;
47 if (!c)
48 data->nr_strip_zones++;
50 c=0;
53 if ((data->strip_zone=vmalloc(sizeof(struct strip_zone)*data->nr_strip_zones)) == NULL)
54 return 1;
56 data->smallest=NULL;
58 for (i=0; i<data->nr_strip_zones; i++)
60 data->strip_zone[i].dev_offset=current_offset;
61 smallest_by_zone=NULL;
62 c=0;
64 for (j=0; j<mddev->nb_dev; j++)
65 if (mddev->devices[j].size>current_offset)
67 data->strip_zone[i].dev[c++]=mddev->devices+j;
68 if (!smallest_by_zone ||
69 smallest_by_zone->size > mddev->devices[j].size)
70 smallest_by_zone=mddev->devices+j;
73 data->strip_zone[i].nb_dev=c;
74 data->strip_zone[i].size=(smallest_by_zone->size-current_offset)*c;
76 if (!data->smallest ||
77 data->smallest->size > data->strip_zone[i].size)
78 data->smallest=data->strip_zone+i;
80 data->strip_zone[i].zone_offset=i ? (data->strip_zone[i-1].zone_offset+
81 data->strip_zone[i-1].size) : 0;
82 current_offset=smallest_by_zone->size;
84 return 0;
87 static int raid0_run (int minor, struct md_dev *mddev)
89 int cur=0, i=0, size, zone0_size, nb_zone;
90 struct raid0_data *data;
92 MOD_INC_USE_COUNT;
94 if ((mddev->private=vmalloc (sizeof (struct raid0_data))) == NULL) return 1;
95 data=(struct raid0_data *) mddev->private;
97 if (create_strip_zones (minor, mddev))
99 vfree(data);
100 return 1;
103 nb_zone=data->nr_zones=
104 md_size[minor]/data->smallest->size +
105 (md_size[minor]%data->smallest->size ? 1 : 0);
107 printk ("raid0 : Allocating %ld bytes for hash.\n",(long)sizeof(struct raid0_hash)*nb_zone);
108 if ((data->hash_table=vmalloc (sizeof (struct raid0_hash)*nb_zone)) == NULL)
110 vfree(data->strip_zone);
111 vfree(data);
112 return 1;
114 size=data->strip_zone[cur].size;
116 i=0;
117 while (cur<data->nr_strip_zones)
119 data->hash_table[i].zone0=data->strip_zone+cur;
121 if (size>=data->smallest->size)/* If we completely fill the slot */
123 data->hash_table[i++].zone1=NULL;
124 size-=data->smallest->size;
126 if (!size)
128 if (++cur==data->nr_strip_zones) continue;
129 size=data->strip_zone[cur].size;
132 continue;
135 if (++cur==data->nr_strip_zones) /* Last dev, set unit1 as NULL */
137 data->hash_table[i].zone1=NULL;
138 continue;
141 zone0_size=size; /* Here, we use a 2nd dev to fill the slot */
142 size=data->strip_zone[cur].size;
143 data->hash_table[i++].zone1=data->strip_zone+cur;
144 size-=(data->smallest->size - zone0_size);
147 return (0);
151 static int raid0_stop (int minor, struct md_dev *mddev)
153 struct raid0_data *data=(struct raid0_data *) mddev->private;
155 vfree (data->hash_table);
156 vfree (data->strip_zone);
157 vfree (data);
159 MOD_DEC_USE_COUNT;
160 return 0;
164 * FIXME - We assume some things here :
165 * - requested buffers NEVER bigger than chunk size,
166 * - requested buffers NEVER cross stripes limits.
167 * Of course, those facts may not be valid anymore (and surely won't...)
168 * Hey guys, there's some work out there ;-)
170 static int raid0_map (struct md_dev *mddev, kdev_t *rdev,
171 unsigned long *rsector, unsigned long size)
173 struct raid0_data *data=(struct raid0_data *) mddev->private;
174 static struct raid0_hash *hash;
175 struct strip_zone *zone;
176 struct real_dev *tmp_dev;
177 int blk_in_chunk, factor, chunk, chunk_size;
178 long block, rblock;
180 factor=FACTOR(mddev);
181 chunk_size=(1UL << FACTOR_SHIFT(factor));
182 block=*rsector >> 1;
183 hash=data->hash_table+(block/data->smallest->size);
185 /* Sanity check */
186 if ((chunk_size*2)<(*rsector % (chunk_size*2))+size)
188 printk ("raid0_convert : can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, *rsector, size);
189 return (-1);
192 if (block >= (hash->zone0->size +
193 hash->zone0->zone_offset))
195 if (!hash->zone1)
197 printk ("raid0_convert : hash->zone1==NULL for block %ld\n", block);
198 return (-1);
201 zone=hash->zone1;
203 else
204 zone=hash->zone0;
206 blk_in_chunk=block & (chunk_size -1);
207 chunk=(block - zone->zone_offset) / (zone->nb_dev<<FACTOR_SHIFT(factor));
208 tmp_dev=zone->dev[(block >> FACTOR_SHIFT(factor)) % zone->nb_dev];
209 rblock=(chunk << FACTOR_SHIFT(factor)) + blk_in_chunk + zone->dev_offset;
211 *rdev=tmp_dev->dev;
212 *rsector=rblock<<1;
214 return (0);
218 static int raid0_status (char *page, int minor, struct md_dev *mddev)
220 int sz=0;
221 #undef MD_DEBUG
222 #ifdef MD_DEBUG
223 int j, k;
224 struct raid0_data *data=(struct raid0_data *) mddev->private;
226 sz+=sprintf (page+sz, " ");
227 for (j=0; j<data->nr_zones; j++)
229 sz+=sprintf (page+sz, "[z%d",
230 data->hash_table[j].zone0-data->strip_zone);
231 if (data->hash_table[j].zone1)
232 sz+=sprintf (page+sz, "/z%d] ",
233 data->hash_table[j].zone1-data->strip_zone);
234 else
235 sz+=sprintf (page+sz, "] ");
238 sz+=sprintf (page+sz, "\n");
240 for (j=0; j<data->nr_strip_zones; j++)
242 sz+=sprintf (page+sz, " z%d=[", j);
243 for (k=0; k<data->strip_zone[j].nb_dev; k++)
244 sz+=sprintf (page+sz, "%s/",
245 partition_name(data->strip_zone[j].dev[k]->dev));
246 sz--;
247 sz+=sprintf (page+sz, "] zo=%d do=%d s=%d\n",
248 data->strip_zone[j].zone_offset,
249 data->strip_zone[j].dev_offset,
250 data->strip_zone[j].size);
252 #endif
253 sz+=sprintf (page+sz, " %dk chunks", 1<<FACTOR_SHIFT(FACTOR(mddev)));
254 return sz;
258 static struct md_personality raid0_personality=
260 "raid0",
261 raid0_map,
262 NULL, /* no special make_request */
263 NULL, /* no special end_request */
264 raid0_run,
265 raid0_stop,
266 raid0_status,
267 NULL, /* no ioctls */
269 NULL, /* no error_handler */
270 NULL, /* hot_add_disk */
271 NULL, /* hot_remove_disk */
272 NULL /* mark_spare */
276 #ifndef MODULE
278 void raid0_init (void)
280 register_md_personality (RAID0, &raid0_personality);
283 #else
285 int init_module (void)
287 return (register_md_personality (RAID0, &raid0_personality));
290 void cleanup_module (void)
292 unregister_md_personality (RAID0);
295 #endif