~ubuntu-branches/ubuntu/raring/mdadm/raring

« back to all changes in this revision

Viewing changes to Create.c

  • Committer: Package Import Robot
  • Author(s): Fabio M. Di Nitto
  • Date: 2004-10-01 06:23:38 UTC
  • Revision ID: package-import@ubuntu.com-20041001062338-qbvwn77thdz9fbwi
Tags: upstream-1.5.0
ImportĀ upstreamĀ versionĀ 1.5.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mdadm - manage Linux "md" devices aka RAID arrays.
 
3
 *
 
4
 * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
 
5
 *
 
6
 *
 
7
 *    This program is free software; you can redistribute it and/or modify
 
8
 *    it under the terms of the GNU General Public License as published by
 
9
 *    the Free Software Foundation; either version 2 of the License, or
 
10
 *    (at your option) any later version.
 
11
 *
 
12
 *    This program is distributed in the hope that it will be useful,
 
13
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *    GNU General Public License for more details.
 
16
 *
 
17
 *    You should have received a copy of the GNU General Public License
 
18
 *    along with this program; if not, write to the Free Software
 
19
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 *
 
21
 *    Author: Neil Brown
 
22
 *    Email: <neilb@cse.unsw.edu.au>
 
23
 *    Paper: Neil Brown
 
24
 *           School of Computer Science and Engineering
 
25
 *           The University of New South Wales
 
26
 *           Sydney, 2052
 
27
 *           Australia
 
28
 */
 
29
 
 
30
#include "mdadm.h"
 
31
#include        "md_u.h"
 
32
#include        "md_p.h"
 
33
 
 
34
int Create(char *mddev, int mdfd,
 
35
           int chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks,
 
36
           int subdevs, mddev_dev_t devlist,
 
37
           int runstop, int verbose, int force)
 
