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>
24 #include <linux/raid/linear.h>
26 #define MAJOR_NR MD_MAJOR
28 #define MD_PERSONALITY
30 static int linear_run (mddev_t *mddev)
33 struct linear_hash *table;
35 int size, i, j, nb_zone;
36 unsigned int curr_offset;
40 conf = kmalloc (sizeof (*conf), GFP_KERNEL);
43 mddev->private = conf;
45 if (md_check_ordering(mddev)) {
46 printk("linear: disks are not ordered, aborting!\n");
50 * Find the smallest device.
53 conf->smallest = NULL;
55 ITERATE_RDEV_ORDERED(mddev,rdev,j) {
56 dev_info_t *disk = conf->disks + j;
58 disk->dev = rdev->dev;
59 disk->size = rdev->size;
60 disk->offset = curr_offset;
62 curr_offset += disk->size;
64 if (!conf->smallest || (disk->size < conf->smallest->size))
65 conf->smallest = disk;
68 nb_zone = conf->nr_zones =
69 md_size[mdidx(mddev)] / conf->smallest->size +
70 ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0);
72 conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone,
74 if (!conf->hash_table)
78 * Here we generate the linear hash table
80 table = conf->hash_table;
83 for (j = 0; j < mddev->nb_dev; j++) {
84 dev_info_t *disk = conf->disks + j;
87 table[-1].dev1 = disk;
94 size -= conf->smallest->size;
98 if (table-conf->hash_table != nb_zone)
110 static int linear_stop (mddev_t *mddev)
112 linear_conf_t *conf = mddev_to_conf(mddev);
114 kfree(conf->hash_table);
122 static int linear_make_request (mddev_t *mddev,
123 int rw, struct buffer_head * bh)
125 linear_conf_t *conf = mddev_to_conf(mddev);
126 struct linear_hash *hash;
130 block = bh->b_rsector >> 1;
131 hash = conf->hash_table + (block / conf->smallest->size);
133 if (block >= (hash->dev0->size + hash->dev0->offset)) {
135 printk ("linear_make_request : hash->dev1==NULL for block %ld\n",
140 tmp_dev = hash->dev1;
142 tmp_dev = hash->dev0;
144 if (block >= (tmp_dev->size + tmp_dev->offset)
145 || block < tmp_dev->offset) {
146 printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset);
150 bh->b_rdev = tmp_dev->dev;
151 bh->b_rsector = bh->b_rsector - (tmp_dev->offset << 1);
156 static int linear_status (char *page, mddev_t *mddev)
163 linear_conf_t *conf = mddev_to_conf(mddev);
165 sz += sprintf(page+sz, " ");
166 for (j = 0; j < conf->nr_zones; j++)
168 sz += sprintf(page+sz, "[%s",
169 partition_name(conf->hash_table[j].dev0->dev));
171 if (conf->hash_table[j].dev1)
172 sz += sprintf(page+sz, "/%s] ",
173 partition_name(conf->hash_table[j].dev1->dev));
175 sz += sprintf(page+sz, "] ");
177 sz += sprintf(page+sz, "\n");
179 sz += sprintf(page+sz, " %dk rounding", mddev->param.chunk_size/1024);
184 static mdk_personality_t linear_personality=
187 make_request: linear_make_request,
190 status: linear_status,
193 static int md__init linear_init (void)
195 return register_md_personality (LINEAR, &linear_personality);
198 static void linear_exit (void)
200 unregister_md_personality (LINEAR);
204 module_init(linear_init);
205 module_exit(linear_exit);
206 MODULE_LICENSE("GPL");