~ubuntu-branches/ubuntu/dapper/mdadm/dapper

« back to all changes in this revision

Viewing changes to {arch}/++pristine-trees/unlocked/mdadm/mdadm--integration/mdadm--integration--1.12.0/pkg-mdadm-devel@lists.alioth.debian.org--2005/mdadm--integration--1.12.0--patch-4/Create.c

  • Committer: Package Import Robot
  • Author(s): Fabio M. Di Nitto
  • Date: 2005-11-28 07:35:36 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20051128073536-ph8pstb6ams9huk4
Tags: 1.12.0-1ubuntu1
Resyncronize with Debian.

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 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 version 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 10:
 
121
                        layout = 0x102; /* near=2, far=1 */
 
122
                        if (verbose)
 
123
                                fprintf(stderr,
 
124
                                        Name ": layout defaults to n1\n");
 
125
                        break;
 
126
                case 5:
 
127
                case 6:
 
128
                        layout = map_name(r5layout, "default");
 
129
                        if (verbose)
 
130
                                fprintf(stderr,
 
131
                                        Name ": layout defaults to %s\n", map_num(r5layout, layout));
 
132
                        break;
 
133
                case LEVEL_FAULTY:
 
134
                        layout = map_name(faultylayout, "default");
 
135
 
 
136
                        if (verbose)
 
137
                                fprintf(stderr,
 
138
                                        Name ": layout defaults to %s\n", map_num(faultylayout, layout));
 
139
                        break;
 
140
                }
 
141
 
 
142
        if (level == 10)
 
143
                /* check layout fits in array*/
 
144
                if ((layout&255) * ((layout>>8)&255) > raiddisks) {
 
145
                        fprintf(stderr, Name ": that layout requires at least %d devices\n",
 
146
                                (layout&255) * ((layout>>8)&255));
 
147
                        return 1;
 
148
                }
 
149
 
 
150
        switch(level) {
 
151
        case 4:
 
152
        case 5:
 
153
        case 10:
 
154
        case 6:
 
155
        case 0:
 
156
        case -1: /* linear */
 
157
                if (chunk == 0) {
 
158
                        chunk = 64;
 
159
                        if (verbose)
 
160
                                fprintf(stderr, Name ": chunk size defaults to 64K\n");
 
161
                }
 
162
                break;
 
163
        default: /* raid1, multipath */
 
164
                if (chunk) {
 
165
                        chunk = 0;
 
166
                        if (verbose)
 
167
                                fprintf(stderr, Name ": chunk size ignored for this level\n");
 
168
                }
 
169
                break;
 
170
        }
 
171
 
 
172
        /* now look at the subdevs */
 
173
        array.active_disks = 0;
 
174
        array.working_disks = 0;
 
175
        dnum = 0;
 
