1 /*
2 linear.c : Multiple Devices driver for Linux
3 Copyright (C) 1994-96 Marc ZYNGIER
4 <zyngier@ufr-info-p7.ibp.fr> or
5 <maz@gloups.fdn.fr>
6
7 Linear mode management functions.
8
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)
12 any later version.
13
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.
17 */
18
19 #include <linux/module.h>
20
21 #include <linux/raid/md.h>
22 #include <linux/malloc.h>
23
24 #include <linux/raid/linear.h>
25
26 #define MAJOR_NR MD_MAJOR
27 #define MD_DRIVER
28 #define MD_PERSONALITY
29
30 static int linear_run (mddev_t *mddev)
31 {
32 linear_conf_t *conf;
33 struct linear_hash *table;
34 mdk_rdev_t *rdev;
35 int size, i, j, nb_zone;
36 unsigned int curr_offset;
37
38 MOD_INC_USE_COUNT;
39
40 conf = kmalloc (sizeof (*conf), GFP_KERNEL);
41 if (!conf)
42 goto out;
43 mddev->private = conf;
44
45 if (md_check_ordering(mddev)) {
46 printk("linear: disks are not ordered, aborting!\n");
47 goto out;
48 }
49 /*
50 * Find the smallest device.
51 */
52
53 conf->smallest = NULL;
54 curr_offset = 0;
55 ITERATE_RDEV_ORDERED(mddev,rdev,j) {
56 dev_info_t *disk = conf->disks + j;
57
58 disk->dev = rdev->dev;
59 disk->size = rdev->size;
60 disk->offset = curr_offset;
61
62 curr_offset += disk->size;
63
64 if (!conf->smallest || (disk->size < conf->smallest->size))
65 conf->smallest = disk;
66 }
67
68 nb_zone = conf->nr_zones =
69 md_size[mdidx(mddev)] / conf->smallest->size +
70 ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0);
71
72 conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone,
73 GFP_KERNEL);
74 if (!conf->hash_table)
75 goto out;
76
77 /*
78 * Here we generate the linear hash table
79 */
80 table = conf->hash_table;
81 i = 0;
82 size = 0;
83 for (j = 0; j < mddev->nb_dev; j++) {
84 dev_info_t *disk = conf->disks + j;
85
86 if (size < 0) {
87 table[-1].dev1 = disk;
88 }
89 size += disk->size;
90
91 while (size>0) {
92 table->dev0 = disk;
93 table->dev1 = NULL;
94 size -= conf->smallest->size;
95 table++;
96 }
97 }
98 if (table-conf->hash_table != nb_zone)
99 BUG();
100
101 return 0;
102
103 out:
104 if (conf)
105 kfree(conf);
106 MOD_DEC_USE_COUNT;
107 return 1;
108 }
109
110 static int linear_stop (mddev_t *mddev)
111 {
112 linear_conf_t *conf = mddev_to_conf(mddev);
113
114 kfree(conf->hash_table);
115 kfree(conf);
116
117 MOD_DEC_USE_COUNT;
118
119 return 0;
120 }
121
122 static int linear_make_request (mddev_t *mddev,
123 int rw, struct buffer_head * bh)
124 {
125 linear_conf_t *conf = mddev_to_conf(mddev);
126 struct linear_hash *hash;
127 dev_info_t *tmp_dev;
128 long block;
129
130 block = bh->b_rsector >> 1;
131 hash = conf->hash_table + (block / conf->smallest->size);
132
133 if (block >= (hash->dev0->size + hash->dev0->offset)) {
134 if (!hash->dev1) {
135 printk ("linear_make_request : hash->dev1==NULL for block %ld\n",
136 block);
137 buffer_IO_error(bh);
138 return 0;
139 }
140 tmp_dev = hash->dev1;
141 } else
142 tmp_dev = hash->dev0;
143
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);
147 buffer_IO_error(bh);
148 return 0;
149 }
150 bh->b_rdev = tmp_dev->dev;
151 bh->b_rsector = bh->b_rsector - (tmp_dev->offset << 1);
152
153 return 1;
154 }
155
156 static int linear_status (char *page, mddev_t *mddev)
157 {
158 int sz = 0;
159
160 #undef MD_DEBUG
161 #ifdef MD_DEBUG
162 int j;
163 linear_conf_t *conf = mddev_to_conf(mddev);
164
165 sz += sprintf(page+sz, " ");
166 for (j = 0; j < conf->nr_zones; j++)
167 {
168 sz += sprintf(page+sz, "[%s",
169 partition_name(conf->hash_table[j].dev0->dev));
170
171 if (conf->hash_table[j].dev1)
172 sz += sprintf(page+sz, "/%s] ",
173 partition_name(conf->hash_table[j].dev1->dev));
174 else
175 sz += sprintf(page+sz, "] ");
176 }
177 sz += sprintf(page+sz, "\n");
178 #endif
179 sz += sprintf(page+sz, " %dk rounding", mddev->param.chunk_size/1024);
180 return sz;
181 }
182
183
184 static mdk_personality_t linear_personality=
185 {
186 name: "linear",
187 make_request: linear_make_request,
188 run: linear_run,
189 stop: linear_stop,
190 status: linear_status,
191 };
192
193 static int md__init linear_init (void)
194 {
195 return register_md_personality (LINEAR, &linear_personality);
196 }
197
198 static void linear_exit (void)
199 {
200 unregister_md_personality (LINEAR);
201 }
202
203
204 module_init(linear_init);
205 module_exit(linear_exit);
206
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.