]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
Bitmap_offset is a signed number
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 7a0403d635b7f2067fa48ecb50e9ba326f5a8037..a1007cf276658f0f158a71c4e33657432f3ca07e 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -90,11 +90,7 @@ void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
        }
        if (devnum == NoMdDev)
                return;
-       if (devnum >= 0)
-               sprintf(mdi->sys_name, "md%d", devnum);
-       else
-               sprintf(mdi->sys_name, "md_d%d",
-                       -1-devnum);
+       fmt_devname(mdi->sys_name, devnum);
 }
 
 
@@ -221,6 +217,19 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                msec = (msec * 1000) / scale;
                sra->safe_mode_delay = msec;
        }
+       if (options & GET_BITMAP_LOCATION) {
+               strcpy(base, "bitmap/location");
+               if (load_sys(fname, buf))
+                       goto abort;
+               if (strncmp(buf, "file", 4) == 0)
+                       sra->bitmap_offset = 1;
+               else if (strncmp(buf, "none", 4) == 0)
+                       sra->bitmap_offset = 0;
+               else if (buf[0] == '+')
+                       sra->bitmap_offset = strtol(buf+1, NULL, 10);
+               else
+                       goto abort;
+       }
 
        if (! (options & GET_DEVS))
                return sra;
@@ -383,7 +392,7 @@ unsigned long long get_component_size(int fd)
                return 0;
        n = read(fd, fname, sizeof(fname));
        close(fd);
-       if (n == sizeof(fname))
+       if (n < 0 || n == sizeof(fname))
                return 0;
        fname[n] = 0;
        return strtoull(fname, NULL, 10) * 2;
@@ -432,6 +441,11 @@ int sysfs_uevent(struct mdinfo *sra, char *event)
                return -1;
        n = write(fd, event, strlen(event));
        close(fd);
+       if (n != (int)strlen(event)) {
+               dprintf(Name ": failed to write '%s' to '%s' (%s)\n",
+                       event, fname, strerror(errno));
+               return -1;
+       }
        return 0;
 }      
 
@@ -469,7 +483,7 @@ int sysfs_fd_get_ll(int fd, unsigned long long *val)
        lseek(fd, 0, 0);
        n = read(fd, buf, sizeof(buf));
        if (n <= 0)
-               return -1;
+               return -2;
        buf[n] = 0;
        *val = strtoull(buf, &ep, 0);
        if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
@@ -535,12 +549,26 @@ int sysfs_set_array(struct mdinfo *info, int vers)
 {
        int rv = 0;
        char ver[100];
+       int raid_disks = info->array.raid_disks;
 
        ver[0] = 0;
        if (info->array.major_version == -1 &&
            info->array.minor_version == -2) {
+               char buf[1024];
+
                strcat(strcpy(ver, "external:"), info->text_version);
 
+               /* meta version might already be set if we are setting
+                * new geometry for a reshape.  In that case we don't
+                * want to over-write the 'readonly' flag that is
+                * stored in the metadata version.  So read the current
+                * version first, and preserve the flag
+                */
+               if (sysfs_get_str(info, NULL, "metadata_version",
+                                 buf, 1024) > 0)
+                       if (strlen(buf) >= 9 && buf[9] == '-')
+                               ver[9] = '-';
+
                if ((vers % 100) < 2 ||
                    sysfs_set_str(info, NULL, "metadata_version",
                                  ver) < 0) {
@@ -553,7 +581,9 @@ int sysfs_set_array(struct mdinfo *info, int vers)
                return 0; /* FIXME */
        rv |= sysfs_set_str(info, NULL, "level",
                            map_num(pers, info->array.level));
-       rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
+       if (info->reshape_active && info->delta_disks != UnSet)
+               raid_disks -= info->delta_disks;
+       rv |= sysfs_set_num(info, NULL, "raid_disks", 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);
@@ -573,6 +603,18 @@ int sysfs_set_array(struct mdinfo *info, int vers)
 
        if (info->array.level > 0)
                rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
+
+       if (info->reshape_active) {
+               rv |= sysfs_set_num(info, NULL, "reshape_position",
+                                   info->reshape_progress);
+               rv |= sysfs_set_num(info, NULL, "chunk_size", info->new_chunk);
+               rv |= sysfs_set_num(info, NULL, "layout", info->new_layout);
+               rv |= sysfs_set_num(info, NULL, "raid_disks",
+                                   info->array.raid_disks);
+               /* We don't set 'new_level' here.  That can only happen
+                * once the reshape completes.
+                */
+       }
        return rv;
 }
 
@@ -590,7 +632,7 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
 
        memset(nm, 0, sizeof(nm));
        sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor);
-       rv = readlink(dv, nm, sizeof(nm));
+       rv = readlink(dv, nm, sizeof(nm)-1);
        if (rv <= 0)
                return -1;
        nm[rv] = '\0';
@@ -693,48 +735,36 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id)
        /* from an open block device, try to retrieve it scsi_id */
        struct stat st;
        char path[256];
-       char *c1, *c2;
        DIR *dir;
        struct dirent *de;
+       int host, bus, target, lun;
 
        if (fstat(fd, &st))
                return 1;
 
-       snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
+       snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device/scsi_device",
                 major(st.st_rdev), minor(st.st_rdev));
 
        dir = opendir(path);
        if (!dir)
                return 1;
 
