]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
Add one sanity check for missing device
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 11ff2ccba70e8e56bbdb550d96efcada86671b58..543ec6cf46ef889f02472d3d186702988c65fc47 100644 (file)
--- a/util.c
+++ b/util.c
@@ -30,6 +30,7 @@
 #include       <sys/un.h>
 #include       <sys/resource.h>
 #include       <sys/vfs.h>
+#include       <sys/mman.h>
 #include       <linux/magic.h>
 #include       <poll.h>
 #include       <ctype.h>
@@ -147,9 +148,9 @@ int cluster_get_dlmlock(int *lockid)
        }
 
        snprintf(str, 64, "bitmap%s", cluster_name);
-       ret = dlm_hooks->ls_lock(dlm_lock_res->ls, LKM_PWMODE, &dlm_lock_res->lksb,
-                         flags, str, strlen(str), 0, dlm_ast,
-                         dlm_lock_res, NULL, NULL);
+       ret = dlm_hooks->ls_lock(dlm_lock_res->ls, LKM_PWMODE,
+                                &dlm_lock_res->lksb, flags, str, strlen(str),
+                                0, dlm_ast, dlm_lock_res, NULL, NULL);
        if (ret) {
                pr_err("error %d when get PW mode on lock %s\n", errno, str);
                dlm_hooks->release_lockspace(cluster_name, dlm_lock_res->ls, 1);
@@ -183,7 +184,8 @@ int cluster_release_dlmlock(int lockid)
 
        errno = dlm_lock_res->lksb.sb_status;
        if (errno != EUNLOCK) {
-               pr_err("error %d happened in ast when unlock lockspace\n", errno);
+               pr_err("error %d happened in ast when unlock lockspace\n",
+                      errno);
                /* XXX make sure the lockspace is unlocked eventually */
                 goto out;
        }
@@ -228,15 +230,11 @@ int md_array_active(int fd)
 {
        struct mdinfo *sra;
        struct mdu_array_info_s array;
-       int ret;
+       int ret = 0;
 
        sra = sysfs_read(fd, NULL, GET_ARRAY_STATE);
        if (sra) {
-               if (sra->array_state != ARRAY_CLEAR &&
-                   sra->array_state != ARRAY_INACTIVE &&
-                   sra->array_state != ARRAY_UNKNOWN_STATE)
-                       ret = 0;
-               else
+               if (!md_array_is_active(sra))
                        ret = -ENODEV;
 
                free(sra);
@@ -251,6 +249,13 @@ int md_array_active(int fd)
        return !ret;
 }
 
+int md_array_is_active(struct mdinfo *info)
+{
+       return (info->array_state != ARRAY_CLEAR &&
+               info->array_state != ARRAY_INACTIVE &&
+               info->array_state != ARRAY_UNKNOWN_STATE);
+}
+
 /*
  * Get array info from the kernel. Longer term we want to deprecate the
  * ioctl and get it from sysfs.
@@ -392,6 +397,17 @@ unsigned long long parse_size(char *size)
        return s;
 }
 
+int is_near_layout_10(int layout)
+{
+       int fc, fo;
+
+       fc = (layout >> 8) & 255;
+       fo = layout & (1 << 16);
+       if (fc > 1 || fo > 0)
+               return 0;
+       return 1;
+}
+
 int parse_layout_10(char *layout)
 {
        int copies, rv;
@@ -636,14 +652,16 @@ char *__fname_from_uuid(int id[4], int swap, char *buf, char sep)
 
 }
 
-char *fname_from_uuid(struct supertype *st, struct mdinfo *info, char *buf, char sep)
+char *fname_from_uuid(struct supertype *st, struct mdinfo *info,
+                     char *buf, char sep)
 {
        // dirty hack to work around an issue with super1 superblocks...
        // super1 superblocks need swapuuid set in order for assembly to
        // work, but can't have it set if we want this printout to match
        // all the other uuid printouts in super1.c, so we force swapuuid
        // to 1 to make our printout match the rest of super1
-       return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 : st->ss->swapuuid, buf, sep);
+       return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 :
+                                st->ss->swapuuid, buf, sep);
 }
 
 int check_ext2(int fd, char *name)
@@ -1014,21 +1032,18 @@ char *get_md_name(char *devnm)
        if (strncmp(devnm, "md_", 3) == 0) {
                snprintf(devname, sizeof(devname), "/dev/md/%s",
                        devnm + 3);
-               if (stat(devname, &stb) == 0
-                   && (S_IFMT&stb.st_mode) == S_IFBLK
-                   && (stb.st_rdev == rdev))
+               if (stat(devname, &stb) == 0 &&
+                   (S_IFMT&stb.st_mode) == S_IFBLK && (stb.st_rdev == rdev))
                        return devname;
        }
        snprintf(devname, sizeof(devname), "/dev/%s", devnm);
-       if (stat(devname, &stb) == 0
-           && (S_IFMT&stb.st_mode) == S_IFBLK
-           && (stb.st_rdev == rdev))
+       if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+           (stb.st_rdev == rdev))
                return devname;
 
        snprintf(devname, sizeof(devname), "/dev/md/%s", devnm+2);
-       if (stat(devname, &stb) == 0
-           && (S_IFMT&stb.st_mode) == S_IFBLK
-           && (stb.st_rdev == rdev))
+       if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+           (stb.st_rdev == rdev))
                return devname;
 
        dn = map_dev(major(rdev), minor(rdev), 0);
@@ -1039,9 +1054,8 @@ char *get_md_name(char *devnm)
                if (errno != EEXIST)
                        return NULL;
 
-       if (stat(devname, &stb) == 0
-           && (S_IFMT&stb.st_mode) == S_IFBLK
-           && (stb.st_rdev == rdev))
+       if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+           (stb.st_rdev == rdev))
                return devname;
        unlink(devname);
        return NULL;
@@ -1085,9 +1099,11 @@ int dev_open(char *dev, int flags)
                }
                if (fd < 0) {
                        /* Try /tmp as /dev appear to be read-only */
-                       snprintf(devname, sizeof(devname), "/tmp/.tmp.md.%d:%d:%d",
+                       snprintf(devname, sizeof(devname),
+                                "/tmp/.tmp.md.%d:%d:%d",
                                 (int)getpid(), major, minor);
-                       if (mknod(devname, S_IFBLK|0600, makedev(major, minor)) == 0) {
+                       if (mknod(devname, S_IFBLK|0600,
+                                 makedev(major, minor)) == 0) {
                                fd = open(devname, flags);
                                unlink(devname);
                        }
@@ -1173,7 +1189,7 @@ void wait_for(char *dev, int fd)
                        delay *= 2;
        }
        if (i == 25)
-               dprintf("timeout waiting for %s\n", dev);
+               pr_err("timeout waiting for %s\n", dev);
 }
 
 struct superswitch *superlist[] =
@@ -1265,6 +1281,23 @@ int dev_size_from_id(dev_t id, unsigned long long *size)
        return 0;
 }
 
+int dev_sector_size_from_id(dev_t id, unsigned int *size)
+{
+       char buf[20];
+       int fd;
+
+       sprintf(buf, "%d:%d", major(id), minor(id));
+       fd = dev_open(buf, O_RDONLY);
+       if (fd < 0)
+               return 0;
+       if (get_dev_sector_size(fd, NULL, size)) {
+               close(fd);
+               return 1;
+       }
+       close(fd);
+       return 0;
+}
+
 struct supertype *dup_super(struct supertype *orig)
 {
        struct supertype *st;
@@ -2107,7 +2140,7 @@ int experimental(void)
  * if spare_group given add it to domains of each spare
  * metadata allows to test domains using metadata of destination array */
 struct mdinfo *container_choose_spares(struct supertype *st,
-                                      unsigned long long min_size,
+                                      struct spare_criteria *criteria,
                                       struct domainlist *domlist,
                                       char *spare_group,
                                       const char *metadata, int get_one)
@@ -2129,12 +2162,24 @@ struct mdinfo *container_choose_spares(struct supertype *st,
                if (d->disk.state == 0) {
                        /* check if size is acceptable */
                        unsigned long long dev_size;
+                       unsigned int dev_sector_size;
+                       int size_valid = 0;
+                       int sector_size_valid = 0;
+
                        dev_t dev = makedev(d->disk.major,d->disk.minor);
 
-                       if (!min_size ||
+                       if (!criteria->min_size ||
                           (dev_size_from_id(dev,  &dev_size) &&
-                           dev_size >= min_size))
-                               found = 1;
+                           dev_size >= criteria->min_size))
+                               size_valid = 1;
+
+                       if (!criteria->sector_size ||
+                           (dev_sector_size_from_id(dev, &dev_sector_size) &&
+                            criteria->sector_size == dev_sector_size))
+                               sector_size_valid = 1;
+
+                       found = size_valid && sector_size_valid;
+
                        /* check if domain matches */
                        if (found && domlist) {
                                struct dev_policy *pol = devid_policy(dev);
@@ -2188,8 +2233,7 @@ void enable_fds(int devices)
 {
        unsigned int fds = 20 + devices;
        struct rlimit lim;
-       if (getrlimit(RLIMIT_NOFILE, &lim) != 0
-           || lim.rlim_cur >= fds)
+       if (getrlimit(RLIMIT_NOFILE, &lim) != 0 || lim.rlim_cur >= fds)
                return;
        if (lim.rlim_max < fds)
                lim.rlim_max = fds;
@@ -2234,8 +2278,10 @@ void set_cmap_hooks(void)
        if (!cmap_hooks->cmap_handle)
                return;
 
-       cmap_hooks->initialize = dlsym(cmap_hooks->cmap_handle, "cmap_initialize");
-       cmap_hooks->get_string = dlsym(cmap_hooks->cmap_handle, "cmap_get_string");
+       cmap_hooks->initialize =
+               dlsym(cmap_hooks->cmap_handle, "cmap_initialize");
+       cmap_hooks->get_string =
+               dlsym(cmap_hooks->cmap_handle, "cmap_get_string");
        cmap_hooks->finalize = dlsym(cmap_hooks->cmap_handle, "cmap_finalize");
 
        if (!cmap_hooks->initialize || !cmap_hooks->get_string ||
@@ -2278,8 +2324,10 @@ void set_dlm_hooks(void)
        if (!dlm_hooks->dlm_handle)
                return;
 
-       dlm_hooks->create_lockspace = dlsym(dlm_hooks->dlm_handle, "dlm_create_lockspace");
-       dlm_hooks->release_lockspace = dlsym(dlm_hooks->dlm_handle, "dlm_release_lockspace");
+       dlm_hooks->create_lockspace =
+               dlsym(dlm_hooks->dlm_handle, "dlm_create_lockspace");
+       dlm_hooks->release_lockspace =
+               dlsym(dlm_hooks->dlm_handle, "dlm_release_lockspace");
        dlm_hooks->ls_lock = dlsym(dlm_hooks->dlm_handle, "dlm_ls_lock");
        dlm_hooks->ls_unlock = dlsym(dlm_hooks->dlm_handle, "dlm_ls_unlock");
        dlm_hooks->ls_get_fd = dlsym(dlm_hooks->dlm_handle, "dlm_ls_get_fd");
@@ -2298,3 +2346,51 @@ void set_hooks(void)
        set_dlm_hooks();
        set_cmap_hooks();
 }
+
+int zero_disk_range(int fd, unsigned long long sector, size_t count)
+{
+       int ret = 0;
+       int fd_zero;
+       void *addr = NULL;
+       size_t written = 0;
+       size_t len = count * 512;
+       ssize_t n;
+
+       fd_zero = open("/dev/zero", O_RDONLY);
+       if (fd_zero < 0) {
+               pr_err("Cannot open /dev/zero\n");
+               return -1;
+       }
+
+       if (lseek64(fd, sector * 512, SEEK_SET) < 0) {
+               ret = -errno;
+               pr_err("Failed to seek offset for zeroing\n");
+               goto out;
+       }
+
+       addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd_zero, 0);
+
+       if (addr == MAP_FAILED) {
+               ret = -errno;
+               pr_err("Mapping /dev/zero failed\n");
+               goto out;
+       }
+
+       do {
+               n = write(fd, addr + written, len - written);
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       ret = -errno;
+                       pr_err("Zeroing disk range failed\n");
+                       break;
+               }
+               written += n;
+       } while (written != len);
+
+       munmap(addr, len);
+
+out:
+       close(fd_zero);
+       return ret;
+}