mdctl-0.6
Neil Brown
22 years ago
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
32 | 32 | |
33 | 33 | int Assemble(char *mddev, int mdfd, |
34 | 34 | mddev_ident_t ident, char *conffile, |
35 | int subdevs, char **subdev, | |
35 | mddev_dev_t devlist, | |
36 | 36 | int readonly, int runstop, |
37 | 37 | int verbose, int force) |
38 | 38 | { |
66 | 66 | * |
67 | 67 | * If !uuidset and scan, look in conf-file for uuid |
68 | 68 | * If not found, give up |
69 | * If !subdevs and scan and uuidset, get list of devs from conf-file | |
69 | * If !devlist and scan and uuidset, get list of devs from conf-file | |
70 | 70 | * |
71 | 71 | * For each device: |
72 | 72 | * Check superblock - discard if bad |
93 | 93 | int old_linux = 0; |
94 | 94 | int vers; |
95 | 95 | mdu_array_info_t array; |
96 | mddev_dev_t devlist = NULL; | |
97 | 96 | mdp_super_t first_super, super; |
98 | 97 | struct { |
99 | 98 | char *devname; |
107 | 106 | int devcnt = 0, okcnt, sparecnt; |
108 | 107 | int i; |
109 | 108 | int most_recent = 0; |
110 | int chosen_drive = -1; | |
109 | int chosen_drive; | |
111 | 110 | int change = 0; |
111 | int inargv = 0; | |
112 | int start_partial_ok = force || devlist==NULL; | |
112 | 113 | |
113 | 114 | vers = md_get_version(mdfd); |
114 | 115 | if (vers <= 0) { |
138 | 139 | * there must be something in the identity |
139 | 140 | */ |
140 | 141 | |
141 | if (subdevs == 0 && | |
142 | if (!devlist && | |
142 | 143 | ident->uuid_set == 0 && |
143 | 144 | ident->super_minor < 0 && |
144 | 145 | ident->devices == NULL) { |
146 | 147 | mddev); |
147 | 148 | return 1; |
148 | 149 | } |
149 | if (subdevs==0) | |
150 | if (devlist == NULL) | |
150 | 151 | devlist = conf_get_devs(conffile); |
152 | else inargv = 1; | |
151 | 153 | |
152 | 154 | first_super.md_magic = 0; |
153 | 155 | for (i=0; i<MD_SB_DISKS; i++) |
157 | 159 | fprintf(stderr, Name ": looking for devices for %s\n", |
158 | 160 | mddev); |
159 | 161 | |
160 | while (subdevs || devlist) { | |
162 | while ( devlist) { | |
161 | 163 | char *devname; |
162 | 164 | int this_uuid[4]; |
163 | 165 | int dfd; |
164 | 166 | struct stat stb; |
165 | int inargv; | |
166 | 167 | int havesuper=0; |
167 | 168 | |
168 | if (subdevs) { | |
169 | devname = *subdev++; | |
170 | subdevs--; | |
171 | inargv=1; | |
172 | } else { | |
173 | devname = devlist->devname; | |
174 | devlist = devlist->next; | |
175 | inargv=0; | |
176 | } | |
169 | devname = devlist->devname; | |
170 | devlist = devlist->next; | |
177 | 171 | |
178 | 172 | if (ident->devices && |
179 | 173 | !match_oneof(ident->devices, devname)) |
189 | 183 | fprintf(stderr, Name ": fstat failed for %s: %s\n", |
190 | 184 | devname, strerror(errno)); |
191 | 185 | close(dfd); |
192 | } if ((stb.st_mode & S_IFMT) != S_IFBLK) { | |
193 | fprintf(stderr, Name ": %d is not a block device.\n", | |
186 | } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { | |
187 | fprintf(stderr, Name ": %s is not a block device.\n", | |
194 | 188 | devname); |
195 | 189 | close(dfd); |
196 | } if (load_super(dfd, &super)) { | |
190 | } else if (load_super(dfd, &super)) { | |
197 | 191 | if (inargv || verbose) |
198 | 192 | fprintf( stderr, Name ": no RAID superblock on %s\n", |
199 | 193 | devname); |
218 | 212 | devname); |
219 | 213 | continue; |
220 | 214 | } |
215 | if (ident->level != -10 && | |
216 | (!havesuper|| ident->level != super.level)) { | |
217 | if (inargv || verbose) | |
218 | fprintf(stderr, Name ": %s has wrong raid level.\n", | |
219 | devname); | |
220 | continue; | |
221 | } | |
222 | if (ident->raid_disks != -1 && | |
223 | (!havesuper || ident->raid_disks!= super.raid_disks)) { | |
224 | if (inargv || verbose) | |
225 | fprintf(stderr, Name ": %s requires wrong number of drives.\n", | |
226 | devname); | |
227 | continue; | |
228 | } | |
221 | 229 | |
222 | 230 | /* If we are this far, then we are commited to this device. |
223 | 231 | * If the super_block doesn't exist, or doesn't match others, |
224 | 232 | * then we cannot continue |
225 | 233 | */ |
226 | if (verbose) | |
227 | fprintf(stderr, Name ": %s is identified as a member of %s.\n", | |
228 | devname, mddev); | |
229 | 234 | |
230 | 235 | if (!havesuper) { |
231 | 236 | fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", |
243 | 248 | devname); |
244 | 249 | continue; |
245 | 250 | } |
251 | if (verbose) | |
252 | fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", | |
253 | devname, mddev, super.this_disk.raid_disk); | |
246 | 254 | devices[devcnt].devname = devname; |
247 | 255 | devices[devcnt].major = MAJOR(stb.st_rdev); |
248 | 256 | devices[devcnt].minor = MINOR(stb.st_rdev); |
276 | 284 | sparecnt=0; |
277 | 285 | for (i=0; i< MD_SB_DISKS;i++) { |
278 | 286 | int j = best[i]; |
287 | int event_margin = !force; | |
279 | 288 | if (j < 0) continue; |
280 | if (devices[j].events+1 >= | |
289 | if (devices[j].events+event_margin >= | |
281 | 290 | devices[most_recent].events) { |
282 | 291 | devices[j].uptodate = 1; |
283 | 292 | if (i < first_super.raid_disks) |
292 | 301 | * and add it. |
293 | 302 | */ |
294 | 303 | int fd; |
304 | chosen_drive = -1; | |
295 | 305 | for (i=0; i<first_super.raid_disks; i++) { |
296 | 306 | int j = best[i]; |
297 | 307 | if (j>=0 && |
343 | 353 | * If there are differences and --force is given, then update this chosen |
344 | 354 | * superblock. |
345 | 355 | */ |
356 | chosen_drive = -1; | |
346 | 357 | for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) { |
347 | 358 | int j = best[i]; |
348 | 359 | int fd; |
367 | 378 | |
368 | 379 | for (i=0; i<MD_SB_DISKS; i++) { |
369 | 380 | int j = best[i]; |
381 | int active_sync = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); | |
370 | 382 | if (j<0) |
371 | 383 | continue; |
372 | 384 | if (!devices[j].uptodate) |
378 | 390 | super.disks[j].minor = devices[j].minor; |
379 | 391 | } |
380 | 392 | if (devices[j].uptodate && |
381 | (super.disks[i].state & (1 << MD_DISK_FAULTY))) { | |
393 | (super.disks[i].state != active_sync)) { | |
382 | 394 | if (force) { |
383 | 395 | fprintf(stderr, Name ": " |
384 | "clearing FAULT flag for device %d in %s for %s\n", | |
396 | "clearing FAULTY flag for device %d in %s for %s\n", | |
385 | 397 | j, mddev, devices[j].devname); |
386 | super.disks[i].state &= ~(1<<MD_DISK_FAULTY); | |
398 | super.disks[i].state = active_sync; | |
387 | 399 | change |= 2; |
388 | 400 | } else { |
389 | 401 | fprintf(stderr, Name ": " |
459 | 471 | |
460 | 472 | if (runstop == 1 || |
461 | 473 | (runstop == 0 && |
462 | enough(first_super.level, first_super.raid_disks, okcnt))) { | |
474 | ( first_super.raid_disks == okcnt | |
475 | || start_partial_ok && enough(first_super.level, first_super.raid_disks, okcnt)) | |
476 | )) { | |
463 | 477 | if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { |
464 | 478 | fprintf(stderr, Name ": %s has been started with %d drive%s", |
465 | 479 | mddev, okcnt, okcnt==1?"":"s"); |
477 | 491 | mddev, okcnt, okcnt==1?"":"s"); |
478 | 492 | return 0; |
479 | 493 | } |
480 | fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it.\n", | |
494 | fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it (use --run to insist).\n", | |
481 | 495 | mddev, okcnt, okcnt==1?"":"s"); |
482 | 496 | return 1; |
483 | 497 | } else { |
485 | 499 | * been updated to point to the current locations of devices. |
486 | 500 | * so we can just start the array |
487 | 501 | */ |
488 | int dev; | |
502 | unsigned long dev; | |
489 | 503 | dev = MKDEV(devices[chosen_drive].major, |
490 | 504 | devices[chosen_drive].minor); |
491 | 505 | if (ioctl(mdfd, START_ARRAY, dev)) { |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
34 | 34 | |
35 | 35 | int Build(char *mddev, int mdfd, int chunk, int level, |
36 | 36 | int raiddisks, |
37 | int subdevs, char *subdev[]) | |
37 | mddev_dev_t devlist) | |
38 | 38 | { |
39 | 39 | /* Build a linear or raid0 arrays without superblocks |
40 | 40 | * We cannot really do any checks, we just do it. |
52 | 52 | int i; |
53 | 53 | int vers; |
54 | 54 | struct stat stb; |
55 | int subdevs = 0; | |
56 | mddev_dev_t dv; | |
57 | ||
58 | /* scan all devices, make sure they really are block devices */ | |
59 | for (dv = devlist; dv; dv=dv->next) { | |
60 | if (stat(dv->devname, &stb)) { | |
61 | fprintf(stderr, Name ": Cannot find %s: %s\n", | |
62 | dv->devname, strerror(errno)); | |
63 | return 1; | |
64 | } | |
65 | if ((stb.st_mode & S_IFMT) != S_IFBLK) { | |
66 | fprintf(stderr, Name ": %s is not a block device.\n", | |
67 | dv->devname); | |
68 | return 1; | |
69 | } | |
70 | subdevs++; | |
71 | } | |
72 | ||
55 | 73 | if (raiddisks != subdevs) { |
56 | 74 | fprintf(stderr, Name ": requested %d devices in array but listed %d\n", |
57 | 75 | raiddisks, subdevs); |
58 | 76 | return 1; |
59 | 77 | } |
60 | 78 | |
61 | /* scan all devices, make sure they really are block devices */ | |
62 | for (i=0; i<subdevs; i++) { | |
63 | if (stat(subdev[i], &stb)) { | |
64 | fprintf(stderr, Name ": Cannot find %s: %s\n", | |
65 | subdev[i], strerror(errno)); | |
66 | return 1; | |
67 | } | |
68 | if ((stb.st_mode & S_IFMT) != S_IFBLK) { | |
69 | fprintf(stderr, Name ": %s is not a block device.\n", | |
70 | subdev[i]); | |
71 | return 1; | |
72 | } | |
73 | } | |
74 | ||
75 | 79 | vers = md_get_version(mdfd); |
76 | 80 | |
77 | 81 | /* looks Ok, go for it */ |
78 | if (vers >= 90000) { | |
82 | if (vers >= 9000) { | |
79 | 83 | mdu_array_info_t array; |
80 | 84 | array.level = level; |
81 | 85 | array.size = 0; |
84 | 88 | array.md_minor = 0; |
85 | 89 | if (fstat(mdfd, &stb)==0) |
86 | 90 | array.md_minor = MINOR(stb.st_rdev); |
87 | array.not_persistent = 0; | |
91 | array.not_persistent = 1; | |
88 | 92 | array.state = 0; /* not clean, but no errors */ |
89 | 93 | array.active_disks = raiddisks; |
90 | 94 | array.working_disks = raiddisks; |
91 | 95 | array.spare_disks = 0; |
92 | 96 | array.failed_disks = 0; |
97 | if (chunk == 0) | |
98 | chunk = 64; | |
93 | 99 | array.chunk_size = chunk*1024; |
94 | 100 | if (ioctl(mdfd, SET_ARRAY_INFO, &array)) { |
95 | 101 | fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", |
98 | 104 | } |
99 | 105 | } |
100 | 106 | /* now add the devices */ |
101 | for (i=0; i<subdevs; i++) { | |
102 | if (stat(subdev[i], &stb)) { | |
107 | for ((i=0), (dv = devlist) ; dv ; i++, dv=dv->next) { | |
108 | if (stat(dv->devname, &stb)) { | |
103 | 109 | fprintf(stderr, Name ": Wierd: %s has disappeared.\n", |
104 | subdev[i]); | |
110 | dv->devname); | |
105 | 111 | goto abort; |
106 | 112 | } |
107 | if ((stb.st_rdev & S_IFMT)!= S_IFBLK) { | |
113 | if ((stb.st_mode & S_IFMT)!= S_IFBLK) { | |
108 | 114 | fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n", |
109 | subdev[i]); | |
115 | dv->devname); | |
110 | 116 | goto abort; |
111 | 117 | } |
112 | if (vers> 90000) { | |
118 | if (vers>= 9000) { | |
113 | 119 | mdu_disk_info_t disk; |
114 | 120 | disk.number = i; |
115 | 121 | disk.raid_disk = i; |
118 | 124 | disk.minor = MINOR(stb.st_rdev); |
119 | 125 | if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { |
120 | 126 | fprintf(stderr, Name ": ADD_NEW_DISK failed for %s: %s\n", |
121 | subdev[i], strerror(errno)); | |
127 | dv->devname, strerror(errno)); | |
122 | 128 | goto abort; |
123 | 129 | } |
124 | 130 | } else { |
125 | 131 | if (ioctl(mdfd, REGISTER_DEV, &stb.st_rdev)) { |
126 | 132 | fprintf(stderr, Name ": REGISTER_DEV failed for %s.\n", |
127 | subdev[i], strerror(errno)); | |
133 | dv->devname, strerror(errno)); | |
128 | 134 | goto abort; |
129 | 135 | } |
130 | 136 | } |
131 | 137 | } |
132 | 138 | /* now to start it */ |
133 | if (vers > 90000) { | |
139 | if (vers >= 9000) { | |
134 | 140 | mdu_param_t param; /* not used by syscall */ |
135 | if (ioctl(mdfd, RUN_ARRAY, param)) { | |
141 | if (ioctl(mdfd, RUN_ARRAY, ¶m)) { | |
136 | 142 | fprintf(stderr, Name ": RUN_ARRAY failed: %s\n", |
137 | 143 | strerror(errno)); |
138 | 144 | goto abort; |
139 | 145 | } |
140 | 146 | } else { |
141 | int arg; | |
147 | unsigned long arg; | |
142 | 148 | arg=0; |
143 | 149 | while (chunk > 4096) { |
144 | 150 | arg++; |
158 | 164 | return 0; |
159 | 165 | |
160 | 166 | abort: |
161 | if (vers > 900000) | |
167 | if (vers >= 9000) | |
162 | 168 | ioctl(mdfd, STOP_ARRAY, 0); |
163 | 169 | else |
164 | 170 | ioctl(mdfd, STOP_MD, 0); |
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 2, June 1991 | |
2 | ||
3 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |
4 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5 | Everyone is permitted to copy and distribute verbatim copies | |
6 | of this license document, but changing it is not allowed. | |
7 | ||
8 | Preamble | |
9 | ||
10 | The licenses for most software are designed to take away your | |
11 | freedom to share and change it. By contrast, the GNU General Public | |
12 | License is intended to guarantee your freedom to share and change free | |
13 | software--to make sure the software is free for all its users. This | |
14 | General Public License applies to most of the Free Software | |
15 | Foundation's software and to any other program whose authors commit to | |
16 | using it. (Some other Free Software Foundation software is covered by | |
17 | the GNU Library General Public License instead.) You can apply it to | |
18 | your programs, too. | |
19 | ||
20 | When we speak of free software, we are referring to freedom, not | |
21 | price. Our General Public Licenses are designed to make sure that you | |
22 | have the freedom to distribute copies of free software (and charge for | |
23 | this service if you wish), that you receive source code or can get it | |
24 | if you want it, that you can change the software or use pieces of it | |
25 | in new free programs; and that you know you can do these things. | |
26 | ||
27 | To protect your rights, we need to make restrictions that forbid | |
28 | anyone to deny you these rights or to ask you to surrender the rights. | |
29 | These restrictions translate to certain responsibilities for you if you | |
30 | distribute copies of the software, or if you modify it. | |
31 | ||
32 | For example, if you distribute copies of such a program, whether | |
33 | gratis or for a fee, you must give the recipients all the rights that | |
34 | you have. You must make sure that they, too, receive or can get the | |
35 | source code. And you must show them these terms so they know their | |
36 | rights. | |
37 | ||
38 | We protect your rights with two steps: (1) copyright the software, and | |
39 | (2) offer you this license which gives you legal permission to copy, | |
40 | distribute and/or modify the software. | |
41 | ||
42 | Also, for each author's protection and ours, we want to make certain | |
43 | that everyone understands that there is no warranty for this free | |
44 | software. If the software is modified by someone else and passed on, we | |
45 | want its recipients to know that what they have is not the original, so | |
46 | that any problems introduced by others will not reflect on the original | |
47 | authors' reputations. | |
48 | ||
49 | Finally, any free program is threatened constantly by software | |
50 | patents. We wish to avoid the danger that redistributors of a free | |
51 | program will individually obtain patent licenses, in effect making the | |
52 | program proprietary. To prevent this, we have made it clear that any | |
53 | patent must be licensed for everyone's free use or not licensed at all. | |
54 | ||
55 | The precise terms and conditions for copying, distribution and | |
56 | modification follow. | |
57 | ||
58 | GNU GENERAL PUBLIC LICENSE | |
59 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
60 | ||
61 | 0. This License applies to any program or other work which contains | |
62 | a notice placed by the copyright holder saying it may be distributed | |
63 | under the terms of this General Public License. The "Program", below, | |
64 | refers to any such program or work, and a "work based on the Program" | |
65 | means either the Program or any derivative work under copyright law: | |
66 | that is to say, a work containing the Program or a portion of it, | |
67 | either verbatim or with modifications and/or translated into another | |
68 | language. (Hereinafter, translation is included without limitation in | |
69 | the term "modification".) Each licensee is addressed as "you". | |
70 | ||
71 | Activities other than copying, distribution and modification are not | |
72 | covered by this License; they are outside its scope. The act of | |
73 | running the Program is not restricted, and the output from the Program | |
74 | is covered only if its contents constitute a work based on the | |
75 | Program (independent of having been made by running the Program). | |
76 | Whether that is true depends on what the Program does. | |
77 | ||
78 | 1. You may copy and distribute verbatim copies of the Program's | |
79 | source code as you receive it, in any medium, provided that you | |
80 | conspicuously and appropriately publish on each copy an appropriate | |
81 | copyright notice and disclaimer of warranty; keep intact all the | |
82 | notices that refer to this License and to the absence of any warranty; | |
83 | and give any other recipients of the Program a copy of this License | |
84 | along with the Program. | |
85 | ||
86 | You may charge a fee for the physical act of transferring a copy, and | |
87 | you may at your option offer warranty protection in exchange for a fee. | |
88 | ||
89 | 2. You may modify your copy or copies of the Program or any portion | |
90 | of it, thus forming a work based on the Program, and copy and | |
91 | distribute such modifications or work under the terms of Section 1 | |
92 | above, provided that you also meet all of these conditions: | |
93 | ||
94 | a) You must cause the modified files to carry prominent notices | |
95 | stating that you changed the files and the date of any change. | |
96 | ||
97 | b) You must cause any work that you distribute or publish, that in | |
98 | whole or in part contains or is derived from the Program or any | |
99 | part thereof, to be licensed as a whole at no charge to all third | |
100 | parties under the terms of this License. | |
101 | ||
102 | c) If the modified program normally reads commands interactively | |
103 | when run, you must cause it, when started running for such | |
104 | interactive use in the most ordinary way, to print or display an | |
105 | announcement including an appropriate copyright notice and a | |
106 | notice that there is no warranty (or else, saying that you provide | |
107 | a warranty) and that users may redistribute the program under | |
108 | these conditions, and telling the user how to view a copy of this | |
109 | License. (Exception: if the Program itself is interactive but | |
110 | does not normally print such an announcement, your work based on | |
111 | the Program is not required to print an announcement.) | |
112 | ||
113 | These requirements apply to the modified work as a whole. If | |
114 | identifiable sections of that work are not derived from the Program, | |
115 | and can be reasonably considered independent and separate works in | |
116 | themselves, then this License, and its terms, do not apply to those | |
117 | sections when you distribute them as separate works. But when you | |
118 | distribute the same sections as part of a whole which is a work based | |
119 | on the Program, the distribution of the whole must be on the terms of | |
120 | this License, whose permissions for other licensees extend to the | |
121 | entire whole, and thus to each and every part regardless of who wrote it. | |
122 | ||
123 | Thus, it is not the intent of this section to claim rights or contest | |
124 | your rights to work written entirely by you; rather, the intent is to | |
125 | exercise the right to control the distribution of derivative or | |
126 | collective works based on the Program. | |
127 | ||
128 | In addition, mere aggregation of another work not based on the Program | |
129 | with the Program (or with a work based on the Program) on a volume of | |
130 | a storage or distribution medium does not bring the other work under | |
131 | the scope of this License. | |
132 | ||
133 | 3. You may copy and distribute the Program (or a work based on it, | |
134 | under Section 2) in object code or executable form under the terms of | |
135 | Sections 1 and 2 above provided that you also do one of the following: | |
136 | ||
137 | a) Accompany it with the complete corresponding machine-readable | |
138 | source code, which must be distributed under the terms of Sections | |
139 | 1 and 2 above on a medium customarily used for software interchange; or, | |
140 | ||
141 | b) Accompany it with a written offer, valid for at least three | |
142 | years, to give any third party, for a charge no more than your | |
143 | cost of physically performing source distribution, a complete | |
144 | machine-readable copy of the corresponding source code, to be | |
145 | distributed under the terms of Sections 1 and 2 above on a medium | |
146 | customarily used for software interchange; or, | |
147 | ||
148 | c) Accompany it with the information you received as to the offer | |
149 | to distribute corresponding source code. (This alternative is | |
150 | allowed only for noncommercial distribution and only if you | |
151 | received the program in object code or executable form with such | |
152 | an offer, in accord with Subsection b above.) | |
153 | ||
154 | The source code for a work means the preferred form of the work for | |
155 | making modifications to it. For an executable work, complete source | |
156 | code means all the source code for all modules it contains, plus any | |
157 | associated interface definition files, plus the scripts used to | |
158 | control compilation and installation of the executable. However, as a | |
159 | special exception, the source code distributed need not include | |
160 | anything that is normally distributed (in either source or binary | |
161 | form) with the major components (compiler, kernel, and so on) of the | |
162 | operating system on which the executable runs, unless that component | |
163 | itself accompanies the executable. | |
164 | ||
165 | If distribution of executable or object code is made by offering | |
166 | access to copy from a designated place, then offering equivalent | |
167 | access to copy the source code from the same place counts as | |
168 | distribution of the source code, even though third parties are not | |
169 | compelled to copy the source along with the object code. | |
170 | ||
171 | 4. You may not copy, modify, sublicense, or distribute the Program | |
172 | except as expressly provided under this License. Any attempt | |
173 | otherwise to copy, modify, sublicense or distribute the Program is | |
174 | void, and will automatically terminate your rights under this License. | |
175 | However, parties who have received copies, or rights, from you under | |
176 | this License will not have their licenses terminated so long as such | |
177 | parties remain in full compliance. | |
178 | ||
179 | 5. You are not required to accept this License, since you have not | |
180 | signed it. However, nothing else grants you permission to modify or | |
181 | distribute the Program or its derivative works. These actions are | |
182 | prohibited by law if you do not accept this License. Therefore, by | |
183 | modifying or distributing the Program (or any work based on the | |
184 | Program), you indicate your acceptance of this License to do so, and | |
185 | all its terms and conditions for copying, distributing or modifying | |
186 | the Program or works based on it. | |
187 | ||
188 | 6. Each time you redistribute the Program (or any work based on the | |
189 | Program), the recipient automatically receives a license from the | |
190 | original licensor to copy, distribute or modify the Program subject to | |
191 | these terms and conditions. You may not impose any further | |
192 | restrictions on the recipients' exercise of the rights granted herein. | |
193 | You are not responsible for enforcing compliance by third parties to | |
194 | this License. | |
195 | ||
196 | 7. If, as a consequence of a court judgment or allegation of patent | |
197 | infringement or for any other reason (not limited to patent issues), | |
198 | conditions are imposed on you (whether by court order, agreement or | |
199 | otherwise) that contradict the conditions of this License, they do not | |
200 | excuse you from the conditions of this License. If you cannot | |
201 | distribute so as to satisfy simultaneously your obligations under this | |
202 | License and any other pertinent obligations, then as a consequence you | |
203 | may not distribute the Program at all. For example, if a patent | |
204 | license would not permit royalty-free redistribution of the Program by | |
205 | all those who receive copies directly or indirectly through you, then | |
206 | the only way you could satisfy both it and this License would be to | |
207 | refrain entirely from distribution of the Program. | |
208 | ||
209 | If any portion of this section is held invalid or unenforceable under | |
210 | any particular circumstance, the balance of the section is intended to | |
211 | apply and the section as a whole is intended to apply in other | |
212 | circumstances. | |
213 | ||
214 | It is not the purpose of this section to induce you to infringe any | |
215 | patents or other property right claims or to contest validity of any | |
216 | such claims; this section has the sole purpose of protecting the | |
217 | integrity of the free software distribution system, which is | |
218 | implemented by public license practices. Many people have made | |
219 | generous contributions to the wide range of software distributed | |
220 | through that system in reliance on consistent application of that | |
221 | system; it is up to the author/donor to decide if he or she is willing | |
222 | to distribute software through any other system and a licensee cannot | |
223 | impose that choice. | |
224 | ||
225 | This section is intended to make thoroughly clear what is believed to | |
226 | be a consequence of the rest of this License. | |
227 | ||
228 | 8. If the distribution and/or use of the Program is restricted in | |
229 | certain countries either by patents or by copyrighted interfaces, the | |
230 | original copyright holder who places the Program under this License | |
231 | may add an explicit geographical distribution limitation excluding | |
232 | those countries, so that distribution is permitted only in or among | |
233 | countries not thus excluded. In such case, this License incorporates | |
234 | the limitation as if written in the body of this License. | |
235 | ||
236 | 9. The Free Software Foundation may publish revised and/or new versions | |
237 | of the General Public License from time to time. Such new versions will | |
238 | be similar in spirit to the present version, but may differ in detail to | |
239 | address new problems or concerns. | |
240 | ||
241 | Each version is given a distinguishing version number. If the Program | |
242 | specifies a version number of this License which applies to it and "any | |
243 | later version", you have the option of following the terms and conditions | |
244 | either of that version or of any later version published by the Free | |
245 | Software Foundation. If the Program does not specify a version number of | |
246 | this License, you may choose any version ever published by the Free Software | |
247 | Foundation. | |
248 | ||
249 | 10. If you wish to incorporate parts of the Program into other free | |
250 | programs whose distribution conditions are different, write to the author | |
251 | to ask for permission. For software which is copyrighted by the Free | |
252 | Software Foundation, write to the Free Software Foundation; we sometimes | |
253 | make exceptions for this. Our decision will be guided by the two goals | |
254 | of preserving the free status of all derivatives of our free software and | |
255 | of promoting the sharing and reuse of software generally. | |
256 | ||
257 | NO WARRANTY | |
258 | ||
259 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
260 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
261 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
262 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |
263 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
264 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |
265 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |
266 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |
267 | REPAIR OR CORRECTION. | |
268 | ||
269 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
270 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
271 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |
272 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |
273 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |
274 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |
275 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |
276 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |
277 | POSSIBILITY OF SUCH DAMAGES. | |
278 | ||
279 | END OF TERMS AND CONDITIONS | |
280 | ||
281 | How to Apply These Terms to Your New Programs | |
282 | ||
283 | If you develop a new program, and you want it to be of the greatest | |
284 | possible use to the public, the best way to achieve this is to make it | |
285 | free software which everyone can redistribute and change under these terms. | |
286 | ||
287 | To do so, attach the following notices to the program. It is safest | |
288 | to attach them to the start of each source file to most effectively | |
289 | convey the exclusion of warranty; and each file should have at least | |
290 | the "copyright" line and a pointer to where the full notice is found. | |
291 | ||
292 | <one line to give the program's name and a brief idea of what it does.> | |
293 | Copyright (C) 19yy <name of author> | |
294 | ||
295 | This program is free software; you can redistribute it and/or modify | |
296 | it under the terms of the GNU General Public License as published by | |
297 | the Free Software Foundation; either version 2 of the License, or | |
298 | (at your option) any later version. | |
299 | ||
300 | This program is distributed in the hope that it will be useful, | |
301 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
302 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
303 | GNU General Public License for more details. | |
304 | ||
305 | You should have received a copy of the GNU General Public License | |
306 | along with this program; if not, write to the Free Software | |
307 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
308 | ||
309 | ||
310 | Also add information on how to contact you by electronic and paper mail. | |
311 | ||
312 | If the program is interactive, make it output a short notice like this | |
313 | when it starts in an interactive mode: | |
314 | ||
315 | Gnomovision version 69, Copyright (C) 19yy name of author | |
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
317 | This is free software, and you are welcome to redistribute it | |
318 | under certain conditions; type `show c' for details. | |
319 | ||
320 | The hypothetical commands `show w' and `show c' should show the appropriate | |
321 | parts of the General Public License. Of course, the commands you use may | |
322 | be called something other than `show w' and `show c'; they could even be | |
323 | mouse-clicks or menu items--whatever suits your program. | |
324 | ||
325 | You should also get your employer (if you work as a programmer) or your | |
326 | school, if any, to sign a "copyright disclaimer" for the program, if | |
327 | necessary. Here is a sample; alter the names: | |
328 | ||
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. | |
331 | ||
332 | <signature of Ty Coon>, 1 April 1989 | |
333 | Ty Coon, President of Vice | |
334 | ||
335 | This General Public License does not permit incorporating your program into | |
336 | proprietary programs. If your program is a subroutine library, you may | |
337 | consider it more useful to permit linking proprietary applications with the | |
338 | library. If this is what you want to do, use the GNU Library General | |
339 | Public License instead of this License. |
0 | ||
1 | Changes Prior to 0.6 release | |
2 | ||
3 | - Remove the limit on the number of device names that can be | |
4 | given on the command line. | |
5 | - Fix bug in --assemble --force where it would only update a | |
6 | single superblock. | |
7 | - Fix bogus printing of big numbers not being block devices | |
8 | when given names of devices that don't exist. | |
9 | - When --assemble --force, consider superblocks with an event | |
10 | count that is 1 behind as out-of-date. Normally they are | |
11 | considered up-to-date (as the kernel assumes this too). | |
12 | - When marking drives as not-failed in the superblock, | |
13 | we also mark them as ACTIVE and SYNC. | |
14 | - Don't start arrays for which not all drives are available unless: | |
15 | --scan which implies that all drives were found automatically | |
16 | --run which means the user knows what they want | |
17 | --force which means that we are fixing something broken | |
18 | - Make sure all device numbers passed as 3rd arg of ioctl | |
19 | are passed as unsigned lock, so that it works on SPARC | |
20 | - If HOT_ADD_DISK failes for -a, then only try ADD_NEW_DISK | |
21 | if we cannot read from the array, i.e. if the array is | |
22 | not started yet. | |
23 | - man page update | |
24 | - Taught Examine to handle --scan. It examines all devices listed | |
25 | on DEVICE lines in the config file. | |
26 | - Added --brief (-b) flag for Examine and Detail to print out | |
27 | and mdctl.conf compatible description with uuid=, level=, | |
28 | disks= and - for Examine - devices= | |
29 | --examine --brief collects all devices the make the one array and | |
30 | list them as one entry. | |
31 | - Added level= and disks= options to ARRAY lines in config files | |
32 | so --brief output could be used as-is. | |
33 | - Make parity style ({left,right}-{,a}symmetric) consistantly use -, | |
34 | never _. | |
35 | - Add "Array Size" to --detail output | |
36 | - Change "Size" to "Device Size" and exclude from Detail of arrays | |
37 | that do not have a consistent device size. | |
38 | - Add Human readable MiB or GiB value on size lines of Detail and Examine | |
39 | - --assemble --scan doesn't complain about active drives | |
40 | - require number of spares given in -x to be listed. | |
41 | - Made --build actually work. | |
42 | Changes Prior to 0.5 release | |
43 | ||
44 | --assemble: | |
45 | spare drives are handled properly. | |
46 | ||
47 | --force can be used to recover from 2-drive failures on RAID5 | |
48 | If you belive that /dev/hda1 /dev/hdb1 /dev/hdc1 /dev/hdd1 should | |
49 | make a raid5 array, but it has experienced multiple failures and | |
50 | wont start, then | |
51 | ||
52 | mdctl --assemble --force /dev/md0 /dev/hd[abcd]1 | |
53 | ||
54 | Should update the superblock on the newest failed drive and | |
55 | restart the array in degraded mode. You should then remove the | |
56 | remaining failed drive and re-add it (if you are happy that it | |
57 | might work). | |
58 | ||
59 | Ofcourse whenever you have a 2-drive failure, you have a risk | |
60 | of corruption in data that hasn't be changed for a long time. So | |
61 | this doesn't give you your array back all nice and happy, but it | |
62 | does allow you to recover data that might not be corrupt. | |
63 | ||
64 | More flexibility in identifying a RAID array in the mdctl.conf | |
65 | e.g. | |
66 | array /dev/md4 super-minor=4 | |
67 | ||
68 | assembles /dev/md4 from all devices found that have a raid | |
69 | superblock that says the minor number of the array is 4. | |
70 | If the blocks with the right minor number do not all have the | |
71 | same UUID, an error is flags and no assembly happens. | |
72 | ||
73 | array /dev/md3 devices=/dev/hd[abc]2 | |
74 | ||
75 | Assembles /dev/md3 drom /dev/hda2 /dev/hdb2 and/dev/hdc2. All | |
76 | devices must exist and have raid superblock with the same uuid. | |
77 | ||
78 | If two identity specifiers are used, only devices that match all | |
79 | of them are considered, so | |
80 | ||
81 | array /dev/md2 devices=/dev/hd?2 super-minor=2 | |
82 | ||
83 | will assemble /dev/md2 using all /dev/hd?2 devices which have a | |
84 | raid superblock with minor number 2. | |
85 | ||
86 | --create: | |
87 | When listing devices for --create, the word "missing" can be | |
88 | used to indicate that the respective slot does not have a | |
89 | working drive currently. This is similar to the "failed-disk" | |
90 | directive in mkraid/raidtab. | |
91 | e.g. | |
92 | mdctl --create --level=5 -raid-disks=4 --spare-disks=2 | |
93 | /dev/md0 /dev/sda /dev/sdb missing /dev/sdc /dev/sdd /dev/sde | |
94 | ||
95 | will create a raid5 array with the third slot empty, and two | |
96 | spares. | |
97 | ||
98 | By default, raid5 arrays are created with the last slot empty | |
99 | and drive listed for the last slot added as a spare. If a | |
100 | "missing" slot is given, or if --force is given, then --create | |
101 | does exactly what you ask and doesn't try to be clever. | |
102 | ||
103 | ||
104 | --follow / --monitor: | |
105 | ||
106 | This is a new mode. I couldn't stop my self from picking a name | |
107 | starting with F (as current modes start A,B,C,D,E) but I | |
108 | relented and provided an alternate name that is somewhat more | |
109 | meaningful. | |
110 | ||
111 | In this mode, mdctl does not exit, but runs continuously and | |
112 | periodically polls all the md devices to see if they have had | |
113 | any interested state change. | |
114 | The changes that it currently notices are: | |
115 | Fail - an active disc fails | |
116 | FailSpare - a spare, that was presumably being build, fails | |
117 | ActiveSpare - a spare becomes active, presumably after a rebuild. | |
118 | ||
119 | Options: | |
120 | --mail mailaddress - send Email on any Fail* event | |
121 | --program program - run the program on any event. | |
122 | Args are: eventname mddevice subdevice(if-known) | |
123 | --delay seconds - change from the default 60second pause | |
124 | between polls. | |
125 | ||
126 | I plan to add functionality to this mode to allow sharing of | |
127 | spare drives. If an array is marks "spare-group=fred", and it | |
128 | has a failed drive and no spares, and if some other array is | |
129 | also "spare-group=fred" and it has no failed drives, but does | |
130 | have a spare drive that is big enough, the spare will be moved | |
131 | to the first array. | |
132 | ||
133 | I also have the idea of adding a --grow mode which will re-organise | |
134 | the data on an N disk raid0/4/5 array to be on an N+M disk array. | |
135 | I have no concrete plans for this though. | |
136 | ||
137 | I got rid of the "v" in the archive file name, and include the | |
138 | version number in the directory created by the archive. | |
139 | ||
140 | There is now a man page and mdctl.spec (for rpm) thanks to | |
141 | Danilo Godec <danci@agenda.si>. | |
142 | ||
143 | Ofcourse, the man page is now out of date and despite being based on | |
144 | the --help output, is not wholy correct. After I get --follow | |
145 | working properly, I plan to revise the various documentation and/or | |
146 | the code to make sure the two match. | |
147 |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
32 | 32 | |
33 | 33 | int Create(char *mddev, int mdfd, |
34 | 34 | int chunk, int level, int layout, int size, int raiddisks, int sparedisks, |
35 | int subdevs, char *subdev[], | |
35 | int subdevs, mddev_dev_t devlist, | |
36 | 36 | int runstop, int verbose, int force) |
37 | 37 | { |
38 | 38 | /* |
52 | 52 | * RUN_ARRAY |
53 | 53 | */ |
54 | 54 | int minsize, maxsize; |
55 | int maxdisc= -1, mindisc = -1; | |
55 | char *mindisc = NULL; | |
56 | char *maxdisc = NULL; | |
56 | 57 | int i; |
58 | mddev_dev_t dv; | |
57 | 59 | int fail=0, warn=0; |
58 | 60 | struct stat stb; |
59 | 61 | int first_missing = MD_SB_DISKS*2; |
92 | 94 | fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks); |
93 | 95 | return 1; |
94 | 96 | } |
95 | if (subdevs < raiddisks) { | |
97 | if (subdevs < raiddisks+sparedisks) { | |
96 | 98 | fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n"); |
97 | 99 | return 1; |
98 | 100 | } |
120 | 122 | /* now look at the subdevs */ |
121 | 123 | array.active_disks = 0; |
122 | 124 | array.working_disks = 0; |
123 | for (i=0; i<subdevs; i++) { | |
124 | char *dname = subdev[i]; | |
125 | for (dv=devlist; dv; dv=dv->next) { | |
126 | char *dname = dv->devname; | |
125 | 127 | int dsize, freesize; |
126 | 128 | int fd; |
127 | if (strcasecmp(subdev[i], "missing")==0) { | |
129 | if (strcasecmp(dname, "missing")==0) { | |
128 | 130 | if (first_missing > i) |
129 | 131 | first_missing = i; |
130 | 132 | missing_disks ++; |
164 | 166 | close(fd); |
165 | 167 | continue; |
166 | 168 | } |
167 | if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) { | |
168 | maxdisc = i; | |
169 | if (maxdisc == NULL || (maxdisc && freesize > maxsize)) { | |
170 | maxdisc = dname; | |
169 | 171 | maxsize = freesize; |
170 | 172 | } |
171 | if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) { | |
172 | mindisc = i; | |
173 | if (mindisc ==NULL || (mindisc && freesize < minsize)) { | |
174 | mindisc = dname; | |
173 | 175 | minsize = freesize; |
174 | 176 | } |
175 | 177 | warn |= check_ext2(fd, dname); |
182 | 184 | return 1; |
183 | 185 | } |
184 | 186 | if (size == 0) { |
185 | if (mindisc == -1) { | |
187 | if (mindisc == NULL) { | |
186 | 188 | fprintf(stderr, Name ": no size and no drives given - aborting create.\n"); |
187 | 189 | return 1; |
188 | 190 | } |
192 | 194 | } |
193 | 195 | if ((maxsize-size)*100 > maxsize) { |
194 | 196 | fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n", |
195 | subdev[maxdisc], size); | |
197 | maxdisc, size); | |
196 | 198 | warn = 1; |
197 | 199 | } |
198 | 200 | |
266 | 268 | return 1; |
267 | 269 | } |
268 | 270 | |
269 | for (i=0; i<subdevs; i++) { | |
271 | for (i=0, dv = devlist ; dv ; dv=dv->next, i++) { | |
270 | 272 | int fd; |
271 | 273 | struct stat stb; |
272 | 274 | mdu_disk_info_t disk; |
279 | 281 | disk.state = 6; /* active and in sync */ |
280 | 282 | else |
281 | 283 | disk.state = 0; |
282 | if (strcasecmp(subdev[i], "missing")==0) { | |
284 | if (strcasecmp(dv->devname, "missing")==0) { | |
283 | 285 | disk.major = 0; |
284 | 286 | disk.minor = 0; |
285 | 287 | disk.state = 1; /* faulty */ |
286 | 288 | } else { |
287 | fd = open(subdev[i], O_RDONLY, 0); | |
289 | fd = open(dv->devname, O_RDONLY, 0); | |
288 | 290 | if (fd < 0) { |
289 | 291 | fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n", |
290 | subdev[i]); | |
292 | dv->devname); | |
291 | 293 | return 1; |
292 | 294 | } |
293 | 295 | fstat(fd, &stb); |
297 | 299 | } |
298 | 300 | if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { |
299 | 301 | fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", |
300 | subdev[i], strerror(errno)); | |
302 | dv->devname, strerror(errno)); | |
301 | 303 | return 1; |
302 | 304 | } |
303 | 305 | } |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
30 | 30 | #include "md_p.h" |
31 | 31 | #include "md_u.h" |
32 | 32 | |
33 | int Detail(char *dev) | |
33 | int Detail(char *dev, int brief) | |
34 | 34 | { |
35 | 35 | /* |
36 | 36 | * Print out details for an md array by using |
76 | 76 | return 1; |
77 | 77 | } |
78 | 78 | /* Ok, we have some info to print... */ |
79 | printf("%s:\n", dev); | |
80 | printf(" Version : %02d.%02d.%02d\n", | |
81 | array.major_version, array.minor_version, array.patch_version); | |
82 | atime = array.ctime; | |
83 | printf(" Creation Time : %.24s\n", ctime(&atime)); | |
84 | 79 | c = map_num(pers, array.level); |
85 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
86 | printf(" Size : %d\n", array.size); | |
87 | printf(" Raid Disks : %d\n", array.raid_disks); | |
88 | printf(" Total Disks : %d\n", array.nr_disks); | |
89 | printf("Preferred Minor : %d\n", array.md_minor); | |
90 | printf(" Persistance : Superblock is %spersistant\n", | |
91 | array.not_persistent?"not ":""); | |
92 | printf("\n"); | |
93 | atime = array.utime; | |
94 | printf(" Update Time : %.24s\n", ctime(&atime)); | |
95 | printf(" State : %s, %serrors\n", | |
96 | (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty", | |
97 | (array.state&(1<<MD_SB_ERRORS))?"":"no-"); | |
98 | printf(" Active Drives : %d\n", array.active_disks); | |
99 | printf(" Working Drives : %d\n", array.working_disks); | |
100 | printf(" Failed Drives : %d\n", array.failed_disks); | |
101 | printf(" Spare Drives : %d\n", array.spare_disks); | |
102 | printf("\n"); | |
103 | if (array.level == 5) { | |
104 | c = map_num(r5layout, array.layout); | |
105 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
80 | if (brief) | |
81 | printf("ARRAY %s level=%s disks=%d", dev, c?c:"-unknown-",array.raid_disks ); | |
82 | else { | |
83 | int array_size; | |
84 | if (ioctl(fd, BLKGETSIZE, &array_size)) | |
85 | array_size = 0; | |
86 | else array_size>>= 1; | |
87 | printf("%s:\n", dev); | |
88 | printf(" Version : %02d.%02d.%02d\n", | |
89 | array.major_version, array.minor_version, array.patch_version); | |
90 | atime = array.ctime; | |
91 | printf(" Creation Time : %.24s\n", ctime(&atime)); | |
92 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
93 | if (array_size) | |
94 | printf(" Array Size : %d%s\n", array_size, human_size(array_size)); | |
95 | if (array.level >= 1) | |
96 | printf(" Device Size : %d%s\n", array.size, human_size(array.size)); | |
97 | printf(" Raid Disks : %d\n", array.raid_disks); | |
98 | printf(" Total Disks : %d\n", array.nr_disks); | |
99 | printf("Preferred Minor : %d\n", array.md_minor); | |
100 | printf(" Persistance : Superblock is %spersistant\n", | |
101 | array.not_persistent?"not ":""); | |
102 | printf("\n"); | |
103 | atime = array.utime; | |
104 | printf(" Update Time : %.24s\n", ctime(&atime)); | |
105 | printf(" State : %s, %serrors\n", | |
106 | (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty", | |
107 | (array.state&(1<<MD_SB_ERRORS))?"":"no-"); | |
108 | printf(" Active Drives : %d\n", array.active_disks); | |
109 | printf(" Working Drives : %d\n", array.working_disks); | |
110 | printf(" Failed Drives : %d\n", array.failed_disks); | |
111 | printf(" Spare Drives : %d\n", array.spare_disks); | |
112 | printf("\n"); | |
113 | if (array.level == 5) { | |
114 | c = map_num(r5layout, array.layout); | |
115 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
116 | } | |
117 | switch (array.level) { | |
118 | case 0: | |
119 | case 4: | |
120 | case 5: | |
121 | printf(" Chunk Size : %dK\n", array.chunk_size/1024); | |
122 | break; | |
123 | case -1: | |
124 | printf(" Rounding : %dK\n", array.chunk_size/1024); | |
125 | break; | |
126 | default: break; | |
127 | } | |
128 | ||
129 | printf("\n"); | |
130 | printf(" Number Major Minor RaidDisk State\n"); | |
106 | 131 | } |
107 | switch (array.level) { | |
108 | case 0: | |
109 | case 4: | |
110 | case 5: | |
111 | printf(" Chunk Size : %dK\n", array.chunk_size/1024); | |
112 | break; | |
113 | case -1: | |
114 | printf(" Rounding : %dK\n", array.chunk_size/1024); | |
115 | break; | |
116 | default: break; | |
117 | } | |
118 | ||
119 | printf("\n"); | |
120 | printf(" Number Major Minor RaidDisk State\n"); | |
121 | 132 | for (d= 0; d<array.raid_disks+array.spare_disks; d++) { |
122 | 133 | mdu_disk_info_t disk; |
123 | 134 | char *dv; |
127 | 138 | d, strerror(errno)); |
128 | 139 | continue; |
129 | 140 | } |
130 | printf(" %5d %5d %5d %5d ", | |
131 | disk.number, disk.major, disk.minor, disk.raid_disk); | |
132 | if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty"); | |
133 | if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active"); | |
134 | if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync"); | |
135 | if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed"); | |
141 | if (!brief) { | |
142 | printf(" %5d %5d %5d %5d ", | |
143 | disk.number, disk.major, disk.minor, disk.raid_disk); | |
144 | if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty"); | |
145 | if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active"); | |
146 | if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync"); | |
147 | if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed"); | |
148 | } | |
136 | 149 | if ((dv=map_dev(disk.major, disk.minor))) { |
137 | printf(" %s", dv); | |
138 | if (!have_super) { | |
139 | /* try to read the superblock from this device | |
140 | * to get more info | |
141 | */ | |
142 | int fd = open(dv, O_RDONLY); | |
143 | if (fd >=0 && | |
144 | load_super(fd, &super) ==0 && | |
145 | super.ctime == array.ctime && | |
146 | super.level == array.level) | |
147 | have_super = 1; | |
148 | } | |
150 | if (!brief) printf(" %s", dv); | |
151 | if (!have_super) { | |
152 | /* try to read the superblock from this device | |
153 | * to get more info | |
154 | */ | |
155 | int fd = open(dv, O_RDONLY); | |
156 | if (fd >=0 && | |
157 | load_super(fd, &super) ==0 && | |
158 | super.ctime == array.ctime && | |
159 | super.level == array.level) | |
160 | have_super = 1; | |
161 | } | |
149 | 162 | } |
150 | printf("\n"); | |
163 | if (!brief) printf("\n"); | |
151 | 164 | } |
152 | 165 | if (have_super) { |
166 | if (brief) printf(" UUID="); | |
167 | else printf(" UUID : "); | |
153 | 168 | if (super.minor_version >= 90) |
154 | printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1, | |
155 | super.set_uuid2, super.set_uuid3); | |
156 | else | |
157 | printf(" UUID : %08x\n", super.set_uuid0); | |
169 | printf("%08x:%08x:%08x:%08x", super.set_uuid0, super.set_uuid1, | |
170 | super.set_uuid2, super.set_uuid3); | |
171 | else | |
172 | printf("%08x", super.set_uuid0); | |
173 | if (!brief) printf("\n"); | |
158 | 174 | } |
175 | if (brief) printf("\n"); | |
159 | 176 | return 0; |
160 | 177 | } |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
27 | 27 | */ |
28 | 28 | |
29 | 29 | #include "mdctl.h" |
30 | #include "dlink.h" | |
30 | 31 | |
31 | 32 | #if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) |
32 | 33 | #error no endian defined |
33 | 34 | #endif |
34 | 35 | #include "md_u.h" |
35 | 36 | #include "md_p.h" |
36 | int Examine(char *dev) | |
37 | int Examine(mddev_dev_t devlist, int brief, char *conffile) | |
37 | 38 | { |
38 | 39 | |
39 | 40 | /* Read the raid superblock from a device and |
48 | 49 | * |
49 | 50 | * utime, state etc |
50 | 51 | * |
52 | * If (brief) gather devices for same array and just print a mdctl.conf line including devices= | |
53 | * if devlist==NULL, use conf_get_devs( | |
51 | 54 | */ |
52 | int fd = open(dev, O_RDONLY); | |
55 | int fd; | |
53 | 56 | time_t atime; |
54 | 57 | mdp_super_t super; |
55 | 58 | int d; |
56 | 59 | char *c; |
57 | int rv; | |
58 | ||
59 | if (fd < 0) { | |
60 | fprintf(stderr,Name ": cannot open %s: %s\n", | |
61 | dev, strerror(errno)); | |
60 | int rv = 0; | |
61 | int err; | |
62 | int scan= 0; | |
63 | ||
64 | struct array { | |
65 | mdp_super_t super; | |
66 | void *devs; | |
67 | struct array *next; | |
68 | } *arrays = NULL; | |
69 | ||
70 | if (devlist == NULL) { | |
71 | devlist = conf_get_devs(conffile); | |
72 | scan=1; | |
73 | } | |
74 | if (devlist == NULL) { | |
75 | fprintf(stderr, Name ": No devices listed in %s\n", conffile); | |
62 | 76 | return 1; |
63 | 77 | } |
64 | 78 | |
65 | rv = load_super(fd, &super); | |
66 | close(fd); | |
67 | switch(rv) { | |
68 | case 1: | |
69 | fprintf(stderr, Name ": cannot find device size for %s: %s\n", | |
70 | dev, strerror(errno)); | |
71 | return 1; | |
72 | case 2: | |
79 | for (; devlist ; devlist=devlist->next) { | |
80 | fd = open(devlist->devname, O_RDONLY); | |
81 | if (fd < 0) { | |
82 | if (!scan) | |
83 | fprintf(stderr,Name ": cannot open %s: %s\n", | |
84 | devlist->devname, strerror(errno)); | |
85 | err = 1; | |
86 | } | |
87 | else { | |
88 | err = load_super(fd, &super); | |
89 | close(fd); | |
90 | } | |
91 | if (err && (brief||scan)) | |
92 | continue; | |
93 | if (err) rv =1; | |
94 | switch(err) { | |
95 | case 1: | |
96 | fprintf(stderr, Name ": cannot find device size for %s: %s\n", | |
97 | devlist->devname, strerror(errno)); | |
98 | continue; | |
99 | case 2: | |
73 | 100 | /* fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n", |
74 | dev, size); | |
101 | devlist->devname, size); | |
75 | 102 | */ |
76 | fprintf(stderr, Name ": %s is too small for md\n", | |
77 | dev); | |
78 | return 1; | |
79 | case 3: | |
80 | fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", | |
81 | dev, strerror(errno)); | |
82 | return 1; | |
83 | case 4: | |
84 | fprintf(stderr, Name ": Cannot read superblock on %s\n", | |
85 | dev); | |
86 | return 1; | |
87 | case 5: | |
88 | fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", | |
89 | dev, MD_SB_MAGIC, super.md_magic); | |
90 | return 1; | |
91 | case 6: | |
92 | fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", | |
93 | dev, super.major_version); | |
94 | return 1; | |
95 | } | |
103 | fprintf(stderr, Name ": %s is too small for md\n", | |
104 | devlist->devname); | |
105 | continue; | |
106 | case 3: | |
107 | fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", | |
108 | devlist->devname, strerror(errno)); | |
109 | continue; | |
110 | case 4: | |
111 | fprintf(stderr, Name ": Cannot read superblock on %s\n", | |
112 | devlist->devname); | |
113 | continue; | |
114 | case 5: | |
115 | fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", | |
116 | devlist->devname, MD_SB_MAGIC, super.md_magic); | |
117 | continue; | |
118 | case 6: | |
119 | fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", | |
120 | devlist->devname, super.major_version); | |
121 | continue; | |
122 | } | |
96 | 123 | |
97 | /* Ok, its good enough to try, though the checksum could be wrong */ | |
98 | printf("%s:\n",dev); | |
99 | printf(" Magic : %08x\n", super.md_magic); | |
100 | printf(" Version : %02d.%02d.%02d\n", super.major_version, super.minor_version, | |
101 | super.patch_version); | |
102 | if (super.minor_version >= 90) | |
103 | printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1, | |
104 | super.set_uuid2, super.set_uuid3); | |
105 | else | |
106 | printf(" UUID : %08x\n", super.set_uuid0); | |
107 | ||
108 | atime = super.ctime; | |
109 | printf(" Creation Time : %.24s\n", ctime(&atime)); | |
110 | c=map_num(pers, super.level); | |
111 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
112 | printf(" Size : %d\n", super.size); | |
113 | printf(" Raid Disks : %d\n", super.raid_disks); | |
114 | printf(" Total Disks : %d\n", super.nr_disks); | |
115 | printf("Preferred Minor : %d\n", super.md_minor); | |
116 | printf("\n"); | |
117 | atime = super.utime; | |
118 | printf(" Update Time : %.24s\n", ctime(&atime)); | |
119 | printf(" State : %s, %serrors\n", | |
120 | (super.state&(1<<MD_SB_CLEAN))?"clean":"dirty", | |
121 | (super.state&(1<<MD_SB_ERRORS))?"":"no-"); | |
122 | printf(" Active Drives : %d\n", super.active_disks); | |
123 | printf(" Working Drives : %d\n", super.working_disks); | |
124 | printf(" Failed Drives : %d\n", super.failed_disks); | |
125 | printf(" Spare Drives : %d\n", super.spare_disks); | |
126 | if (calc_sb_csum(&super) == super.sb_csum) | |
127 | printf(" Checksum : %x - correct\n", super.sb_csum); | |
128 | else | |
129 | printf(" Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super)); | |
130 | printf(" Events : %d.%d\n", super.events_hi, super.events_lo); | |
131 | printf("\n"); | |
132 | if (super.level == 5) { | |
133 | c = map_num(r5layout, super.layout); | |
134 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
135 | } | |
136 | switch(super.level) { | |
137 | case 0: | |
138 | case 4: | |
139 | case 5: | |
140 | printf(" Chunk Size : %dK\n", super.chunk_size/1024); | |
141 | break; | |
142 | case -1: | |
143 | printf(" Rounding : %dK\n", super.chunk_size/1024); | |
144 | break; | |
145 | default: break; | |
146 | } | |
147 | printf("\n"); | |
148 | printf(" Number Major Minor RaidDisk State\n"); | |
149 | for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) { | |
150 | mdp_disk_t *dp; | |
151 | char *dv; | |
152 | char nb[5]; | |
153 | if (d>=0) dp = &super.disks[d]; | |
154 | else dp = &super.this_disk; | |
155 | sprintf(nb, "%4d", d); | |
156 | printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb, | |
157 | dp->number, dp->major, dp->minor, dp->raid_disk); | |
158 | if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty"); | |
159 | if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active"); | |
160 | if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync"); | |
161 | if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed"); | |
162 | if ((dv=map_dev(dp->major, dp->minor))) | |
163 | printf(" %s", dv); | |
164 | printf("\n"); | |
165 | } | |
166 | return 0; | |
124 | /* Ok, its good enough to try, though the checksum could be wrong */ | |
125 | if (brief) { | |
126 | struct array *ap; | |
127 | char *d; | |
128 | for (ap=arrays; ap; ap=ap->next) { | |
129 | if (compare_super(&ap->super, &super)==0) | |
130 | break; | |
131 | } | |
132 | if (!ap) { | |
133 | ap = malloc(sizeof(*ap)); | |
134 | ap->super = super; | |
135 | ap->devs = dl_head(); | |
136 | ap->next = arrays; | |
137 | arrays = ap; | |
138 | } | |
139 | d = dl_strdup(devlist->devname); | |
140 | dl_add(ap->devs, d); | |
141 | } else { | |
142 | printf("%s:\n",devlist->devname); | |
143 | printf(" Magic : %08x\n", super.md_magic); | |
144 | printf(" Version : %02d.%02d.%02d\n", super.major_version, super.minor_version, | |
145 | super.patch_version); | |
146 | if (super.minor_version >= 90) | |
147 | printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1, | |
148 | super.set_uuid2, super.set_uuid3); | |
149 | else | |
150 | printf(" UUID : %08x\n", super.set_uuid0); | |
151 | ||
152 | atime = super.ctime; | |
153 | printf(" Creation Time : %.24s\n", ctime(&atime)); | |
154 | c=map_num(pers, super.level); | |
155 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
156 | printf(" Device Size : %d%s\n", super.size, human_size(super.size)); | |
157 | printf(" Raid Disks : %d\n", super.raid_disks); | |
158 | printf(" Total Disks : %d\n", super.nr_disks); | |
159 | printf("Preferred Minor : %d\n", super.md_minor); | |
160 | printf("\n"); | |
161 | atime = super.utime; | |
162 | printf(" Update Time : %.24s\n", ctime(&atime)); | |
163 | printf(" State : %s, %serrors\n", | |
164 | (super.state&(1<<MD_SB_CLEAN))?"clean":"dirty", | |
165 | (super.state&(1<<MD_SB_ERRORS))?"":"no-"); | |
166 | printf(" Active Drives : %d\n", super.active_disks); | |
167 | printf(" Working Drives : %d\n", super.working_disks); | |
168 | printf(" Failed Drives : %d\n", super.failed_disks); | |
169 | printf(" Spare Drives : %d\n", super.spare_disks); | |
170 | if (calc_sb_csum(&super) == super.sb_csum) | |
171 | printf(" Checksum : %x - correct\n", super.sb_csum); | |
172 | else | |
173 | printf(" Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super)); | |
174 | printf(" Events : %d.%d\n", super.events_hi, super.events_lo); | |
175 | printf("\n"); | |
176 | if (super.level == 5) { | |
177 | c = map_num(r5layout, super.layout); | |
178 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
179 | } | |
180 | switch(super.level) { | |
181 | case 0: | |
182 | case 4: | |
183 | case 5: | |
184 | printf(" Chunk Size : %dK\n", super.chunk_size/1024); | |
185 | break; | |
186 | case -1: | |
187 | printf(" Rounding : %dK\n", super.chunk_size/1024); | |
188 | break; | |
189 | default: break; | |
190 | } | |
191 | printf("\n"); | |
192 | printf(" Number Major Minor RaidDisk State\n"); | |
193 | for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) { | |
194 | mdp_disk_t *dp; | |
195 | char *dv; | |
196 | char nb[5]; | |
197 | if (d>=0) dp = &super.disks[d]; | |
198 | else dp = &super.this_disk; | |
199 | sprintf(nb, "%4d", d); | |
200 | printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb, | |
201 | dp->number, dp->major, dp->minor, dp->raid_disk); | |
202 | if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty"); | |
203 | if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active"); | |
204 | if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync"); | |
205 | if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed"); | |
206 | if ((dv=map_dev(dp->major, dp->minor))) | |
207 | printf(" %s", dv); | |
208 | printf("\n"); | |
209 | } | |
210 | } | |
211 | } | |
212 | if (brief) { | |
213 | struct array *ap; | |
214 | for (ap=arrays; ap; ap=ap->next) { | |
215 | char sep='='; | |
216 | char *c=map_num(pers, ap->super.level); | |
217 | char *d; | |
218 | printf("ARRAY /dev/md%d level=%s disks=%d UUID=", | |
219 | ap->super.md_minor, c?c:"-unknown-", ap->super.raid_disks); | |
220 | if (ap->super.minor_version >= 90) | |
221 | printf("%08x:%08x:%08x:%08x", ap->super.set_uuid0, ap->super.set_uuid1, | |
222 | ap->super.set_uuid2, ap->super.set_uuid3); | |
223 | else | |
224 | printf("%08x", ap->super.set_uuid0); | |
225 | printf("\n devices"); | |
226 | for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { | |
227 | printf("%c%s", sep, d); | |
228 | sep=','; | |
229 | } | |
230 | printf("\n"); | |
231 | } | |
232 | } | |
233 | return rv; | |
167 | 234 | } |
0 | 0 | # |
1 | 1 | # mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | # |
3 | # Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | # Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | # |
5 | 5 | # |
6 | 6 | # This program is free software; you can redistribute it and/or modify |
26 | 26 | # Australia |
27 | 27 | # |
28 | 28 | |
29 | CC = gcc | |
29 | 30 | CFLAGS = -Wall,error,strict-prototypes -ggdb |
30 | 31 | |
32 | INSTALL = /usr/bin/install | |
33 | DESTDIR = /sbin | |
34 | ||
31 | 35 | OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Monitor.o dlink.o |
32 | all : mdctl | |
36 | ||
37 | all : mdctl mdctl.man | |
33 | 38 | |
34 | 39 | mdctl : $(OBJS) |
35 | 40 | $(CC) -o mdctl $^ |
36 | 41 | |
42 | mdctl.man : mdctl.8 | |
43 | nroff -man mdctl.8 > mdctl.man | |
44 | ||
37 | 45 | $(OBJS) : mdctl.h |
38 | 46 | |
47 | install : mdctl | |
48 | $(INSTALL) -m 755 mdctl $(DESTDIR)/sbin | |
49 | ||
39 | 50 | clean : |
40 | rm -f mdctl $(OBJS) core | |
51 | rm -f mdctl $(OBJS) core mdctl.man | |
41 | 52 | |
42 | 53 | dist : clean |
43 | 54 | ./makedist |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
115 | 115 | } |
116 | 116 | |
117 | 117 | int Manage_subdevs(char *devname, int fd, |
118 | int devcnt, char *devnames[], int devmodes[]) | |
119 | { | |
118 | mddev_dev_t devlist) | |
119 | { | |
120 | 120 | /* do something to each dev. |
121 | 121 | * devmode can be |
122 | 122 | * 'a' - add the device |
127 | 127 | */ |
128 | 128 | mdu_array_info_t array; |
129 | 129 | mdu_disk_info_t disc; |
130 | mddev_dev_t dv; | |
130 | 131 | struct stat stb; |
131 | 132 | int i,j; |
133 | int save_errno; | |
134 | static buf[4096]; | |
132 | 135 | |
133 | 136 | if (ioctl(fd, GET_ARRAY_INFO, &array)) { |
134 | 137 | fprintf(stderr, Name ": cannot get array info for %s\n", |
135 | 138 | devname); |
136 | 139 | return 1; |
137 | 140 | } |
138 | for (i=0 ; i<devcnt; i++) { | |
139 | if (stat(devnames[i], &stb)) { | |
141 | for (dv = devlist ; dv; dv=dv->next) { | |
142 | if (stat(dv->devname, &stb)) { | |
140 | 143 | fprintf(stderr, Name ": cannot find %s: %s\n", |
141 | devnames[i], strerror(errno)); | |
144 | dv->devname, strerror(errno)); | |
142 | 145 | return 1; |
143 | 146 | } |
144 | 147 | if ((stb.st_mode & S_IFMT) != S_IFBLK) { |
145 | 148 | fprintf(stderr, Name ": %s is not a block device.\n", |
146 | devnames[i]); | |
147 | return 1; | |
148 | } | |
149 | switch(devmodes[i]){ | |
149 | dv->devname); | |
150 | return 1; | |
151 | } | |
152 | switch(dv->disposition){ | |
150 | 153 | default: |
151 | 154 | fprintf(stderr, Name ": internal error - devmode[%d]=%d\n", |
152 | i, devmodes[i]); | |
155 | i, dv->disposition); | |
153 | 156 | return 1; |
154 | 157 | case 'a': |
155 | 158 | /* add the device - hot or cold */ |
156 | if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) { | |
159 | if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { | |
157 | 160 | fprintf(stderr, Name ": hot added %s\n", |
158 | devnames[i]); | |
161 | dv->devname); | |
159 | 162 | continue; |
163 | } | |
164 | save_errno = errno; | |
165 | if (read(fd, buf, sizeof(buf)) > 0) { | |
166 | /* array is active, so don't try to add. | |
167 | * i.e. something is wrong | |
168 | */ | |
169 | fprintf(stderr, Name ": hot add failed for %s: %s\n", | |
170 | dv->devname, strerror(save_errno)); | |
171 | return 1; | |
160 | 172 | } |
161 | 173 | /* try ADD_NEW_DISK. |
162 | 174 | * we might be creating, we might be assembling, |
179 | 191 | disc.minor = MINOR(stb.st_rdev); |
180 | 192 | if (ioctl(fd,ADD_NEW_DISK, &disc)) { |
181 | 193 | fprintf(stderr, Name ": add new disk failed for %s: %s\n", |
182 | devnames[i], strerror(errno)); | |
183 | return 1; | |
184 | } | |
185 | fprintf(stderr, Name ": added %s\n", devnames[i]); | |
194 | dv->devname, strerror(errno)); | |
195 | return 1; | |
196 | } | |
197 | fprintf(stderr, Name ": added %s\n", dv->devname); | |
186 | 198 | break; |
187 | 199 | |
188 | 200 | case 'r': |
189 | 201 | /* hot remove */ |
190 | 202 | /* FIXME check that it is a current member */ |
191 | if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) { | |
203 | if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) { | |
192 | 204 | fprintf(stderr, Name ": hot remove failed for %s: %s\n", |
193 | devnames[i], strerror(errno)); | |
194 | return 1; | |
195 | } | |
196 | fprintf(stderr, Name ": hot removed %s\n", devnames[i]); | |
205 | dv->devname, strerror(errno)); | |
206 | return 1; | |
207 | } | |
208 | fprintf(stderr, Name ": hot removed %s\n", dv->devname); | |
197 | 209 | break; |
198 | 210 | |
199 | 211 | case 'f': /* set faulty */ |
200 | 212 | /* FIXME check current member */ |
201 | if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) { | |
213 | if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) { | |
202 | 214 | fprintf(stderr, Name ": set disk faulty failed for %s: %s\n", |
203 | devnames[i], strerror(errno)); | |
215 | dv->devname, strerror(errno)); | |
204 | 216 | return 1; |
205 | 217 | } |
206 | 218 | fprintf(stderr, Name ": set %s faulty in %s\n", |
207 | devnames[i], devname); | |
219 | dv->devname, devname); | |
208 | 220 | break; |
209 | 221 | } |
210 | 222 | } |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
33 | 33 | |
34 | 34 | static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd); |
35 | 35 | |
36 | int Monitor(int num_devs, char *devlist[], | |
36 | int Monitor(mddev_dev_t devlist, | |
37 | 37 | char *mailaddr, char *alert_cmd, |
38 | 38 | int period, |
39 | 39 | char *config) |
74 | 74 | int finished = 0; |
75 | 75 | while (! finished) { |
76 | 76 | mddev_ident_t mdlist = NULL; |
77 | mddev_dev_t dv; | |
77 | 78 | int dnum=0; |
78 | if (num_devs == 0) | |
79 | if (devlist== NULL) | |
79 | 80 | mdlist = conf_get_ident(config, NULL); |
80 | while (dnum < num_devs || mdlist) { | |
81 | dv = devlist; | |
82 | while (dv || mdlist) { | |
81 | 83 | mddev_ident_t mdident; |
82 | 84 | struct state *st; |
83 | 85 | mdu_array_info_t array; |
86 | 88 | char *event = NULL; |
87 | 89 | int i; |
88 | 90 | char *event_disc = NULL; |
89 | if (num_devs) { | |
90 | dev = devlist[dnum++]; | |
91 | if (dv) { | |
92 | dev = dv->devname; | |
91 | 93 | mdident = conf_get_ident(config, dev); |
94 | dv = dv->next; | |
92 | 95 | } else { |
93 | 96 | mdident = mdlist; |
94 | 97 | dev = mdident->devname; |
170 | 173 | |
171 | 174 | static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd) |
172 | 175 | { |
176 | if (!cmd && !mailaddr) { | |
177 | time_t now = time(0); | |
178 | ||
179 | printf("%0.15s: %s on %s %s\n", ctime(&now)+4, event, dev, disc?disc:"unknown device"); | |
180 | } | |
173 | 181 | if (cmd) { |
174 | 182 | int pid = fork(); |
175 | 183 | switch(pid) { |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
28 | 28 | |
29 | 29 | #include "mdctl.h" |
30 | 30 | |
31 | char Version[] = Name " - v0.5 - 23 August 2001\n"; | |
31 | char Version[] = Name " - v0.6 - 7 March 2002\n"; | |
32 | 32 | /* |
33 | 33 | * File: ReadMe.c |
34 | 34 | * |
77 | 77 | * command, subsequent Manage commands can finish the job. |
78 | 78 | */ |
79 | 79 | |
80 | char short_options[]="-ABCDEFhVvc:l:p:m:n:x:u:c:d:z:sarfRSow"; | |
80 | char short_options[]="-ABCDEFhVvbc:l:p:m:n:x:u:c:d:z:sarfRSow"; | |
81 | 81 | struct option long_options[] = { |
82 | 82 | {"manage", 0, 0, '@'}, |
83 | 83 | {"assemble", 0, 0, 'A'}, |
121 | 121 | {"readonly", 0, 0, 'o'}, |
122 | 122 | {"readwrite", 0, 0, 'w'}, |
123 | 123 | |
124 | /* For Detail/Examine */ | |
125 | {"brief", 0, 0, 'b'}, | |
126 | ||
124 | 127 | /* For Follow/monitor */ |
125 | 128 | {"mail", 1, 0, 'm'}, |
126 | 129 | {"program", 1, 0, 'p'}, |
173 | 176 | " --paritiy= -p : raid5 parity algorith: {left,right}-{,a}symmetric\n" |
174 | 177 | " --layout= : same as --parity\n" |
175 | 178 | " --raid-disks= -n : number of active devices in array\n" |
176 | " --spare-disks= -x : number of spares (eXtras) to allow space for\n" | |
179 | " --spare-disks= -x : number of spares (eXtras) devices in initial array\n" | |
177 | 180 | " --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n" |
178 | 181 | " --force -f : Honour devices as listed on command line. Don't\n" |
179 | 182 | " : insert a missing drive for RAID5.\n" |
186 | 189 | " --config= -c : config file\n" |
187 | 190 | " --scan -s : scan config file for missing information\n" |
188 | 191 | " --force -f : Assemble the array even if some superblocks appear out-of-date\n" |
192 | "\n" | |
193 | " For detail or examine:\n" | |
194 | " --brief -b : Just print device name and UUID\n" | |
189 | 195 | "\n" |
190 | 196 | " For follow/monitor:\n" |
191 | 197 | " --mail= -m : Address to mail alerts of failure to\n" |
305 | 311 | /* name/number mappings */ |
306 | 312 | |
307 | 313 | mapping_t r5layout[] = { |
308 | { "left_asymmetric", 0}, | |
309 | { "right_asymmetric", 1}, | |
310 | { "left_symmetric", 2}, | |
311 | { "right_symmetric", 3}, | |
314 | { "left-asymmetric", 0}, | |
315 | { "right-asymmetric", 1}, | |
316 | { "left-symmetric", 2}, | |
317 | { "right-symmetric", 3}, | |
312 | 318 | |
313 | 319 | { "default", 2}, |
314 | 320 | { "la", 0}, |
0 | ||
1 | ||
2 | ?? Allow -S /dev/md? - current complains subsequent not a/d/r | |
3 | ||
4 | * write proc.c to parse /proc/mdstat file, and maybe /proc/partitions too. | |
5 | Build list of arrays: name, rebuild-percent | |
6 | ||
7 | * --detail --scan to read mdctl.conf, and then iterate over these, | |
8 | but assume --brief. --verbose can override | |
9 | check each subdevice to see if it is in conf_get_devs. | |
10 | Warn if not. | |
11 | ||
12 | * Support multipath ... maybe... | |
13 | ||
14 | * --follow to syslog | |
15 | ||
16 | * --follow to move spares around | |
17 | ||
18 | * --follow to notice other events: | |
19 | rebuild started | |
20 | spare activated | |
21 | spare removed | |
22 | spare added | |
23 | ||
24 | ------------------------------------ | |
25 | - --examine --scan scans all drives and build an mdctl.conf file DONE | |
0 | 26 | |
1 | 27 | - check superblock checksum in examine DONE |
2 | 28 | - report "chunk" or "rounding" depending on raid level DONE |
3 | 29 | - report "linear" instead of "-1" for raid level DONE |
4 | 30 | - decode ayout depending on raid level DONE |
5 | - --verbose and --force flags. | |
31 | - --verbose and --force flags. DONE | |
6 | 32 | |
7 | 33 | - set md_minor, *_disks for Create - DONE |
8 | 34 | - for create raid5, how to choose between |
9 | 35 | all working, but not insync |
10 | one missing, one spare, insync | |
11 | - and for raid1 - some failed drives... | |
36 | one missing, one spare, insync DONE (--force) | |
37 | - and for raid1 - some failed drives... (missing) | |
12 | 38 | |
13 | 39 | - when RUN_ARRAY, make sure *_disks counts are right |
14 | 40 | |
15 | 41 | - get --detail to extract extra stuff from superblock, |
16 | 42 | like uuid DONE |
17 | - --detail --brief to give a config file line | |
43 | - --detail --brief to give a config file line DONE | |
18 | 44 | - parse config file. DONE |
19 | 45 | - test... |
20 | 46 | |
22 | 48 | then try to assemble that device first. |
23 | 49 | |
24 | 50 | |
25 | - mdctl -S /dev/md0 /dev/md1 gives internal error | |
51 | - mdctl -S /dev/md0 /dev/md1 gives internal error FIXED | |
26 | 52 | |
27 | 53 | - mdctl --detail --scan print summary of what it can find? |
28 | 54 | |
73 | 99 | rebuild started |
74 | 100 | spare activated |
75 | 101 | spare removed |
76 | spare added⏎ | |
102 | spare added |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
228 | 228 | |
229 | 229 | mis.uuid_set = 0; |
230 | 230 | mis.super_minor = -1; |
231 | mis.level = -10; | |
232 | mis.raid_disks = -1; | |
231 | 233 | mis.devices = NULL; |
232 | 234 | mis.devname = NULL; |
233 | 235 | |
272 | 274 | w); |
273 | 275 | else |
274 | 276 | mis.spare_group = strdup(w+12); |
277 | } else if (strncasecmp(w, "level=", 6) == 0 ) { | |
278 | /* this is mainly for compatability with --brief output */ | |
279 | mis.level = map_name(pers, w+6); | |
280 | } else if (strncasecmp(w, "disks=", 6) == 0 ) { | |
281 | /* again, for compat */ | |
282 | mis.raid_disks = atoi(w+6); | |
275 | 283 | } else { |
276 | 284 | fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n", |
277 | 285 | w); |
15 | 15 | exit 1 |
16 | 16 | fi |
17 | 17 | trap "rm $target/$base; exit" 1 2 3 |
18 | ( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude=RCS mdctl-$version ; rm mdctl-$version ) > $target/$base | |
18 | ( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude mdctl --exclude=RCS mdctl-$version ; rm mdctl-$version ) > $target/$base | |
19 | 19 | chmod a+r $target/$base |
20 | 20 | ls -l $target/$base |
0 | 0 | .\" -*- nroff -*- |
1 | 1 | .TH mdctl 8 |
2 | 2 | .SH NAME |
3 | mdctl \- a single program that can be used to control Linux md devices | |
3 | mdctl \- manage MD devices | |
4 | .I aka | |
5 | Linux Software Raid. | |
6 | ||
4 | 7 | .SH SYNOPSIS |
5 | 8 | |
6 | .BI mdctl | |
7 | [mode] <raiddevice> [options] | |
9 | .BI mdctl " [mode] <raiddevice> [options] <subdevices>" | |
8 | 10 | |
9 | 11 | .SH DESCRIPTION |
10 | 12 | RAID devices are virtual devices created from two or more |
11 | real block devices. This allows multiple disks to be combined into a single | |
12 | filesystem, possibly with integrated redundancy to survive drive failure.. Linux RAID devices | |
13 | are implemented through the md device driver. | |
13 | real block devices. This allows multiple devices (typically disk | |
14 | drives or partitions there-of) to be combined into a single device to | |
15 | hold (for example) a single filesystem. | |
16 | Some RAID levels included redundancy and so can survive some degree of | |
17 | device failure. | |
18 | ||
19 | Linux Software RAID devices are implemented through the md (Multiple Devices) device driver. | |
20 | ||
21 | Currently, Linux supports | |
22 | .B LINEAR | |
23 | md devices, | |
24 | .B RAID0 | |
25 | (striping), | |
26 | .B RAID1 | |
27 | (mirroring), | |
28 | .B RAID4 | |
29 | and | |
30 | .B RAID5. | |
31 | ||
32 | Recent kernels (2002) also support a mode known as | |
33 | .BR MULTIPATH . | |
34 | .B mdctl | |
35 | does not support MULTIPATH as yet. | |
36 | ||
37 | .B mdctl | |
38 | is a program that can be used to create and manage MD devices. As | |
39 | such it provides a similar set of functionality to the | |
40 | .B raidtools | |
41 | packages. | |
42 | The key differences between | |
43 | .B mdctl | |
44 | and | |
45 | .B raidtools | |
46 | are: | |
47 | .IP \(bu 4 | |
48 | .B mdctl | |
49 | is a single program and not a collection of programs. | |
50 | .IP \(bu 4 | |
51 | .B mdctl | |
52 | can perform (almost) all of its functions without having a | |
53 | configuration file. Also mdctl helps with management of the configuration | |
54 | file. | |
55 | .IP \(bu 4 | |
56 | .B mdctl | |
57 | can provide information about your arrays (through Detail and Examine) | |
58 | that | |
59 | .B raidtools | |
60 | cannot. | |
61 | .IP \(bu 4 | |
62 | .B raidtools | |
63 | can manage MULTIPATH devices which | |
64 | .B mdctl | |
65 | cannot yet manage. | |
66 | ||
67 | .SH MODES | |
68 | mdctl has 7 major modes of operation: | |
69 | .TP | |
70 | .B Assemble | |
71 | Assemble the parts of a previously created | |
72 | array into an active array. Components can be explicitly given | |
73 | or can be searched for. | |
74 | .B mdctl | |
75 | checks that the components | |
76 | do form a bona fide array, and can, on request, fiddle superblock | |
77 | information so as to assemble a faulty array. | |
78 | ||
79 | .TP | |
80 | .B Build | |
81 | Build a legacy array without per-device superblocks. | |
82 | ||
83 | .TP | |
84 | .B Create | |
85 | Create a new array with per-device superblocks. | |
86 | '''It can progress | |
87 | '''in several step create-add-add-run or it can all happen with one command. | |
88 | ||
89 | .TP | |
90 | .B Detail | |
91 | Display the details of a given md device. Details include the RAID | |
92 | level, the number of devices, which ones are faulty (if any), and the | |
93 | array UUID. | |
94 | ||
95 | .TP | |
96 | .B Examine | |
97 | Examine a device to see if it is part of an md array, and print out | |
98 | the details of that array. | |
99 | This mode can also be used to examine a large number of devices and to | |
100 | print out a summary of the arrays found in a format suitable for the | |
101 | .B mdctl.conf | |
102 | configuration file. | |
103 | ||
104 | .TP | |
105 | .B "Follow or Monitor" | |
106 | Monitor one or more md devices and act on any state changes. | |
107 | ||
108 | .TP | |
109 | .B Manage | |
110 | This is for odd bits an pieces like hotadd, hotremove, setfaulty, stop, | |
111 | readonly, readwrite. | |
112 | '''If an array is only partially setup by the | |
113 | '''Create or Assemble commands, subsequent Manage commands can finish the | |
114 | '''job. | |
115 | ||
116 | .SH OPTIONS | |
117 | ||
118 | Available options are: | |
119 | ||
120 | .TP | |
121 | .BR -A ", " --assemble | |
122 | Assemble an existing array. | |
123 | ||
124 | .TP | |
125 | .BR -B ", " --build | |
126 | Build a legacy array without superblocks. | |
127 | ||
128 | .TP | |
129 | .BR -C ", " --create | |
130 | Create a new array. | |
131 | ||
132 | .TP | |
133 | .BR -D ", " --detail | |
134 | Print detail of one or more md devices. | |
135 | ||
136 | .TP | |
137 | .BR -E ", " --examine | |
138 | Print content of md superblock on device(s). | |
139 | ||
140 | .TP | |
141 | .BR -F ", " --follow ", " --monitor | |
142 | Select | |
143 | .B Monitor | |
144 | mode. | |
145 | ||
146 | .TP | |
147 | .BR -h ", " --help | |
148 | Display help message or, after above option, mode specific help message. | |
149 | ||
150 | .TP | |
151 | .BR -V ", " --version | |
152 | Print version information for mdctl. | |
153 | ||
154 | .TP | |
155 | .BR -v ", " --verbose | |
156 | Be more verbose about what is happening. | |
157 | ||
158 | .TP | |
159 | .BR -b ", " --brief | |
160 | Be less verbose. This is used with | |
161 | .B --detail | |
162 | and | |
163 | .BR --examine . | |
164 | ||
165 | .SH For create or build: | |
166 | ||
167 | .TP | |
168 | .BR -c ", " --chunk= | |
169 | Specify chunk size of kibibytes. The default is 64. | |
170 | ||
171 | .TP | |
172 | .BR --rounding= | |
173 | Specify rounding factor for linear array (==chunk size) | |
174 | ||
175 | .TP | |
176 | .BR -l ", " --level= | |
177 | Set raid level. Options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid5, 4, | |
178 | raid5, 5. Obviously some of these are synonymous. | |
179 | Only the first 4 are valid when Building. | |
180 | ||
181 | .TP | |
182 | .BR -p ", " --parity= | |
183 | Set raid5 parity algorithm. Options are: | |
184 | {left,right}-{,a}symmetric, la, ra, ls, rs. The default is left-symmetric. | |
185 | ||
186 | .TP | |
187 | .BR --layout= | |
188 | same as --parity | |
189 | ||
190 | .TP | |
191 | .BR -n ", " --raid-disks= | |
192 | number of active devices in array. | |
193 | ||
194 | .TP | |
195 | .BR -x ", " --spare-disks= | |
196 | number of spare (eXtra) disks in initial array. Spares can be added | |
197 | and removed later. | |
198 | ||
199 | .TP | |
200 | .BR -z ", " --size= | |
201 | Amount (in Kibibytes) of space to use from each drive in RAID1/4/5. | |
202 | This must be a multiple of the chunk size, and must leave about 128Kb | |
203 | of space at the end of the drive for the RAID superblock. | |
204 | If this is not specified | |
205 | (as it normally is not) the smallest drive (or partition) sets the | |
206 | size, though if there is a variance among the drives of greater than 1%, a warning is | |
207 | issued. | |
208 | ||
209 | .SH For assemble: | |
210 | ||
211 | .TP | |
212 | .BR -u ", " --uuid= | |
213 | uuid of array to assemble. Devices which don't have this uuid are | |
214 | excluded | |
215 | ||
216 | .TP | |
217 | .BR -m ", " --super-minor= | |
218 | Minor number of device that array was created for. Devices which | |
219 | don't have this minor number are excluded. If you create an array as | |
220 | /dev/md1, then all superblock will contain the minor number 1, even if | |
221 | the array is later assembled as /dev/md2. | |
222 | ||
223 | .TP | |
224 | .BR -c ", " --config= | |
225 | config file. Default is | |
226 | .BR /etc/mdctl.conf . | |
227 | ||
228 | .TP | |
229 | .BR -s ", " --scan | |
230 | scan config file for missing information | |
231 | ||
232 | .TP | |
233 | .BR -f ", " --force | |
234 | Assemble the array even if some superblocks appear out-of-date | |
235 | ||
236 | .TP | |
237 | .BR -R ", " --run | |
238 | Attempt to start the array even if fewer drives were given than are | |
239 | needed for a full array. Normally if not all drives are found and | |
240 | .B --scan | |
241 | is not used, then the array will be assembled but not started. | |
242 | With | |
243 | .B --run | |
244 | an attempt will be made to start it anyway. | |
245 | ||
246 | .SH General management | |
247 | ||
248 | .TP | |
249 | .BR -a ", " --add | |
250 | '''add, or | |
251 | hotadd listed devices. | |
252 | ||
253 | .TP | |
254 | .BR -r ", " --remove | |
255 | remove listed devices. The must not be active. i.e. they should | |
256 | be failed or spare devices. | |
257 | ||
258 | .TP | |
259 | .BR -f ", " --fail | |
260 | mark listed devices as faulty. | |
261 | ||
262 | .TP | |
263 | .BR --set-faulty | |
264 | same as --fail. | |
265 | ||
266 | .TP | |
267 | .BR -R ", " --run | |
268 | start a partially built array. | |
269 | ||
270 | .TP | |
271 | .BR -S ", " --stop | |
272 | deactivate array, releasing all resources. | |
273 | ||
274 | .TP | |
275 | .BR -o ", " --readonly | |
276 | mark array as readonly. | |
277 | ||
278 | .TP | |
279 | .BR -w ", " --readwrite | |
280 | mark array as readwrite. | |
281 | ||
282 | ||
283 | .SH ASSEMBLY MODE | |
284 | ||
285 | .HP 12 | |
286 | Usage: | |
287 | .B mdctl --assemble | |
288 | .I device options... | |
289 | .HP 12 | |
290 | Usage: | |
291 | .B mdctl --assemble --scan | |
292 | .I options... | |
293 | ||
294 | .PP | |
295 | This usage assembles one or more raid arrays from pre-existing components. | |
296 | For each array, mdctl needs to know the md device, the identity of the | |
297 | array, and a number of sub devices. These can be found in a number of ways. | |
298 | ||
299 | The md device is either given before | |
300 | .B --scan | |
301 | or is found from the config file. In the latter case, multiple md devices | |
302 | can be started with a single mdctl command. | |
303 | ||
304 | The identity can be given with the | |
305 | .B --uuid | |
306 | option, with the | |
307 | .B --super-minor | |
308 | option, can be found in in the config file, or will be taken from the | |
309 | super block on the first subdevice listed on the command line. | |
310 | ||
311 | Devices can be given on the | |
312 | .B --assemble | |
313 | command line or from the config file. Only devices which have an md | |
314 | superblock which contains the right identity will be considered for any device. | |
315 | ||
316 | The config file is only used if explicitly named with | |
317 | .B --config | |
318 | or requested with | |
319 | .B --scan. | |
320 | In the later case, | |
321 | .B /etc/mdctl.conf | |
322 | is used. | |
323 | ||
324 | If | |
325 | .B --scan | |
326 | is not given, then the config file will only be used to find the | |
327 | identity of md arrays. | |
328 | ||
329 | Normally the array will be started after it is assembled. However is | |
330 | .B --scan | |
331 | is not given and insufficient drives were lists to start a complete | |
332 | (non-degraded) array, then the array is not started (to guard against | |
333 | usage errors). To insist that the array be started in this case (as | |
334 | may work for RAID1 or RAID5), give the | |
335 | .B --run | |
336 | flag. | |
337 | ||
338 | ||
339 | .SH BUILD MODE | |
340 | ||
341 | .HP 12 | |
342 | Usage: | |
343 | .B mdctl --build | |
344 | .I device | |
345 | .BI --chunk= X | |
346 | .BI --level= Y | |
347 | .BI --raid-disks= Z | |
348 | .I devices | |
349 | ||
350 | .PP | |
351 | This usage is similar to | |
352 | .BR --create . | |
353 | The difference is that it creates a legacy array without a superblock. With | |
354 | these arrays there is no difference between initially creating the array and | |
355 | subsequently assembling the array, except that hopefully there is useful | |
356 | data there in the second case. | |
357 | ||
358 | The level may only be 0, raid0, or linear. All devices must be listed | |
359 | and the array will be started once complete. | |
360 | ||
361 | .SH CREATE MODE | |
362 | ||
363 | .HP 12 | |
364 | Usage: | |
365 | .B mdctl --create | |
366 | .I device | |
367 | .BI --chunk= X | |
368 | .BI --level= Y | |
369 | .br | |
370 | .BI --raid-disks= Z | |
371 | .I devices | |
372 | ||
373 | .PP | |
374 | This usage will initialise a new md array, associate some devices with | |
375 | it, and activate the array. | |
376 | ||
377 | As devices are added, they are checked to see if they contain raid | |
378 | superblocks or filesystems. They are also check to see if the variance in | |
379 | device size exceeds 1%. | |
380 | ||
381 | If any discrepancy is found, the array will not automatically be run, though | |
382 | the presence of a | |
383 | .B --run | |
384 | can override this caution. | |
385 | ||
386 | '''If the | |
387 | '''.B --size | |
388 | '''option is given, it is not necessary to list any subdevices in this command. | |
389 | '''They can be added later, before a | |
390 | '''.B --run. | |
391 | '''If no | |
392 | '''.B --size | |
393 | '''is given, the apparent size of the smallest drive given is used. | |
394 | ||
395 | The General Management options that are valid with --create are: | |
396 | .TP | |
397 | .B --run | |
398 | insist of running the array even if some devices look like they might | |
399 | be in use. | |
400 | ||
401 | .TP | |
402 | .B --readonly | |
403 | start the array readonly - not supported yet. | |
404 | ||
405 | .SH DETAIL MODE | |
406 | .HP 12 | |
407 | Usage: | |
408 | .B mdctl --detail | |
409 | .RB [ --brief ] | |
410 | .I device ... | |
411 | .PP | |
412 | ||
413 | This usage sill print out the details of the given array including a | |
414 | list of component devices. To determine names for the devices, | |
415 | .B mdctl | |
416 | searches | |
417 | .B /dev | |
418 | for device files with the right major and minor numbers. | |
419 | ||
420 | With | |
421 | .B --brief | |
422 | .B mdctl | |
423 | prints a single line that identifies the level, number of disks, and | |
424 | UUID of the array. This line is suitable for inclusion in | |
425 | .BR /etc/mdctl.conf . | |
426 | ||
427 | .SH EXAMINE MODE | |
428 | .HP 12 | |
429 | Usage: | |
430 | .B mdctl --examine | |
431 | .RB [ --scan ] | |
432 | .RB [ --brief ] | |
433 | .I device ... | |
434 | .PP | |
435 | This usage will examine some block devices to see if that have a valid | |
436 | RAID superblock on them. The information in each valid raid | |
437 | superblock will be printed. | |
438 | ||
439 | If | |
440 | .B --scan | |
441 | is used, the no devices should be listed, and the complete set of | |
442 | devices identified in the configuration file are checked. | |
443 | .B --scan | |
444 | implies | |
445 | .B --brief | |
446 | but this implication can be countered by specifying | |
447 | .BR --verbose . | |
448 | ||
449 | With | |
450 | .B --brief | |
451 | .B mdctl | |
452 | will output an config file entry of each distinct array that was | |
453 | found. This entry will list the UUID, the raid level, and a list of | |
454 | the individual devices on which a superblock for that array was found. | |
455 | This output will by syntactically suitable for inclusion in the | |
456 | configuration file, but should | |
457 | .B NOT | |
458 | be used blindly. Often the array description that you want in the | |
459 | configuration file is much less specific than that given by | |
460 | .BR "mdctl -Bs" . | |
461 | For example, you normally do not want to list the devices, | |
462 | particularly if they are SCSI devices. | |
463 | ||
464 | '''.SH BUGS | |
465 | '''no known bugs. | |
466 | ||
467 | .SH FILES | |
468 | ||
469 | .SS /proc/mdstat | |
14 | 470 | |
15 | 471 | If you're using the |
16 | 472 | .B /proc |
17 | 473 | filesystem, |
18 | 474 | .B /proc/mdstat |
19 | 475 | gives you informations about md devices status. |
20 | ||
21 | Currently, Linux supports linear md devices, RAID0 (striping), RAID1 | |
22 | (mirrroring), RAID4 and RAID5. For information on the various levels of | |
476 | This file is not currently used by | |
477 | .BR mdctl . | |
478 | ||
479 | .SS /etc/mdctl.conf | |
480 | ||
481 | The config file is line oriented with, as usual, blank lines and lines | |
482 | beginning with a hash (or pound sign or sharp or number sign, | |
483 | whichever you like to call it) ignored. | |
484 | Lines that start with a blank are treated as continuations of the | |
485 | previous line (I don't like trailing slashes). | |
486 | ||
487 | Each line contains a sequence of space-separated words, the first of | |
488 | which identified the type of line. Keywords are case-insensitive, and | |
489 | the first work on a line can be abbreviated to 3 letters. | |
490 | ||
491 | There are two types of lines. ARRAY and DEVICE. | |
492 | ||
493 | The DEVICE lines usually come first. All remaining words on the line | |
494 | are treated as names of devices, possibly containing wild cards (see | |
495 | .IR glob (7)). | |
496 | These list all the devices that | |
497 | .B mdctl | |
498 | is allowed to scan | |
499 | when looking for devices with RAID superblocks. | |
500 | Each line can contain multiple device names, and there can be multiple | |
501 | DEVICE lines. For example: | |
502 | .IP | |
503 | DEVICE /dev/hda* /dev/hdc* | |
504 | .br | |
505 | DEV /dev/sd* | |
506 | .br | |
507 | DEVICE /dev/discs/disc*/disc | |
508 | .PP | |
509 | The ARRAY lines identify actual arrays. The second word on the line | |
510 | should be the name of the device where the array is normally | |
511 | assembled, such as /dev/md1. | |
512 | Subsequent words identify the array. If multiple identities are given, | |
513 | then the array much match ALL identities to be considered a match. | |
514 | Each identity word has a tag, and equals sign, and some value. | |
515 | The options are: | |
516 | ||
517 | .TP | |
518 | .B uuid= | |
519 | The value should be a 128 bit uuid in hexadecimal, with punctuation | |
520 | interspersed if desired. This must match the uuid stored in the | |
521 | superblock. | |
522 | .TP | |
523 | .B super-minor= | |
524 | The value is an integer which indicates the minor number that was | |
525 | stored in the superblock when the array was created. When an array is | |
526 | created as /dev/mdX, then the minor number X is stored. | |
527 | .TP | |
528 | .B devices= | |
529 | The value is a comma separated list of device names. Precisely these | |
530 | devices will be used to assemble the array. Note that the devices | |
531 | listed there must also be listed on a DEVICE line. | |
532 | .TP | |
533 | .B level= | |
534 | The value is a raid level. This is normally used to identify an | |
535 | array, but is supported so that the output of | |
536 | .B "mdctl --examine --scan" | |
537 | can be use directly in the configuration file. | |
538 | .TP | |
539 | .B disks= | |
540 | The value is the number of disks in a complete active array. As with | |
541 | .B level= | |
542 | this is mainly for compatibility with the output of | |
543 | .BR "mdctl --examine --scan" . | |
544 | ||
545 | .SH TODO | |
546 | ||
547 | Finish and document Follow mode. | |
548 | ||
549 | .SH SEE ALSO | |
550 | For information on the various levels of | |
23 | 551 | RAID, check out: |
24 | 552 | |
25 | http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/ | |
26 | ||
553 | .IP | |
554 | .UR http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/ | |
555 | http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/ | |
556 | .UE | |
557 | .PP | |
27 | 558 | for new releases of the RAID driver check out: |
28 | 559 | |
29 | ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches | |
30 | ||
31 | .B mdctl | |
32 | is a single program that can be used to control Linux md devices. It | |
33 | is intended to provide all the functionality (and more) of the mdtools | |
34 | and raidtools but with a very different interface. | |
35 | ||
36 | mdctl can perform all functions without a configuration file. There is the | |
37 | option of using a configuration file, but not in the same way that raidtools | |
38 | uses one. raidtools uses a configuration file to describe how to create a | |
39 | RAID array, and also uses this file partially to start a previously created | |
40 | RAID array. Further, raidtools requires the configuration file for such | |
41 | things as stopping a raid array which needs to know nothing about the array. | |
42 | ||
43 | The configuration file that can be used by mdctl lists two different things: | |
44 | ||
45 | .IP "\fB\-\fP" | |
46 | a list of md devices and information about how to identify each. The | |
47 | identity can consist of a UUID, and minor-number as recorded on the | |
48 | superblock, or a list of devices. | |
49 | ||
50 | .IP "\fB\-\fP" | |
51 | a list of devices that should be scanned for md sub-devices. | |
52 | ||
53 | .SH MODES | |
54 | mdctl has 4 major modes of operation: | |
55 | .IP "\fBCreate\fP" | |
56 | This mode is used to create a new array with a superblock. It can progress | |
57 | in several step create-add-add-run or it can all happen with one command. | |
58 | ||
59 | .IP "\fBAssemble\fP" | |
60 | This mode is used to assemble the parts of a previously created | |
61 | array into an active array. Components can be explicitly given | |
62 | or can be searched for. | |
63 | .B mdctl | |
64 | (optionally) checks that the components | |
65 | do form a bonafide array, and can, on request, fiddle superblock | |
66 | version numbers so as to assemble a faulty array. | |
67 | ||
68 | .IP "\fBBuild\fP" | |
69 | This is for building legacy arrays without superblocks. | |
70 | ||
71 | .IP "\fBManage\fP" | |
72 | This is for odd bits an pieces like hotadd, hotremove, setfaulty, stop, | |
73 | readonly,readwrite If an array is only partially setup by the | |
74 | Create/Assemble/Build command, subsequent Manage commands can finish the | |
75 | job. | |
76 | ||
77 | .SH OPTIONS | |
78 | ||
79 | Available options are: | |
80 | ||
81 | .IP "\fB\-C\fP, \fB\-\-create\fP" | |
82 | Create a new array | |
83 | ||
84 | .IP "\fB-A\fP, \fB\-\-assemble\fP" | |
85 | Assemble an existing array | |
86 | ||
87 | .IP "\fB\-B\fP, \fB\-\-build\fP" | |
88 | Build a legacy array without superblock | |
89 | ||
90 | .IP "\fB\-D\fP, \fB\-\-detail\fP" | |
91 | Print detail of a given md array | |
92 | ||
93 | .IP "\fB\-E\fP, \fB\-\-examine\fP" | |
94 | Print content of md superblock on device | |
95 | ||
96 | .IP "\fB\-h\fP, \fB\-\-help\fP" | |
97 | This help message or, after above option, mode specific help message | |
98 | ||
99 | .IP "\fB\-V\fP, \fB\-\-version\fP" | |
100 | Print version information for mdctl | |
101 | ||
102 | .IP "\fB\-v\fP, \fB\-\-verbose\fP" | |
103 | Be more verbose about what is happening | |
104 | ||
105 | .SH For create or build: | |
106 | ||
107 | .IP "\fB\-c\fP, \fB\-\-chunk=\fP" | |
108 | chunk size of kibibytes | |
109 | ||
110 | .IP "\fB\-\-rounding=\fP" | |
111 | rounding factor for linear array (==chunk size) | |
112 | ||
113 | .IP "\fB\-l\fP, \fB\-\-level=\fP" | |
114 | raid level: 0,1,4,5,linear. 0 or linear for build | |
115 | ||
116 | .IP "\fB\-p\fP, \fB\-\-parity=\fP" | |
117 | raid5 parity algorithm: {left,right}-{,a}symmetric | |
118 | ||
119 | .IP "\fB\-\-layout=\fP" | |
120 | same as --parity | |
121 | ||
122 | .IP "\fB\-n\fP, \fB\-\-raid-disks=\fP" | |
123 | number of active devices in array | |
124 | ||
125 | .IP "\fB\-x\fP, \fB\-\-spare-disks=\fP" | |
126 | number of spares (eXtras) to allow space for | |
127 | ||
128 | .IP "\fB\-z\fP, \fB\-\-size=\fP" | |
129 | Size (in K) of each drive in RAID1/4/5 - optional | |
130 | ||
131 | .SH For assemble: | |
132 | ||
133 | .IP "\fB\-u\fP, \fB\-\-uuid=\fP" | |
134 | uuid of array to assemble. Devices which don't have this uuid are excluded | |
135 | ||
136 | .IP "\fB\-c\fP, \fB\-\-config=\fP" | |
137 | config file | |
138 | ||
139 | .IP "\fB\-s\fP, \fB\-\-scan\fP" | |
140 | scan config file for missing information | |
141 | ||
142 | .IP "\fB\-f\fP, \fB\-\-force\fP" | |
143 | Assemble the array even if some superblocks appear out-of-date | |
144 | ||
145 | .SH General management | |
146 | ||
147 | .IP "\fB\-a\fP, \fB\-\-add\fP" | |
148 | add, or hotadd subsequent devices | |
149 | ||
150 | .IP "\fB\-r\fP, \fB\-\-remove\fP" | |
151 | remove subsequent devices | |
152 | ||
153 | .IP "\fB\-f\fP, \fB\-\-fail\fP" | |
154 | mark subsequent devices a faulty | |
155 | ||
156 | .IP "\fB\-\-set-faulty\fP" | |
157 | same as --fail | |
158 | ||
159 | .IP "\fB\-R\fP, \fB\-\-run\fP" | |
160 | start a partially built array | |
161 | ||
162 | .IP "\fB\-S\fP, \fB\-\-stop\fP" | |
163 | deactivate array, releasing all resources | |
164 | ||
165 | .IP "\fB\-o\fP, \fB\-\-readonly\fP" | |
166 | mark array as readonly | |
167 | ||
168 | .IP "\fB\-w\fP, \fB\-\-readwrite\fP" | |
169 | mark array as readwrite | |
170 | ||
171 | .SH CREATE MODE | |
172 | ||
173 | Usage: | |
174 | ||
175 | .B mdctl | |
176 | --create device --chunk=X --level=Y --raid-disks=Z devices | |
177 | ||
178 | This usage will initialise a new md array and possibly associate some | |
179 | devices with it. If enough devices are given to complete the array, the | |
180 | array will be activated. Otherwise it will be left inactive to be completed | |
181 | and activated by subsequent management commands. | |
182 | ||
183 | As devices are added, they are checked to see if they contain raid | |
184 | superblocks or filesystems. They are also check to see if the variance in | |
185 | device size exceeds 1%. | |
186 | ||
187 | If any discrepancy is found, the array will not automatically be run, though | |
188 | the presence of a | |
189 | .B --run | |
190 | can override this caution. | |
191 | ||
192 | If the | |
193 | .B --size | |
194 | option is given, it is not necessary to list any subdevices in this command. | |
195 | They can be added later, before a | |
196 | .B --run. | |
197 | If no | |
198 | .B --size | |
199 | is given, the apparent size of the smallest drive given is used. | |
200 | ||
201 | The General management options that are valid with --create are: | |
202 | .IP "\fB\-\-run\fP" | |
203 | insist of running the array even if not all devices are present or some look | |
204 | odd. | |
205 | ||
206 | .IP "\fB\-\-readonly\fP" | |
207 | start the array readonly - not supported yet. | |
208 | ||
209 | .SH ASSEMBLY MODE | |
210 | ||
211 | Usage: | |
212 | ||
213 | .B mdctl | |
214 | --assemble device options... | |
215 | ||
216 | .B mdctl | |
217 | --assemble --scan options... | |
218 | ||
219 | This usage assembles one or more raid arrays from pre-existing components. | |
220 | For each array, mdctl needs to know the md device, the uuid, and a number of | |
221 | sub devices. These can be found in a number of ways. | |
222 | ||
223 | The md device is either given before | |
224 | .B --scan | |
225 | or is found from the config file. In the latter case, multiple md devices | |
226 | can be started with a single mdctl command. | |
227 | ||
228 | The uuid can be given with the | |
229 | .B --uuid | |
230 | option, or can be found in in the config file, or will be taken from the | |
231 | super block on the first subdevice listed on the command line or in a | |
232 | subsequent | |
233 | .B --add | |
234 | command. | |
235 | ||
236 | Devices can be given on the | |
237 | .B --assemble | |
238 | command line, on subsequent | |
239 | .B 'mdctl --add' | |
240 | command lines, or from the config file. Only devices which have an md | |
241 | superblock which contains the right uuid will be considered for any device. | |
242 | ||
243 | The config file is only used if explicitly named with | |
244 | .B --config | |
245 | or requested with | |
246 | .B --scan. | |
247 | In the later case, | |
248 | .B /etc/md.conf | |
249 | is used. | |
250 | ||
251 | If | |
252 | .B --scan | |
253 | is not given, then the config file will only be used to find uuids for md | |
254 | arrays. | |
255 | ||
256 | The format of the config file is: | |
257 | not yet documented | |
258 | ||
259 | .SH BUILD MDOE | |
260 | ||
261 | Usage: | |
262 | ||
263 | .B mdctl | |
264 | --build device -chunk=X --level=Y --raid-disks=Z devices | |
265 | ||
266 | This usage is similar to | |
267 | .B --create. | |
268 | The difference is that it creates a legacy array without a superblock. With | |
269 | these arrays there is no different between initially creating the array and | |
270 | subsequently assembling the array, except that hopefully there is useful | |
271 | data there in the second case. | |
272 | ||
273 | The level may only be 0 or linear. All devices must be listed and the array | |
274 | will be started once complete. | |
275 | ||
276 | .SH BUGS | |
277 | no known bugs. | |
278 | ||
279 | .SH TODO | |
280 | ||
281 | ||
282 | .SH SEE ALSO | |
560 | .IP | |
561 | .UR ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches | |
562 | ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches | |
563 | .UE | |
564 | .PP | |
565 | or | |
566 | .IP | |
567 | .UR http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/ | |
568 | http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/ | |
569 | .URk | |
570 | .PP | |
283 | 571 | .IR raidtab (5), |
284 | 572 | .IR raid0run (8), |
285 | 573 | .IR raidstop (8), |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
63 | 63 | int sparedisks = 0; |
64 | 64 | struct mddev_ident_s ident; |
65 | 65 | char *configfile = NULL; |
66 | char *cp; | |
66 | 67 | int scan = 0; |
67 | 68 | char devmode = 0; |
68 | 69 | int runstop = 0; |
69 | 70 | int readonly = 0; |
70 | char *devs[MD_SB_DISKS+1]; | |
71 | int devmodes[MD_SB_DISKS+1]; | |
71 | mddev_dev_t devlist = NULL; | |
72 | mddev_dev_t *devlistend = & devlist; | |
73 | mddev_dev_t dv; | |
72 | 74 | int devs_found = 0; |
73 | 75 | int verbose = 0; |
76 | int brief = 0; | |
74 | 77 | int force = 0; |
75 | 78 | |
76 | 79 | char *mailaddr = NULL; |
80 | 83 | int mdfd = -1; |
81 | 84 | |
82 | 85 | ident.uuid_set=0; |
86 | ident.level = -10; | |
87 | ident.raid_disks = -1; | |
83 | 88 | ident.super_minor= -1; |
84 | 89 | ident.devices=0; |
85 | 90 | |
123 | 128 | case 'v': verbose = 1; |
124 | 129 | continue; |
125 | 130 | |
131 | case 'b': brief = 1; | |
132 | continue; | |
133 | ||
126 | 134 | case 1: /* an undecorated option - must be a device name. |
127 | 135 | * Depending on mode, it could be that: |
128 | * All devices listed are "md" devices : --Detail, -As | |
129 | * No devices are "md" devices : --Examine | |
130 | * First device is "md", others are component: -A,-B,-C | |
136 | * All devices listed are "md" devices : --Detail, -As | |
137 | * No devices are "md" devices : --Examine | |
138 | * First device is "md", others are component: -A,-B,-C | |
139 | * Only accept on device before mode is determined. | |
140 | * If mode is @, then require devmode for other devices. | |
131 | 141 | */ |
132 | if (devs_found >= MD_SB_DISKS+1) { | |
133 | fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n", | |
134 | optarg, MD_SB_DISKS+1); | |
135 | exit(2); | |
136 | } | |
137 | devs[devs_found] = optarg; | |
138 | devmodes[devs_found] = devmode; | |
142 | if (devs_found > 0 && !mode ) { | |
143 | fprintf(stderr, Name ": Must give mode flag before second device name at %s\n", optarg); | |
144 | exit(2); | |
145 | } | |
146 | if (devs_found > 0 && mode == '@' && !devmode) { | |
147 | fprintf(stderr, Name ": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg); | |
148 | exit(2); | |
149 | } | |
150 | dv = malloc(sizeof(*dv)); | |
151 | if (dv == NULL) { | |
152 | fprintf(stderr, Name ": malloc failed\n"); | |
153 | exit(3); | |
154 | } | |
155 | dv->devname = optarg; | |
156 | dv->disposition = devmode; | |
157 | dv->next = NULL; | |
158 | *devlistend = dv; | |
159 | devlistend = &dv->next; | |
160 | ||
139 | 161 | devs_found++; |
140 | 162 | continue; |
141 | 163 | |
204 | 226 | optarg); |
205 | 227 | exit(2); |
206 | 228 | } |
229 | ident.level = level; | |
207 | 230 | continue; |
208 | 231 | |
209 | 232 | case O('C','p'): /* raid5 layout */ |
245 | 268 | optarg); |
246 | 269 | exit(2); |
247 | 270 | } |
271 | ident.raid_disks = raiddisks; | |
248 | 272 | continue; |
249 | 273 | |
250 | 274 | case O('C','x'): /* number of spare (eXtra) discs */ |
275 | 299 | continue; |
276 | 300 | case O('A','u'): /* uuid of array */ |
277 | 301 | if (ident.uuid_set) { |
278 | fprintf(stderr, Name ": uuid cannot bet set twice. " | |
302 | fprintf(stderr, Name ": uuid cannot be set twice. " | |
279 | 303 | "Second value %s.\n", optarg); |
280 | 304 | exit(2); |
281 | 305 | } |
283 | 307 | ident.uuid_set = 1; |
284 | 308 | else { |
285 | 309 | fprintf(stderr,Name ": Bad uuid: %s\n", optarg); |
310 | exit(2); | |
311 | } | |
312 | continue; | |
313 | ||
314 | case O('A','m'): /* super-minor for array */ | |
315 | if (ident.super_minor >= 0) { | |
316 | fprintf(stderr, Name ": super-minor cannot be set twice. " | |
317 | "Second value: %s.\n", optarg); | |
318 | exit(2); | |
319 | } | |
320 | ident.super_minor = strtoul(optarg, &cp, 10); | |
321 | if (!optarg[0] || *cp) { | |
322 | fprintf(stderr, Name ": Bad super-minor number: %s.\n", optarg); | |
286 | 323 | exit(2); |
287 | 324 | } |
288 | 325 | continue; |
298 | 335 | /* FIXME possibly check that config file exists. Even parse it */ |
299 | 336 | continue; |
300 | 337 | case O('A','s'): /* scan */ |
338 | case O('E','s'): | |
301 | 339 | scan = 1; |
302 | 340 | continue; |
303 | 341 | |
408 | 446 | fprintf(stderr, Name ": an md device must be given in this mode\n"); |
409 | 447 | exit(2); |
410 | 448 | } |
411 | mdfd = open_mddev(devs[0]); | |
449 | mdfd = open_mddev(devlist->devname); | |
412 | 450 | if (mdfd < 0) |
413 | 451 | exit(1); |
414 | 452 | } |
419 | 457 | case '@':/* Management */ |
420 | 458 | /* readonly, add/remove, readwrite, runstop */ |
421 | 459 | if (readonly>0) |
422 | rv = Manage_ro(devs[0], mdfd, readonly); | |
460 | rv = Manage_ro(devlist->devname, mdfd, readonly); | |
423 | 461 | if (!rv && devs_found>1) |
424 | rv = Manage_subdevs(devs[0], mdfd, | |
425 | devs_found-1, devs+1, devmodes+1); | |
462 | rv = Manage_subdevs(devlist->devname, mdfd, | |
463 | devlist->next); | |
426 | 464 | if (!rv && readonly < 0) |
427 | rv = Manage_ro(devs[0], mdfd, readonly); | |
465 | rv = Manage_ro(devlist->devname, mdfd, readonly); | |
428 | 466 | if (!rv && runstop) |
429 | rv = Manage_runstop(devs[0], mdfd, runstop); | |
467 | rv = Manage_runstop(devlist->devname, mdfd, runstop); | |
430 | 468 | break; |
431 | 469 | case 'A': /* Assemble */ |
432 | 470 | if (!scan) |
433 | rv = Assemble(devs[0], mdfd, &ident, configfile, | |
434 | devs_found-1, devs+1, | |
471 | rv = Assemble(devlist->devname, mdfd, &ident, configfile, | |
472 | devlist->next, | |
435 | 473 | readonly, runstop, verbose, force); |
436 | 474 | else if (devs_found>0) |
437 | for (i=0; i<devs_found; i++) { | |
438 | mddev_ident_t array_ident = conf_get_ident(configfile, devs[i]); | |
439 | mdfd = open_mddev(devs[i]); | |
475 | for (dv = devlist ; dv ; dv=dv->next) { | |
476 | mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname); | |
477 | mdfd = open_mddev(dv->devname); | |
440 | 478 | if (mdfd < 0) { |
441 | 479 | rv |= 1; |
442 | 480 | continue; |
443 | 481 | } |
444 | 482 | if (array_ident == NULL) { |
445 | 483 | fprintf(stderr, Name ": %s not identified in config file.\n", |
446 | devs[i]); | |
484 | dv->devname); | |
447 | 485 | rv |= 1; |
448 | 486 | continue; |
449 | 487 | } |
450 | rv |= Assemble(devs[i], mdfd, array_ident, configfile, | |
451 | 0, NULL, | |
488 | rv |= Assemble(dv->devname, mdfd, array_ident, configfile, | |
489 | NULL, | |
452 | 490 | readonly, runstop, verbose, force); |
453 | 491 | } |
454 | 492 | else { |
458 | 496 | rv = 1; |
459 | 497 | } else |
460 | 498 | for (; array_list; array_list = array_list->next) { |
499 | mdu_array_info_t array; | |
461 | 500 | mdfd = open_mddev(array_list->devname); |
462 | 501 | if (mdfd < 0) { |
463 | 502 | rv |= 1; |
464 | 503 | continue; |
465 | 504 | } |
505 | if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) | |
506 | /* already assembled, skip */ | |
507 | continue; | |
466 | 508 | rv |= Assemble(array_list->devname, mdfd, |
467 | 509 | array_list, configfile, |
468 | 0, NULL, | |
510 | NULL, | |
469 | 511 | readonly, runstop, verbose, force); |
470 | 512 | } |
471 | 513 | } |
472 | 514 | break; |
473 | 515 | case 'B': /* Build */ |
474 | rv = Build(devs[0], mdfd, chunk, level, raiddisks, devs_found-1,devs+1); | |
516 | rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next); | |
475 | 517 | break; |
476 | 518 | case 'C': /* Create */ |
477 | rv = Create(devs[0], mdfd, chunk, level, layout, size, | |
519 | rv = Create(devlist->devname, mdfd, chunk, level, layout, size, | |
478 | 520 | raiddisks, sparedisks, |
479 | devs_found-1,devs+1, runstop, verbose, force); | |
521 | devs_found-1, devlist->next, runstop, verbose, force); | |
480 | 522 | break; |
481 | 523 | case 'D': /* Detail */ |
482 | for (i=0; i<devs_found; i++) | |
483 | rv |= Detail(devs[i]); | |
524 | for (dv=devlist ; dv; dv=dv->next) | |
525 | rv |= Detail(dv->devname, brief); | |
484 | 526 | break; |
485 | 527 | case 'E': /* Examine */ |
486 | for (i=0; i<devs_found; i++) | |
487 | rv |= Examine(devs[i]); | |
528 | if (devlist == NULL && scan==0) { | |
529 | fprintf(stderr, Name ": No devices to examine\n"); | |
530 | exit(2); | |
531 | } | |
532 | rv = Examine(devlist, devlist?brief:!verbose, configfile); | |
488 | 533 | break; |
489 | 534 | case 'F': /* Follow */ |
490 | rv= Monitor(devs_found, devs, mailaddr, program, | |
535 | rv= Monitor(devlist, mailaddr, program, | |
491 | 536 | delay?delay:60, configfile); |
492 | 537 | } |
493 | 538 | exit(rv); |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
75 | 75 | char *devices; /* comma separated list of device |
76 | 76 | * names with wild cards |
77 | 77 | */ |
78 | ||
78 | int level; /* -10 if not set */ | |
79 | int raid_disks; /* -1 if not set */ | |
79 | 80 | char *spare_group; |
80 | 81 | struct mddev_ident_s *next; |
81 | 82 | } *mddev_ident_t; |
83 | 84 | /* List of device names - wildcards expanded */ |
84 | 85 | typedef struct mddev_dev_s { |
85 | 86 | char *devname; |
87 | char disposition; /* 'a' for add, 'r' for remove, 'f' for fail. | |
88 | * Not set for names read from .config | |
89 | */ | |
86 | 90 | struct mddev_dev_s *next; |
87 | 91 | } *mddev_dev_t; |
88 | 92 | |
105 | 109 | extern int Manage_ro(char *devname, int fd, int readonly); |
106 | 110 | extern int Manage_runstop(char *devname, int fd, int runstop); |
107 | 111 | extern int Manage_subdevs(char *devname, int fd, |
108 | int devcnt, char *devnames[], int devmodes[]); | |
112 | mddev_dev_t devlist); | |
109 | 113 | |
110 | 114 | |
111 | 115 | extern int Assemble(char *mddev, int mdfd, |
112 | 116 | mddev_ident_t ident, |
113 | 117 | char *conffile, |
114 | int subdevs, char *subdev[], | |
118 | mddev_dev_t devlist, | |
115 | 119 | int readonly, int runstop, |
116 | 120 | int verbose, int force); |
117 | 121 | |
118 | 122 | extern int Build(char *mddev, int mdfd, int chunk, int level, |
119 | 123 | int raiddisks, |
120 | int subdevs, char *subdev[]); | |
124 | mddev_dev_t devlist); | |
121 | 125 | |
122 | 126 | |
123 | 127 | extern int Create(char *mddev, int mdfd, |
124 | 128 | int chunk, int level, int layout, int size, int raiddisks, int sparedisks, |
125 | int subdevs, char *subdev[], | |
129 | int subdevs, mddev_dev_t devlist, | |
126 | 130 | int runstop, int verbose, int force); |
127 | 131 | |
128 | extern int Detail(char *dev); | |
129 | extern int Examine(char *dev); | |
130 | extern int Monitor(int num_devs, char *devlist[], | |
132 | extern int Detail(char *dev, int brief); | |
133 | extern int Examine(mddev_dev_t devlist, int brief, char *conffile); | |
134 | extern int Monitor(mddev_dev_t devlist, | |
131 | 135 | char *mailaddr, char *alert_cmd, |
132 | 136 | int period, |
133 | 137 | char *config); |
141 | 145 | |
142 | 146 | extern mddev_ident_t conf_get_ident(char *, char*); |
143 | 147 | extern mddev_dev_t conf_get_devs(char *); |
148 | ||
149 | extern char *human_size(long kbytes); |
0 | mdctl(8) mdctl(8) | |
1 | ||
2 | ||
3 | ||
4 | NNAAMMEE | |
5 | mdctl - manage MD devices _a_k_a Linux Software Raid. | |
6 | ||
7 | ||
8 | SSYYNNOOPPSSIISS | |
9 | mmddccttll _[_m_o_d_e_] _<_r_a_i_d_d_e_v_i_c_e_> _[_o_p_t_i_o_n_s_] _<_s_u_b_d_e_v_i_c_e_s_> | |
10 | ||
11 | ||
12 | DDEESSCCRRIIPPTTIIOONN | |
13 | RAID devices are virtual devices created from two or more | |
14 | real block devices. This allows multiple devices (typi- | |
15 | cally disk drives or partitions there-of) to be combined | |
16 | into a single device to hold (for example) a single | |
17 | filesystem. Some RAID levels included redundancy and so | |
18 | can survive some degree of device failure. | |
19 | ||
20 | Linux Software RAID devices are implemented through the md | |
21 | (Multiple Devices) device driver. | |
22 | ||
23 | Currently, Linux supports LLIINNEEAARR md devices, RRAAIIDD00 (strip- | |
24 | ing), RRAAIIDD11 (mirroring), RRAAIIDD44 and RRAAIIDD55.. | |
25 | ||
26 | Recent kernels (2002) also support a mode known as MMUULLTTII-- | |
27 | PPAATTHH. mmddccttll does not support MULTIPATH as yet. | |
28 | ||
29 | mmddccttll is a program that can be used to create and manage | |
30 | MD devices. As such it provides a similar set of func- | |
31 | tionality to the rraaiiddttoooollss packages. The key differences | |
32 | between mmddccttll and rraaiiddttoooollss are: | |
33 | ||
34 | +o mmddccttll is a single program and not a collection of pro- | |
35 | grams. | |
36 | ||
37 | +o mmddccttll can perform (almost) all of its functions with- | |
38 | out having a configuration file. Also mdctl helps | |
39 | with management of the configuration file. | |
40 | ||
41 | +o mmddccttll can provide information about your arrays | |
42 | (through Detail and Examine) that rraaiiddttoooollss cannot. | |
43 | ||
44 | +o rraaiiddttoooollss can manage MULTIPATH devices which mmddccttll | |
45 | cannot yet manage. | |
46 | ||
47 | ||
48 | MMOODDEESS | |
49 | mdctl has 7 major modes of operation: | |
50 | ||
51 | AAsssseemmbbllee | |
52 | Assemble the parts of a previously created array | |
53 | into an active array. Components can be explicitly | |
54 | given or can be searched for. mmddccttll checks that | |
55 | the components do form a bona fide array, and can, | |
56 | on request, fiddle superblock information so as to | |
57 | assemble a faulty array. | |
58 | ||
59 | ||
60 | BBuuiilldd Build a legacy array without per-device | |
61 | superblocks. | |
62 | ||
63 | ||
64 | CCrreeaattee Create a new array with per-device superblocks. | |
65 | ||
66 | ||
67 | DDeettaaiill Display the details of a given md device. Details | |
68 | include the RAID level, the number of devices, | |
69 | which ones are faulty (if any), and the array UUID. | |
70 | ||
71 | ||
72 | EExxaammiinnee | |
73 | Examine a device to see if it is part of an md | |
74 | array, and print out the details of that array. | |
75 | This mode can also be used to examine a large num- | |
76 | ber of devices and to print out a summary of the | |
77 | arrays found in a format suitable for the | |
78 | mmddccttll..ccoonnff configuration file. | |
79 | ||
80 | ||
81 | FFoollllooww oorr MMoonniittoorr | |
82 | Monitor one or more md devices and act on any state | |
83 | changes. | |
84 | ||
85 | ||
86 | MMaannaaggee This is for odd bits an pieces like hotadd, | |
87 | hotremove, setfaulty, stop, readonly, readwrite. | |
88 | ||
89 | ||
90 | OOPPTTIIOONNSS | |
91 | Available options are: | |
92 | ||
93 | ||
94 | --AA, ----aasssseemmbbllee | |
95 | Assemble an existing array. | |
96 | ||
97 | ||
98 | --BB, ----bbuuiilldd | |
99 | Build a legacy array without superblocks. | |
100 | ||
101 | ||
102 | --CC, ----ccrreeaattee | |
103 | Create a new array. | |
104 | ||
105 | ||
106 | --DD, ----ddeettaaiill | |
107 | Print detail of one or more md devices. | |
108 | ||
109 | ||
110 | --EE, ----eexxaammiinnee | |
111 | Print content of md superblock on device(s). | |
112 | ||
113 | ||
114 | --FF, ----ffoollllooww, ----mmoonniittoorr | |
115 | Select MMoonniittoorr mode. | |
116 | ||
117 | ||
118 | --hh, ----hheellpp | |
119 | Display help message or, after above option, mode | |
120 | specific help message. | |
121 | ||
122 | ||
123 | --VV, ----vveerrssiioonn | |
124 | Print version information for mdctl. | |
125 | ||
126 | ||
127 | --vv, ----vveerrbboossee | |
128 | Be more verbose about what is happening. | |
129 | ||
130 | ||
131 | --bb, ----bbrriieeff | |
132 | Be less verbose. This is used with ----ddeettaaiill and | |
133 | ----eexxaammiinnee. | |
134 | ||
135 | ||
136 | FFoorr ccrreeaattee oorr bbuuiilldd:: | |
137 | --cc, ----cchhuunnkk== | |
138 | Specify chunk size of kibibytes. The default is | |
139 | 64. | |
140 | ||
141 | ||
142 | ----rroouunnddiinngg== | |
143 | Specify rounding factor for linear array (==chunk | |
144 | size) | |
145 | ||
146 | ||
147 | --ll, ----lleevveell== | |
148 | Set raid level. Options are: linear, raid0, 0, | |
149 | stripe, raid1, 1, mirror, raid5, 4, raid5, 5. | |
150 | Obviously some of these are synonymous. Only the | |
151 | first 4 are valid when Building. | |
152 | ||
153 | ||
154 | --pp, ----ppaarriittyy== | |
155 | Set raid5 parity algorithm. Options are: | |
156 | {left,right}-{,a}symmetric, la, ra, ls, rs. The | |
157 | default is left-symmetric. | |
158 | ||
159 | ||
160 | ----llaayyoouutt== | |
161 | same as --parity | |
162 | ||
163 | ||
164 | --nn, ----rraaiidd--ddiisskkss== | |
165 | number of active devices in array. | |
166 | ||
167 | ||
168 | --xx, ----ssppaarree--ddiisskkss== | |
169 | number of spare (eXtra) disks in initial array. | |
170 | Spares can be added and removed later. | |
171 | ||
172 | ||
173 | --zz, ----ssiizzee== | |
174 | Amount (in Kibibytes) of space to use from each | |
175 | drive in RAID1/4/5. This must be a multiple of the | |
176 | chunk size, and must leave about 128Kb of space at | |
177 | the end of the drive for the RAID superblock. If | |
178 | this is not specified (as it normally is not) the | |
179 | smallest drive (or partition) sets the size, though | |
180 | if there is a variance among the drives of greater | |
181 | than 1%, a warning is issued. | |
182 | ||
183 | ||
184 | FFoorr aasssseemmbbllee:: | |
185 | --uu, ----uuuuiidd== | |
186 | uuid of array to assemble. Devices which don't have | |
187 | this uuid are excluded | |
188 | ||
189 | ||
190 | --mm, ----ssuuppeerr--mmiinnoorr== | |
191 | Minor number of device that array was created for. | |
192 | Devices which don't have this minor number are | |
193 | excluded. If you create an array as /dev/md1, then | |
194 | all superblock will contain the minor number 1, | |
195 | even if the array is later assembled as /dev/md2. | |
196 | ||
197 | ||
198 | --cc, ----ccoonnffiigg== | |
199 | config file. Default is //eettcc//mmddccttll..ccoonnff. | |
200 | ||
201 | ||
202 | --ss, ----ssccaann | |
203 | scan config file for missing information | |
204 | ||
205 | ||
206 | --ff, ----ffoorrccee | |
207 | Assemble the array even if some superblocks appear | |
208 | out-of-date | |
209 | ||
210 | ||
211 | --RR, ----rruunn | |
212 | Attempt to start the array even if fewer drives | |
213 | were given than are needed for a full array. Nor- | |
214 | mally if not all drives are found and ----ssccaann is not | |
215 | used, then the array will be assembled but not | |
216 | started. With ----rruunn an attempt will be made to | |
217 | start it anyway. | |
218 | ||
219 | ||
220 | GGeenneerraall mmaannaaggeemmeenntt | |
221 | --aa, ----aadddd | |
222 | hotadd listed devices. | |
223 | ||
224 | ||
225 | --rr, ----rreemmoovvee | |
226 | remove listed devices. The must not be active. | |
227 | i.e. they should be failed or spare devices. | |
228 | ||
229 | ||
230 | --ff, ----ffaaiill | |
231 | mark listed devices as faulty. | |
232 | ||
233 | ||
234 | ----sseett--ffaauullttyy | |
235 | same as --fail. | |
236 | ||
237 | ||
238 | --RR, ----rruunn | |
239 | start a partially built array. | |
240 | ||
241 | ||
242 | --SS, ----ssttoopp | |
243 | deactivate array, releasing all resources. | |
244 | ||
245 | ||
246 | --oo, ----rreeaaddoonnllyy | |
247 | mark array as readonly. | |
248 | ||
249 | ||
250 | --ww, ----rreeaaddwwrriittee | |
251 | mark array as readwrite. | |
252 | ||
253 | ||
254 | ||
255 | AASSSSEEMMBBLLYY MMOODDEE | |
256 | Usage: mmddccttll ----aasssseemmbbllee _d_e_v_i_c_e _o_p_t_i_o_n_s_._._. | |
257 | ||
258 | Usage: mmddccttll ----aasssseemmbbllee ----ssccaann _o_p_t_i_o_n_s_._._. | |
259 | ||
260 | ||
261 | This usage assembles one or more raid arrays from pre- | |
262 | existing components. For each array, mdctl needs to know | |
263 | the md device, the identity of the array, and a number of | |
264 | sub devices. These can be found in a number of ways. | |
265 | ||
266 | The md device is either given before ----ssccaann or is found | |
267 | from the config file. In the latter case, multiple md | |
268 | devices can be started with a single mdctl command. | |
269 | ||
270 | The identity can be given with the ----uuuuiidd option, with the | |
271 | ----ssuuppeerr--mmiinnoorr option, can be found in in the config file, | |
272 | or will be taken from the super block on the first subde- | |
273 | vice listed on the command line. | |
274 | ||
275 | Devices can be given on the ----aasssseemmbbllee command line or | |
276 | from the config file. Only devices which have an md | |
277 | superblock which contains the right identity will be con- | |
278 | sidered for any device. | |
279 | ||
280 | The config file is only used if explicitly named with | |
281 | ----ccoonnffiigg or requested with ----ssccaann.. In the later case, | |
282 | //eettcc//mmddccttll..ccoonnff is used. | |
283 | ||
284 | If ----ssccaann is not given, then the config file will only be | |
285 | used to find the identity of md arrays. | |
286 | ||
287 | Normally the array will be started after it is assembled. | |
288 | However is ----ssccaann is not given and insufficient drives | |
289 | were lists to start a complete (non-degraded) array, then | |
290 | the array is not started (to guard against usage errors). | |
291 | To insist that the array be started in this case (as may | |
292 | work for RAID1 or RAID5), give the ----rruunn flag. | |
293 | ||
294 | ||
295 | ||
296 | BBUUIILLDD MMOODDEE | |
297 | Usage: mmddccttll ----bbuuiilldd _d_e_v_i_c_e ----cchhuunnkk==_X ----lleevveell==_Y ----rraaiidd-- | |
298 | ddiisskkss==_Z _d_e_v_i_c_e_s | |
299 | ||
300 | ||
301 | This usage is similar to ----ccrreeaattee. The difference is that | |
302 | it creates a legacy array without a superblock. With these | |
303 | arrays there is no difference between initially creating | |
304 | the array and subsequently assembling the array, except | |
305 | that hopefully there is useful data there in the second | |
306 | case. | |
307 | ||
308 | The level may only be 0, raid0, or linear. All devices | |
309 | must be listed and the array will be started once com- | |
310 | plete. | |
311 | ||
312 | ||
313 | CCRREEAATTEE MMOODDEE | |
314 | Usage: mmddccttll ----ccrreeaattee _d_e_v_i_c_e ----cchhuunnkk==_X ----lleevveell==_Y | |
315 | ----rraaiidd--ddiisskkss==_Z _d_e_v_i_c_e_s | |
316 | ||
317 | ||
318 | This usage will initialise a new md array, associate some | |
319 | devices with it, and activate the array. | |
320 | ||
321 | As devices are added, they are checked to see if they con- | |
322 | tain raid superblocks or filesystems. They are also check | |
323 | to see if the variance in device size exceeds 1%. | |
324 | ||
325 | If any discrepancy is found, the array will not automati- | |
326 | cally be run, though the presence of a ----rruunn can override | |
327 | this caution. | |
328 | ||
329 | ||
330 | The General Management options that are valid with --cre- | |
331 | ate are: | |
332 | ||
333 | ----rruunn insist of running the array even if some devices | |
334 | look like they might be in use. | |
335 | ||
336 | ||
337 | ----rreeaaddoonnllyy | |
338 | start the array readonly - not supported yet. | |
339 | ||
340 | ||
341 | DDEETTAAIILL MMOODDEE | |
342 | Usage: mmddccttll ----ddeettaaiill [----bbrriieeff] _d_e_v_i_c_e _._._. | |
343 | ||
344 | ||
345 | This usage sill print out the details of the given array | |
346 | including a list of component devices. To determine names | |
347 | for the devices, mmddccttll searches //ddeevv for device files with | |
348 | the right major and minor numbers. | |
349 | ||
350 | With ----bbrriieeff mmddccttll prints a single line that identifies | |
351 | the level, number of disks, and UUID of the array. This | |
352 | line is suitable for inclusion in //eettcc//mmddccttll..ccoonnff. | |
353 | ||
354 | ||
355 | EEXXAAMMIINNEE MMOODDEE | |
356 | Usage: mmddccttll ----eexxaammiinnee [----ssccaann] [----bbrriieeff] _d_e_v_i_c_e _._._. | |
357 | ||
358 | This usage will examine some block devices to see if that | |
359 | have a valid RAID superblock on them. The information in | |
360 | each valid raid superblock will be printed. | |
361 | ||
362 | If ----ssccaann is used, the no devices should be listed, and | |
363 | the complete set of devices identified in the configura- | |
364 | tion file are checked. ----ssccaann implies ----bbrriieeff but this | |
365 | implication can be countered by specifying ----vveerrbboossee. | |
366 | ||
367 | With ----bbrriieeff mmddccttll will output an config file entry of | |
368 | each distinct array that was found. This entry will list | |
369 | the UUID, the raid level, and a list of the individual | |
370 | devices on which a superblock for that array was found. | |
371 | This output will by syntactically suitable for inclusion | |
372 | in the configuration file, but should NNOOTT be used blindly. | |
373 | Often the array description that you want in the configu- | |
374 | ration file is much less specific than that given by mmddccttll | |
375 | --BBss. For example, you normally do not want to list the | |
376 | devices, particularly if they are SCSI devices. | |
377 | ||
378 | ||
379 | ||
380 | FFIILLEESS | |
381 | //pprroocc//mmddssttaatt | |
382 | If you're using the //pprroocc filesystem, //pprroocc//mmddssttaatt gives | |
383 | you informations about md devices status. This file is | |
384 | not currently used by mmddccttll. | |
385 | ||
386 | ||
387 | //eettcc//mmddccttll..ccoonnff | |
388 | The config file is line oriented with, as usual, blank | |
389 | lines and lines beginning with a hash (or pound sign or | |
390 | sharp or number sign, whichever you like to call it) | |
391 | ignored. Lines that start with a blank are treated as | |
392 | continuations of the previous line (I don't like trailing | |
393 | slashes). | |
394 | ||
395 | Each line contains a sequence of space-separated words, | |
396 | the first of which identified the type of line. Keywords | |
397 | are case-insensitive, and the first work on a line can be | |
398 | abbreviated to 3 letters. | |
399 | ||
400 | There are two types of lines. ARRAY and DEVICE. | |
401 | ||
402 | The DEVICE lines usually come first. All remaining words | |
403 | on the line are treated as names of devices, possibly con- | |
404 | taining wild cards (see _g_l_o_b(7)). These list all the | |
405 | devices that mmddccttll is allowed to scan when looking for | |
406 | devices with RAID superblocks. Each line can contain mul- | |
407 | tiple device names, and there can be multiple DEVICE | |
408 | lines. For example: | |
409 | ||
410 | DEVICE /dev/hda* /dev/hdc* | |
411 | DEV /dev/sd* | |
412 | DEVICE /dev/discs/disc*/disc | |
413 | ||
414 | The ARRAY lines identify actual arrays. The second word | |
415 | on the line should be the name of the device where the | |
416 | array is normally assembled, such as /dev/md1. Subsequent | |
417 | words identify the array. If multiple identities are | |
418 | given, then the array much match ALL identities to be con- | |
419 | sidered a match. Each identity word has a tag, and equals | |
420 | sign, and some value. The options are: | |
421 | ||
422 | ||
423 | uuuuiidd== The value should be a 128 bit uuid in hexadecimal, | |
424 | with punctuation interspersed if desired. This | |
425 | must match the uuid stored in the superblock. | |
426 | ||
427 | ssuuppeerr--mmiinnoorr== | |
428 | The value is an integer which indicates the minor | |
429 | number that was stored in the superblock when the | |
430 | array was created. When an array is created as | |
431 | /dev/mdX, then the minor number X is stored. | |
432 | ||
433 | ddeevviicceess== | |
434 | The value is a comma separated list of device | |
435 | names. Precisely these devices will be used to | |
436 | assemble the array. Note that the devices listed | |
437 | there must also be listed on a DEVICE line. | |
438 | ||
439 | lleevveell== The value is a raid level. This is normally used | |
440 | to identify an array, but is supported so that the | |
441 | output of mmddccttll ----eexxaammiinnee ----ssccaann can be use | |
442 | directly in the configuration file. | |
443 | ||
444 | ddiisskkss== The value is the number of disks in a complete | |
445 | active array. As with lleevveell== this is mainly for | |
446 | compatibility with the output of mmddccttll ----eexxaammiinnee | |
447 | ----ssccaann. | |
448 | ||
449 | ||
450 | TTOODDOO | |
451 | Finish and document Follow mode. | |
452 | ||
453 | ||
454 | SSEEEE AALLSSOO | |
455 | For information on the various levels of RAID, check out: | |
456 | ||
457 | ||
458 | http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/ | |
459 | ||
460 | for new releases of the RAID driver check out: | |
461 | ||
462 | ||
463 | ftp://ftp.kernel.org/pub/linux/kernel/peo- | |
464 | ple/mingo/raid-patches | |
465 | ||
466 | or | |
467 | ||
468 | http://www.cse.unsw.edu.au/~neilb/patches/linux- | |
469 | stable/ | |
470 | ||
471 | _r_a_i_d_t_a_b(5), _r_a_i_d_0_r_u_n(8), _r_a_i_d_s_t_o_p(8), _m_k_r_a_i_d(8) | |
472 | ||
473 | ||
474 | ||
475 | mdctl(8) |
0 | 0 | /* |
1 | 1 | * mdctl - manage Linux "md" devices aka RAID arrays. |
2 | 2 | * |
3 | * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> | |
3 | * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au> | |
4 | 4 | * |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
423 | 423 | super->sb_csum = oldcsum; |
424 | 424 | return csum; |
425 | 425 | } |
426 | ||
427 | char *human_size(long kbytes) | |
428 | { | |
429 | static char buf[30]; | |
430 | ||
431 | if (kbytes < 2000) | |
432 | buf[0]=0; | |
433 | else if (kbytes < 2*1024*1024) | |
434 | sprintf(buf, " (%d MiB)", kbytes>>10); | |
435 | else | |
436 | sprintf(buf, " (%d GiB)", kbytes>>20); | |
437 | return buf; | |
438 | } |