38
{
 
39
        /*
 
40
         * Create a new raid array.
 
41
         *
 
42
         * First check that necessary details are available
 
43
         * (i.e. level, raid-disks)
 
44
         *
 
45
         * Then check each disk to see what might be on it
 
46
         * and report anything interesting.
 
47
         *
 
48
         * If anything looks odd, and runstop not set,
 
49
         * abort.
 
50
         *
 
51
         * SET_ARRAY_INFO and ADD_NEW_DISK, and
 
52
         * if runstop==run, or raiddisks diskswere used,
 
53
         * RUN_ARRAY
 
54
         */
 
55
        unsigned long minsize=0, maxsize=0;
 
56
        char *mindisc = NULL;
 
57
        char *maxdisc = NULL;
 
58
        int dnum;
 
59
        mddev_dev_t dv;
 
60
        int fail=0, warn=0;
 
61
        struct stat stb;
 
62
        int first_missing = MD_SB_DISKS*2;
 
63
        int missing_disks = 0;
 
64
        int insert_point = MD_SB_DISKS*2; /* where to insert a missing drive */
 
65
        mddev_dev_t moved_disk = NULL; /* the disk that was moved out of the insert point */
 
66
 
 
67
        mdu_array_info_t array;
 
68
        
 
69
 
 
70
        if (md_get_version(mdfd) < 9000) {
 
71
                fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
 
72
                return 1;
 
73
        }
 
74
        if (level == UnSet) {
 
75
                fprintf(stderr,
 
76
                        Name ": a RAID level is needed to create an array.\n");
 
77
                return 1;
 
78
        }
 
79
        if (raiddisks < 1) {
 
80
                fprintf(stderr,
 
81
                        Name ": a number of --raid-devices must be given to create an array\n");
 
82
                return 1;
 
83
        }
 
84
        if (raiddisks < 4 && level == 6) {
 
85
                fprintf(stderr,
 
86
                        Name ": at least 4 raid-devices needed for level 6\n");
 
87
                return 1;
 
88
        }
 
89
        if (raiddisks > 256 && level == 6) {
 
90
                fprintf(stderr,
 
91
                        Name ": no more than 256 raid-devices supported for level 6\n");
 
92
                return 1;
 
93
        }
 
94
        if (raiddisks < 2 && level >= 4) {
 
95
                fprintf(stderr,
 
96
                        Name ": at least 2 raid-devices needed for level 4 or 5\n");
 
97
                return 1;
 
98
        }
 
99
        if (raiddisks+sparedisks > MD_SB_DISKS) {
 
100
                fprintf(stderr,
 
101
                        Name ": too many devices requested: %d+%d > %d\n",
 
102
                        raiddisks, sparedisks, MD_SB_DISKS);
 
103
                return 1;
 
104
        }
 
105
        if (subdevs > raiddisks+sparedisks) {
 
106
                fprintf(stderr, Name ": You have listed more devices (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
 
107
                return 1;
 
108
        }
 
109
        if (subdevs < raiddisks+sparedisks) {
 
110
                fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
 
111
                return 1;
 
112
        }
 
113
 
 
114
        /* now set some defaults */
 
115
        if (layout == UnSet)
 
116
                switch(level) {
 
117
                default: /* no layout */
 
118
                        layout = 0;
 
119
                        break;
 
120
                case 5:
 
121
                case 6:
 
122
                        layout = map_name(r5layout, "default");
 
123
                        if (verbose)
 
124
                                fprintf(stderr,
 
125
                                        Name ": layout defaults to %s\n", map_num(r5layout, layout));
 
126
                        break;
 
127
                }
 
128
 
 
129
        switch(level) {
 
130
        case 4:
 
131
        case 5:
 
132
        case 6:
 
133
        case 0:
 
134
        case -1: /* linear */
 
135
                if (chunk == 0) {
 
136
                        chunk = 64;
 
137
                        if (verbose)
 
138
                                fprintf(stderr, Name ": chunk size defaults to 64K\n");
 
139
                }
 
140
                break;
 
141
        default: /* raid1, multipath */
 
142
                if (chunk) {
 
143
                        chunk = 0;
 
144
                        if (verbose)
 
145
                                fprintf(stderr, Name ": chunk size ignored for this level\n");
 
146
                }
 
147
                break;
 
148
        }
 
149
 
 
150
        /* now look at the subdevs */
 
151
        array.active_disks = 0;
 
152
        array.working_disks = 0;
 
153
        dnum = 0;
 
154
        for (dv=devlist; dv; dv=dv->next, dnum++) {
 
155
                char *dname = dv->devname;
 
156
                unsigned long dsize, freesize;
 
157
                int fd;
 
158
                if (strcasecmp(dname, "missing")==0) {
 
159
                        if (first_missing > dnum)
 
160
                                first_missing = dnum;
 
161
                        missing_disks ++;
 
162
                        continue;
 
163
                }
 
164
                array.working_disks++;
 
165
                if (dnum < raiddisks)
 
166
                        array.active_disks++;
 
167
                fd = open(dname, O_RDONLY, 0);
 
168
                if (fd <0 ) {
 
169
                        fprintf(stderr, Name ": Cannot open %s: %s\n",
 
170
                                dname, strerror(errno));
 
171
                        fail=1;
 
172
                        continue;
 
173
                }
 
174
                if (ioctl(fd, BLKGETSIZE, &dsize)) {
 
175
                        fprintf(stderr, Name ": Cannot get size of %s: %s\n",
 
176
                                dname, strerror(errno));
 
177
                        fail = 1;
 
178
                        close(fd);
 
179
                        continue;
 
180
                }
 
181
                if (dsize < MD_RESERVED_SECTORS*2) {
 
182
                        fprintf(stderr, Name ": %s is too small: %luK\n",
 
183
                                dname, dsize/2);
 
184
                        fail = 1;
 
185
                        close(fd);
 
186
                        continue;
 
187
                }
 
188
                freesize = MD_NEW_SIZE_SECTORS(dsize);
 
189
                freesize /= 2;
 
190
 
 
191
                if (size && freesize < size) {
 
192
                        fprintf(stderr, Name ": %s is smaller that given size."
 
193
                                " %luK < %luK + superblock\n", dname, freesize, size);
 
194
                        fail = 1;
 
195
                        close(fd);
 
196
                        continue;
 
197
                }
 
198
                if (maxdisc == NULL || (maxdisc && freesize > maxsize)) {
 
199
                        maxdisc = dname;
 
200
                        maxsize = freesize;
 
201
                }
 
202
                if (mindisc ==NULL || (mindisc && freesize < minsize)) {
 
203
                        mindisc = dname;
 
204
                        minsize = freesize;
 
205
                }
 
206
                warn |= check_ext2(fd, dname);
 
207
                warn |= check_reiser(fd, dname);
 
208
                warn |= check_raid(fd, dname);
 
209
                close(fd);
 
210
        }
 
211
        if (fail) {
 
212
                fprintf(stderr, Name ": create aborted\n");
 
213
                return 1;
 
214
        }
 
215
        if (size == 0) {
 
216
                if (mindisc == NULL) {
 
217
                        fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
 
218
                        return 1;
 
219
                }
 
220
                size = minsize;
 
221
                if (verbose && level>0)
 
222
                        fprintf(stderr, Name ": size set to %luK\n", size);
 
223
        }
 
224
        if (level >= 1 && ((maxsize-size)*100 > maxsize)) {
 
225
                fprintf(stderr, Name ": largest drive (%s) exceed size (%luK) by more than 1%%\n",
 
226
                        maxdisc, size);
 
227
                warn = 1;
 
228
        }
 
229
 
 
230
        if (warn) {
 
231
                if (runstop!= 1) {
 
232
                        if (!ask("Continue creating array? ")) {
 
233
                                fprintf(stderr, Name ": create aborted.\n");
 
234
                                return 1;
 
235
                        }
 
236
                } else {
 
237
                        if (verbose)
 
238
                                fprintf(stderr, Name ": creation continuing despite oddities due to --run\n");
 
239
                }
 
240
        }
 
241
 
 
242
        /* If this is  raid5, we want to configure the last active slot
 
243
         * as missing, so that a reconstruct happens (faster than re-parity)
 
244
         * FIX: Can we do this for raid6 as well?
 
245
         */
 
246
        if (force == 0 && first_missing >= raiddisks) {
 
247
                switch ( level ) {
 
248
                case 5:
 
249
                        insert_point = raiddisks-1;
 
250
                        sparedisks++;
 
251
                        array.active_disks--;
 
252
                        missing_disks++;
 
253
                        break;
 
254
                default:
 
255
                        break;
 
256
                }
 
257
        }
 
258
        
 
259
        /* Ok, lets try some ioctls */
 
260
 
 
261
        array.level = level;
 
262
        array.size = size;
 
263
        array.raid_disks = raiddisks;
 
264
        /* The kernel should *know* what md_minor we are dealing
 
265
         * with, but it chooses to trust me instead. Sigh
 
266
         */
 
267
        array.md_minor = 0;
 
268
        if (fstat(mdfd, &stb)==0)
 
269
                array.md_minor = MINOR(stb.st_rdev);
 
270
        array.not_persistent = 0;
 
271
        /*** FIX: Need to do something about RAID-6 here ***/
 
272
        if ( (level == 5 || level == 6) &&
 
273
             (insert_point < raiddisks || first_missing < raiddisks) )
 
274
                array.state = 1; /* clean, but one+ drive will be missing */
 
275
        else
 
276
                array.state = 0; /* not clean, but no errors */
 
277
 
 
278
        /* There is lots of redundancy in these disk counts,
 
279
         * raid_disks is the most meaningful value
 
280
         *          it describes the geometry of the array
 
281
         *          it is constant
 
282
         * nr_disks is total number of used slots.
 
283
         *          it should be raid_disks+spare_disks
 
284
         * spare_disks is the number of extra disks present
 
285
         *          see above
 
286
         * active_disks is the number of working disks in
 
287
         *          active slots. (With raid_disks)
 
288
         * working_disks is the total number of working disks,
 
289
         *          including spares
 
290
         * failed_disks is the number of disks marked failed
 
291
         *
 
292
         * Ideally, the kernel would keep these (except raid_disks)
 
293
         * up-to-date as we ADD_NEW_DISK, but it doesn't (yet).
 
294
         * So for now, we assume that all raid and spare
 
295
         * devices will be given.
 
296
         */
 
297
        array.spare_disks=sparedisks;
 
298
        array.failed_disks=missing_disks;
 
299
        array.nr_disks = array.working_disks + array.failed_disks;
 
300
        array.layout = layout;
 
301
        array.chunk_size = chunk*1024;
 
302
 
 
303
        if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
 
304
                fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
 
305
                        mddev, strerror(errno));
 
306
                return 1;
 
307
        }
 