176
        for (dv=devlist; dv; dv=dv->next, dnum++) {
 
177
                char *dname = dv->devname;
 
178
                unsigned long dsize;
 
179
                unsigned long long ldsize, freesize;
 
180
                int fd;
 
181
                if (strcasecmp(dname, "missing")==0) {
 
182
                        if (first_missing > dnum)
 
183
                                first_missing = dnum;
 
184
                        missing_disks ++;
 
185
                        continue;
 
186
                }
 
187
                array.working_disks++;
 
188
                if (dnum < raiddisks)
 
189
                        array.active_disks++;
 
190
                fd = open(dname, O_RDONLY|O_EXCL, 0);
 
191
                if (fd <0 ) {
 
192
                        fprintf(stderr, Name ": Cannot open %s: %s\n",
 
193
                                dname, strerror(errno));
 
194
                        fail=1;
 
195
                        continue;
 
196
                }
 
197
#ifdef BLKGETSIZE64
 
198
                if (ioctl(fd, BLKGETSIZE64, &ldsize)==0)
 
199
                        ;
 
200
                else
 
201
#endif
 
202
                if (ioctl(fd, BLKGETSIZE, &dsize)) {
 
203
                        fprintf(stderr, Name ": Cannot get size of %s: %s\n",
 
204
                                dname, strerror(errno));
 
205
                        fail = 1;
 
206
                        close(fd);
 
207
                        continue;
 
208
                }
 
209
                else {
 
210
                        ldsize = dsize;
 
211
                        ldsize <<= 9;
 
212
                }
 
213
                if (ldsize < MD_RESERVED_SECTORS*2LL*512LL) {
 
214
                        fprintf(stderr, Name ": %s is too small: %luK\n",
 
215
                                dname, (unsigned long)(ldsize>>10));
 
216
                        fail = 1;
 
217
                        close(fd);
 
218
                        continue;
 
219
                }
 
220
                freesize = MD_NEW_SIZE_SECTORS((ldsize>>9));
 
221
                freesize /= 2;
 
222
 
 
223
                if (size && freesize < size) {
 
224
                        fprintf(stderr, Name ": %s is smaller that given size."
 
225
                                " %lluK < %luK + superblock\n", dname, freesize, size);
 
226
                        fail = 1;
 
227
                        close(fd);
 
228
                        continue;
 
229
                }
 
230
                if (maxdisc == NULL || (maxdisc && freesize > maxsize)) {
 
231
                        maxdisc = dname;
 
232
                        maxsize = freesize;
 
233
                }
 
234
                if (mindisc ==NULL || (mindisc && freesize < minsize)) {
 
235
                        mindisc = dname;
 
236
                        minsize = freesize;
 
237
                }
 
238
                warn |= check_ext2(fd, dname);
 
239
                warn |= check_reiser(fd, dname);
 
240
                warn |= check_raid(fd, dname);
 
241
                close(fd);
 
242
        }
 
243
        if (fail) {
 
244
                fprintf(stderr, Name ": create aborted\n");
 
245
                return 1;
 
246
        }
 
247
        if (size == 0) {
 
248
                if (mindisc == NULL) {
 
249
                        fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
 
250
                        return 1;
 
251
                }
 
252
                if (level > 0) {
 
253
                        /* size is meaningful */
 
254
                        if (minsize > 0x100000000ULL) {
 
255
                                fprintf(stderr, Name ": devices too large for RAID level %d\n", level); 
 
256
                                return 1;
 
257
                        }
 
258
                        size = minsize;
 
259
                        if (verbose)
 
260
                                fprintf(stderr, Name ": size set to %luK\n", size);
 
261
                }
 
262
        }
 
263
        if (level > 0 && ((maxsize-size)*100 > maxsize)) {
 
264
                fprintf(stderr, Name ": largest drive (%s) exceed size (%luK) by more than 1%%\n",
 
265
                        maxdisc, size);
 
266
                warn = 1;
 
267
        }
 
268
 
 
269
        if (warn) {
 
270
                if (runstop!= 1) {
 
271
                        if (!ask("Continue creating array? ")) {
 
272
                                fprintf(stderr, Name ": create aborted.\n");
 
273
                                return 1;
 
274
                        }
 
275
                } else {
 
276
                        if (verbose)
 
277
                                fprintf(stderr, Name ": creation continuing despite oddities due to --run\n");
 
278
                }
 
279
        }
 
280
 
 
281
        /* If this is  raid5, we want to configure the last active slot
 
282
         * as missing, so that a reconstruct happens (faster than re-parity)
 
283
         * FIX: Can we do this for raid6 as well?
 
284
         */
 
285
        if (force == 0 && first_missing >= raiddisks) {
 
286
                switch ( level ) {
 
287
                case 5:
 
288
                        insert_point = raiddisks-1;
 
289
                        sparedisks++;
 
290
                        array.active_disks--;
 
291
                        missing_disks++;
 
292
                        break;
 
293
                default:
 
294
                        break;
 
295
                }
 
296
        }
 
297
        
 
298
        /* Ok, lets try some ioctls */
 
299
 
 
300
        array.level = level;
 
301
        array.size = size;
 
302
        array.raid_disks = raiddisks;
 
303
        /* The kernel should *know* what md_minor we are dealing
 
304
         * with, but it chooses to trust me instead. Sigh
 
305
         */
 
306
        array.md_minor = 0;
 
307
        if (fstat(mdfd, &stb)==0)
 
