]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
sysfs: provide a helper function for locating scsi_generic interfaces
authorDan Williams <dan.j.williams@intel.com>
Sat, 14 Jun 2008 00:27:30 +0000 (17:27 -0700)
committerDan Williams <dan.j.williams@intel.com>
Sat, 14 Jun 2008 00:27:30 +0000 (17:27 -0700)
imsm records and validates this data in its metadata

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
mdadm.h
super-intel.c
sysfs.c

diff --git a/mdadm.h b/mdadm.h
index 79ec5e294bc22bb7ebae7bf8e8f22ff6ed709085..f29cf0180f9740cbdba937df7a1f89f8eb3e59e3 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -346,7 +346,7 @@ extern int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
 extern int sysfs_set_array(struct mdinfo *sra,
                           struct mdinfo *info);
 extern int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd);
-
+extern int sysfs_disk_to_sg(int fd);
 
 
 
index 2da4514e65b7b5d70c9e1aecbf054ba99cd86bb7..4052aa673c1bed1422f0bdda9a3b6ac632cb661b 100644 (file)
@@ -544,26 +544,19 @@ static int imsm_read_serial(int fd, char *devname,
                            __u8 serial[MAX_RAID_SERIAL_LEN])
 {
        unsigned char scsi_serial[255];
-       struct stat stb;
        int sg_fd;
-       int minor;
-       char sg_path[20];
        int rv;
        int rsp_len;
        int i, cnt;
 
        memset(scsi_serial, 0, sizeof(scsi_serial));
-       fstat(fd, &stb);
-       minor = minor(stb.st_rdev);
-       minor /= 16;
 
-       sprintf(sg_path, "/dev/sg%d", minor);
-       sg_fd = open(sg_path, O_RDONLY);
+       sg_fd = sysfs_disk_to_sg(fd);
        if (sg_fd < 0) {
                if (devname)
                        fprintf(stderr,
-                               Name ": Failed to open %s for %s: %s\n",
-                               sg_path,  devname, strerror(errno));
+                               Name ": Failed to open sg interface for %s: %s\n",
+                               devname, strerror(errno));
                return 1;
        }
 
diff --git a/sysfs.c b/sysfs.c
index bbb9cd37c884aeb7fbbd5e6c980445f8d0b93417..37b8b0974a142121be5ba6d9f7556dac33376427 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -399,3 +399,68 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd)
        }
        return rv;
 }
+
+int sysfs_disk_to_sg(int fd)
+{
+       /* from an open block device, try find and open its corresponding
+        * scsi_generic interface
+        */
+       struct stat st;
+       char path[256];
+       char sg_path[256];
+       char sg_major_minor[8];
+       char *c;
+       DIR *dir;
+       struct dirent *de;
+       int major, minor, rv;
+
+       if (fstat(fd, &st))
+               return -1;
+
+       snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
+                major(st.st_rdev), minor(st.st_rdev));
+
+       dir = opendir(path);
+       if (!dir)
+               return -1;
+
+       de = readdir(dir);
+       while (de) {
+               if (strncmp("scsi_generic:", de->d_name,
+                           strlen("scsi_generic:")) == 0)
+                       break;
+               de = readdir(dir);
+       }
+       closedir(dir);
+
+       if (!de)
+               return -1;
+
+       snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name);
+       fd = open(sg_path, O_RDONLY);
+       if (fd < 0)
+               return fd;
+
+       rv = read(fd, sg_major_minor, sizeof(sg_major_minor));
+       close(fd);
+       if (rv < 0)
+               return -1;
+       else
+               sg_major_minor[rv - 1] = '\0';
+
+       c = strchr(sg_major_minor, ':');
+       *c = '\0';
+       c++;
+       major = strtol(sg_major_minor, NULL, 10);
+       minor = strtol(c, NULL, 10);
+       snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d",
+                (int) getpid(), major, minor);
+       if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) {
+                       fd = open(path, O_RDONLY);
+                       unlink(path);
+                       return fd;
+       }
+
+       return -1;
+}
+