]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
Merge branch 'master' into devel-3.0
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index fdad790f06e2d1294e5ace28ca62462949a6767e..58c84e26339e8014027bcea6d722bf87b73b4030 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -61,8 +61,12 @@ int sysfs_open(int devnum, char *devname, char *attr)
 {
        char fname[50];
        int fd;
+       char *mdname = devnum2devname(devnum);
 
-       sprintf(fname, "/sys/block/%s/md/", devnum2devname(devnum));
+       if (!mdname)
+               return -1;
+
+       sprintf(fname, "/sys/block/%s/md/", mdname);
        if (devname) {
                strcat(fname, devname);
                strcat(fname, "/");
@@ -71,9 +75,33 @@ int sysfs_open(int devnum, char *devname, char *attr)
        fd = open(fname, O_RDWR);
        if (fd < 0 && errno == EACCES)
                fd = open(fname, O_RDONLY);
+       free(mdname);
        return fd;
 }
 
+void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
+{
+       if (fd >= 0) {
+               struct stat stb;
+               mdu_version_t vers;
+               if (fstat(fd, &stb))
+                       return;
+               if (ioctl(fd, RAID_VERSION, &vers) != 0)
+                       return;
+               if (major(stb.st_rdev)==9)
+                       sprintf(mdi->sys_name, "md%d", (int)minor(stb.st_rdev));
+               else
+                       sprintf(mdi->sys_name, "md_d%d",
+                               (int)minor(stb.st_rdev)>>MdpMinorShift);
+       } else {
+               if (devnum >= 0)
+                       sprintf(mdi->sys_name, "md%d", devnum);
+               else
+                       sprintf(mdi->sys_name, "md_d%d",
+                               -1-devnum);
+       }
+}
+
 struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
 {
        /* Longest possible name in sysfs, mounted at /sys, is
@@ -93,26 +121,9 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
        sra = malloc(sizeof(*sra));
        if (sra == NULL)
                return sra;
-       sra->next = NULL;
+       memset(sra, 0, sizeof(*sra));
+       sysfs_init(sra, fd, devnum);
 
-       if (fd >= 0) {
-               struct stat stb;
-               mdu_version_t vers;
-               if (fstat(fd, &stb)) return NULL;
-               if (ioctl(fd, RAID_VERSION, &vers) != 0)
-                       return NULL;
-               if (major(stb.st_rdev)==9)
-                       sprintf(sra->sys_name, "md%d", (int)minor(stb.st_rdev));
-               else
-                       sprintf(sra->sys_name, "md_d%d",
-                               (int)minor(stb.st_rdev)>>MdpMinorShift);
-       } else {
-               if (devnum >= 0)
-                       sprintf(sra->sys_name, "md%d", devnum);
-               else
-                       sprintf(sra->sys_name, "md_d%d",
-                               -1-devnum);
-       }
        sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
        base = fname + strlen(fname);
 
@@ -383,8 +394,11 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
                return -1;
        n = write(fd, val, strlen(val));
        close(fd);
-       if (n != strlen(val))
+       if (n != strlen(val)) {
+               dprintf(Name ": failed to write '%s' to '%s' (%s)\n",
+                       val, fname, strerror(errno));
                return -1;
+       }
        return 0;
 }
 
@@ -427,28 +441,41 @@ int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
        char delay[30];
 
        sec = ms / 1000;
-       msec = ms - (sec * 1000);
+       msec = ms % 1000;
 
-       sprintf(delay, "%ld.%ld", sec, msec);
+       sprintf(delay, "%ld.%03ld\n", sec, msec);
+       /*             this '\n' ^ needed for kernels older than 2.6.28 */
        return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
 }
 
-int sysfs_set_array(struct mdinfo *sra,
-                   struct mdinfo *info)
+int sysfs_set_array(struct mdinfo *info, int vers)
 {
        int rv = 0;
-       sra->array = info->array;
-
+       char ver[100];
+
+       ver[0] = 0;
+       if (info->array.major_version == -1 &&
+           info->array.minor_version == -2) {
+               strcat(strcpy(ver, "external:"), info->text_version);
+
+               if ((vers % 100) < 2 ||
+                   sysfs_set_str(info, NULL, "metadata_version",
+                                 ver) < 0) {
+                       fprintf(stderr, Name ": This kernel does not "
+                               "support external metadata.\n");
+                       return 1;
+               }
+       }
        if (info->array.level < 0)
                return 0; /* FIXME */
-       rv |= sysfs_set_str(sra, NULL, "level",
+       rv |= sysfs_set_str(info, NULL, "level",
                            map_num(pers, info->array.level));
-       rv |= sysfs_set_num(sra, NULL, "raid_disks", info->array.raid_disks);
-       rv |= sysfs_set_num(sra, NULL, "chunk_size", info->array.chunk_size);
-       rv |= sysfs_set_num(sra, NULL, "layout", info->array.layout);
-       rv |= sysfs_set_num(sra, NULL, "component_size", info->component_size/2);
-       rv |= sysfs_set_num(sra, NULL, "resync_start", info->resync_start);
-       sra->array = info->array;
+       rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
+       rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
+       rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
+       rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
+       if (info->array.level > 0)
+               rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
        return rv;
 }