-       de = readdir(dir);
-       while (de) {
-               if (strncmp("scsi_disk:", de->d_name,
-                           strlen("scsi_disk:")) == 0)
+       for (de = readdir(dir); de; de = readdir(dir)) {
+               int count;
+
+               if (de->d_type != DT_DIR)
+                       continue;
+
+               count = sscanf(de->d_name, "%d:%d:%d:%d", &host, &bus, &target, &lun);
+               if (count == 4)
                        break;
-               de = readdir(dir);
        }
        closedir(dir);
 
        if (!de)
                return 1;
 
-       c1 = strchr(de->d_name, ':');
-       c1++;
-       c2 = strchr(c1, ':');
-       *c2 = '\0';
-       *id = strtol(c1, NULL, 10) << 24; /* host */
-       c1 = c2 + 1;
-       c2 = strchr(c1, ':');
-       *c2 = '\0';
-       *id |= strtol(c1, NULL, 10) << 16; /* channel */
-       c1 = c2 + 1;
-       c2 = strchr(c1, ':');
-       *c2 = '\0';
-       *id |= strtol(c1, NULL, 10) << 8; /* lun */
-       c1 = c2 + 1;
-       *id |= strtol(c1, NULL, 10); /* id */
-
+       *id = (host << 24) | (bus << 16) | (target << 8) | (lun << 0);
        return 0;
 }
 
@@ -779,6 +809,8 @@ int sysfs_unique_holder(int devnum, long rdev)
                }
                n = read(fd, buf, sizeof(buf)-1);
                close(fd);
+               if (n < 0)
+                       continue;
                buf[n] = 0;
                if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 ||
                    c != '\n') {
@@ -805,7 +837,6 @@ int sysfs_freeze_array(struct mdinfo *sra)
 {
        /* Try to freeze resync/rebuild on this array/container.
         * Return -1 if the array is busy,
-        * return -2 container cannot be frozen,
         * return 0 if this kernel doesn't support 'frozen'
         * return 1 if it worked.
         */
@@ -815,113 +846,12 @@ int sysfs_freeze_array(struct mdinfo *sra)
                return 1; /* no sync_action == frozen */
        if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0)
                return 0;
-       if (strcmp(buf, "idle\n") != 0 &&
-           strcmp(buf, "frozen\n") != 0)
+       if (strcmp(buf, "frozen\n") == 0)
+               /* Already frozen */
+               return 0;
+       if (strcmp(buf, "idle\n") != 0)
                return -1;
        if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
                return 0;
        return 1;
 }
-
-#ifndef MDASSEMBLE
-
-static char *clean_states[] = {
-       "clear", "inactive", "readonly", "read-auto", "clean", NULL };
-
-int WaitClean(char *dev, int sock, int verbose)
-{
-       int fd;
-       struct mdinfo *mdi;
-       int rv = 1;
-       int devnum;
-
-       fd = open(dev, O_RDONLY); 
-       if (fd < 0) {
-               if (verbose)
-                       fprintf(stderr, Name ": Couldn't open %s: %s\n", dev, strerror(errno));
-               return 1;
-       }
-
-       devnum = fd2devnum(fd);
-       mdi = sysfs_read(fd, devnum, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
-       if (!mdi) {
-               if (verbose)
-                       fprintf(stderr, Name ": Failed to read sysfs attributes for "
-                               "%s\n", dev);
-               close(fd);
-               return 0;
-       }
-
-       switch(mdi->array.level) {
-       case LEVEL_LINEAR:
-       case LEVEL_MULTIPATH:
-       case 0:
-               /* safemode delay is irrelevant for these levels */
-               rv = 0;
-               
-       }
-
-       /* for internal metadata the kernel handles the final clean
-        * transition, containers can never be dirty
-        */
-       if (!is_subarray(mdi->text_version))
-               rv = 0;
-
-       /* safemode disabled ? */
-       if (mdi->safe_mode_delay == 0)
-               rv = 0;
-
-       if (rv) {
-               int state_fd = sysfs_open(fd2devnum(fd), NULL, "array_state");
-               char buf[20];
-               fd_set fds;
-               struct timeval tm;
-
-               /* minimize the safe_mode_delay and prepare to wait up to 5s
-                * for writes to quiesce
-                */
-               sysfs_set_safemode(mdi, 1);
-               tm.tv_sec = 5;
-               tm.tv_usec = 0;
-
-               FD_ZERO(&fds);
-
-               /* wait for array_state to be clean */
-               while (1) {
-                       rv = read(state_fd, buf, sizeof(buf));
-                       if (rv < 0)
-                               break;
-                       if (sysfs_match_word(buf, clean_states) <= 4)
-                               break;
-                       FD_SET(state_fd, &fds);
-                       rv = select(state_fd + 1, NULL, NULL, &fds, &tm);
-                       if (rv < 0 && errno != EINTR)
-                               break;
-                       lseek(state_fd, 0, SEEK_SET);
-               }
-               if (rv < 0)
-                       rv = 1;
-               else if (fping_monitor(sock) == 0 ||
-                        ping_monitor(mdi->text_version) == 0) {
-                       /* we need to ping to close the window between array
-                        * state transitioning to clean and the metadata being
-                        * marked clean
-                        */
-                       rv = 0;
-               } else
-                       rv = 1;
-               if (rv && verbose)
-                       fprintf(stderr, Name ": Error waiting for %s to be clean\n",
-                               dev);
-
-               /* restore the original safe_mode_delay */
-               sysfs_set_safemode(mdi, mdi->safe_mode_delay);
-               close(state_fd);
-       }
-
-       sysfs_free(mdi);
-       close(fd);
-
-       return rv;
-}
-#endif /* MDASSEMBLE */