Create missing /dev files where needed.
[thirdparty/mdadm.git] / Manage.c
1 /*
2  * mdadm - manage Linux "md" devices aka RAID arrays.
3  *
4  * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
5  *
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2 of the License, or
10  *    (at your option) any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *    Author: Neil Brown
22  *    Email: <neilb@cse.unsw.edu.au>
23  *    Paper: Neil Brown
24  *           School of Computer Science and Engineering
25  *           The University of New South Wales
26  *           Sydney, 2052
27  *           Australia
28  */
29
30 #include "mdadm.h"
31 #include "md_u.h"
32 #include "md_p.h"
33
34 #define REGISTER_DEV            _IO (MD_MAJOR, 1)
35 #define START_MD                _IO (MD_MAJOR, 2)
36 #define STOP_MD                 _IO (MD_MAJOR, 3)
37
38 int Manage_ro(char *devname, int fd, int readonly)
39 {
40         /* switch to readonly or rw
41          *
42          * requires >= 0.90.0
43          * first check that array is runing
44          * use RESTART_ARRAY_RW or STOP_ARRAY_RO
45          *
46          */
47         mdu_array_info_t array;
48         
49         if (md_get_version(fd) < 9000) {
50                 fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
51                 return 1;
52         }
53         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
54                 fprintf(stderr, Name ": %s does not appear to be active.\n",
55                         devname);
56                 return 1;
57         }
58         
59         if (readonly>0) {
60                 if (ioctl(fd, STOP_ARRAY_RO, NULL)) {
61                         fprintf(stderr, Name ": failed to set readonly for %s: %s\n",
62                                 devname, strerror(errno));
63                         return 1;
64                 }
65         } else if (readonly < 0) {
66                 if (ioctl(fd, RESTART_ARRAY_RW, NULL)) {
67                         fprintf(stderr, Name ": failed to set writable for %s: %s\n",
68                                 devname, strerror(errno));
69                         return 1;
70                 }
71         }
72         return 0;                       
73 }
74
75 int Manage_runstop(char *devname, int fd, int runstop, int quiet)
76 {
77         /* Run or stop the array. array must already be configured
78          * required >= 0.90.0
79          */
80         mdu_param_t param; /* unused */
81
82         if (runstop == -1 && md_get_version(fd) < 9000) {
83                 if (ioctl(fd, STOP_MD, 0)) {
84                         if (!quiet) fprintf(stderr, Name ": stopping device %s failed: %s\n",
85                                             devname, strerror(errno));
86                         return 1;
87                 }
88         }
89         
90         if (md_get_version(fd) < 9000) {
91                 fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
92                 return 1;
93         }
94         /*
95         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
96                 fprintf(stderr, Name ": %s does not appear to be active.\n",
97                         devname);
98                 return 1;
99         }
100         */
101         if (runstop>0) {
102                 if (ioctl(fd, RUN_ARRAY, &param)) {
103                         fprintf(stderr, Name ": failed to run array %s: %s\n",
104                                 devname, strerror(errno));
105                         return 1;
106                 }
107         } else if (runstop < 0){
108                 if (ioctl(fd, STOP_ARRAY, NULL)) {
109                         if (!quiet)
110                                 fprintf(stderr, Name ": fail to stop array %s: %s\n",
111                                         devname, strerror(errno));
112                         return 1;
113                 }
114         }
115         return 0;
116 }
117
118 int Manage_resize(char *devname, int fd, long long size, int raid_disks)
119 {
120         mdu_array_info_t info;
121         if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) {
122                 fprintf(stderr, Name ": Cannot get array information for %s: %s\n",
123                         devname, strerror(errno));
124                 return 1;
125         }
126         if (size >= 0)
127                 info.size = size;
128         if (raid_disks > 0)
129                 info.raid_disks = raid_disks;
130         if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) {
131                 fprintf(stderr, Name ": Cannot set device size/shape for %s: %s\n",
132                         devname, strerror(errno));
133                 return 1;
134         }
135         return 0;
136 }
137
138 int Manage_reconfig(char *devname, int fd, int layout)
139 {
140         mdu_array_info_t info;
141         if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) {
142                 fprintf(stderr, Name ": Cannot get array information for %s: %s\n",
143                         devname, strerror(errno));
144                 return 1;
145         }
146         info.layout = layout;
147         printf("layout set to %d\n", info.layout);
148         if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) {
149                 fprintf(stderr, Name ": Cannot set layout for %s: %s\n",
150                         devname, strerror(errno));
151                 return 1;
152         }
153         return 0;
154 }
155
156 int Manage_subdevs(char *devname, int fd,
157                    mddev_dev_t devlist, int verbose)
158 {
159         /* do something to each dev.
160          * devmode can be
161          *  'a' - add the device
162          *         try HOT_ADD_DISK
163          *         If that fails EINVAL, try ADD_NEW_DISK
164          *  'r' - remove the device HOT_REMOVE_DISK
165          *  'f' - set the device faulty SET_DISK_FAULTY
166          */
167         mdu_array_info_t array;
168         mdu_disk_info_t disc;
169         mddev_dev_t dv;
170         struct stat stb;
171         int j;
172         int tfd;
173         struct supertype *st;
174         void *dsuper = NULL;
175         void *osuper = NULL; /* original super */
176         int duuid[4];
177         int ouuid[4];
178
179         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
180                 fprintf(stderr, Name ": cannot get array info for %s\n",
181                         devname);
182                 return 1;
183         }
184         for (dv = devlist ; dv; dv=dv->next) {
185                 if (stat(dv->devname, &stb)) {
186                         fprintf(stderr, Name ": cannot find %s: %s\n",
187                                 dv->devname, strerror(errno));
188                         return 1;
189                 }
190                 if ((stb.st_mode & S_IFMT) != S_IFBLK) {
191                         fprintf(stderr, Name ": %s is not a block device.\n",
192                                 dv->devname);
193                         return 1;
194                 }
195                 switch(dv->disposition){
196                 default:
197                         fprintf(stderr, Name ": internal error - devmode[%s]=%d\n",
198                                 dv->devname, dv->disposition);
199                         return 1;
200                 case 'a':
201                         /* add the device - hot or cold */
202                         st = super_by_version(array.major_version,
203                                               array.minor_version);
204                         if (!st) {
205                                 fprintf(stderr, Name ": unsupport array - version %d.%d\n",
206                                         array.major_version, array.minor_version);
207                                 return 1;
208                         }
209
210                         /* Make sure it isn't in use (in 2.6 or later) */
211                         tfd = open(dv->devname, O_RDONLY|O_EXCL);
212                         if (tfd < 0) {
213                                 fprintf(stderr, Name ": Cannot open %s: %s\n",
214                                         dv->devname, strerror(errno));
215                                 return 1;
216                         }
217                         if (array.not_persistent==0)
218                                 st->ss->load_super(st, tfd, &osuper, NULL);
219                         /* will use osuper later */
220                         close(tfd);
221
222                         if (array.major_version == 0 &&
223                             md_get_version(fd)%100 < 2) {
224                                 if (ioctl(fd, HOT_ADD_DISK,
225                                           (unsigned long)stb.st_rdev)==0) {
226                                         if (verbose >= 0)
227                                                 fprintf(stderr, Name ": hot added %s\n",
228                                                         dv->devname);
229                                         continue;
230                                 }
231
232                                 fprintf(stderr, Name ": hot add failed for %s: %s\n",
233                                         dv->devname, strerror(errno));
234                                 return 1;
235                         }
236
237                         if (array.not_persistent == 0) {
238
239                                 /* need to find a sample superblock to copy, and
240                                  * a spare slot to use 
241                                  */
242                                 for (j=0; j<st->max_devs; j++) {
243                                         char *dev;
244                                         int dfd;
245                                         disc.number = j;
246                                         if (ioctl(fd, GET_DISK_INFO, &disc))
247                                                 continue;
248                                         if (disc.major==0 && disc.minor==0)
249                                                 continue;
250                                         if ((disc.state & 4)==0) continue; /* sync */
251                                         /* Looks like a good device to try */
252                                         dev = map_dev(disc.major, disc.minor, 1);
253                                         if (!dev) continue;
254                                         dfd = dev_open(dev, O_RDONLY);
255                                         if (dfd < 0) continue;
256                                         if (st->ss->load_super(st, dfd, &dsuper, NULL)) {
257                                                 close(dfd);
258                                                 continue;
259                                         }
260                                         close(dfd);
261                                         break;
262                                 }
263                                 if (!dsuper) {
264                                         fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
265                                         return 1;
266                                 }
267                                 /* Possibly this device was recently part of the array
268                                  * and was temporarily removed, and is now being re-added.
269                                  * If so, we can simply re-add it.
270                                  */
271                                 st->ss->uuid_from_super(duuid, dsuper);
272                         
273                                 if (osuper) {
274                                         st->ss->uuid_from_super(ouuid, osuper);
275                                         if (memcmp(duuid, ouuid, sizeof(ouuid))==0) {
276                                                 /* look close enough for now.  Kernel
277                                                  * will worry about where a bitmap
278                                                  * based reconstruct is possible
279                                                  */
280                                                 struct mdinfo mdi;
281                                                 st->ss->getinfo_super(&mdi, osuper);
282                                                 disc.major = major(stb.st_rdev);
283                                                 disc.minor = minor(stb.st_rdev);
284                                                 disc.number = mdi.disk.number;
285                                                 disc.raid_disk = mdi.disk.raid_disk;
286                                                 disc.state = mdi.disk.state;
287                                                 if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
288                                                         if (verbose >= 0)
289                                                                 fprintf(stderr, Name ": re-added %s\n", dv->devname);
290                                                         continue;
291                                                 }
292                                                 /* fall back on normal-add */
293                                         }
294                                 }
295                         }
296                         for (j=0; j< st->max_devs; j++) {
297                                 disc.number = j;
298                                 if (ioctl(fd, GET_DISK_INFO, &disc))
299                                         break;
300                                 if (disc.major==0 && disc.minor==0)
301                                         break;
302                                 if (disc.state & 8) /* removed */
303                                         break;
304                         }
305                         disc.major = major(stb.st_rdev);
306                         disc.minor = minor(stb.st_rdev);
307                         disc.number =j;
308                         disc.state = 0;
309                         if (array.not_persistent==0) {
310                                 if (dv->writemostly)
311                                         disc.state |= 1 << MD_DISK_WRITEMOSTLY;
312                                 st->ss->add_to_super(dsuper, &disc);
313                                 if (st->ss->write_init_super(st, dsuper, &disc, dv->devname))
314                                         return 1;
315                         } else if (dv->re_add) {
316                                 /*  this had better be raid1.
317                                  * As we are "--re-add"ing we must find a spare slot
318                                  * to fill.
319                                  */
320                                 char *used = malloc(array.raid_disks);
321                                 memset(used, 0, array.raid_disks);
322                                 for (j=0; j< st->max_devs; j++) {
323                                         mdu_disk_info_t disc2;
324                                         disc2.number = j;
325                                         if (ioctl(fd, GET_DISK_INFO, &disc2))
326                                                 continue;
327                                         if (disc2.major==0 && disc2.minor==0)
328                                                 continue;
329                                         if (disc2.state & 8) /* removed */
330                                                 continue;
331                                         if (disc2.raid_disk < 0)
332                                                 continue;
333                                         if (disc2.raid_disk > array.raid_disks)
334                                                 continue;
335                                         used[disc2.raid_disk] = 1;
336                                 }
337                                 for (j=0 ; j<array.raid_disks; j++)
338                                         if (!used[j]) {
339                                                 disc.raid_disk = j;
340                                                 disc.state |= (1<<MD_DISK_SYNC);
341                                                 break;
342                                         }
343                         }
344                         if (ioctl(fd,ADD_NEW_DISK, &disc)) {
345                                 fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
346                                         dv->devname, j, strerror(errno));
347                                 return 1;
348                         }
349                         if (verbose >= 0)
350                                 fprintf(stderr, Name ": added %s\n", dv->devname);
351                         break;
352
353                 case 'r':
354                         /* hot remove */
355                         /* FIXME check that it is a current member */
356                         if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) {
357                                 fprintf(stderr, Name ": hot remove failed for %s: %s\n",
358                                         dv->devname, strerror(errno));
359                                 return 1;
360                         }
361                         if (verbose >= 0)
362                                 fprintf(stderr, Name ": hot removed %s\n", dv->devname);
363                         break;
364
365                 case 'f': /* set faulty */
366                         /* FIXME check current member */
367                         if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
368                                 fprintf(stderr, Name ": set device faulty failed for %s:  %s\n",
369                                         dv->devname, strerror(errno));
370                                 return 1;
371                         }
372                         if (verbose >= 0)
373                                 fprintf(stderr, Name ": set %s faulty in %s\n",
374                                         dv->devname, devname);
375                         break;
376                 }
377         }
378         return 0;
379         
380 }