308
                array.md_minor = minor(stb.st_rdev);
 
309
        array.not_persistent = 0;
 
310
        /*** FIX: Need to do something about RAID-6 here ***/
 
311
        if ( ( (level == 5) &&
 
312
               (insert_point < raiddisks || first_missing < raiddisks) )
 
313
             ||
 
314
             ( level == 6 && missing_disks == 2)
 
315
                )
 
316
                array.state = 1; /* clean, but one+ drive will be missing */
 
317
        else
 
318
                array.state = 0; /* not clean, but no errors */
 
319
 
 
320
        /* There is lots of redundancy in these disk counts,
 
321
         * raid_disks is the most meaningful value
 
322
         *          it describes the geometry of the array
 
323
         *          it is constant
 
324
         * nr_disks is total number of used slots.
 
325
         *          it should be raid_disks+spare_disks
 
326
         * spare_disks is the number of extra disks present
 
327
         *          see above
 
328
         * active_disks is the number of working disks in
 
329
         *          active slots. (With raid_disks)
 
330
         * working_disks is the total number of working disks,
 
331
         *          including spares
 
332
         * failed_disks is the number of disks marked failed
 
333
         *
 
334
         * Ideally, the kernel would keep these (except raid_disks)
 
335
         * up-to-date as we ADD_NEW_DISK, but it doesn't (yet).
 
336
         * So for now, we assume that all raid and spare
 
337
         * devices will be given.
 
338
         */
 
339
        array.spare_disks=sparedisks;
 
340
        array.failed_disks=missing_disks;
 
341
        array.nr_disks = array.working_disks + array.failed_disks;
 
342
        array.layout = layout;
 
343
        array.chunk_size = chunk*1024;
 
344
 
 
345
        if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
 
346
                fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
 
347
                        mddev, strerror(errno));
 
348
                return 1;
 
349
        }
 
350
        
 
351
        for (dnum=0, dv = devlist ; dv ; dv=(dv->next)?(dv->next):moved_disk, dnum++) {
 
352
                int fd;
 
353
                struct stat stb;
 
354
                mdu_disk_info_t disk;
 
355
 
 
356
                disk.number = dnum;
 
357
                if (dnum == insert_point) {
 
358
                        moved_disk = dv;
 
359
                }
 
360
                disk.raid_disk = disk.number;
 
361
                if (disk.raid_disk < raiddisks)
 
362
                        disk.state = 6; /* active and in sync */
 
363
                else
 
364
                        disk.state = 0;
 
365
                if (dnum == insert_point ||
 
366
                    strcasecmp(dv->devname, "missing")==0) {
 
367
                        disk.major = 0;
 
368
                        disk.minor = 0;
 
369
                        disk.state = 1; /* faulty */
 
370
                } else {
 
371
                        fd = open(dv->devname, O_RDONLY|O_EXCL, 0);
 
372
                        if (fd < 0) {
 
373
                                fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
 
374
                                        dv->devname);
 
375
                                return 1;
 
376
                        }
 
377
                        fstat(fd, &stb);
 
378
                        disk.major = major(stb.st_rdev);
 
379
                        disk.minor = minor(stb.st_rdev);
 
380
                        close(fd);
 
381
                }
 
382
                if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
 
383
                        fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
 
384
                                dv->devname, strerror(errno));
 
385
                        return 1;
 
386
                }
 
387
                if (dv == moved_disk && dnum != insert_point) break;
 
388
        }
 
389
 
 
390
        /* param is not actually used */
 
391
        if (runstop == 1 || subdevs >= raiddisks) {
 
392
                mdu_param_t param;
 
393
                if (ioctl(mdfd, RUN_ARRAY, &param)) {
 
394
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
 
395
                                strerror(errno));
 
396
                        Manage_runstop(mddev, mdfd, -1, 0);
 
397
                        return 1;
 
398
                }
 
399
                fprintf(stderr, Name ": array %s started.\n", mddev);
 
400
        } else {
 
401
                fprintf(stderr, Name ": not starting array - not enough devices.\n");
 
402
        }
 
403
        return 0;
 
404
}