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 void linear_status (struct seq_file *seq, mddev_t *mddev)
162 linear_conf_t *conf = mddev_to_conf(mddev);
164 seq_printf(seq, " ");
165 for (j = 0; j < conf->nr_zones; j++)
167 seq_printf(seq, "[%s",
168 partition_name(conf->hash_table[j].dev0->dev));
170 if (conf->hash_table[j].dev1)
171 seq_printf(seq, "/%s] ",
172 partition_name(conf->hash_table[j].dev1->dev));
174 seq_printf(seq, "] ");
176 seq_printf(seq, "\n");
178 seq_printf(seq, " %dk rounding", mddev->param.chunk_size/1024);
182 static mdk_personality_t linear_personality=
185 make_request: linear_make_request,
188 status: linear_status,
191 static int md__init linear_init (void)
193 return register_md_personality (LINEAR, &linear_personality);
196 static void linear_exit (void)
198 unregister_md_personality (LINEAR);
202 module_init(linear_init);
203 module_exit(linear_exit);
204 MODULE_LICENSE("GPL");