308
        
 
309
        for (dnum=0, dv = devlist ; dv ; dv=(dv->next)?(dv->next):moved_disk, dnum++) {
 
310
                int fd;
 
311
                struct stat stb;
 
312
                mdu_disk_info_t disk;
 
313
 
 
314
                disk.number = dnum;
 
315
                if (dnum == insert_point) {
 
316
                        moved_disk = dv;
 
317
                }
 
318
                disk.raid_disk = disk.number;
 
319
                if (disk.raid_disk < raiddisks)
 
320
                        disk.state = 6; /* active and in sync */
 
321
                else
 
322
                        disk.state = 0;
 
323
                if (dnum == insert_point ||
 
324
                    strcasecmp(dv->devname, "missing")==0) {
 
325
                        disk.major = 0;
 
326
                        disk.minor = 0;
 
327
                        disk.state = 1; /* faulty */
 
328
                } else {
 
329
                        fd = open(dv->devname, O_RDONLY, 0);
 
330
                        if (fd < 0) {
 
331
                                fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
 
332
                                        dv->devname);
 
333
                                return 1;
 
334
                        }
 
335
                        fstat(fd, &stb);
 
336
                        disk.major = MAJOR(stb.st_rdev);
 
337
                        disk.minor = MINOR(stb.st_rdev);
 
338
                        close(fd);
 
339
                }
 
340
                if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
 
341
                        fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
 
342
                                dv->devname, strerror(errno));
 
343
                        return 1;
 
344
                }
 
345
                if (dv == moved_disk && dnum != insert_point) break;
 
346
        }
 
347
 
 
348
        /* param is not actually used */
 
349
        if (runstop == 1 || subdevs >= raiddisks) {
 
350
                mdu_param_t param;
 
351
                if (ioctl(mdfd, RUN_ARRAY, &param)) {
 
352
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
 
353
                                strerror(errno));
 
354
                        return 1;
 
355
                }
 
356
                fprintf(stderr, Name ": array %s started.\n", mddev);
 
357
        } else {
 
358
                fprintf(stderr, Name ": not starting array - not enough devices.\n");
 
359
        }
 
360
        return 0;
 
361
}