mdctl-v0.3
Neil Brown
22 years ago
106 | 106 | int most_recent = 0; |
107 | 107 | |
108 | 108 | if (!mddev && !scan) { |
109 | fputs("mdctl: internal error - Assemble called with no devie or scan\n", stderr); | |
109 | fputs(Name ": internal error - Assemble called with no devie or scan\n", stderr); | |
110 | 110 | return 1; |
111 | 111 | } |
112 | 112 | if (!mddev) { |
114 | 114 | int found = 0; |
115 | 115 | device_list = conf_get_uuids(conffile); |
116 | 116 | if (!device_list) { |
117 | fprintf(stderr, "mdctl: No devices found in config file\n"); | |
117 | fprintf(stderr, Name ": No devices found in config file\n"); | |
118 | 118 | return 1; |
119 | 119 | } |
120 | 120 | while (device_list) { |
122 | 122 | mdfd = open(device_list->devname, O_RDONLY, 0); |
123 | 123 | if (mdfd < 0) { |
124 | 124 | fprintf(stderr, |
125 | "mdctl: error opening %s: %s\n", | |
125 | Name ": error opening %s: %s\n", | |
126 | 126 | device_list->devname, |
127 | 127 | strerror(errno)); |
128 | 128 | continue; |
139 | 139 | } |
140 | 140 | if (found) |
141 | 141 | return 0; |
142 | fprintf(stderr,"mdctl: Did not successful Assemble any devices\n"); | |
142 | fprintf(stderr,Name ": Did not successful Assemble any devices\n"); | |
143 | 143 | return 1; |
144 | 144 | } |
145 | 145 | |
148 | 148 | */ |
149 | 149 | vers = md_get_version(mdfd); |
150 | 150 | if (vers <= 0) { |
151 | fprintf(stderr, "mdctl: %s appears not to be an md device.\n"); | |
152 | return 1; | |
153 | } | |
154 | if (vers < (90<<8)) { | |
155 | fprintf(stderr, "mdctl: Assemble requires driver version 0.90.0 or later.\n" | |
151 | fprintf(stderr, Name ": %s appears not to be an md device.\n"); | |
152 | return 1; | |
153 | } | |
154 | if (vers < 9000) { | |
155 | fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" | |
156 | 156 | " Upgrade your kernel or try --Build\n"); |
157 | 157 | return 1; |
158 | 158 | } |
159 | if (get_linux_version() < 0x020400) | |
159 | if (get_linux_version() < 2004000) | |
160 | 160 | old_linux = 1; |
161 | 161 | |
162 | 162 | if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) { |
163 | fprintf(stderr, "mdctl: device %s already active - cannot assemble it\n", | |
163 | fprintf(stderr, Name ": device %s already active - cannot assemble it\n", | |
164 | 164 | mddev); |
165 | 165 | return 1; |
166 | 166 | } |
178 | 178 | device_list = device_list->next; |
179 | 179 | |
180 | 180 | if (!device_list) { |
181 | fprintf(stderr, "mdctl: --scan set and no uuid found for %s in config file.\n", | |
181 | fprintf(stderr, Name ": --scan set and no uuid found for %s in config file.\n", | |
182 | 182 | mddev); |
183 | 183 | return 1; |
184 | 184 | } |
197 | 197 | devlist = conf_get_devs(conffile); |
198 | 198 | |
199 | 199 | if (subdevs == 0 && devlist == NULL) { |
200 | fprintf(stderr, "mdctl: no devices given for %s\n", mddev); | |
200 | fprintf(stderr, Name ": no devices given for %s\n", mddev); | |
201 | 201 | return 1; |
202 | 202 | } |
203 | 203 | /* now for each device */ |
224 | 224 | dfd = open(devname, O_RDONLY, 0); |
225 | 225 | if (dfd < 0) { |
226 | 226 | if (inargv || verbose) |
227 | fprintf(stderr, "mdctl: cannot open device %s: %s\n", | |
227 | fprintf(stderr, Name ": cannot open device %s: %s\n", | |
228 | 228 | devname, strerror(errno)); |
229 | 229 | continue; |
230 | 230 | } |
231 | 231 | if (fstat(dfd, &stb)< 0) { |
232 | 232 | /* Impossible! */ |
233 | fprintf(stderr, "mdctl: fstat failed for %s: %s\n", | |
233 | fprintf(stderr, Name ": fstat failed for %s: %s\n", | |
234 | 234 | devname, strerror(errno)); |
235 | 235 | close(dfd); |
236 | 236 | continue; |
237 | 237 | } |
238 | 238 | if ((stb.st_mode & S_IFMT) != S_IFBLK) { |
239 | fprintf(stderr, "mdctl: %d is not a block device.\n", | |
239 | fprintf(stderr, Name ": %d is not a block device.\n", | |
240 | 240 | devname); |
241 | 241 | close(dfd); |
242 | 242 | continue; |
243 | 243 | } |
244 | 244 | if (load_super(dfd, &super)) { |
245 | 245 | if (inargv || verbose) |
246 | fprintf( stderr, "mdctl: no RAID superblock on %s\n", | |
246 | fprintf( stderr, Name ": no RAID superblock on %s\n", | |
247 | 247 | devname); |
248 | 248 | close(dfd); |
249 | 249 | continue; |
251 | 251 | close(dfd); |
252 | 252 | if (compare_super(&first_super, &super)) { |
253 | 253 | if (inargv || verbose) |
254 | fprintf(stderr, "mdctl: superblock on %s doesn't match\n", | |
254 | fprintf(stderr, Name ": superblock on %s doesn't match\n", | |
255 | 255 | devname); |
256 | 256 | continue; |
257 | 257 | } |
259 | 259 | uuid_from_super(this_uuid, &first_super); |
260 | 260 | if (!same_uuid(this_uuid, uuid)) { |
261 | 261 | if (inargv || verbose) |
262 | fprintf(stderr, "mdctl: %s has wrong uuid.\n", | |
262 | fprintf(stderr, Name ": %s has wrong uuid.\n", | |
263 | 263 | devname); |
264 | 264 | continue; |
265 | 265 | } |
270 | 270 | |
271 | 271 | /* Ok, this one is at least worth considering */ |
272 | 272 | if (devcnt >= MD_SB_DISKS) { |
273 | fprintf(stderr, "mdctl: ouch - too many devices appear to be in this array. Ignoring %s\n", | |
273 | fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n", | |
274 | 274 | devname); |
275 | 275 | continue; |
276 | 276 | } |
294 | 294 | } |
295 | 295 | |
296 | 296 | if (devcnt == 0) { |
297 | fprintf(stderr, "mdctl: no devices found for %s\n", | |
297 | fprintf(stderr, Name ": no devices found for %s\n", | |
298 | 298 | mddev); |
299 | 299 | return 1; |
300 | 300 | } |
316 | 316 | * not up-to-date, update the superblock |
317 | 317 | * and add it. |
318 | 318 | */ |
319 | fprintf(stderr,"NoImplementedYet\n"); | |
319 | fprintf(stderr,"NotImplementedYet\n"); | |
320 | 320 | /* FIXME */ |
321 | 321 | exit(2); |
322 | 322 | } |
323 | 323 | /* Almost ready to actually *do* something */ |
324 | 324 | if (!old_linux) { |
325 | 325 | if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) { |
326 | fprintf(stderr, "mdctl: SET_ARRAY_INFO failed for %s: %s\n", | |
326 | fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", | |
327 | 327 | mddev, strerror(errno)); |
328 | 328 | return 1; |
329 | 329 | } |
336 | 336 | disk.major = devices[j].major; |
337 | 337 | disk.minor = devices[j].minor; |
338 | 338 | if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { |
339 | fprintf(stderr, "mdctl: failed to add %s to %s: %s\n", | |
339 | fprintf(stderr, Name ": failed to add %s to %s: %s\n", | |
340 | 340 | devices[j].devname, |
341 | 341 | mddev, |
342 | 342 | strerror(errno)); |
343 | 343 | } else |
344 | 344 | okcnt--; |
345 | 345 | } else if (verbose) |
346 | fprintf(stderr, "mdctl: no uptodate device for slot %d of %s\n", | |
346 | fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", | |
347 | 347 | i, mddev); |
348 | 348 | } |
349 | 349 | if (runstop == 1 || |
351 | 351 | enough(first_super.level, first_super.raid_disks, okcnt))) { |
352 | 352 | if (ioctl(mdfd, RUN_ARRAY, NULL)==0) |
353 | 353 | return 0; |
354 | fprintf(stderr, "mdctl: failed to RUN_ARRAY %s: %s\n", | |
354 | fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", | |
355 | 355 | mddev, strerror(errno)); |
356 | 356 | return 1; |
357 | 357 | } |
27 | 27 | */ |
28 | 28 | |
29 | 29 | #include "mdctl.h" |
30 | #include "md_u.h" | |
31 | #include "md_p.h" | |
30 | 32 | |
31 | 33 | int Create(char *mddev, int mdfd, |
32 | int chunk, int level, int layout, int raiddisks, int sparedisks, | |
34 | int chunk, int level, int layout, int size, int raiddisks, int sparedisks, | |
33 | 35 | int subdevs, char *subdev[], |
34 | int runstop) | |
36 | int runstop, int verbose) | |
35 | 37 | { |
38 | /* | |
39 | * Create a new raid array. | |
40 | * | |
41 | * First check that necessary details are available | |
42 | * (i.e. level, raid-disks) | |
43 | * | |
44 | * Then check each disk to see what might be on it | |
45 | * and report anything interesting. | |
46 | * | |
47 | * If anything looks odd, and runstop not set, | |
48 | * abort. | |
49 | * | |
50 | * SET_ARRAY_INFO and ADD_NEW_DISK, and | |
51 | * if runstop==run, or raiddisks diskswere used, | |
52 | * RUN_ARRAY | |
53 | */ | |
54 | int minsize, maxsize; | |
55 | int maxdisc= -1, mindisc = -1; | |
56 | int i; | |
57 | int fail=0, warn=0; | |
58 | ||
59 | mdu_array_info_t array; | |
60 | mdu_param_t param; | |
61 | ||
62 | ||
63 | if (md_get_version(mdfd) < 9000) { | |
64 | fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n"); | |
65 | return 1; | |
66 | } | |
67 | if (level == -10) { | |
68 | fprintf(stderr, | |
69 | Name ": a RAID level is needed to create an array.\n"); | |
70 | return 1; | |
71 | } | |
72 | if (raiddisks < 1) { | |
73 | fprintf(stderr, | |
74 | Name ": a number of --raid-disks must be given to create an array\n"); | |
75 | return 1; | |
76 | } | |
77 | if (raiddisks+sparedisks > MD_SB_DISKS) { | |
78 | fprintf(stderr, | |
79 | Name ": too many discs requested: %d+%d > %d\n", | |
80 | raiddisks, sparedisks, MD_SB_DISKS); | |
81 | return 1; | |
82 | } | |
83 | if (subdevs > raiddisks+sparedisks) { | |
84 | fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks); | |
85 | return 1; | |
86 | } | |
87 | /* now set some defaults */ | |
88 | if (layout == -1) | |
89 | switch(level) { | |
90 | default: /* no layout */ | |
91 | layout = 0; | |
92 | break; | |
93 | case 5: | |
94 | layout = map_name(r5layout, "default"); | |
95 | if (verbose) | |
96 | fprintf(stderr, | |
97 | Name ": layout defaults to %s\n", map_num(r5layout, layout)); | |
98 | break; | |
99 | } | |
100 | ||
101 | if (chunk == 0) { | |
102 | chunk = 64; | |
103 | if (verbose) | |
104 | fprintf(stderr, Name ": chunk size defaults to 64K\n"); | |
105 | } | |
106 | ||
107 | /* now look at the subdevs */ | |
108 | for (i=0; i<subdevs; i++) { | |
109 | char *dname = subdev[i]; | |
110 | int dsize, freesize; | |
111 | int fd = open(dname, O_RDONLY, 0); | |
112 | if (fd <0 ) { | |
113 | fprintf(stderr, Name ": Cannot open %s: %s\n", | |
114 | dname, strerror(errno)); | |
115 | fail=1; | |
116 | continue; | |
117 | } | |
118 | if (ioctl(fd, BLKGETSIZE, &dsize)) { | |
119 | fprintf(stderr, Name ": Cannot get size of %s: %s\n", | |
120 | dname, strerror(errno)); | |
121 | fail = 1; | |
122 | close(fd); | |
123 | continue; | |
124 | } | |
125 | if (dsize < MD_RESERVED_SECTORS*2) { | |
126 | fprintf(stderr, Name ": %s is too small: %dK\n", | |
127 | dname, dsize/2); | |
128 | fail = 1; | |
129 | close(fd); | |
130 | continue; | |
131 | } | |
132 | freesize = MD_NEW_SIZE_SECTORS(dsize); | |
133 | freesize /= 2; | |
134 | ||
135 | if (size && freesize < size) { | |
136 | fprintf(stderr, Name ": %s is smaller that given size." | |
137 | " %dK < %dK + superblock\n", dname, freesize, size); | |
138 | fail = 1; | |
139 | close(fd); | |
140 | continue; | |
141 | } | |
142 | if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) { | |
143 | maxdisc = i; | |
144 | maxsize = freesize; | |
145 | } | |
146 | if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) { | |
147 | mindisc = i; | |
148 | minsize = freesize; | |
149 | } | |
150 | warn |= check_ext2(fd, dname); | |
151 | warn |= check_reiser(fd, dname); | |
152 | warn |= check_raid(fd, dname); | |
153 | close(fd); | |
154 | } | |
155 | if (fail) { | |
156 | fprintf(stderr, Name ": create aborted\n"); | |
157 | return 1; | |
158 | } | |
159 | if (size == 0) { | |
160 | if (mindisc == -1) { | |
161 | fprintf(stderr, Name ": no size and no drives given - aborting create.\n"); | |
162 | return 1; | |
163 | } | |
164 | size = minsize; | |
165 | if (verbose) | |
166 | fprintf(stderr, Name ": size set to %dK\n", size); | |
167 | } | |
168 | if ((maxsize-size)*100 > maxsize) { | |
169 | fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n", | |
170 | subdev[maxdisc], size); | |
171 | warn = 1; | |
172 | } | |
173 | ||
174 | if (warn) { | |
175 | if (runstop!= 1) { | |
176 | if (!ask("Continue creating array? ")) { | |
177 | fprintf(stderr, Name ": create aborted.\n"); | |
178 | return 1; | |
179 | } | |
180 | } else { | |
181 | if (verbose) | |
182 | fprintf(stderr, Name ": creation continuing despite oddities due to --run\n"); | |
183 | } | |
184 | } | |
185 | ||
186 | /* Ok, lets try some ioctls */ | |
187 | ||
188 | array.level = level; | |
189 | array.size = size; | |
190 | array.nr_disks = raiddisks+sparedisks; | |
191 | array.raid_disks = raiddisks; | |
192 | array.md_minor = 0; | |
193 | array.not_persistent = 0; | |
194 | array.state = 0; /* not clean, but no errors */ | |
195 | array.active_disks=0; | |
196 | array.working_disks=0; | |
197 | array.spare_disks=0; | |
198 | array.failed_disks=0; | |
199 | array.layout = layout; | |
200 | array.chunk_size = chunk*1024; | |
201 | ||
202 | if (ioctl(mdfd, SET_ARRAY_INFO, &array)) { | |
203 | fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", | |
204 | mddev, strerror(errno)); | |
205 | return 1; | |
206 | } | |
207 | ||
208 | for (i=0; i<subdevs; i++) { | |
209 | int fd = open(subdev[i], O_RDONLY, 0); | |
210 | struct stat stb; | |
211 | mdu_disk_info_t disk; | |
212 | if (fd < 0) { | |
213 | fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n", | |
214 | subdev[i]); | |
215 | return 1; | |
216 | } | |
217 | fstat(fd, &stb); | |
218 | disk.number = i; | |
219 | disk.raid_disk = i; | |
220 | disk.state = 6; /* active and in sync */ | |
221 | disk.major = MAJOR(stb.st_rdev); | |
222 | disk.minor = MINOR(stb.st_rdev); | |
223 | close(fd); | |
224 | if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { | |
225 | fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\b", | |
226 | subdev[i], strerror(errno)); | |
227 | return 1; | |
228 | } | |
229 | } | |
230 | ||
231 | /* param is not actually used */ | |
232 | if (runstop == 1 || subdevs >= raiddisks) { | |
233 | if (ioctl(mdfd, RUN_ARRAY, ¶m)) { | |
234 | fprintf(stderr, Name ": RUN_ARRAY failed: %s\n", | |
235 | strerror(errno)); | |
236 | return 1; | |
237 | } | |
238 | fprintf(stderr, Name ": array %s started.\n", mddev); | |
239 | } else { | |
240 | fprintf(stderr, Name ": not starting array - not enough discs.\n"); | |
241 | } | |
242 | return 0; | |
36 | 243 | } |
42 | 42 | mdu_array_info_t array; |
43 | 43 | int d; |
44 | 44 | time_t atime; |
45 | char *c; | |
45 | 46 | |
46 | 47 | if (fd < 0) { |
47 | fprintf(stderr, "mdctl: cannot open %s: %s\n", | |
48 | fprintf(stderr, Name ": cannot open %s: %s\n", | |
48 | 49 | dev, strerror(errno)); |
49 | 50 | return 1; |
50 | 51 | } |
51 | 52 | vers = md_get_version(fd); |
52 | 53 | if (vers < 0) { |
53 | fprintf(stderr, "mdctl: %s does not appear to be an md device\n", | |
54 | fprintf(stderr, Name ": %s does not appear to be an md device\n", | |
54 | 55 | dev); |
55 | 56 | close(fd); |
56 | 57 | return 1; |
57 | 58 | } |
58 | if (vers < (90<<8)) { | |
59 | fprintf(stderr, "mdctl: cannot get detail for md device %s: driver version too old.\n", | |
59 | if (vers < 9000) { | |
60 | fprintf(stderr, Name ": cannot get detail for md device %s: driver version too old.\n", | |
60 | 61 | dev); |
61 | 62 | close(fd); |
62 | 63 | return 1; |
63 | 64 | } |
64 | 65 | if (ioctl(fd, GET_ARRAY_INFO, &array)<0) { |
65 | 66 | if (errno == ENODEV) |
66 | fprintf(stderr, "mdctl: md device %s does not appear to be active.\n", | |
67 | fprintf(stderr, Name ": md device %s does not appear to be active.\n", | |
67 | 68 | dev); |
68 | 69 | else |
69 | fprintf(stderr, "mdctl: cannot get array detail for %s: %s\n", | |
70 | fprintf(stderr, Name ": cannot get array detail for %s: %s\n", | |
70 | 71 | dev, strerror(errno)); |
71 | 72 | close(fd); |
72 | 73 | return 1; |
77 | 78 | array.major_version, array.minor_version, array.patch_version); |
78 | 79 | atime = array.ctime; |
79 | 80 | printf(" Creation Time : %.24s\n", ctime(&atime)); |
80 | printf(" Raid Level : %d\n", array.level); | |
81 | c = map_num(pers, array.level); | |
82 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
81 | 83 | printf(" Size : %d\n", array.size); |
82 | 84 | printf(" Raid Disks : %d\n", array.raid_disks); |
83 | 85 | printf(" Total Disks : %d\n", array.nr_disks); |
95 | 97 | printf(" Failed Drives : %d\n", array.failed_disks); |
96 | 98 | printf(" Spare Drives : %d\n", array.spare_disks); |
97 | 99 | printf("\n"); |
98 | printf(" Layout : %d\n", array.layout); | |
100 | if (array.level == 5) { | |
101 | c = map_num(r5layout, array.layout); | |
102 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
103 | } | |
99 | 104 | printf(" Chunk Size : %dK\n", array.chunk_size/1024); |
100 | 105 | printf("\n"); |
101 | 106 | printf(" Number Major Minor RaidDisk State\n"); |
103 | 108 | mdu_disk_info_t disk; |
104 | 109 | disk.number = d; |
105 | 110 | if (ioctl(fd, GET_DISK_INFO, &disk) < 0) { |
106 | fprintf(stderr, "mdctl: cannot get disk detail for disk %d: %s\n", | |
111 | fprintf(stderr, Name ": cannot get disk detail for disk %d: %s\n", | |
107 | 112 | d, strerror(errno)); |
108 | 113 | continue; |
109 | 114 | } |
50 | 50 | time_t atime; |
51 | 51 | mdp_super_t super; |
52 | 52 | int d; |
53 | char *c; | |
53 | 54 | int rv; |
54 | 55 | |
55 | 56 | if (fd < 0) { |
56 | fprintf(stderr,"mdctl: cannot open %s: %s\n", | |
57 | fprintf(stderr,Name ": cannot open %s: %s\n", | |
57 | 58 | dev, strerror(errno)); |
58 | 59 | return 1; |
59 | 60 | } |
62 | 63 | close(fd); |
63 | 64 | switch(rv) { |
64 | 65 | case 1: |
65 | fprintf(stderr, "mdctl: cannot find device size for %s: %s\n", | |
66 | fprintf(stderr, Name ": cannot find device size for %s: %s\n", | |
66 | 67 | dev, strerror(errno)); |
67 | 68 | return 1; |
68 | 69 | case 2: |
69 | /* fprintf(stderr, "mdctl: %s is too small for md: size is %ld sectors\n", | |
70 | /* fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n", | |
70 | 71 | dev, size); |
71 | 72 | */ |
72 | fprintf(stderr, "mdctl: %s is too small for md\n", | |
73 | fprintf(stderr, Name ": %s is too small for md\n", | |
73 | 74 | dev); |
74 | 75 | return 1; |
75 | 76 | case 3: |
76 | fprintf(stderr, "mdctl: Cannot seek to superblock on %s: %s\n", | |
77 | fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", | |
77 | 78 | dev, strerror(errno)); |
78 | 79 | return 1; |
79 | 80 | case 4: |
80 | fprintf(stderr, "mdctl: Cannot read superblock on %s\n", | |
81 | fprintf(stderr, Name ": Cannot read superblock on %s\n", | |
81 | 82 | dev); |
82 | 83 | return 1; |
83 | 84 | case 5: |
84 | fprintf(stderr, "mdctl: No super block found on %s (Expected magic %08x, got %08x)\n", | |
85 | fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", | |
85 | 86 | dev, MD_SB_MAGIC, super.md_magic); |
86 | 87 | return 1; |
87 | 88 | case 6: |
88 | fprintf(stderr, "mdctl: Cannot interpret superblock on %s - version is %d\n", | |
89 | fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", | |
89 | 90 | dev, super.major_version); |
90 | 91 | return 1; |
91 | 92 | } |
103 | 104 | |
104 | 105 | atime = super.ctime; |
105 | 106 | printf(" Creation Time : %.24s\n", ctime(&atime)); |
106 | printf(" Raid Level : %d\n", super.level); | |
107 | c=map_num(pers, super.level); | |
108 | printf(" Raid Level : %s\n", c?c:"-unknown-"); | |
107 | 109 | printf(" Size : %d\n", super.size); |
108 | 110 | printf(" Raid Disks : %d\n", super.raid_disks); |
109 | 111 | printf(" Total Disks : %d\n", super.nr_disks); |
121 | 123 | printf(" - checksum not checked yet - \n"); |
122 | 124 | printf(" Events : %d.%d\n", super.events_hi, super.events_lo); |
123 | 125 | printf("\n"); |
124 | printf(" Layout : %d\n", super.layout); | |
126 | if (super.level == 5) { | |
127 | c = map_num(r5layout, super.layout); | |
128 | printf(" Layout : %s\n", c?c:"-unknown-"); | |
129 | } | |
125 | 130 | printf(" Chunk Size : %dK\n", super.chunk_size/1024); |
126 | 131 | printf("\n"); |
127 | 132 | printf(" Number Major Minor RaidDisk State\n"); |
27 | 27 | */ |
28 | 28 | |
29 | 29 | #include "mdctl.h" |
30 | #include "md_u.h" | |
31 | #include "md_p.h" | |
30 | 32 | |
31 | 33 | int Manage_ro(char *devname, int fd, int readonly) |
32 | 34 | { |
35 | /* switch to readonly or rw | |
36 | * | |
37 | * requires >= 0.90.0 | |
38 | * first check that array is runing | |
39 | * use RESTART_ARRAY_RW or STOP_ARRAY_RO | |
40 | * | |
41 | */ | |
42 | mdu_array_info_t array; | |
43 | ||
44 | if (md_get_version(fd) < 9000) { | |
45 | fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); | |
46 | return 1; | |
47 | } | |
48 | if (ioctl(fd, GET_ARRAY_INFO, &array)) { | |
49 | fprintf(stderr, Name ": %s does not appear to be active.\n", | |
50 | devname); | |
51 | return 1; | |
52 | } | |
53 | ||
54 | if (readonly>0) { | |
55 | if (ioctl(fd, STOP_ARRAY_RO, NULL)) { | |
56 | fprintf(stderr, Name ": failed to set readonly for %s: %s\n", | |
57 | devname, strerror(errno)); | |
58 | return 1; | |
59 | } | |
60 | } else if (readonly < 0) { | |
61 | if (ioctl(fd, RESTART_ARRAY_RW, NULL)) { | |
62 | fprintf(stderr, Name ": fail to re writable for %s: %s\n", | |
63 | devname, strerror(errno)); | |
64 | return 1; | |
65 | } | |
66 | } | |
67 | return 0; | |
33 | 68 | } |
34 | 69 | |
35 | 70 | int Manage_runstop(char *devname, int fd, int runstop) |
36 | 71 | { |
72 | /* Run or stop the array. array must already be configured | |
73 | * required >= 0.90.0 | |
74 | */ | |
75 | mdu_array_info_t array; | |
76 | mdu_param_t param; /* unused */ | |
77 | ||
78 | if (md_get_version(fd) < 9000) { | |
79 | fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); | |
80 | return 1; | |
81 | } | |
82 | if (ioctl(fd, GET_ARRAY_INFO, &array)) { | |
83 | fprintf(stderr, Name ": %s does not appear to be active.\n", | |
84 | devname); | |
85 | return 1; | |
86 | } | |
87 | ||
88 | if (runstop>0) { | |
89 | if (ioctl(fd, RUN_ARRAY, ¶m)) { | |
90 | fprintf(stderr, Name ": failed to run array %s: %s\n", | |
91 | devname, strerror(errno)); | |
92 | return 1; | |
93 | } | |
94 | } else if (runstop < 0){ | |
95 | if (ioctl(fd, STOP_ARRAY, NULL)) { | |
96 | fprintf(stderr, Name ": fail to re writable for %s: %s\n", | |
97 | devname, strerror(errno)); | |
98 | return 1; | |
99 | } | |
100 | } | |
101 | return 0; | |
37 | 102 | } |
38 | 103 | |
39 | 104 | int Manage_subdevs(char *devname, int fd, |
40 | 105 | int devcnt, char *devnames[], int devmodes[]) |
41 | { | |
106 | { | |
107 | /* do something to each dev. | |
108 | * devmode can be | |
109 | * 'a' - add the device | |
110 | * try HOT_ADD_DISK | |
111 | * If that fails EINVAL, try ADD_NEW_DISK | |
112 | * 'r' - remove the device HOT_REMOVE_DISK | |
113 | * 'f' - set the device faulty SET_DISK_FAULTY | |
114 | */ | |
115 | mdu_array_info_t array; | |
116 | mdu_disk_info_t disc; | |
117 | struct stat stb; | |
118 | int i,j; | |
119 | ||
120 | if (ioctl(fd, GET_ARRAY_INFO, &array)) { | |
121 | fprintf(stderr, Name ": cannot get array info for %s\n", | |
122 | devname); | |
123 | return 1; | |
124 | } | |
125 | for (i=0 ; i<devcnt; i++) { | |
126 | if (stat(devnames[i], &stb)) { | |
127 | fprintf(stderr, Name ": cannot find %s: %s\n", | |
128 | devnames[i], strerror(errno)); | |
129 | return 1; | |
130 | } | |
131 | if ((stb.st_mode & S_IFMT) != S_IFBLK) { | |
132 | fprintf(stderr, Name ": %s is not a block device.\n", | |
133 | devnames[i]); | |
134 | return 1; | |
135 | } | |
136 | switch(devmodes[i]){ | |
137 | default: | |
138 | fprintf(stderr, Name ": internal error - devmode[%d]=%d\n", | |
139 | i, devmodes[i]); | |
140 | return 1; | |
141 | case 'a': | |
142 | /* add the device - hot or cold */ | |
143 | if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) { | |
144 | fprintf(stderr, Name ": hot added %s\n", | |
145 | devnames[i]); | |
146 | continue; | |
147 | } | |
148 | /* try ADD_NEW_DISK. | |
149 | * we might be creating, we might be assembling, | |
150 | * it is hard to tell. | |
151 | * set up number/raid_disk/state just | |
152 | * in case | |
153 | */ | |
154 | for (j=0; j<array.nr_disks; j++) { | |
155 | if (ioctl(fd, GET_DISK_INFO, &disc)) | |
156 | break; | |
157 | if (disc.major==0 && disc.minor==0) | |
158 | break; | |
159 | if (disc.state & 8) /* removed */ | |
160 | break; | |
161 | } | |
162 | disc.number =j; | |
163 | disc.raid_disk = j; | |
164 | disc.state = 0; | |
165 | disc.major = MAJOR(stb.st_rdev); | |
166 | disc.minor = MINOR(stb.st_rdev); | |
167 | if (ioctl(fd,ADD_NEW_DISK, &disc)) { | |
168 | fprintf(stderr, Name ": add new disk failed for %s: %s\n", | |
169 | devnames[i], strerror(errno)); | |
170 | return 1; | |
171 | } | |
172 | fprintf(stderr, Name ": added %s\n", devnames[i]); | |
173 | break; | |
174 | ||
175 | case 'r': | |
176 | /* hot remove */ | |
177 | /* FIXME check that is is a current member */ | |
178 | if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) { | |
179 | fprintf(stderr, Name ": hot remove failed for %s: %s\n", | |
180 | devnames[i], strerror(errno)); | |
181 | return 1; | |
182 | } | |
183 | fprintf(stderr, Name ": hot removed %s\n", devnames[i]); | |
184 | break; | |
185 | ||
186 | case 'f': /* set faulty */ | |
187 | /* FIXME check current member */ | |
188 | if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) { | |
189 | fprintf(stderr, Name ": set disk faulty failed for %s: %s\n", | |
190 | devnames[i], strerror(errno)); | |
191 | return 1; | |
192 | } | |
193 | fprintf(stderr, Name ": set %s faulty in %s\n", | |
194 | devnames[i], devname); | |
195 | break; | |
196 | } | |
197 | } | |
198 | return 0; | |
199 | ||
42 | 200 | } |
28 | 28 | |
29 | 29 | #include "mdctl.h" |
30 | 30 | |
31 | char Version[] = "mdctl - v0.2 - 06 June 2001\n"; | |
31 | char Version[] = Name " - v0.3 - 14 June 2001\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[]="-ABCDEhVvc:l:p:n:x:u:c:sarfRSow"; | |
80 | char short_options[]="-ABCDEhVvc:l:p:n:x:u:c:z:sarfRSow"; | |
81 | 81 | struct option long_options[] = { |
82 | 82 | {"manage", 0, 0, '@'}, |
83 | 83 | {"assemble", 0, 0, 'A'}, |
98 | 98 | {"layout", 1, 0, 'p'}, |
99 | 99 | {"raid-disks",1, 0, 'n'}, |
100 | 100 | {"spare-disks",1,0, 'x'}, |
101 | {"size" ,1, 0, 'z'}, | |
101 | 102 | |
102 | 103 | /* For assemble */ |
103 | 104 | {"uuid", 1, 0, 'u'}, |
156 | 157 | " --layout= : same as --parity\n" |
157 | 158 | " --raid-disks= -n : number of active devices in array\n" |
158 | 159 | " --spare-disks= -x : number of spares (eXtras) to allow space for\n" |
160 | " --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n" | |
159 | 161 | "\n" |
160 | 162 | " For assemble:\n" |
161 | 163 | " --uuid= -u : uuid of array to assemble. Devices which don't\n" |
191 | 193 | " be run, though the presence of a '--run' can override this\n" |
192 | 194 | " caution.\n" |
193 | 195 | "\n" |
196 | " If the --size option is given, it is not necessary to list any subdevices\n" | |
197 | " in this command. They can be added later, before a --run.\n" | |
198 | " If no --size is given, the apparent size of the smallest drive given\n" | |
199 | " is used.\n" | |
200 | "\n" | |
194 | 201 | " The General management options that are valid with --create are:\n" |
195 | 202 | " --run : insist of running the array even if not all devices\n" |
196 | 203 | " are present or some look odd.\n" |
243 | 250 | " not yet documented\n" |
244 | 251 | "\n" |
245 | 252 | ; |
253 | ||
254 | ||
255 | /* name/number mappings */ | |
256 | ||
257 | mapping_t r5layout[] = { | |
258 | { "left_asymmetric", 0}, | |
259 | { "right_asymmetric", 1}, | |
260 | { "left_symmetric", 2}, | |
261 | { "right_symmetric", 3}, | |
262 | ||
263 | { "default", 2}, | |
264 | { "la", 0}, | |
265 | { "ra", 1}, | |
266 | { "ls", 2}, | |
267 | { "rs", 3}, | |
268 | { NULL, 0} | |
269 | }; | |
270 | ||
271 | mapping_t pers[] = { | |
272 | { "linear", -1}, | |
273 | { "raid0", 0}, | |
274 | { "0", 0}, | |
275 | { "stripe", 0}, | |
276 | { "raid1", 1}, | |
277 | { "1", 1}, | |
278 | { "mirror", 1}, | |
279 | { "raid4", 4}, | |
280 | { "4", 4}, | |
281 | { "raid5", 5}, | |
282 | { "5", 5}, | |
283 | { NULL, 0} | |
284 | }; |
0 | ||
1 | md_p.h,1316 | |
2 | #define _MD_P_H16,582 | |
3 | #define MD_RESERVED_BYTES 44,1414 | |
4 | #define MD_RESERVED_SECTORS 45,1453 | |
5 | #define MD_RESERVED_BLOCKS 46,1508 | |
6 | #define MD_NEW_SIZE_SECTORS(MD_NEW_SIZE_SECTORS48,1570 | |
7 | #define MD_NEW_SIZE_BLOCKS(MD_NEW_SIZE_BLOCKS49,1659 | |
8 | #define MD_SB_BYTES 51,1746 | |
9 | #define MD_SB_WORDS 52,1773 | |
10 | #define MD_SB_BLOCKS 53,1813 | |
11 | #define MD_SB_SECTORS 54,1863 | |
12 | #define MD_SB_GENERIC_OFFSET 59,1960 | |
13 | #define MD_SB_PERSONALITY_OFFSET 60,1992 | |
14 | #define MD_SB_DISKS_OFFSET 61,2028 | |
15 | #define MD_SB_DESCRIPTOR_OFFSET 62,2060 | |
16 | #define MD_SB_GENERIC_CONSTANT_WORDS 64,2098 | |
17 | #define MD_SB_GENERIC_STATE_WORDS 65,2138 | |
18 | #define MD_SB_GENERIC_WORDS 66,2175 | |
19 | #define MD_SB_PERSONALITY_WORDS 67,2263 | |
20 | #define MD_SB_DESCRIPTOR_WORDS 68,2299 | |
21 | #define MD_SB_DISKS 69,2334 | |
22 | #define MD_SB_DISKS_WORDS 70,2359 | |
23 | #define MD_SB_RESERVED_WORDS 71,2423 | |
24 | #define MD_SB_EQUAL_WORDS 72,2553 | |
25 | #define MD_DISK_FAULTY 77,2691 | |
26 | #define MD_DISK_ACTIVE 78,2752 | |
27 | #define MD_DISK_SYNC 79,2814 | |
28 | #define MD_DISK_REMOVED 80,2878 | |
29 | typedef struct mdp_device_descriptor_s mdp_device_descriptor_s82,2946 | |
30 | } mdp_disk_t;mdp_disk_t89,3310 | |
31 | #define MD_SB_MAGIC 91,3325 | |
32 | #define MD_SB_CLEAN 96,3390 | |
33 | #define MD_SB_ERRORS 97,3413 | |
34 | typedef struct mdp_superblock_s mdp_superblock_s99,3438 | |
35 | } mdp_super_t;mdp_super_t164,5820 | |
36 | static inline __u64 md_event(166,5836 | |
37 | ||
38 | md_u.h,1118 | |
39 | #define _MD_U_H16,590 | |
40 | #define RAID_VERSION 21,634 | |
41 | #define GET_ARRAY_INFO 22,693 | |
42 | #define GET_DISK_INFO 23,757 | |
43 | #define PRINT_RAID_DEBUG 24,819 | |
44 | #define RAID_AUTORUN 25,865 | |
45 | #define CLEAR_ARRAY 28,929 | |
46 | #define ADD_NEW_DISK 29,971 | |
47 | #define HOT_REMOVE_DISK 30,1032 | |
48 | #define SET_ARRAY_INFO 31,1078 | |
49 | #define SET_DISK_INFO 32,1142 | |
50 | #define WRITE_RAID_INFO 33,1186 | |
51 | #define UNPROTECT_ARRAY 34,1232 | |
52 | #define PROTECT_ARRAY 35,1278 | |
53 | #define HOT_ADD_DISK 36,1322 | |
54 | #define SET_DISK_FAULTY 37,1365 | |
55 | #define RUN_ARRAY 40,1424 | |
56 | #define START_ARRAY 41,1478 | |
57 | #define STOP_ARRAY 42,1520 | |
58 | #define STOP_ARRAY_RO 43,1561 | |
59 | #define RESTART_ARRAY_RW 44,1605 | |
60 | typedef struct mdu_version_s mdu_version_s46,1652 | |
61 | } mdu_version_t;mdu_version_t50,1724 | |
62 | typedef struct mdu_array_info_s mdu_array_info_s52,1742 | |
63 | } mdu_array_info_t;mdu_array_info_t83,2516 | |
64 | typedef struct mdu_disk_info_s mdu_disk_info_s85,2537 | |
65 | } mdu_disk_info_t;mdu_disk_info_t95,2693 | |
66 | typedef struct mdu_start_info_s mdu_start_info_s97,2713 | |
67 | } mdu_start_info_t;mdu_start_info_t106,2857 | |
68 | typedef struct mdu_param_smdu_param_s108,2878 | |
69 | } mdu_param_t;mdu_param_t113,3014 | |
70 | ||
71 | mdctl.h,823 | |
72 | #define __USE_LARGEFILE6430,1115 | |
73 | #define MD_MAJOR 47,1491 | |
74 | extern char short_options[52,1531 | |
75 | extern struct option long_options[53,1560 | |
76 | extern char Version[54,1597 | |
77 | extern char Version[], Usage[54,1597 | |
78 | extern char Version[], Usage[], Help[54,1597 | |
79 | extern char Version[], Usage[], Help[], Help_create[54,1597 | |
80 | extern char Version[], Usage[], Help[], Help_create[], Help_build[54,1597 | |
81 | extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[54,1597 | |
82 | typedef struct mddev_uuid_s mddev_uuid_s58,1762 | |
83 | } *mddev_uuid_t;mddev_uuid_t62,1852 | |
84 | typedef struct mddev_dev_s mddev_dev_s65,1918 | |
85 | } *mddev_dev_t;mddev_dev_t68,1990 | |
86 | #define ALGORITHM_LEFT_ASYMMETRIC 73,2044 | |
87 | #define ALGORITHM_RIGHT_ASYMMETRIC 74,2080 | |
88 | #define ALGORITHM_LEFT_SYMMETRIC 75,2117 | |
89 | #define ALGORITHM_RIGHT_SYMMETRIC 76,2152 | |
90 | ||
91 | Assemble.c,22 | |
92 | int Assemble(34,1171 | |
93 | ||
94 | Build.c,19 | |
95 | int Build(32,1135 | |
96 | ||
97 | Create.c,20 | |
98 | int Create(32,1135 | |
99 | ||
100 | Detail.c,20 | |
101 | int Detail(34,1171 | |
102 | ||
103 | Examine.c,21 | |
104 | int Examine(34,1171 | |
105 | ||
106 | Manage.c,79 | |
107 | int Manage_ro(32,1135 | |
108 | int Manage_runstop(36,1191 | |
109 | int Manage_subdevs(40,1251 | |
110 | ||
111 | ReadMe.c,231 | |
112 | #define Name 32,1135 | |
113 | char Version[33,1156 | |
114 | char short_options[82,3241 | |
115 | struct option long_options[83,3297 | |
116 | char Usage[122,4441 | |
117 | char Help[127,4498 | |
118 | char Help_create[181,6989 | |
119 | char Help_build[203,7973 | |
120 | char Help_assemble[216,8513 | |
121 | ||
122 | config.c,102 | |
123 | char DefaultConfFile[43,1371 | |
124 | mddev_uuid_t conf_get_uuids(45,1416 | |
125 | mddev_dev_t conf_get_devs(50,1482 | |
126 | ||
127 | mdctl.c,40 | |
128 | int main(33,1153 | |
129 | #define O(O131,3313 | |
130 | ||
131 | util.c,212 | |
132 | int parse_uuid(40,1354 | |
133 | int md_get_version(80,2091 | |
134 | int get_linux_version(99,2448 | |
135 | int enough(111,2639 | |
136 | int same_uuid(127,2889 | |
137 | void uuid_from_super(137,3018 | |
138 | int compare_super(151,3295 | |
139 | int load_super(185,4258 |
0 | 0 | |
1 | 1 | - check superblock checksum in examine |
2 | 2 | - report "chunk" or "rounding" depending on raid level |
3 | - report "linear" instead of "-1" for raid level | |
4 | - decode ayout depending on raid level | |
3 | - report "linear" instead of "-1" for raid level DONE | |
4 | - decode ayout depending on raid level DONE | |
5 | 5 | - get Assemble to upgrade devices if force flag. |
6 | - --verbose and --force flags.⏎ | |
6 | - --verbose and --force flags. | |
7 | ||
8 | - set md_minor, *_disks for Create | |
9 | - for create raid5, how to choose between | |
10 | all working, but not insync | |
11 | one missing, one spare, insync |
6 | 6 | exit 2 |
7 | 7 | fi |
8 | 8 | set `grep '^char Version' ReadMe.c ` |
9 | echo version = $6 | |
10 | base=mdctl-$6.tgz | |
9 | echo version = $7 | |
10 | base=mdctl-$7.tgz | |
11 | 11 | if [ -f $target/$base ] |
12 | 12 | then |
13 | 13 | echo $target/$base exists. |
16 | 16 | trap "rm $target/$base; exit" 1 2 3 |
17 | 17 | ( cd .. ; tar czvf - mdctl ) > $target/$base |
18 | 18 | chmod a+r $target/$base |
19 | ls -l $target/$base⏎ | |
19 | ls -l $target/$base |
39 | 39 | int i; |
40 | 40 | |
41 | 41 | int chunk = 0; |
42 | int size = 0; | |
42 | 43 | int level = -10; |
43 | 44 | int layout = -1; |
44 | 45 | int raiddisks = 0; |
72 | 73 | case 'E': |
73 | 74 | /* setting mode - only once */ |
74 | 75 | if (mode) { |
75 | fprintf(stderr, "mdctl: --%s/-%c not allowed, mode already set to %s\n", | |
76 | fprintf(stderr, Name ": --%s/-%c not allowed, mode already set to %s\n", | |
76 | 77 | long_options[opt-'A'+1].name, |
77 | 78 | long_options[opt-'A'+1].val, |
78 | 79 | long_options[mode-'A'+1].name); |
106 | 107 | mddev = optarg; |
107 | 108 | else { |
108 | 109 | if (subdevs +1 >= MD_SB_DISKS) { |
109 | fprintf(stderr, "mdctl: too many devices at %s - current limit -s %d\n", | |
110 | fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n", | |
110 | 111 | optarg, MD_SB_DISKS); |
111 | 112 | exit(2); |
112 | 113 | } |
132 | 133 | case O('C','c'): |
133 | 134 | case O('B','c'): /* chunk or rounding */ |
134 | 135 | if (chunk) { |
135 | fprintf(stderr, "mdctl: chunk/rounding may only be specified once. " | |
136 | fprintf(stderr, Name ": chunk/rounding may only be specified once. " | |
136 | 137 | "Second value is %s.\n", optarg); |
137 | 138 | exit(2); |
138 | 139 | } |
139 | 140 | chunk = strtol(optarg, &c, 10); |
140 | if (!optarg[0] || *c) { | |
141 | fprintf(stderr, "mdctl: invalid chunk/rounding value: %s\n", | |
142 | optarg); | |
143 | exit(2); | |
144 | } | |
145 | continue; | |
141 | if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) { | |
142 | fprintf(stderr, Name ": invalid chunk/rounding value: %s\n", | |
143 | optarg); | |
144 | exit(2); | |
145 | } | |
146 | continue; | |
147 | ||
148 | case O('c','z'): /* size */ | |
149 | if (size) { | |
150 | fprintf(stderr, Name ": size may only be specified once. " | |
151 | "Second value is %s.\n", optarg); | |
152 | exit(2); | |
153 | } | |
154 | size = strtol(optarg, &c, 10); | |
155 | if (!optarg[0] || *c || size < 4) { | |
156 | fprintf(stderr, Name ": invalid size: %s\n", | |
157 | optarg); | |
158 | exit(2); | |
159 | } | |
160 | continue; | |
146 | 161 | |
147 | 162 | case O('C','l'): |
148 | 163 | case O('B','l'): /* set raid level*/ |
149 | 164 | if (level != -10) { |
150 | fprintf(stderr, "mdctl: raid level may only be set once. " | |
165 | fprintf(stderr, Name ": raid level may only be set once. " | |
151 | 166 | "Second value is %s.\n", optarg); |
152 | 167 | exit(2); |
153 | 168 | } |
154 | if (strcmp(optarg,"linear")==0) | |
155 | level = -1; | |
156 | else if (strlen(optarg)==1 && strchr("01245", optarg[0])) | |
157 | level = optarg[0]-'0'; | |
158 | else { | |
159 | fprintf(stderr, "mdctl: invalid raid level: %s\n", | |
169 | level = map_name(pers, optarg); | |
170 | if (level == -10) { | |
171 | fprintf(stderr, Name ": invalid raid level: %s\n", | |
160 | 172 | optarg); |
161 | 173 | exit(2); |
162 | 174 | } |
163 | 175 | if (level > 0 && mode == 'B') { |
164 | fprintf(stderr, "mdctl: Raid level %s not permitted with --build.\n", | |
165 | optarg); | |
166 | exit(2); | |
167 | } | |
168 | if (layout >=0 && level < 4) { | |
169 | fprintf(stderr, "mdctl: raid level %s is incompatible with layout setting\n", | |
176 | fprintf(stderr, Name ": Raid level %s not permitted with --build.\n", | |
170 | 177 | optarg); |
171 | 178 | exit(2); |
172 | 179 | } |
173 | 180 | if (sparedisks > 0 && level < 1) { |
174 | fprintf(stderr, "mdctl: raid level %s is incompatible with spare-disks setting.\n", | |
181 | fprintf(stderr, Name ": raid level %s is incompatible with spare-disks setting.\n", | |
175 | 182 | optarg); |
176 | 183 | exit(2); |
177 | 184 | } |
179 | 186 | |
180 | 187 | case O('C','p'): /* raid5 layout */ |
181 | 188 | if (layout >= 0) { |
182 | fprintf(stderr,"mdctl: layout may only be sent once. " | |
189 | fprintf(stderr,Name ": layout may only be sent once. " | |
183 | 190 | "Second value was %s\n", optarg); |
184 | 191 | exit(2); |
185 | 192 | } |
186 | if (level > -10 && level < 4) { | |
187 | fprintf(stderr,"mdctl: layout is incompatible with raid levels below 4.\n"); | |
188 | exit(2); | |
189 | } | |
190 | if (strcmp(optarg, "left-symmetric")==0 || strcmp(optarg,"ls")==0) | |
191 | layout = ALGORITHM_LEFT_SYMMETRIC; | |
192 | else if (strcmp(optarg, "left-asymmetric")==0 || strcmp(optarg,"la")==0) | |
193 | layout = ALGORITHM_LEFT_ASYMMETRIC; | |
194 | else if (strcmp(optarg, "right-symmetric")==0 || strcmp(optarg,"rs")==0) | |
195 | layout = ALGORITHM_RIGHT_SYMMETRIC; | |
196 | else if (strcmp(optarg, "right-asymmetric")==0 || strcmp(optarg,"ra")==0) | |
197 | layout = ALGORITHM_RIGHT_ASYMMETRIC; | |
198 | else { | |
199 | fprintf(stderr,"mdctl: %s is not a valid layout value\n", | |
200 | optarg); | |
201 | exit(2); | |
193 | switch(level) { | |
194 | default: | |
195 | fprintf(stderr, Name ": layout now meaningful for %s arrays.\n", | |
196 | map_num(pers, level)); | |
197 | exit(2); | |
198 | case -10: | |
199 | fprintf(stderr, Name ": raid level must be given before layout.\n"); | |
200 | exit(2); | |
201 | ||
202 | case 5: | |
203 | layout = map_name(r5layout, optarg); | |
204 | if (layout==-10) { | |
205 | fprintf(stderr, Name ": layout %s not understood for raid5.\n", | |
206 | optarg); | |
207 | exit(2); | |
208 | } | |
209 | break; | |
202 | 210 | } |
203 | 211 | continue; |
204 | 212 | |
205 | 213 | case O('C','n'): |
206 | 214 | case O('B','n'): /* number of raid disks */ |
207 | 215 | if (raiddisks) { |
208 | fprintf(stderr, "mdctl: raid-disks set twice: %d and %s\n", | |
216 | fprintf(stderr, Name ": raid-disks set twice: %d and %s\n", | |
209 | 217 | raiddisks, optarg); |
210 | 218 | exit(2); |
211 | 219 | } |
212 | 220 | raiddisks = strtol(optarg, &c, 10); |
213 | 221 | if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) { |
214 | fprintf(stderr, "mdctl: invalid number of raid disks: %s\n", | |
222 | fprintf(stderr, Name ": invalid number of raid disks: %s\n", | |
215 | 223 | optarg); |
216 | 224 | exit(2); |
217 | 225 | } |
219 | 227 | |
220 | 228 | case O('C','x'): /* number of spare (eXtra) discs */ |
221 | 229 | if (sparedisks) { |
222 | fprintf(stderr,"mdctl: spare-disks set twice: %d and %s\n", | |
230 | fprintf(stderr,Name ": spare-disks set twice: %d and %s\n", | |
223 | 231 | sparedisks, optarg); |
224 | 232 | exit(2); |
225 | 233 | } |
226 | 234 | if (level > -10 && level < 1) { |
227 | fprintf(stderr, "mdctl: spare-disks setting is incompatible with raid level %d\n", | |
235 | fprintf(stderr, Name ": spare-disks setting is incompatible with raid level %d\n", | |
228 | 236 | level); |
229 | 237 | exit(2); |
230 | 238 | } |
231 | 239 | sparedisks = strtol(optarg, &c, 10); |
232 | 240 | if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) { |
233 | fprintf(stderr, "mdctl: invalid number of spare disks: %s\n", | |
241 | fprintf(stderr, Name ": invalid number of spare disks: %s\n", | |
234 | 242 | optarg); |
235 | 243 | exit(2); |
236 | 244 | } |
242 | 250 | continue; |
243 | 251 | case O('A','u'): /* uuid of array */ |
244 | 252 | if (uuidset) { |
245 | fprintf(stderr, "mdctl: uuid cannot bet set twice. " | |
253 | fprintf(stderr, Name ": uuid cannot bet set twice. " | |
246 | 254 | "Second value %s.\n", optarg); |
247 | 255 | exit(2); |
248 | 256 | } |
249 | 257 | if (parse_uuid(optarg, uuid)) |
250 | 258 | uuidset = 1; |
251 | 259 | else { |
252 | fprintf(stderr,"mdctl: Bad uuid: %s\n", optarg); | |
260 | fprintf(stderr,Name ": Bad uuid: %s\n", optarg); | |
253 | 261 | exit(2); |
254 | 262 | } |
255 | 263 | continue; |
256 | 264 | |
257 | 265 | case O('A','c'): /* config file */ |
258 | 266 | if (configfile) { |
259 | fprintf(stderr, "mdctl: configfile cannot be set twice. " | |
267 | fprintf(stderr, Name ": configfile cannot be set twice. " | |
260 | 268 | "Second value is %s.\n", optarg); |
261 | 269 | exit(2); |
262 | 270 | } |
288 | 296 | case O('B','R'): |
289 | 297 | case O('C','R'): /* Run the array */ |
290 | 298 | if (runstop < 0) { |
291 | fprintf(stderr, "mdctl: Cannot both Stop and Run an array\n"); | |
299 | fprintf(stderr, Name ": Cannot both Stop and Run an array\n"); | |
292 | 300 | exit(2); |
293 | 301 | } |
294 | 302 | runstop = 1; |
295 | 303 | continue; |
296 | 304 | case O('@','S'): |
297 | 305 | if (runstop > 0) { |
298 | fprintf(stderr, "mdctl: Cannot both Run and Stop an array\n"); | |
306 | fprintf(stderr, Name ": Cannot both Run and Stop an array\n"); | |
299 | 307 | exit(2); |
300 | 308 | } |
301 | 309 | runstop = -1; |
303 | 311 | |
304 | 312 | case O('@','o'): |
305 | 313 | if (readonly < 0) { |
306 | fprintf(stderr, "mdctl: Cannot have both readonly and readwrite\n"); | |
314 | fprintf(stderr, Name ": Cannot have both readonly and readwrite\n"); | |
307 | 315 | exit(2); |
308 | 316 | } |
309 | 317 | readonly = 1; |
319 | 327 | /* We have now processed all the valid options. Anything else is |
320 | 328 | * an error |
321 | 329 | */ |
322 | fprintf(stderr, "mdctl: option %c not valid in mode %c\n", | |
330 | fprintf(stderr, Name ": option %c not valid in mode %c\n", | |
323 | 331 | opt, mode); |
324 | 332 | exit(2); |
325 | 333 | |
340 | 348 | */ |
341 | 349 | if (mode !='D' && mode !='E' && ! (mode =='A' && scan)) { |
342 | 350 | if (!mddev) { |
343 | fprintf(stderr, "mdctl: an md device must be given in this mode\n"); | |
351 | fprintf(stderr, Name ": an md device must be given in this mode\n"); | |
344 | 352 | exit(2); |
345 | 353 | } |
346 | 354 | mdfd = open(mddev, O_RDWR, 0); |
347 | 355 | if (mdfd < 0) { |
348 | fprintf(stderr,"mdctl: error opening %s: %s\n", | |
356 | fprintf(stderr,Name ": error opening %s: %s\n", | |
349 | 357 | mddev, strerror(errno)); |
350 | 358 | exit(1); |
351 | 359 | } |
352 | 360 | if (md_get_version(mdfd) <= 0) { |
353 | fprintf(stderr, "mdctl: %s does not appear to be an md device\n", | |
361 | fprintf(stderr, Name ": %s does not appear to be an md device\n", | |
354 | 362 | mddev); |
355 | 363 | close(mdfd); |
356 | 364 | exit(1); |
377 | 385 | rv = Build(mddev, mdfd, chunk, level, raiddisks, subdevs,subdev); |
378 | 386 | break; |
379 | 387 | case 'C': /* Create */ |
380 | rv = Create(mddev, mdfd, chunk, level, layout, raiddisks, sparedisks, | |
381 | subdevs,subdev,runstop); | |
388 | rv = Create(mddev, mdfd, chunk, level, layout, size, raiddisks, sparedisks, | |
389 | subdevs,subdev,runstop, verbose); | |
382 | 390 | break; |
383 | 391 | case 'D': /* Detail */ |
384 | 392 | for (i=0; i<subdevs; i++) |
48 | 48 | |
49 | 49 | #include "md_u.h" |
50 | 50 | |
51 | #define Name "mdctl" | |
52 | ||
51 | 53 | extern char short_options[]; |
52 | 54 | extern struct option long_options[]; |
53 | 55 | extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[]; |
66 | 68 | struct mddev_dev_s *next; |
67 | 69 | } *mddev_dev_t; |
68 | 70 | |
69 | /* | |
70 | * RAID5 supported algorithms | |
71 | */ | |
72 | #define ALGORITHM_LEFT_ASYMMETRIC 0 | |
73 | #define ALGORITHM_RIGHT_ASYMMETRIC 1 | |
74 | #define ALGORITHM_LEFT_SYMMETRIC 2 | |
75 | #define ALGORITHM_RIGHT_SYMMETRIC 3 | |
71 | typedef struct mapping { | |
72 | char *name; | |
73 | int num; | |
74 | } mapping_t; | |
75 | ||
76 | extern char *map_num(mapping_t *map, int num); | |
77 | extern int map_name(mapping_t *map, char *name); | |
78 | extern mapping_t r5layout[], pers[]; | |
79 | ||
76 | 80 | |
77 | 81 | |
78 | 82 | extern int Manage_ro(char *devname, int fd, int readonly); |
94 | 98 | |
95 | 99 | |
96 | 100 | extern int Create(char *mddev, int mdfd, |
97 | int chunk, int level, int layout, int raiddisks, int sparedisks, | |
101 | int chunk, int level, int layout, int size, int raiddisks, int sparedisks, | |
98 | 102 | int subdevs, char *subdev[], |
99 | int runstop); | |
103 | int runstop, int verbose); | |
100 | 104 | |
101 | 105 | extern int Detail(char *dev); |
102 | 106 | extern int Examine(char *dev); |
104 | 108 | extern int md_get_version(int fd); |
105 | 109 | extern int get_linux_version(); |
106 | 110 | extern int parse_uuid(char *str, int uuid[4]); |
111 | extern int check_ext2(int fd, char *name); | |
112 | extern int check_reiser(int fd, char *name); | |
113 | extern int check_raid(int fd, char *name); | |
107 | 114 | |
108 | 115 | extern mddev_uuid_t conf_get_uuids(char *); |
109 | 116 | extern mddev_dev_t conf_get_devs(char *); |
87 | 87 | return -1; |
88 | 88 | |
89 | 89 | if (ioctl(fd, RAID_VERSION, &vers) == 0) |
90 | return (vers.major<<16) | (vers.minor<<8) | vers.patchlevel; | |
90 | return (vers.major*10000) + (vers.minor*100) + vers.patchlevel; | |
91 | 91 | |
92 | 92 | if (MAJOR(stb.st_rdev) == MD_MAJOR) |
93 | return (36<<8); | |
93 | return (3600); | |
94 | 94 | return -1; |
95 | 95 | } |
96 | 96 | |
104 | 104 | |
105 | 105 | if (sscanf(name.release, "%d.%d.%d", &a,&b,&c)!= 3) |
106 | 106 | return -1; |
107 | return (a<<16)+(b<<8)+c; | |
107 | return (a*1000000)+(b*1000)+c; | |
108 | 108 | } |
109 | 109 | |
110 | 110 | int enough(int level, int raid_disks, int avail_disks) |
210 | 210 | if (lseek64(fd, offset, 0)< 0LL) |
211 | 211 | return 3; |
212 | 212 | |
213 | if (read(fd, &super, sizeof(super)) != sizeof(super)) | |
213 | if (read(fd, super, sizeof(*super)) != sizeof(*super)) | |
214 | 214 | return 4; |
215 | 215 | |
216 | 216 | if (super->md_magic != MD_SB_MAGIC) |
221 | 221 | return 0; |
222 | 222 | } |
223 | 223 | |
224 | ||
225 | int check_ext2(int fd, char *name) | |
226 | { | |
227 | /* | |
228 | * Check for an ext2fs file system. | |
229 | * Superblock is always 1K at 1K offset | |
230 | * | |
231 | * s_magic is le16 at 56 == 0xEF53 | |
232 | * report mtime - le32 at 44 | |
233 | * blocks - le32 at 4 | |
234 | * logblksize - le32 at 24 | |
235 | */ | |
236 | unsigned char sb[1024]; | |
237 | time_t mtime; | |
238 | int size, bsize; | |
239 | if (lseek(fd, 1024,0)!= 1024) | |
240 | return 0; | |
241 | if (read(fd, sb, 1024)!= 1024) | |
242 | return 0; | |
243 | if (sb[56] != 0x53 || sb[57] != 0xef) | |
244 | return 0; | |
245 | ||
246 | mtime = sb[44]|(sb[45]|(sb[46]|sb[47]<<8)<<8)<<8; | |
247 | bsize = sb[24]|(sb[25]|(sb[26]|sb[27]<<8)<<8)<<8; | |
248 | size = sb[4]|(sb[5]|(sb[6]|sb[7]<<8)<<8)<<8; | |
249 | fprintf(stderr, Name ": %s appears to contain an ext2fs file system\n", | |
250 | name); | |
251 | fprintf(stderr," size=%dK mtime=%s", | |
252 | size*(1<<bsize), ctime(&mtime)); | |
253 | return 1; | |
254 | } | |
255 | ||
256 | int check_reiser(int fd, char *name) | |
257 | { | |
258 | /* | |
259 | * superblock is at 64K | |
260 | * size is 1024; | |
261 | * Magic string "ReIsErFs" or "ReIsEr2Fs" at 52 | |
262 | * | |
263 | */ | |
264 | unsigned char sb[1024]; | |
265 | int size; | |
266 | if (lseek(fd, 64*1024, 0) != 64*1024) | |
267 | return 0; | |
268 | if (read(fd, sb, 1024) != 1024) | |
269 | return 0; | |
270 | if (strncmp(sb+52, "ReIsErFs",8)!=0 && | |
271 | strncmp(sb+52, "ReIsEr2Fs",9)!=0) | |
272 | return 0; | |
273 | fprintf(stderr, Name ": %s appears to contain a reiserfs file system\n",name); | |
274 | size = sb[0]|(sb[1]|(sb[2]|sb[3]<<8)<<8)<<8; | |
275 | fprintf(stderr, " size = %dK\n", size*4); | |
276 | ||
277 | return 1; | |
278 | } | |
279 | ||
280 | int check_raid(int fd, char *name) | |
281 | { | |
282 | mdp_super_t super; | |
283 | time_t crtime; | |
284 | if (load_super(fd, &super)) | |
285 | return 0; | |
286 | /* Looks like a raid array .. */ | |
287 | fprintf(stderr, Name ": %s appear to be part of a raid array:\n", | |
288 | name); | |
289 | crtime = super.ctime; | |
290 | fprintf(stderr, " level=%d disks=%d ctime=%s", | |
291 | super.level, super.raid_disks, ctime(&crtime)); | |
292 | return 1; | |
293 | } | |
294 | ||
295 | ||
296 | int ask(char *mesg) | |
297 | { | |
298 | char *add = ""; | |
299 | int i; | |
300 | for (i=0; i<5; i++) { | |
301 | char buf[100]; | |
302 | fprintf(stderr, "%s%s", mesg, add); | |
303 | fflush(stderr); | |
304 | if (fgets(buf, 100, stdin)==NULL) | |
305 | return 0; | |
306 | if (buf[0]=='y' || buf[0]=='Y') | |
307 | return 1; | |
308 | if (buf[0]=='n' || buf[0]=='N') | |
309 | return 0; | |
310 | add = "(y/n) "; | |
311 | } | |
312 | fprintf(stderr, Name ": assuming 'no'\n"); | |
313 | return 0; | |
314 | } | |
315 | ||
316 | char *map_num(mapping_t *map, int num) | |
317 | { | |
318 | while (map->name) { | |
319 | if (map->num == num) | |
320 | return map->name; | |
321 | map++; | |
322 | } | |
323 | return NULL; | |
324 | } | |
325 | ||
326 | int map_name(mapping_t *map, char *name) | |
327 | { | |
328 | while (map->name) { | |
329 | if (strcmp(map->name, name)==0) | |
330 | return map->num; | |
331 | map++; | |
332 | } | |
333 | return -10; | |
334 | } |