c3137818974ed9eb4c031e5aa4a6f6d36c389cfb
[thirdparty/mdadm.git] / sysfs.c
1 /*
2  * sysfs - extract md related information from sysfs.  Part of:
3  * mdadm - manage Linux "md" devices aka RAID arrays.
4  *
5  * Copyright (C) 2006-2009 Neil Brown <neilb@suse.de>
6  *
7  *
8  *    This program is free software; you can redistribute it and/or modify
9  *    it under the terms of the GNU General Public License as published by
10  *    the Free Software Foundation; either version 2 of the License, or
11  *    (at your option) any later version.
12  *
13  *    This program is distributed in the hope that it will be useful,
14  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *    GNU General Public License for more details.
17  *
18  *    You should have received a copy of the GNU General Public License
19  *    along with this program; if not, write to the Free Software
20  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  *    Author: Neil Brown
23  *    Email: <neilb@suse.de>
24  */
25
26 #include        "mdadm.h"
27 #include        <dirent.h>
28 #include        <ctype.h>
29 #include        "dlink.h"
30
31 #define MAX_SYSFS_PATH_LEN      120
32
33 struct dev_sysfs_rule {
34         struct dev_sysfs_rule *next;
35         char *devname;
36         int uuid[4];
37         int uuid_set;
38         struct sysfs_entry {
39                 struct sysfs_entry *next;
40                 char *name;
41                 char *value;
42         } *entry;
43 };
44
45 int load_sys(char *path, char *buf, int len)
46 {
47         int fd = open(path, O_RDONLY);
48         int n;
49         if (fd < 0)
50                 return -1;
51         n = read(fd, buf, len);
52         close(fd);
53         if (n <0 || n >= len)
54                 return -1;
55         buf[n] = 0;
56         if (n && buf[n-1] == '\n')
57                 buf[n-1] = 0;
58         return 0;
59 }
60
61 void sysfs_free(struct mdinfo *sra)
62 {
63         while (sra) {
64                 struct mdinfo *sra2 = sra->next;
65                 while (sra->devs) {
66                         struct mdinfo *d = sra->devs;
67                         sra->devs = d->next;
68                         free(d->bb.entries);
69                         free(d);
70                 }
71                 free(sra->bb.entries);
72                 free(sra);
73                 sra = sra2;
74         }
75 }
76
77 int sysfs_open(char *devnm, char *devname, char *attr)
78 {
79         char fname[MAX_SYSFS_PATH_LEN];
80         int fd;
81
82         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", devnm);
83         if (devname) {
84                 strncat(fname, devname, MAX_SYSFS_PATH_LEN - strlen(fname));
85                 strncat(fname, "/", MAX_SYSFS_PATH_LEN - strlen(fname));
86         }
87         strncat(fname, attr, MAX_SYSFS_PATH_LEN - strlen(fname));
88         fd = open(fname, O_RDWR);
89         if (fd < 0 && errno == EACCES)
90                 fd = open(fname, O_RDONLY);
91         return fd;
92 }
93
94 void sysfs_init_dev(struct mdinfo *mdi, dev_t devid)
95 {
96         snprintf(mdi->sys_name,
97                  sizeof(mdi->sys_name), "dev-%s", devid2kname(devid));
98 }
99
100 int sysfs_init(struct mdinfo *mdi, int fd, char *devnm)
101 {
102         struct stat stb;
103         char fname[MAX_SYSFS_PATH_LEN];
104         int retval = -ENODEV;
105
106         mdi->sys_name[0] = 0;
107         if (fd >= 0)
108                 devnm = fd2devnm(fd);
109
110         if (devnm == NULL)
111                 goto out;
112
113         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md", devnm);
114
115         if (stat(fname, &stb))
116                 goto out;
117         if (!S_ISDIR(stb.st_mode))
118                 goto out;
119         strcpy(mdi->sys_name, devnm);
120
121         retval = 0;
122 out:
123         return retval;
124 }
125
126 struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
127 {
128         char fname[PATH_MAX];
129         char buf[PATH_MAX];
130         char *base;
131         char *dbase;
132         struct mdinfo *sra;
133         struct mdinfo *dev, **devp;
134         DIR *dir = NULL;
135         struct dirent *de;
136
137         sra = xcalloc(1, sizeof(*sra));
138         if (sysfs_init(sra, fd, devnm)) {
139                 free(sra);
140                 return NULL;
141         }
142
143         sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
144         base = fname + strlen(fname);
145
146         sra->devs = NULL;
147         if (options & GET_VERSION) {
148                 strcpy(base, "metadata_version");
149                 if (load_sys(fname, buf, sizeof(buf)))
150                         goto abort;
151                 if (strncmp(buf, "none", 4) == 0) {
152                         sra->array.major_version =
153                                 sra->array.minor_version = -1;
154                         strcpy(sra->text_version, "");
155                 } else if (strncmp(buf, "external:", 9) == 0) {
156                         sra->array.major_version = -1;
157                         sra->array.minor_version = -2;
158                         strcpy(sra->text_version, buf+9);
159                 } else {
160                         sscanf(buf, "%d.%d",
161                                &sra->array.major_version,
162                                &sra->array.minor_version);
163                         strcpy(sra->text_version, buf);
164                 }
165         }
166         if (options & GET_LEVEL) {
167                 strcpy(base, "level");
168                 if (load_sys(fname, buf, sizeof(buf)))
169                         goto abort;
170                 sra->array.level = map_name(pers, buf);
171         }
172         if (options & GET_LAYOUT) {
173                 strcpy(base, "layout");
174                 if (load_sys(fname, buf, sizeof(buf)))
175                         goto abort;
176                 sra->array.layout = strtoul(buf, NULL, 0);
177         }
178         if (options & (GET_DISKS|GET_STATE)) {
179                 strcpy(base, "raid_disks");
180                 if (load_sys(fname, buf, sizeof(buf)))
181                         goto abort;
182                 sra->array.raid_disks = strtoul(buf, NULL, 0);
183         }
184         if (options & GET_COMPONENT) {
185                 strcpy(base, "component_size");
186                 if (load_sys(fname, buf, sizeof(buf)))
187                         goto abort;
188                 sra->component_size = strtoull(buf, NULL, 0);
189                 /* sysfs reports "K", but we want sectors */
190                 sra->component_size *= 2;
191         }
192         if (options & GET_CHUNK) {
193                 strcpy(base, "chunk_size");
194                 if (load_sys(fname, buf, sizeof(buf)))
195                         goto abort;
196                 sra->array.chunk_size = strtoul(buf, NULL, 0);
197         }
198         if (options & GET_CACHE) {
199                 strcpy(base, "stripe_cache_size");
200                 if (load_sys(fname, buf, sizeof(buf)))
201                         /* Probably level doesn't support it */
202                         sra->cache_size = 0;
203                 else
204                         sra->cache_size = strtoul(buf, NULL, 0);
205         }
206         if (options & GET_MISMATCH) {
207                 strcpy(base, "mismatch_cnt");
208                 if (load_sys(fname, buf, sizeof(buf)))
209                         goto abort;
210                 sra->mismatch_cnt = strtoul(buf, NULL, 0);
211         }
212         if (options & GET_SAFEMODE) {
213                 int scale = 1;
214                 int dot = 0;
215                 unsigned i;
216                 unsigned long msec;
217                 size_t len;
218
219                 strcpy(base, "safe_mode_delay");
220                 if (load_sys(fname, buf, sizeof(buf)))
221                         goto abort;
222
223                 /* remove a period, and count digits after it */
224                 len = strlen(buf);
225                 for (i = 0; i < len; i++) {
226                         if (dot) {
227                                 if (isdigit(buf[i])) {
228                                         buf[i-1] = buf[i];
229                                         scale *= 10;
230                                 }
231                                 buf[i] = 0;
232                         } else if (buf[i] == '.') {
233                                 dot=1;
234                                 buf[i] = 0;
235                         }
236                 }
237                 msec = strtoul(buf, NULL, 10);
238                 msec = (msec * 1000) / scale;
239                 sra->safe_mode_delay = msec;
240         }
241         if (options & GET_BITMAP_LOCATION) {
242                 strcpy(base, "bitmap/location");
243                 if (load_sys(fname, buf, sizeof(buf)))
244                         goto abort;
245                 if (strncmp(buf, "file", 4) == 0)
246                         sra->bitmap_offset = 1;
247                 else if (strncmp(buf, "none", 4) == 0)
248                         sra->bitmap_offset = 0;
249                 else if (buf[0] == '+')
250                         sra->bitmap_offset = strtol(buf+1, NULL, 10);
251                 else
252                         goto abort;
253         }
254
255         if (options & GET_ARRAY_STATE) {
256                 strcpy(base, "array_state");
257                 if (load_sys(fname, buf, sizeof(buf)))
258                         goto abort;
259                 sra->array_state = map_name(sysfs_array_states, buf);
260         }
261
262         if (options & GET_CONSISTENCY_POLICY) {
263                 strcpy(base, "consistency_policy");
264                 if (load_sys(fname, buf, sizeof(buf)))
265                         sra->consistency_policy = CONSISTENCY_POLICY_UNKNOWN;
266                 else
267                         sra->consistency_policy = map_name(consistency_policies,
268                                                            buf);
269         }
270
271         if (! (options & GET_DEVS))
272                 return sra;
273
274         /* Get all the devices as well */
275         *base = 0;
276         dir = opendir(fname);
277         if (!dir)
278                 goto abort;
279         sra->array.spare_disks = 0;
280         sra->array.active_disks = 0;
281         sra->array.failed_disks = 0;
282         sra->array.working_disks = 0;
283
284         devp = &sra->devs;
285         sra->devs = NULL;
286         while ((de = readdir(dir)) != NULL) {
287                 char *ep;
288                 if (de->d_ino == 0 ||
289                     strncmp(de->d_name, "dev-", 4) != 0)
290                         continue;
291                 strcpy(base, de->d_name);
292                 dbase = base + strlen(base);
293                 *dbase++ = '/';
294
295                 dev = xcalloc(1, sizeof(*dev));
296
297                 /* Always get slot, major, minor */
298                 strcpy(dbase, "slot");
299                 if (load_sys(fname, buf, sizeof(buf))) {
300                         /* hmm... unable to read 'slot' maybe the device
301                          * is going away?
302                          */
303                         strcpy(dbase, "block");
304                         if (readlink(fname, buf, sizeof(buf)) < 0 &&
305                             errno != ENAMETOOLONG) {
306                                 /* ...yup device is gone */
307                                 free(dev);
308                                 continue;
309                         } else {
310                                 /* slot is unreadable but 'block' link
311                                  * still intact... something bad is happening
312                                  * so abort
313                                  */
314                                 free(dev);
315                                 goto abort;
316                         }
317
318                 }
319                 strcpy(dev->sys_name, de->d_name);
320                 dev->disk.raid_disk = strtoul(buf, &ep, 10);
321                 if (*ep) dev->disk.raid_disk = -1;
322
323                 sra->array.nr_disks++;
324                 strcpy(dbase, "block/dev");
325                 if (load_sys(fname, buf, sizeof(buf))) {
326                         /* assume this is a stale reference to a hot
327                          * removed device
328                          */
329                         if (!(options & GET_DEVS_ALL)) {
330                                 free(dev);
331                                 continue;
332                         }
333                 } else {
334                         sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
335                 }
336
337                 if (!(options & GET_DEVS_ALL)) {
338                         /* special case check for block devices that can go 'offline' */
339                         strcpy(dbase, "block/device/state");
340                         if (load_sys(fname, buf, sizeof(buf)) == 0 &&
341                             strncmp(buf, "offline", 7) == 0) {
342                                 free(dev);
343                                 continue;
344                         }
345                 }
346
347                 /* finally add this disk to the array */
348                 *devp = dev;
349                 devp = & dev->next;
350                 dev->next = NULL;
351
352                 if (options & GET_OFFSET) {
353                         strcpy(dbase, "offset");
354                         if (load_sys(fname, buf, sizeof(buf)))
355                                 goto abort;
356                         dev->data_offset = strtoull(buf, NULL, 0);
357                         strcpy(dbase, "new_offset");
358                         if (load_sys(fname, buf, sizeof(buf)) == 0)
359                                 dev->new_data_offset = strtoull(buf, NULL, 0);
360                         else
361                                 dev->new_data_offset = dev->data_offset;
362                 }
363                 if (options & GET_SIZE) {
364                         strcpy(dbase, "size");
365                         if (load_sys(fname, buf, sizeof(buf)))
366                                 goto abort;
367                         dev->component_size = strtoull(buf, NULL, 0) * 2;
368                 }
369                 if (options & GET_STATE) {
370                         dev->disk.state = 0;
371                         strcpy(dbase, "state");
372                         if (load_sys(fname, buf, sizeof(buf)))
373                                 goto abort;
374                         if (strstr(buf, "faulty"))
375                                 dev->disk.state |= (1<<MD_DISK_FAULTY);
376                         else {
377                                 sra->array.working_disks++;
378                                 if (strstr(buf, "in_sync")) {
379                                         dev->disk.state |= (1<<MD_DISK_SYNC);
380                                         sra->array.active_disks++;
381                                 }
382                                 if (dev->disk.state == 0)
383                                         sra->array.spare_disks++;
384                         }
385                 }
386                 if (options & GET_ERROR) {
387                         strcpy(buf, "errors");
388                         if (load_sys(fname, buf, sizeof(buf)))
389                                 goto abort;
390                         dev->errors = strtoul(buf, NULL, 0);
391                 }
392         }
393
394         if ((options & GET_STATE) && sra->array.raid_disks)
395                 sra->array.failed_disks = sra->array.raid_disks -
396                         sra->array.active_disks - sra->array.spare_disks;
397
398         closedir(dir);
399         return sra;
400
401  abort:
402         if (dir)
403                 closedir(dir);
404         sysfs_free(sra);
405         return NULL;
406 }
407
408 int sysfs_attr_match(const char *attr, const char *str)
409 {
410         /* See if attr, read from a sysfs file, matches
411          * str.  They must either be the same, or attr can
412          * have a trailing newline or comma
413          */
414         while (*attr && *str && *attr == *str) {
415                 attr++;
416                 str++;
417         }
418
419         if (*str || (*attr && *attr != ',' && *attr != '\n'))
420                 return 0;
421         return 1;
422 }
423
424 int sysfs_match_word(const char *word, char **list)
425 {
426         int n;
427         for (n=0; list[n]; n++)
428                 if (sysfs_attr_match(word, list[n]))
429                         break;
430         return n;
431 }
432
433 unsigned long long get_component_size(int fd)
434 {
435         /* Find out the component size of the array.
436          * We cannot trust GET_ARRAY_INFO ioctl as it's
437          * size field is only 32bits.
438          * So look in /sys/block/mdXXX/md/component_size
439          *
440          * This returns in units of sectors.
441          */
442         struct stat stb;
443         char fname[MAX_SYSFS_PATH_LEN];
444         int n;
445         if (fstat(fd, &stb))
446                 return 0;
447         snprintf(fname, MAX_SYSFS_PATH_LEN,
448                  "/sys/block/%s/md/component_size", stat2devnm(&stb));
449         fd = open(fname, O_RDONLY);
450         if (fd < 0)
451                 return 0;
452         n = read(fd, fname, sizeof(fname));
453         close(fd);
454         if (n < 0 || n == sizeof(fname))
455                 return 0;
456         fname[n] = 0;
457         return strtoull(fname, NULL, 10) * 2;
458 }
459
460 int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
461                   char *name, char *val)
462 {
463         char fname[MAX_SYSFS_PATH_LEN];
464         unsigned int n;
465         int fd;
466
467         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
468                 sra->sys_name, dev?dev->sys_name:"", name);
469         fd = open(fname, O_WRONLY);
470         if (fd < 0)
471                 return -1;
472         n = write(fd, val, strlen(val));
473         close(fd);
474         if (n != strlen(val)) {
475                 dprintf("failed to write '%s' to '%s' (%s)\n",
476                         val, fname, strerror(errno));
477                 return -1;
478         }
479         return 0;
480 }
481
482 int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
483                   char *name, unsigned long long val)
484 {
485         char valstr[50];
486         sprintf(valstr, "%llu", val);
487         return sysfs_set_str(sra, dev, name, valstr);
488 }
489
490 int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev,
491                          char *name, long long val)
492 {
493         char valstr[50];
494         sprintf(valstr, "%lli", val);
495         return sysfs_set_str(sra, dev, name, valstr);
496 }
497
498 int sysfs_uevent(struct mdinfo *sra, char *event)
499 {
500         char fname[MAX_SYSFS_PATH_LEN];
501         int n;
502         int fd;
503
504         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/uevent",
505                 sra->sys_name);
506         fd = open(fname, O_WRONLY);
507         if (fd < 0)
508                 return -1;
509         n = write(fd, event, strlen(event));
510         close(fd);
511         if (n != (int)strlen(event)) {
512                 dprintf("failed to write '%s' to '%s' (%s)\n",
513                         event, fname, strerror(errno));
514                 return -1;
515         }
516         return 0;
517 }
518
519 int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name)
520 {
521         char fname[MAX_SYSFS_PATH_LEN];
522         struct stat st;
523
524         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
525                 sra->sys_name, dev?dev->sys_name:"", name);
526
527         return stat(fname, &st) == 0;
528 }
529
530 int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
531                        char *name)
532 {
533         char fname[MAX_SYSFS_PATH_LEN];
534         int fd;
535
536         snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
537                 sra->sys_name, dev?dev->sys_name:"", name);
538         fd = open(fname, O_RDWR);
539         if (fd < 0)
540                 fd = open(fname, O_RDONLY);
541         return fd;
542 }
543
544 int sysfs_fd_get_ll(int fd, unsigned long long *val)
545 {
546         char buf[50];
547         int n;
548         char *ep;
549
550         lseek(fd, 0, 0);
551         n = read(fd, buf, sizeof(buf));
552         if (n <= 0 || n == sizeof(buf))
553                 return -2;
554         buf[n] = 0;
555         *val = strtoull(buf, &ep, 0);
556         if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
557                 return -1;
558         return 0;
559 }
560
561 int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
562                        char *name, unsigned long long *val)
563 {
564         int n;
565         int fd;
566
567         fd = sysfs_get_fd(sra, dev, name);
568         if (fd < 0)
569                 return -1;
570         n = sysfs_fd_get_ll(fd, val);
571         close(fd);
572         return n;
573 }
574
575 int sysfs_fd_get_two(int fd, unsigned long long *v1, unsigned long long *v2)
576 {
577         /* two numbers in this sysfs file, either
578          *  NNN (NNN)
579          * or
580          *  NNN / NNN
581          */
582         char buf[80];
583         int n;
584         char *ep, *ep2;
585
586         lseek(fd, 0, 0);
587         n = read(fd, buf, sizeof(buf));
588         if (n <= 0 || n == sizeof(buf))
589                 return -2;
590         buf[n] = 0;
591         *v1 = strtoull(buf, &ep, 0);
592         if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
593                 return -1;
594         while (*ep == ' ' || *ep == '/' || *ep == '(')
595                 ep++;
596         *v2 = strtoull(ep, &ep2, 0);
597         if (ep2 == ep || (*ep2 != 0 && *ep2 != '\n' && *ep2 != ' ' && *ep2 != ')')) {
598                 *v2 = *v1;
599                 return 1;
600         }
601         return 2;
602 }
603
604 int sysfs_get_two(struct mdinfo *sra, struct mdinfo *dev,
605                   char *name, unsigned long long *v1, unsigned long long *v2)
606 {
607         int n;
608         int fd;
609
610         fd = sysfs_get_fd(sra, dev, name);
611         if (fd < 0)
612                 return -1;
613         n = sysfs_fd_get_two(fd, v1, v2);
614         close(fd);
615         return n;
616 }
617
618 int sysfs_fd_get_str(int fd, char *val, int size)
619 {
620         int n;
621
622         lseek(fd, 0, 0);
623         n = read(fd, val, size);
624         if (n <= 0 || n == size)
625                 return -1;
626         val[n] = 0;
627         return n;
628 }
629
630 int sysfs_get_str(struct mdinfo *sra, struct mdinfo *dev,
631                        char *name, char *val, int size)
632 {
633         int n;
634         int fd;
635
636         fd = sysfs_get_fd(sra, dev, name);
637         if (fd < 0)
638                 return -1;
639         n = sysfs_fd_get_str(fd, val, size);
640         close(fd);
641         return n;
642 }
643
644 int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
645 {
646         unsigned long sec;
647         unsigned long msec;
648         char delay[30];
649
650         sec = ms / 1000;
651         msec = ms % 1000;
652
653         sprintf(delay, "%ld.%03ld\n", sec, msec);
654         /*             this '\n' ^ needed for kernels older than 2.6.28 */
655         return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
656 }
657
658 int sysfs_set_array(struct mdinfo *info, int vers)
659 {
660         int rv = 0;
661         char ver[100];
662         int raid_disks = info->array.raid_disks;
663
664         ver[0] = 0;
665         if (info->array.major_version == -1 &&
666             info->array.minor_version == -2) {
667                 char buf[1024];
668
669                 strcat(strcpy(ver, "external:"), info->text_version);
670
671                 /* meta version might already be set if we are setting
672                  * new geometry for a reshape.  In that case we don't
673                  * want to over-write the 'readonly' flag that is
674                  * stored in the metadata version.  So read the current
675                  * version first, and preserve the flag
676                  */
677                 if (sysfs_get_str(info, NULL, "metadata_version",
678                                   buf, 1024) > 0)
679                         if (strlen(buf) >= 9 && buf[9] == '-')
680                                 ver[9] = '-';
681
682                 if ((vers % 100) < 2 ||
683                     sysfs_set_str(info, NULL, "metadata_version",
684                                   ver) < 0) {
685                         pr_err("This kernel does not support external metadata.\n");
686                         return 1;
687                 }
688         }
689         if (info->array.level < 0)
690                 return 0; /* FIXME */
691         rv |= sysfs_set_str(info, NULL, "level",
692                             map_num(pers, info->array.level));
693         if (info->reshape_active && info->delta_disks != UnSet)
694                 raid_disks -= info->delta_disks;
695         rv |= sysfs_set_num(info, NULL, "raid_disks", raid_disks);
696         rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
697         rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
698         rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
699         if (info->custom_array_size) {
700                 int rc;
701
702                 rc = sysfs_set_num(info, NULL, "array_size",
703                                    info->custom_array_size/2);
704                 if (rc && errno == ENOENT) {
705                         pr_err("This kernel does not have the md/array_size attribute, the array may be larger than expected\n");
706                         rc = 0;
707                 }
708                 rv |= rc;
709         }
710
711         if (info->array.level > 0)
712                 rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
713
714         if (info->reshape_active) {
715                 rv |= sysfs_set_num(info, NULL, "reshape_position",
716                                     info->reshape_progress);
717                 rv |= sysfs_set_num(info, NULL, "chunk_size", info->new_chunk);
718                 rv |= sysfs_set_num(info, NULL, "layout", info->new_layout);
719                 rv |= sysfs_set_num(info, NULL, "raid_disks",
720                                     info->array.raid_disks);
721                 /* We don't set 'new_level' here.  That can only happen
722                  * once the reshape completes.
723                  */
724         }
725
726         if (info->consistency_policy == CONSISTENCY_POLICY_PPL) {
727                 if (sysfs_set_str(info, NULL, "consistency_policy",
728                                   map_num(consistency_policies,
729                                           info->consistency_policy))) {
730                         pr_err("This kernel does not support PPL. Falling back to consistency-policy=resync.\n");
731                         info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
732                 }
733         }
734
735         return rv;
736 }
737
738 int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
739 {
740         char dv[PATH_MAX];
741         char nm[PATH_MAX];
742         char *dname;
743         int rv;
744         int i;
745
746         sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
747         rv = sysfs_set_str(sra, NULL, "new_dev", dv);
748         if (rv)
749                 return rv;
750
751         memset(nm, 0, sizeof(nm));
752         dname = devid2kname(makedev(sd->disk.major, sd->disk.minor));
753         strcpy(sd->sys_name, "dev-");
754         strcpy(sd->sys_name+4, dname);
755
756         /* test write to see if 'recovery_start' is available */
757         if (resume && sd->recovery_start < MaxSector &&
758             sysfs_set_num(sra, sd, "recovery_start", 0)) {
759                 sysfs_set_str(sra, sd, "state", "remove");
760                 return -1;
761         }
762
763         rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
764         rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
765         if (sra->array.level != LEVEL_CONTAINER) {
766                 if (sra->consistency_policy == CONSISTENCY_POLICY_PPL) {
767                         rv |= sysfs_set_num(sra, sd, "ppl_sector", sd->ppl_sector);
768                         rv |= sysfs_set_num(sra, sd, "ppl_size", sd->ppl_size);
769                 }
770                 if (sd->recovery_start == MaxSector)
771                         /* This can correctly fail if array isn't started,
772                          * yet, so just ignore status for now.
773                          */
774                         sysfs_set_str(sra, sd, "state", "insync");
775                 if (sd->disk.raid_disk >= 0)
776                         rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
777                 if (resume)
778                         sysfs_set_num(sra, sd, "recovery_start", sd->recovery_start);
779         }
780         if (sd->bb.supported) {
781                 if (sysfs_set_str(sra, sd, "state", "external_bbl")) {
782                         /*
783                          * backward compatibility - if kernel doesn't support
784                          * bad blocks for external metadata, let it continue
785                          * as long as there are none known so far
786                          */
787                         if (sd->bb.count) {
788                                 pr_err("The kernel has no support for bad blocks in external metadata\n");
789                                 return -1;
790                         }
791                 }
792
793                 for (i = 0; i < sd->bb.count; i++) {
794                         char s[30];
795                         const struct md_bb_entry *entry = &sd->bb.entries[i];
796
797                         snprintf(s, sizeof(s) - 1, "%llu %d\n", entry->sector,
798                                  entry->length);
799                         rv |= sysfs_set_str(sra, sd, "bad_blocks", s);
800                 }
801         }
802         return rv;
803 }
804
805 #if 0
806 int sysfs_disk_to_sg(int fd)
807 {
808         /* from an open block device, try find and open its corresponding
809          * scsi_generic interface
810          */
811         struct stat st;
812         char path[256];
813         char sg_path[256];
814         char sg_major_minor[10];
815         char *c;
816         DIR *dir;
817         struct dirent *de;
818         int major, minor, rv;
819
820         if (fstat(fd, &st))
821                 return -1;
822
823         snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
824                  major(st.st_rdev), minor(st.st_rdev));
825
826         dir = opendir(path);
827         if (!dir)
828                 return -1;
829
830         de = readdir(dir);
831         while (de) {
832                 if (strncmp("scsi_generic:", de->d_name,
833                             strlen("scsi_generic:")) == 0)
834                         break;
835                 de = readdir(dir);
836         }
837         closedir(dir);
838
839         if (!de)
840                 return -1;
841
842         snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name);
843         fd = open(sg_path, O_RDONLY);
844         if (fd < 0)
845                 return fd;
846
847         rv = read(fd, sg_major_minor, sizeof(sg_major_minor));
848         close(fd);
849         if (rv < 0 || rv == sizeof(sg_major_minor))
850                 return -1;
851         else
852                 sg_major_minor[rv - 1] = '\0';
853
854         c = strchr(sg_major_minor, ':');
855         *c = '\0';
856         c++;
857         major = strtol(sg_major_minor, NULL, 10);
858         minor = strtol(c, NULL, 10);
859         snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d",
860                  (int) getpid(), major, minor);
861         if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) {
862                         fd = open(path, O_RDONLY);
863                         unlink(path);
864                         return fd;
865         }
866
867         return -1;
868 }
869 #endif
870
871 int sysfs_disk_to_scsi_id(int fd, __u32 *id)
872 {
873         /* from an open block device, try to retrieve it scsi_id */
874         struct stat st;
875         char path[256];
876         DIR *dir;
877         struct dirent *de;
878         int host, bus, target, lun;
879
880         if (fstat(fd, &st))
881                 return 1;
882
883         snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device/scsi_device",
884                  major(st.st_rdev), minor(st.st_rdev));
885
886         dir = opendir(path);
887         if (!dir)
888                 return 1;
889
890         for (de = readdir(dir); de; de = readdir(dir)) {
891                 int count;
892
893                 if (de->d_type != DT_DIR)
894                         continue;
895
896                 count = sscanf(de->d_name, "%d:%d:%d:%d", &host, &bus, &target, &lun);
897                 if (count == 4)
898                         break;
899         }
900         closedir(dir);
901
902         if (!de)
903                 return 1;
904
905         *id = (host << 24) | (bus << 16) | (target << 8) | (lun << 0);
906         return 0;
907 }
908
909 int sysfs_unique_holder(char *devnm, long rdev)
910 {
911         /* Check that devnm is a holder of rdev,
912          * and is the only holder.
913          * we should be locked against races by
914          * an O_EXCL on devnm
915          * Return values:
916          *  0 - not unique, not even a holder
917          *  1 - unique, this is the only holder.
918          *  2/3 - not unique, there is another holder
919          * -1 - error, cannot find the holders
920          */
921         DIR *dir;
922         struct dirent *de;
923         char dirname[100];
924         char l;
925         int ret = 0;
926         sprintf(dirname, "/sys/dev/block/%d:%d/holders",
927                 major(rdev), minor(rdev));
928         dir = opendir(dirname);
929         if (!dir)
930                 return -1;
931         l = strlen(dirname);
932         while ((de = readdir(dir)) != NULL) {
933                 char buf[100];
934                 char *sl;
935                 int n;
936
937                 if (de->d_ino == 0)
938                         continue;
939                 if (de->d_name[0] == '.')
940                         continue;
941                 strcpy(dirname+l, "/");
942                 strcat(dirname+l, de->d_name);
943                 n = readlink(dirname, buf, sizeof(buf)-1);
944                 if (n <= 0)
945                         continue;
946                 buf[n] = 0;
947                 sl = strrchr(buf, '/');
948                 if (!sl)
949                         continue;
950                 sl++;
951
952                 if (strcmp(devnm, sl) == 0)
953                         ret |= 1;
954                 else
955                         ret |= 2;
956         }
957         closedir(dir);
958         return ret;
959 }
960
961 int sysfs_freeze_array(struct mdinfo *sra)
962 {
963         /* Try to freeze resync/rebuild on this array/container.
964          * Return -1 if the array is busy,
965          * return 0 if this kernel doesn't support 'frozen'
966          * return 1 if it worked.
967          */
968         char buf[20];
969
970         if (!sysfs_attribute_available(sra, NULL, "sync_action"))
971                 return 1; /* no sync_action == frozen */
972         if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0)
973                 return 0;
974         if (strcmp(buf, "frozen\n") == 0)
975                 /* Already frozen */
976                 return 0;
977         if (strcmp(buf, "idle\n") != 0 && strcmp(buf, "recover\n") != 0)
978                 return -1;
979         if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
980                 return 0;
981         return 1;
982 }
983
984 int sysfs_wait(int fd, int *msec)
985 {
986         /* Wait up to '*msec' for fd to have an exception condition.
987          * if msec == NULL, wait indefinitely.
988          */
989         fd_set fds;
990         int n;
991         FD_ZERO(&fds);
992         FD_SET(fd, &fds);
993         if (msec == NULL)
994                 n = select(fd+1, NULL, NULL, &fds, NULL);
995         else if (*msec < 0)
996                 n = 0;
997         else {
998                 struct timeval start, end, tv;
999                 gettimeofday(&start, NULL);
1000                 if (*msec < 1000) {
1001                         tv.tv_sec = 0;
1002                         tv.tv_usec = (*msec)*1000;
1003                 } else {
1004                         tv.tv_sec = (*msec)/1000;
1005                         tv.tv_usec = 0;
1006                 }
1007                 n = select(fd+1, NULL, NULL, &fds, &tv);
1008                 gettimeofday(&end, NULL);
1009                 end.tv_sec -= start.tv_sec;
1010                 *msec -= (end.tv_sec * 1000 + end.tv_usec/1000
1011                           - start.tv_usec/1000) + 1;
1012         }
1013         return n;
1014 }
1015
1016 int sysfs_rules_apply_check(const struct mdinfo *sra,
1017                             const struct sysfs_entry *ent)
1018 {
1019         /* Check whether parameter is regular file,
1020          * exists and is under specified directory.
1021          */
1022         char fname[MAX_SYSFS_PATH_LEN];
1023         char dname[MAX_SYSFS_PATH_LEN];
1024         char resolved_path[PATH_MAX];
1025         char resolved_dir[PATH_MAX];
1026
1027         if (sra == NULL || ent == NULL)
1028                 return -1;
1029
1030         snprintf(dname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", sra->sys_name);
1031         snprintf(fname, MAX_SYSFS_PATH_LEN, "%s/%s", dname, ent->name);
1032
1033         if (realpath(fname, resolved_path) == NULL ||
1034             realpath(dname, resolved_dir) == NULL)
1035                 return -1;
1036
1037         if (strncmp(resolved_dir, resolved_path,
1038                     strnlen(resolved_dir, PATH_MAX)) != 0)
1039                 return -1;
1040
1041         return 0;
1042 }
1043
1044 static struct dev_sysfs_rule *sysfs_rules;
1045
1046 void sysfs_rules_apply(char *devnm, struct mdinfo *dev)
1047 {
1048         struct dev_sysfs_rule *rules = sysfs_rules;
1049
1050         while (rules) {
1051                 struct sysfs_entry *ent = rules->entry;
1052                 int match  = 0;
1053
1054                 if (!rules->uuid_set) {
1055                         if (rules->devname)
1056                                 match = strcmp(devnm, rules->devname) == 0;
1057                 } else {
1058                         match = memcmp(dev->uuid, rules->uuid,
1059                                        sizeof(int[4])) == 0;
1060                 }
1061
1062                 while (match && ent) {
1063                         if (sysfs_rules_apply_check(dev, ent) < 0)
1064                                 pr_err("SYSFS: failed to write '%s' to '%s'\n",
1065                                         ent->value, ent->name);
1066                         else
1067                                 sysfs_set_str(dev, NULL, ent->name, ent->value);
1068                         ent = ent->next;
1069                 }
1070                 rules = rules->next;
1071         }
1072 }
1073
1074 static void sysfs_rule_free(struct dev_sysfs_rule *rule)
1075 {
1076         struct sysfs_entry *entry;
1077
1078         while (rule) {
1079                 struct dev_sysfs_rule *tmp = rule->next;
1080
1081                 entry = rule->entry;
1082                 while (entry) {
1083                         struct sysfs_entry *tmp = entry->next;
1084
1085                         free(entry->name);
1086                         free(entry->value);
1087                         free(entry);
1088                         entry = tmp;
1089                 }
1090
1091                 if (rule->devname)
1092                         free(rule->devname);
1093                 free(rule);
1094                 rule = tmp;
1095         }
1096 }
1097
1098 void sysfsline(char *line)
1099 {
1100         struct dev_sysfs_rule *sr;
1101         char *w;
1102
1103         sr = xcalloc(1, sizeof(*sr));
1104         for (w = dl_next(line); w != line ; w = dl_next(w)) {
1105                 if (strncasecmp(w, "name=", 5) == 0) {
1106                         char *devname = w + 5;
1107
1108                         if (strncmp(devname, "/dev/md/", 8) == 0) {
1109                                 if (sr->devname)
1110                                         pr_err("Only give one device per SYSFS line: %s\n",
1111                                                 devname);
1112                                 else
1113                                         sr->devname = xstrdup(devname);
1114                         } else {
1115                                 pr_err("%s is an invalid name for an md device - ignored.\n",
1116                                        devname);
1117                         }
1118                 } else if (strncasecmp(w, "uuid=", 5) == 0) {
1119                         char *uuid = w + 5;
1120
1121                         if (sr->uuid_set) {
1122                                 pr_err("Only give one uuid per SYSFS line: %s\n",
1123                                         uuid);
1124                         } else {
1125                                 if (parse_uuid(w + 5, sr->uuid) &&
1126                                     memcmp(sr->uuid, uuid_zero,
1127                                            sizeof(int[4])) != 0)
1128                                         sr->uuid_set = 1;
1129                                 else
1130                                         pr_err("Invalid uuid: %s\n", uuid);
1131                         }
1132                 } else {
1133                         struct sysfs_entry *prop;
1134
1135                         char *sep = strchr(w, '=');
1136
1137                         if (sep == NULL || *(sep + 1) == 0) {
1138                                 pr_err("Cannot parse \"%s\" - ignoring.\n", w);
1139                                 continue;
1140                         }
1141
1142                         prop = xmalloc(sizeof(*prop));
1143                         prop->value = xstrdup(sep + 1);
1144                         *sep = 0;
1145                         prop->name = xstrdup(w);
1146                         prop->next = sr->entry;
1147                         sr->entry = prop;
1148                 }
1149         }
1150
1151         if (!sr->devname && !sr->uuid_set) {
1152                 pr_err("Device name not found in sysfs config entry - ignoring.\n");
1153                 sysfs_rule_free(sr);
1154                 return;
1155         }
1156
1157         sr->next = sysfs_rules;
1158         sysfs_rules = sr;
1159 }