3 raid0.c : Multiple Devices driver for Linux
4 Copyright (C) 1994-96 Marc ZYNGIER
5 <zyngier@ufr-info-p7.ibp.fr> or
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)
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>
22 #include <linux/raid0.h>
23 #include <linux/vmalloc.h>
25 #define MAJOR_NR MD_MAJOR
27 #define MD_PERSONALITY
29 static int create_strip_zones (int minor
, struct md_dev
*mddev
)
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
++)
41 if (mddev
->devices
[i
].size
==mddev
->devices
[j
].size
)
48 data
->nr_strip_zones
++;
53 if ((data
->strip_zone
=vmalloc(sizeof(struct strip_zone
)*data
->nr_strip_zones
)) == 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
;
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
;
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
;
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
))
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
);
114 size
=data
->strip_zone
[cur
].size
;
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
;
128 if (++cur
==data
->nr_strip_zones
) continue;
129 size
=data
->strip_zone
[cur
].size
;
135 if (++cur
==data
->nr_strip_zones
) /* Last dev, set unit1 as NULL */
137 data
->hash_table
[i
].zone1
=NULL
;
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
);
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
);
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
;
180 factor
=FACTOR(mddev
);
181 chunk_size
=(1UL << FACTOR_SHIFT(factor
));
183 hash
=data
->hash_table
+(block
/data
->smallest
->size
);
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
);
192 if (block
>= (hash
->zone0
->size
+
193 hash
->zone0
->zone_offset
))
197 printk ("raid0_convert : hash->zone1==NULL for block %ld\n", block
);
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
;
218 static int raid0_status (char *page
, int minor
, struct md_dev
*mddev
)
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
);
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
));
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
);
253 sz
+=sprintf (page
+sz
, " %dk chunks", 1<<FACTOR_SHIFT(FACTOR(mddev
)));
258 static struct md_personality raid0_personality
=
262 NULL
, /* no special make_request */
263 NULL
, /* no special end_request */
267 NULL
, /* no ioctls */
269 NULL
, /* no error_handler */
270 NULL
, /* hot_add_disk */
271 NULL
, /* hot_remove_disk */
272 NULL
/* mark_spare */
278 void raid0_init (void)
280 register_md_personality (RAID0
, &raid0_personality
);
285 int init_module (void)
287 return (register_md_personality (RAID0
, &raid0_personality
));
290 void cleanup_module (void)
292 unregister_md_personality (RAID0
);