PageRenderTime 75ms CodeModel.GetById 22ms RepoModel.GetById 2ms app.codeStats 0ms

/sysfs.c

https://github.com/jaalto/ext-mdadm
C | 893 lines | 718 code | 95 blank | 80 comment | 192 complexity | beeff36a405c7f525d29f711ac7e25e1 MD5 | raw file
Possible License(s): GPL-2.0
  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. #include "mdadm.h"
  26. #include <dirent.h>
  27. #include <ctype.h>
  28. int load_sys(char *path, char *buf)
  29. {
  30. int fd = open(path, O_RDONLY);
  31. int n;
  32. if (fd < 0)
  33. return -1;
  34. n = read(fd, buf, 1024);
  35. close(fd);
  36. if (n <0 || n >= 1024)
  37. return -1;
  38. buf[n] = 0;
  39. if (n && buf[n-1] == '\n')
  40. buf[n-1] = 0;
  41. return 0;
  42. }
  43. void sysfs_free(struct mdinfo *sra)
  44. {
  45. while (sra) {
  46. struct mdinfo *sra2 = sra->next;
  47. while (sra->devs) {
  48. struct mdinfo *d = sra->devs;
  49. sra->devs = d->next;
  50. free(d);
  51. }
  52. free(sra);
  53. sra = sra2;
  54. }
  55. }
  56. int sysfs_open(int devnum, char *devname, char *attr)
  57. {
  58. char fname[50];
  59. int fd;
  60. char *mdname = devnum2devname(devnum);
  61. if (!mdname)
  62. return -1;
  63. sprintf(fname, "/sys/block/%s/md/", mdname);
  64. if (devname) {
  65. strcat(fname, devname);
  66. strcat(fname, "/");
  67. }
  68. strcat(fname, attr);
  69. fd = open(fname, O_RDWR);
  70. if (fd < 0 && errno == EACCES)
  71. fd = open(fname, O_RDONLY);
  72. free(mdname);
  73. return fd;
  74. }
  75. void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
  76. {
  77. mdi->sys_name[0] = 0;
  78. if (fd >= 0) {
  79. mdu_version_t vers;
  80. if (ioctl(fd, RAID_VERSION, &vers) != 0)
  81. return;
  82. devnum = fd2devnum(fd);
  83. }
  84. if (devnum == NoMdDev)
  85. return;
  86. if (devnum >= 0)
  87. sprintf(mdi->sys_name, "md%d", devnum);
  88. else
  89. sprintf(mdi->sys_name, "md_d%d",
  90. -1-devnum);
  91. }
  92. struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
  93. {
  94. char fname[PATH_MAX];
  95. char buf[PATH_MAX];
  96. char *base;
  97. char *dbase;
  98. struct mdinfo *sra;
  99. struct mdinfo *dev;
  100. DIR *dir = NULL;
  101. struct dirent *de;
  102. sra = malloc(sizeof(*sra));
  103. if (sra == NULL)
  104. return sra;
  105. memset(sra, 0, sizeof(*sra));
  106. sysfs_init(sra, fd, devnum);
  107. if (sra->sys_name[0] == 0) {
  108. free(sra);
  109. return NULL;
  110. }
  111. sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
  112. base = fname + strlen(fname);
  113. sra->devs = NULL;
  114. if (options & GET_VERSION) {
  115. strcpy(base, "metadata_version");
  116. if (load_sys(fname, buf))
  117. goto abort;
  118. if (strncmp(buf, "none", 4) == 0) {
  119. sra->array.major_version =
  120. sra->array.minor_version = -1;
  121. strcpy(sra->text_version, "");
  122. } else if (strncmp(buf, "external:", 9) == 0) {
  123. sra->array.major_version = -1;
  124. sra->array.minor_version = -2;
  125. strcpy(sra->text_version, buf+9);
  126. } else {
  127. sscanf(buf, "%d.%d",
  128. &sra->array.major_version,
  129. &sra->array.minor_version);
  130. strcpy(sra->text_version, buf);
  131. }
  132. }
  133. if (options & GET_LEVEL) {
  134. strcpy(base, "level");
  135. if (load_sys(fname, buf))
  136. goto abort;
  137. sra->array.level = map_name(pers, buf);
  138. }
  139. if (options & GET_LAYOUT) {
  140. strcpy(base, "layout");
  141. if (load_sys(fname, buf))
  142. goto abort;
  143. sra->array.layout = strtoul(buf, NULL, 0);
  144. }
  145. if (options & GET_DISKS) {
  146. strcpy(base, "raid_disks");
  147. if (load_sys(fname, buf))
  148. goto abort;
  149. sra->array.raid_disks = strtoul(buf, NULL, 0);
  150. }
  151. if (options & GET_DEGRADED) {
  152. strcpy(base, "degraded");
  153. if (load_sys(fname, buf))
  154. goto abort;
  155. sra->array.failed_disks = strtoul(buf, NULL, 0);
  156. }
  157. if (options & GET_COMPONENT) {
  158. strcpy(base, "component_size");
  159. if (load_sys(fname, buf))
  160. goto abort;
  161. sra->component_size = strtoull(buf, NULL, 0);
  162. /* sysfs reports "K", but we want sectors */
  163. sra->component_size *= 2;
  164. }
  165. if (options & GET_CHUNK) {
  166. strcpy(base, "chunk_size");
  167. if (load_sys(fname, buf))
  168. goto abort;
  169. sra->array.chunk_size = strtoul(buf, NULL, 0);
  170. }
  171. if (options & GET_CACHE) {
  172. strcpy(base, "stripe_cache_size");
  173. if (load_sys(fname, buf))
  174. goto abort;
  175. sra->cache_size = strtoul(buf, NULL, 0);
  176. }
  177. if (options & GET_MISMATCH) {
  178. strcpy(base, "mismatch_cnt");
  179. if (load_sys(fname, buf))
  180. goto abort;
  181. sra->mismatch_cnt = strtoul(buf, NULL, 0);
  182. }
  183. if (options & GET_SAFEMODE) {
  184. int scale = 1;
  185. int dot = 0;
  186. unsigned i;
  187. unsigned long msec;
  188. size_t len;
  189. strcpy(base, "safe_mode_delay");
  190. if (load_sys(fname, buf))
  191. goto abort;
  192. /* remove a period, and count digits after it */
  193. len = strlen(buf);
  194. for (i = 0; i < len; i++) {
  195. if (dot) {
  196. if (isdigit(buf[i])) {
  197. buf[i-1] = buf[i];
  198. scale *= 10;
  199. }
  200. buf[i] = 0;
  201. } else if (buf[i] == '.') {
  202. dot=1;
  203. buf[i] = 0;
  204. }
  205. }
  206. msec = strtoul(buf, NULL, 10);
  207. msec = (msec * 1000) / scale;
  208. sra->safe_mode_delay = msec;
  209. }
  210. if (! (options & GET_DEVS))
  211. return sra;
  212. /* Get all the devices as well */
  213. *base = 0;
  214. dir = opendir(fname);
  215. if (!dir)
  216. goto abort;
  217. sra->array.spare_disks = 0;
  218. while ((de = readdir(dir)) != NULL) {
  219. char *ep;
  220. if (de->d_ino == 0 ||
  221. strncmp(de->d_name, "dev-", 4) != 0)
  222. continue;
  223. strcpy(base, de->d_name);
  224. dbase = base + strlen(base);
  225. *dbase++ = '/';
  226. dev = malloc(sizeof(*dev));
  227. if (!dev)
  228. goto abort;
  229. /* Always get slot, major, minor */
  230. strcpy(dbase, "slot");
  231. if (load_sys(fname, buf)) {
  232. /* hmm... unable to read 'slot' maybe the device
  233. * is going away?
  234. */
  235. strcpy(dbase, "block");
  236. if (readlink(fname, buf, sizeof(buf)) < 0 &&
  237. errno != ENAMETOOLONG) {
  238. /* ...yup device is gone */
  239. free(dev);
  240. continue;
  241. } else {
  242. /* slot is unreadable but 'block' link
  243. * still intact... something bad is happening
  244. * so abort
  245. */
  246. free(dev);
  247. goto abort;
  248. }
  249. }
  250. strcpy(dev->sys_name, de->d_name);
  251. dev->disk.raid_disk = strtoul(buf, &ep, 10);
  252. if (*ep) dev->disk.raid_disk = -1;
  253. strcpy(dbase, "block/dev");
  254. if (load_sys(fname, buf)) {
  255. /* assume this is a stale reference to a hot
  256. * removed device
  257. */
  258. free(dev);
  259. continue;
  260. }
  261. sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
  262. /* special case check for block devices that can go 'offline' */
  263. strcpy(dbase, "block/device/state");
  264. if (load_sys(fname, buf) == 0 &&
  265. strncmp(buf, "offline", 7) == 0) {
  266. free(dev);
  267. continue;
  268. }
  269. /* finally add this disk to the array */
  270. dev->next = sra->devs;
  271. sra->devs = dev;
  272. if (options & GET_OFFSET) {
  273. strcpy(dbase, "offset");
  274. if (load_sys(fname, buf))
  275. goto abort;
  276. dev->data_offset = strtoull(buf, NULL, 0);
  277. }
  278. if (options & GET_SIZE) {
  279. strcpy(dbase, "size");
  280. if (load_sys(fname, buf))
  281. goto abort;
  282. dev->component_size = strtoull(buf, NULL, 0) * 2;
  283. }
  284. if (options & GET_STATE) {
  285. dev->disk.state = 0;
  286. strcpy(dbase, "state");
  287. if (load_sys(fname, buf))
  288. goto abort;
  289. if (strstr(buf, "in_sync"))
  290. dev->disk.state |= (1<<MD_DISK_SYNC);
  291. if (strstr(buf, "faulty"))
  292. dev->disk.state |= (1<<MD_DISK_FAULTY);
  293. if (dev->disk.state == 0)
  294. sra->array.spare_disks++;
  295. }
  296. if (options & GET_ERROR) {
  297. strcpy(buf, "errors");
  298. if (load_sys(fname, buf))
  299. goto abort;
  300. dev->errors = strtoul(buf, NULL, 0);
  301. }
  302. }
  303. closedir(dir);
  304. return sra;
  305. abort:
  306. if (dir)
  307. closedir(dir);
  308. sysfs_free(sra);
  309. return NULL;
  310. }
  311. int sysfs_attr_match(const char *attr, const char *str)
  312. {
  313. /* See if attr, read from a sysfs file, matches
  314. * str. They must either be the same, or attr can
  315. * have a trailing newline or comma
  316. */
  317. while (*attr && *str && *attr == *str) {
  318. attr++;
  319. str++;
  320. }
  321. if (*str || (*attr && *attr != ',' && *attr != '\n'))
  322. return 0;
  323. return 1;
  324. }
  325. int sysfs_match_word(const char *word, char **list)
  326. {
  327. int n;
  328. for (n=0; list[n]; n++)
  329. if (sysfs_attr_match(word, list[n]))
  330. break;
  331. return n;
  332. }
  333. unsigned long long get_component_size(int fd)
  334. {
  335. /* Find out the component size of the array.
  336. * We cannot trust GET_ARRAY_INFO ioctl as it's
  337. * size field is only 32bits.
  338. * So look in /sys/block/mdXXX/md/component_size
  339. *
  340. * This returns in units of sectors.
  341. */
  342. struct stat stb;
  343. char fname[50];
  344. int n;
  345. if (fstat(fd, &stb)) return 0;
  346. if (major(stb.st_rdev) != (unsigned)get_mdp_major())
  347. sprintf(fname, "/sys/block/md%d/md/component_size",
  348. (int)minor(stb.st_rdev));
  349. else
  350. sprintf(fname, "/sys/block/md_d%d/md/component_size",
  351. (int)minor(stb.st_rdev)>>MdpMinorShift);
  352. fd = open(fname, O_RDONLY);
  353. if (fd < 0)
  354. return 0;
  355. n = read(fd, fname, sizeof(fname));
  356. close(fd);
  357. if (n == sizeof(fname))
  358. return 0;
  359. fname[n] = 0;
  360. return strtoull(fname, NULL, 10) * 2;
  361. }
  362. int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
  363. char *name, char *val)
  364. {
  365. char fname[50];
  366. unsigned int n;
  367. int fd;
  368. sprintf(fname, "/sys/block/%s/md/%s/%s",
  369. sra->sys_name, dev?dev->sys_name:"", name);
  370. fd = open(fname, O_WRONLY);
  371. if (fd < 0)
  372. return -1;
  373. n = write(fd, val, strlen(val));
  374. close(fd);
  375. if (n != strlen(val)) {
  376. dprintf(Name ": failed to write '%s' to '%s' (%s)\n",
  377. val, fname, strerror(errno));
  378. return -1;
  379. }
  380. return 0;
  381. }
  382. int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
  383. char *name, unsigned long long val)
  384. {
  385. char valstr[50];
  386. sprintf(valstr, "%llu", val);
  387. return sysfs_set_str(sra, dev, name, valstr);
  388. }
  389. int sysfs_uevent(struct mdinfo *sra, char *event)
  390. {
  391. char fname[50];
  392. int n;
  393. int fd;
  394. sprintf(fname, "/sys/block/%s/uevent",
  395. sra->sys_name);
  396. fd = open(fname, O_WRONLY);
  397. if (fd < 0)
  398. return -1;
  399. n = write(fd, event, strlen(event));
  400. close(fd);
  401. return 0;
  402. }
  403. int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
  404. char *name)
  405. {
  406. char fname[50];
  407. int fd;
  408. sprintf(fname, "/sys/block/%s/md/%s/%s",
  409. sra->sys_name, dev?dev->sys_name:"", name);
  410. fd = open(fname, O_RDWR);
  411. if (fd < 0)
  412. fd = open(fname, O_RDONLY);
  413. return fd;
  414. }
  415. int sysfs_fd_get_ll(int fd, unsigned long long *val)
  416. {
  417. char buf[50];
  418. int n;
  419. char *ep;
  420. lseek(fd, 0, 0);
  421. n = read(fd, buf, sizeof(buf));
  422. if (n <= 0)
  423. return -1;
  424. buf[n] = 0;
  425. *val = strtoull(buf, &ep, 0);
  426. if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
  427. return -1;
  428. return 0;
  429. }
  430. int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
  431. char *name, unsigned long long *val)
  432. {
  433. int n;
  434. int fd;
  435. fd = sysfs_get_fd(sra, dev, name);
  436. if (fd < 0)
  437. return -1;
  438. n = sysfs_fd_get_ll(fd, val);
  439. close(fd);
  440. return n;
  441. }
  442. int sysfs_fd_get_str(int fd, char *val, int size)
  443. {
  444. int n;
  445. lseek(fd, 0, 0);
  446. n = read(fd, val, size);
  447. if (n <= 0)
  448. return -1;
  449. val[n] = 0;
  450. return n;
  451. }
  452. int sysfs_get_str(struct mdinfo *sra, struct mdinfo *dev,
  453. char *name, char *val, int size)
  454. {
  455. int n;
  456. int fd;
  457. fd = sysfs_get_fd(sra, dev, name);
  458. if (fd < 0)
  459. return -1;
  460. n = sysfs_fd_get_str(fd, val, size);
  461. close(fd);
  462. return n;
  463. }
  464. int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
  465. {
  466. unsigned long sec;
  467. unsigned long msec;
  468. char delay[30];
  469. sec = ms / 1000;
  470. msec = ms % 1000;
  471. sprintf(delay, "%ld.%03ld\n", sec, msec);
  472. /* this '\n' ^ needed for kernels older than 2.6.28 */
  473. return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
  474. }
  475. int sysfs_set_array(struct mdinfo *info, int vers)
  476. {
  477. int rv = 0;
  478. char ver[100];
  479. ver[0] = 0;
  480. if (info->array.major_version == -1 &&
  481. info->array.minor_version == -2) {
  482. strcat(strcpy(ver, "external:"), info->text_version);
  483. if ((vers % 100) < 2 ||
  484. sysfs_set_str(info, NULL, "metadata_version",
  485. ver) < 0) {
  486. fprintf(stderr, Name ": This kernel does not "
  487. "support external metadata.\n");
  488. return 1;
  489. }
  490. }
  491. if (info->array.level < 0)
  492. return 0; /* FIXME */
  493. rv |= sysfs_set_str(info, NULL, "level",
  494. map_num(pers, info->array.level));
  495. rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
  496. rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
  497. rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
  498. rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
  499. if (info->custom_array_size) {
  500. int rc;
  501. rc = sysfs_set_num(info, NULL, "array_size",
  502. info->custom_array_size/2);
  503. if (rc && errno == ENOENT) {
  504. fprintf(stderr, Name ": This kernel does not "
  505. "have the md/array_size attribute, "
  506. "the array may be larger than expected\n");
  507. rc = 0;
  508. }
  509. rv |= rc;
  510. }
  511. if (info->array.level > 0)
  512. rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
  513. return rv;
  514. }
  515. int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
  516. {
  517. char dv[PATH_MAX];
  518. char nm[PATH_MAX];
  519. char *dname;
  520. int rv;
  521. sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
  522. rv = sysfs_set_str(sra, NULL, "new_dev", dv);
  523. if (rv)
  524. return rv;
  525. memset(nm, 0, sizeof(nm));
  526. sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor);
  527. rv = readlink(dv, nm, sizeof(nm));
  528. if (rv <= 0)
  529. return -1;
  530. nm[rv] = '\0';
  531. dname = strrchr(nm, '/');
  532. if (dname) dname++;
  533. strcpy(sd->sys_name, "dev-");
  534. strcpy(sd->sys_name+4, dname);
  535. /* test write to see if 'recovery_start' is available */
  536. if (resume && sd->recovery_start < MaxSector &&
  537. sysfs_set_num(sra, sd, "recovery_start", 0)) {
  538. sysfs_set_str(sra, sd, "state", "remove");
  539. return -1;
  540. }
  541. rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
  542. rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
  543. if (sra->array.level != LEVEL_CONTAINER) {
  544. if (sd->recovery_start == MaxSector)
  545. /* This can correctly fail if array isn't started,
  546. * yet, so just ignore status for now.
  547. */
  548. sysfs_set_str(sra, sd, "state", "insync");
  549. rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
  550. if (resume)
  551. sysfs_set_num(sra, sd, "recovery_start", sd->recovery_start);
  552. }
  553. return rv;
  554. }
  555. #if 0
  556. int sysfs_disk_to_sg(int fd)
  557. {
  558. /* from an open block device, try find and open its corresponding
  559. * scsi_generic interface
  560. */
  561. struct stat st;
  562. char path[256];
  563. char sg_path[256];
  564. char sg_major_minor[8];
  565. char *c;
  566. DIR *dir;
  567. struct dirent *de;
  568. int major, minor, rv;
  569. if (fstat(fd, &st))
  570. return -1;
  571. snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
  572. major(st.st_rdev), minor(st.st_rdev));
  573. dir = opendir(path);
  574. if (!dir)
  575. return -1;
  576. de = readdir(dir);
  577. while (de) {
  578. if (strncmp("scsi_generic:", de->d_name,
  579. strlen("scsi_generic:")) == 0)
  580. break;
  581. de = readdir(dir);
  582. }
  583. closedir(dir);
  584. if (!de)
  585. return -1;
  586. snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name);
  587. fd = open(sg_path, O_RDONLY);
  588. if (fd < 0)
  589. return fd;
  590. rv = read(fd, sg_major_minor, sizeof(sg_major_minor));
  591. close(fd);
  592. if (rv < 0)
  593. return -1;
  594. else
  595. sg_major_minor[rv - 1] = '\0';
  596. c = strchr(sg_major_minor, ':');
  597. *c = '\0';
  598. c++;
  599. major = strtol(sg_major_minor, NULL, 10);
  600. minor = strtol(c, NULL, 10);
  601. snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d",
  602. (int) getpid(), major, minor);
  603. if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) {
  604. fd = open(path, O_RDONLY);
  605. unlink(path);
  606. return fd;
  607. }
  608. return -1;
  609. }
  610. #endif
  611. int sysfs_disk_to_scsi_id(int fd, __u32 *id)
  612. {
  613. /* from an open block device, try to retrieve it scsi_id */
  614. struct stat st;
  615. char path[256];
  616. char *c1, *c2;
  617. DIR *dir;
  618. struct dirent *de;
  619. if (fstat(fd, &st))
  620. return 1;
  621. snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
  622. major(st.st_rdev), minor(st.st_rdev));
  623. dir = opendir(path);
  624. if (!dir)
  625. return 1;
  626. de = readdir(dir);
  627. while (de) {
  628. if (strncmp("scsi_disk:", de->d_name,
  629. strlen("scsi_disk:")) == 0)
  630. break;
  631. de = readdir(dir);
  632. }
  633. closedir(dir);
  634. if (!de)
  635. return 1;
  636. c1 = strchr(de->d_name, ':');
  637. c1++;
  638. c2 = strchr(c1, ':');
  639. *c2 = '\0';
  640. *id = strtol(c1, NULL, 10) << 24; /* host */
  641. c1 = c2 + 1;
  642. c2 = strchr(c1, ':');
  643. *c2 = '\0';
  644. *id |= strtol(c1, NULL, 10) << 16; /* channel */
  645. c1 = c2 + 1;
  646. c2 = strchr(c1, ':');
  647. *c2 = '\0';
  648. *id |= strtol(c1, NULL, 10) << 8; /* lun */
  649. c1 = c2 + 1;
  650. *id |= strtol(c1, NULL, 10); /* id */
  651. return 0;
  652. }
  653. int sysfs_unique_holder(int devnum, long rdev)
  654. {
  655. /* Check that devnum is a holder of rdev,
  656. * and is the only holder.
  657. * we should be locked against races by
  658. * an O_EXCL on devnum
  659. */
  660. DIR *dir;
  661. struct dirent *de;
  662. char dirname[100];
  663. char l;
  664. int found = 0;
  665. sprintf(dirname, "/sys/dev/block/%d:%d/holders",
  666. major(rdev), minor(rdev));
  667. dir = opendir(dirname);
  668. errno = ENOENT;
  669. if (!dir)
  670. return 0;
  671. l = strlen(dirname);
  672. while ((de = readdir(dir)) != NULL) {
  673. char buf[10];
  674. int n;
  675. int mj, mn;
  676. char c;
  677. int fd;
  678. if (de->d_ino == 0)
  679. continue;
  680. if (de->d_name[0] == '.')
  681. continue;
  682. strcpy(dirname+l, "/");
  683. strcat(dirname+l, de->d_name);
  684. strcat(dirname+l, "/dev");
  685. fd = open(dirname, O_RDONLY);
  686. if (fd < 0) {
  687. errno = ENOENT;
  688. break;
  689. }
  690. n = read(fd, buf, sizeof(buf)-1);
  691. close(fd);
  692. buf[n] = 0;
  693. if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 ||
  694. c != '\n') {
  695. errno = ENOENT;
  696. break;
  697. }
  698. if (mj != MD_MAJOR)
  699. mn = -1-(mn>>6);
  700. if (devnum != mn) {
  701. errno = EEXIST;
  702. break;
  703. }
  704. found = 1;
  705. }
  706. closedir(dir);
  707. if (de)
  708. return 0;
  709. else
  710. return found;
  711. }
  712. #ifndef MDASSEMBLE
  713. static char *clean_states[] = {
  714. "clear", "inactive", "readonly", "read-auto", "clean", NULL };
  715. int WaitClean(char *dev, int sock, int verbose)
  716. {
  717. int fd;
  718. struct mdinfo *mdi;
  719. int rv = 1;
  720. int devnum;
  721. fd = open(dev, O_RDONLY);
  722. if (fd < 0) {
  723. if (verbose)
  724. fprintf(stderr, Name ": Couldn't open %s: %s\n", dev, strerror(errno));
  725. return 1;
  726. }
  727. devnum = fd2devnum(fd);
  728. mdi = sysfs_read(fd, devnum, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
  729. if (!mdi) {
  730. if (verbose)
  731. fprintf(stderr, Name ": Failed to read sysfs attributes for "
  732. "%s\n", dev);
  733. close(fd);
  734. return 0;
  735. }
  736. switch(mdi->array.level) {
  737. case LEVEL_LINEAR:
  738. case LEVEL_MULTIPATH:
  739. case 0:
  740. /* safemode delay is irrelevant for these levels */
  741. rv = 0;
  742. }
  743. /* for internal metadata the kernel handles the final clean
  744. * transition, containers can never be dirty
  745. */
  746. if (!is_subarray(mdi->text_version))
  747. rv = 0;
  748. /* safemode disabled ? */
  749. if (mdi->safe_mode_delay == 0)
  750. rv = 0;
  751. if (rv) {
  752. int state_fd = sysfs_open(fd2devnum(fd), NULL, "array_state");
  753. char buf[20];
  754. fd_set fds;
  755. struct timeval tm;
  756. /* minimize the safe_mode_delay and prepare to wait up to 5s
  757. * for writes to quiesce
  758. */
  759. sysfs_set_safemode(mdi, 1);
  760. tm.tv_sec = 5;
  761. tm.tv_usec = 0;
  762. FD_ZERO(&fds);
  763. /* wait for array_state to be clean */
  764. while (1) {
  765. rv = read(state_fd, buf, sizeof(buf));
  766. if (rv < 0)
  767. break;
  768. if (sysfs_match_word(buf, clean_states) <= 4)
  769. break;
  770. FD_SET(state_fd, &fds);
  771. rv = select(state_fd + 1, NULL, NULL, &fds, &tm);
  772. if (rv < 0 && errno != EINTR)
  773. break;
  774. lseek(state_fd, 0, SEEK_SET);
  775. }
  776. if (rv < 0)
  777. rv = 1;
  778. else if (fping_monitor(sock) == 0 ||
  779. ping_monitor(mdi->text_version) == 0) {
  780. /* we need to ping to close the window between array
  781. * state transitioning to clean and the metadata being
  782. * marked clean
  783. */
  784. rv = 0;
  785. } else
  786. rv = 1;
  787. if (rv && verbose)
  788. fprintf(stderr, Name ": Error waiting for %s to be clean\n",
  789. dev);
  790. /* restore the original safe_mode_delay */
  791. sysfs_set_safemode(mdi, mdi->safe_mode_delay);
  792. close(state_fd);
  793. }
  794. sysfs_free(mdi);
  795. close(fd);
  796. return rv;
  797. }
  798. #endif /* MDASSEMBLE */