]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
imsm: support RAID 10 with more than 4 drives
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index aa27e59de7b8807c0664e04b829f6bb47a21e0f0..4fbf11c4e2bd71fad9df89b9b259ad50ac4b28d7 100644 (file)
--- a/util.c
+++ b/util.c
 #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>
 #include       <dirent.h>
-#include       <signal.h>
 #include       <dlfcn.h>
-
+#include       <limits.h>
 
 /*
  * following taken from linux/blkpg.h because they aren't
@@ -89,7 +89,6 @@ int dlm_funs_ready(void)
        return is_dlm_hooks_ready ? 1 : 0;
 }
 
-#ifndef MDASSEMBLE
 static struct dlm_hooks *dlm_hooks = NULL;
 struct dlm_lock_resource *dlm_lock_res = NULL;
 static int ast_called = 0;
@@ -128,11 +127,17 @@ static void dlm_ast(void *arg)
 
 static char *cluster_name = NULL;
 /* Create the lockspace, take bitmapXXX locks on all the bitmaps. */
-int cluster_get_dlmlock(int *lockid)
+int cluster_get_dlmlock(void)
 {
        int ret = -1;
        char str[64];
        int flags = LKF_NOQUEUE;
+       int retry_count = 0;
+
+       if (!dlm_funs_ready()) {
+               pr_err("Something wrong with dlm library\n");
+               return -1;
+       }
 
        ret = get_cluster_name(&cluster_name);
        if (ret) {
@@ -141,38 +146,57 @@ int cluster_get_dlmlock(int *lockid)
        }
 
        dlm_lock_res = xmalloc(sizeof(struct dlm_lock_resource));
-       dlm_lock_res->ls = dlm_hooks->create_lockspace(cluster_name, O_RDWR);
+       dlm_lock_res->ls = dlm_hooks->open_lockspace(cluster_name);
        if (!dlm_lock_res->ls) {
-               pr_err("%s failed to create lockspace\n", cluster_name);
-               return -ENOMEM;
+               dlm_lock_res->ls = dlm_hooks->create_lockspace(cluster_name, O_RDWR);
+               if (!dlm_lock_res->ls) {
+                       pr_err("%s failed to create lockspace\n", cluster_name);
+                       return -ENOMEM;
+               }
+       } else {
+               pr_err("open existed %s lockspace\n", cluster_name);
        }
 
        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);
+retry:
+       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);
+               /* let's try several times if EAGAIN happened */
+               if (dlm_lock_res->lksb.sb_status == EAGAIN && retry_count < 10) {
+                       sleep_for(10, 0, true);
+                       retry_count++;
+                       goto retry;
+               }
                dlm_hooks->release_lockspace(cluster_name, dlm_lock_res->ls, 1);
                return ret;
        }
 
        /* Wait for it to complete */
        poll_for_ast(dlm_lock_res->ls);
-       *lockid = dlm_lock_res->lksb.sb_lkid;
 
-       return dlm_lock_res->lksb.sb_status;
+       if (dlm_lock_res->lksb.sb_status) {
+               pr_err("failed to lock cluster\n");
+               return -1;
+       }
+       return 1;
 }
 
-int cluster_release_dlmlock(int lockid)
+int cluster_release_dlmlock(void)
 {
        int ret = -1;
 
        if (!cluster_name)
-               return -1;
+                goto out;
+
+       if (!dlm_lock_res->lksb.sb_lkid)
+                goto out;
 
-       ret = dlm_hooks->ls_unlock(dlm_lock_res->ls, lockid, 0,
-                                    &dlm_lock_res->lksb, dlm_lock_res);
+       ret = dlm_hooks->ls_unlock_wait(dlm_lock_res->ls,
+                                       dlm_lock_res->lksb.sb_lkid, 0,
+                                       &dlm_lock_res->lksb);
        if (ret) {
                pr_err("error %d happened when unlock\n", errno);
                /* XXX make sure the lock is unlocked eventually */
@@ -184,7 +208,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;
        }
@@ -200,16 +225,60 @@ int cluster_release_dlmlock(int lockid)
 out:
        return ret;
 }
-#else
-int cluster_get_dlmlock(int *lockid)
+
+int md_array_valid(int fd)
 {
-       return -1;
+       struct mdinfo *sra;
+       int ret;
+
+       sra = sysfs_read(fd, NULL, GET_ARRAY_STATE);
+       if (sra) {
+               if (sra->array_state != ARRAY_UNKNOWN_STATE)
+                       ret = 0;
+               else
+                       ret = -ENODEV;
+
+               free(sra);
+       } else {
+               /*
+                * GET_ARRAY_INFO doesn't provide access to the proper state
+                * information, so fallback to a basic check for raid_disks != 0
+                */
+               ret = ioctl(fd, RAID_VERSION);
+       }
+
+       return !ret;
 }
-int cluster_release_dlmlock(int lockid)
+
+int md_array_active(int fd)
 {
-       return -1;
+       struct mdinfo *sra;
+       struct mdu_array_info_s array;
+       int ret = 0;
+
+       sra = sysfs_read(fd, NULL, GET_ARRAY_STATE);
+       if (sra) {
+               if (!md_array_is_active(sra))
+                       ret = -ENODEV;
+
+               free(sra);
+       } else {
+               /*
+                * GET_ARRAY_INFO doesn't provide access to the proper state
+                * information, so fallback to a basic check for raid_disks != 0
+                */
+               ret = md_get_array_info(fd, &array);
+       }
+
+       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);
 }
-#endif
 
 /*
  * Get array info from the kernel. Longer term we want to deprecate the
@@ -221,77 +290,19 @@ int md_get_array_info(int fd, struct mdu_array_info_s *array)
 }
 
 /*
- * Get disk info from the kernel.
+ * Set array info
  */
-int md_get_disk_info(int fd, struct mdu_disk_info_s *disk)
+int md_set_array_info(int fd, struct mdu_array_info_s *array)
 {
-       return ioctl(fd, GET_DISK_INFO, disk);
-}
-
-/*
- * Parse a 128 bit uuid in 4 integers
- * format is 32 hexx nibbles with options :.<space> separator
- * If not exactly 32 hex digits are found, return 0
- * else return 1
- */
-int parse_uuid(char *str, int uuid[4])
-{
-       int hit = 0; /* number of Hex digIT */
-       int i;
-       char c;
-       for (i = 0; i < 4; i++)
-               uuid[i] = 0;
-
-       while ((c = *str++) != 0) {
-               int n;
-               if (c >= '0' && c <= '9')
-                       n = c-'0';
-               else if (c >= 'a' && c <= 'f')
-                       n = 10 + c - 'a';
-               else if (c >= 'A' && c <= 'F')
-                       n = 10 + c - 'A';
-               else if (strchr(":. -", c))
-                       continue;
-               else return 0;
-
-               if (hit<32) {
-                       uuid[hit/8] <<= 4;
-                       uuid[hit/8] += n;
-               }
-               hit++;
-       }
-       if (hit == 32)
-               return 1;
-       return 0;
+       return ioctl(fd, SET_ARRAY_INFO, array);
 }
 
 /*
- * Get the md version number.
- * We use the RAID_VERSION ioctl if it is supported
- * If not, but we have a block device with major '9', we assume
- * 0.36.0
- *
- * Return version number as 24 but number - assume version parts
- * always < 255
+ * Get disk info from the kernel.
  */
-
-int md_get_version(int fd)
+int md_get_disk_info(int fd, struct mdu_disk_info_s *disk)
 {
-       struct stat stb;
-       mdu_version_t vers;
-
-       if (fstat(fd, &stb)<0)
-               return -1;
-       if ((S_IFMT&stb.st_mode) != S_IFBLK)
-               return -1;
-
-       if (ioctl(fd, RAID_VERSION, &vers) == 0)
-               return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
-       if (errno == EACCES)
-               return -1;
-       if (major(stb.st_rdev) == MD_MAJOR)
-               return (3600);
-       return -1;
+       return ioctl(fd, GET_DISK_INFO, disk);
 }
 
 int get_linux_version()
@@ -312,7 +323,6 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
-#ifndef MDASSEMBLE
 int mdadm_version(char *version)
 {
        int a, b, c;
@@ -341,7 +351,7 @@ int mdadm_version(char *version)
 unsigned long long parse_size(char *size)
 {
        /* parse 'size' which should be a number optionally
-        * followed by 'K', 'M', or 'G'.
+        * followed by 'K', 'M'. 'G' or 'T'.
         * Without a suffix, K is assumed.
         * Number returned is in sectors (half-K)
         * INVALID_SECTORS returned on error.
@@ -363,6 +373,10 @@ unsigned long long parse_size(char *size)
                        c++;
                        s *= 1024 * 1024 * 2;
                        break;
+               case 'T':
+                       c++;
+                       s *= 1024 * 1024 * 1024 * 2LL;
+                       break;
                case 's': /* sectors */
                        c++;
                        break;
@@ -374,6 +388,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;
@@ -396,30 +421,25 @@ int parse_layout_10(char *layout)
 
 int parse_layout_faulty(char *layout)
 {
+       int ln, mode;
+       char *m;
+
+       if (!layout)
+               return -1;
+
        /* Parse the layout string for 'faulty' */
-       int ln = strcspn(layout, "0123456789");
-       char *m = xstrdup(layout);
-       int mode;
+       ln = strcspn(layout, "0123456789");
+       m = xstrdup(layout);
        m[ln] = 0;
        mode = map_name(faultylayout, m);
+       free(m);
+
        if (mode == UnSet)
                return -1;
 
        return mode | (atoi(layout+ln)<< ModeShift);
 }
 
-long parse_num(char *num)
-{
-       /* Either return a valid number, or -1 */
-       char *c;
-       long rv = strtol(num, &c, 10);
-       if (rv < 0 || *c || !num[0])
-               return -1;
-       else
-               return rv;
-}
-#endif
-
 int parse_cluster_confirm_arg(char *input, char **devname, int *slot)
 {
        char *dev;
@@ -549,87 +569,6 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
        }
 }
 
-int enough_fd(int fd)
-{
-       struct mdu_array_info_s array;
-       struct mdu_disk_info_s disk;
-       int i, rv;
-       char *avail;
-
-       if (md_get_array_info(fd, &array) != 0 || array.raid_disks <= 0)
-               return 0;
-       avail = xcalloc(array.raid_disks, 1);
-       for (i = 0; i < MAX_DISKS && array.nr_disks > 0; i++) {
-               disk.number = i;
-               if (md_get_disk_info(fd, &disk) != 0)
-                       continue;
-               if (disk.major == 0 && disk.minor == 0)
-                       continue;
-               array.nr_disks--;
-
-               if (! (disk.state & (1<<MD_DISK_SYNC)))
-                       continue;
-               if (disk.raid_disk < 0 || disk.raid_disk >= array.raid_disks)
-                       continue;
-               avail[disk.raid_disk] = 1;
-       }
-       /* This is used on an active array, so assume it is clean */
-       rv = enough(array.level, array.raid_disks, array.layout,
-                   1, avail);
-       free(avail);
-       return rv;
-}
-
-const int uuid_zero[4] = { 0, 0, 0, 0 };
-
-int same_uuid(int a[4], int b[4], int swapuuid)
-{
-       if (swapuuid) {
-               /* parse uuids are hostendian.
-                * uuid's from some superblocks are big-ending
-                * if there is a difference, we need to swap..
-                */
-               unsigned char *ac = (unsigned char *)a;
-               unsigned char *bc = (unsigned char *)b;
-               int i;
-               for (i = 0; i < 16; i += 4) {
-                       if (ac[i+0] != bc[i+3] ||
-                           ac[i+1] != bc[i+2] ||
-                           ac[i+2] != bc[i+1] ||
-                           ac[i+3] != bc[i+0])
-                               return 0;
-               }
-               return 1;
-       } else {
-               if (a[0]==b[0] &&
-                   a[1]==b[1] &&
-                   a[2]==b[2] &&
-                   a[3]==b[3])
-                       return 1;
-               return 0;
-       }
-}
-
-void copy_uuid(void *a, int b[4], int swapuuid)
-{
-       if (swapuuid) {
-               /* parse uuids are hostendian.
-                * uuid's from some superblocks are big-ending
-                * if there is a difference, we need to swap..
-                */
-               unsigned char *ac = (unsigned char *)a;
-               unsigned char *bc = (unsigned char *)b;
-               int i;
-               for (i = 0; i < 16; i += 4) {
-                       ac[i+0] = bc[i+3];
-                       ac[i+1] = bc[i+2];
-                       ac[i+2] = bc[i+1];
-                       ac[i+3] = bc[i+0];
-               }
-       } else
-               memcpy(a, b, 16);
-}
-
 char *__fname_from_uuid(int id[4], int swap, char *buf, char sep)
 {
        int i, j;
@@ -650,17 +589,24 @@ 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)
+/**
+ * fname_from_uuid() - generate uuid string. Should not be used with super1.
+ * @info: info with uuid
+ * @buf: buf to fill.
+ *
+ * This routine should not be used with super1. See detail_fname_from_uuid() for details. It does
+ * not use superswitch swapuuid as it should be 0 but it has to do UUID conversion if host is big
+ * endian- left for backward compatibility.
+ */
+char *fname_from_uuid(struct mdinfo *info, char *buf)
 {
-       // 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);
+#if __BYTE_ORDER == BIG_ENDIAN
+       return __fname_from_uuid(info->uuid, true, buf, ':');
+#else
+       return __fname_from_uuid(info->uuid, false, buf, ':');
+#endif
 }
 
-#ifndef MDASSEMBLE
 int check_ext2(int fd, char *name)
 {
        /*
@@ -745,26 +691,69 @@ int check_raid(int fd, char *name)
        return 1;
 }
 
+int fstat_is_blkdev(int fd, char *devname, dev_t *rdev)
+{
+       struct stat stb;
+
+       if (fstat(fd, &stb) != 0) {
+               pr_err("fstat failed for %s: %s\n", devname, strerror(errno));
+               return 0;
+       }
+       if ((S_IFMT & stb.st_mode) != S_IFBLK) {
+               pr_err("%s is not a block device.\n", devname);
+               return 0;
+       }
+       if (rdev)
+               *rdev = stb.st_rdev;
+       return 1;
+}
+
+int stat_is_blkdev(char *devname, dev_t *rdev)
+{
+       struct stat stb;
+
+       if (stat(devname, &stb) != 0) {
+               pr_err("stat failed for %s: %s\n", devname, strerror(errno));
+               return 0;
+       }
+       if ((S_IFMT & stb.st_mode) != S_IFBLK) {
+               pr_err("%s is not a block device.\n", devname);
+               return 0;
+       }
+       if (rdev)
+               *rdev = stb.st_rdev;
+       return 1;
+}
+
+/**
+ * ask() - prompt user for "yes/no" dialog.
+ * @mesg: message to be printed, without '?' sign.
+ * Returns: 1 if 'Y/y', 0 otherwise.
+ *
+ * The default value is 'N/n', thus the caps on "N" on prompt.
+ */
 int ask(char *mesg)
 {
-       char *add = "";
-       int i;
-       for (i = 0; i < 5; i++) {
-               char buf[100];
-               fprintf(stderr, "%s%s", mesg, add);
-               fflush(stderr);
-               if (fgets(buf, 100, stdin)==NULL)
-                       return 0;
-               if (buf[0]=='y' || buf[0]=='Y')
-                       return 1;
-               if (buf[0]=='n' || buf[0]=='N')
-                       return 0;
-               add = "(y/n) ";
+       char buf[3] = {0};
+
+       fprintf(stderr, "%s [y/N]? ", mesg);
+       fflush(stderr);
+       if (fgets(buf, 3, stdin) == NULL)
+               return 0;
+       if (strlen(buf) == 1) {
+               pr_err("assuming no.\n");
+               return 0;
        }
-       pr_err("assuming 'no'\n");
+       if (buf[1] != '\n')
+               goto bad_option;
+       if (toupper(buf[0]) == 'Y')
+               return 1;
+       if (toupper(buf[0]) == 'N')
+               return 0;
+bad_option:
+       pr_err("bad option.\n");
        return 0;
 }
-#endif /* MDASSEMBLE */
 
 int is_standard(char *dev, int *nump)
 {
@@ -824,18 +813,18 @@ unsigned long calc_csum(void *super, int bytes)
        return csum;
 }
 
-#ifndef MDASSEMBLE
 char *human_size(long long bytes)
 {
        static char buf[47];
 
-       /* We convert bytes to either centi-M{ega,ibi}bytes or
-        * centi-G{igi,ibi}bytes, with appropriate rounding,
-        * and then print 1/100th of those as a decimal.
+       /* We convert bytes to either centi-M{ega,ibi}bytes,
+        * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes
+        * with appropriate rounding, and then print
+        * 1/100th of those as a decimal.
         * We allow upto 2048Megabytes before converting to
-        * gigabytes, as that shows more precision and isn't
+        * gigabytes and 2048Gigabytes before converting to
+        * terabytes, as that shows more precision and isn't
         * too large a number.
-        * Terabytes are not yet handled.
         */
 
        if (bytes < 5000*1024)
@@ -845,11 +834,16 @@ char *human_size(long long bytes)
                long cMB  = (bytes / ( 1000000LL / 200LL ) +1) /2;
                snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)",
                        cMiB/100, cMiB % 100, cMB/100, cMB % 100);
-       } else {
+       } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
                long cGiB = (bytes * 200LL / (1LL<<30) +1) / 2;
                long cGB  = (bytes / (1000000000LL/200LL ) +1) /2;
                snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)",
                        cGiB/100, cGiB % 100, cGB/100, cGB % 100);
+       } else {
+               long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2;
+               long cTB  = (bytes / (1000000000000LL / 200LL) + 1) / 2;
+               snprintf(buf, sizeof(buf), " (%ld.%02ld TiB %ld.%02ld TB)",
+                       cTiB/100, cTiB % 100, cTB/100, cTB % 100);
        }
        return buf;
 }
@@ -858,13 +852,14 @@ char *human_size_brief(long long bytes, int prefix)
 {
        static char buf[30];
 
-       /* We convert bytes to either centi-M{ega,ibi}bytes or
-        * centi-G{igi,ibi}bytes, with appropriate rounding,
-        * and then print 1/100th of those as a decimal.
+       /* We convert bytes to either centi-M{ega,ibi}bytes,
+        * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes
+        * with appropriate rounding, and then print
+        * 1/100th of those as a decimal.
         * We allow upto 2048Megabytes before converting to
-        * gigabytes, as that shows more precision and isn't
+        * gigabytes and 2048Gigabytes before converting to
+        * terabytes, as that shows more precision and isn't
         * too large a number.
-        * Terabytes are not yet handled.
         *
         * If prefix == IEC, we mean prefixes like kibi,mebi,gibi etc.
         * If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc.
@@ -877,10 +872,14 @@ char *human_size_brief(long long bytes, int prefix)
                        long cMiB = (bytes * 200LL / (1LL<<20) +1) /2;
                        snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
                                 cMiB/100, cMiB % 100);
-               } else {
+               } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
                        long cGiB = (bytes * 200LL / (1LL<<30) +1) /2;
                        snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
                                 cGiB/100, cGiB % 100);
+               } else {
+                       long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldTiB",
+                                cTiB/100, cTiB % 100);
                }
        }
        else if (prefix == JEDEC) {
@@ -888,10 +887,14 @@ char *human_size_brief(long long bytes, int prefix)
                        long cMB  = (bytes / ( 1000000LL / 200LL ) +1) /2;
                        snprintf(buf, sizeof(buf), "%ld.%02ldMB",
                                 cMB/100, cMB % 100);
-               } else {
+               } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
                        long cGB  = (bytes / (1000000000LL/200LL ) +1) /2;
                        snprintf(buf, sizeof(buf), "%ld.%02ldGB",
                                 cGB/100, cGB % 100);
+               } else {
+                       long cTB  = (bytes / (1000000000000LL / 200LL) + 1) / 2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldTB",
+                                cTB/100, cTB % 100);
                }
        }
        else
@@ -916,7 +919,6 @@ void print_r10_layout(int layout)
        if (near*far == 1)
                printf("NO REDUNDANCY");
 }
-#endif
 
 unsigned long long calc_array_size(int level, int raid_disks, int layout,
                                   int chunksize, unsigned long long devsize)
@@ -952,12 +954,12 @@ dev_t devnm2devid(char *devnm)
        /* First look in /sys/block/$DEVNM/dev for %d:%d
         * If that fails, try parsing out a number
         */
-       char path[100];
+       char path[PATH_MAX];
        char *ep;
        int fd;
        int mjr,mnr;
 
-       sprintf(path, "/sys/block/%s/dev", devnm);
+       snprintf(path, sizeof(path), "/sys/block/%s/dev", devnm);
        fd = open(path, O_RDONLY);
        if (fd >= 0) {
                char buf[20];
@@ -983,52 +985,74 @@ dev_t devnm2devid(char *devnm)
        return 0;
 }
 
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
-char *get_md_name(char *devnm)
+/**
+ * is_devname_numbered() - helper for numbered devname verification.
+ * @devname: path or name to check.
+ * @pref: expected devname prefix.
+ * @pref_len: prefix len.
+ */
+static bool is_devname_numbered(const char *devname, const char *pref, const int pref_len)
+{
+       int val;
+
+       assert(devname && pref);
+
+       if (strncmp(devname, pref, pref_len) != 0)
+               return false;
+
+       if (parse_num(&val, devname + pref_len) != 0)
+               return false;
+
+       if (val > 127)
+               return false;
+
+       return true;
+}
+
+/**
+ * is_devname_md_numbered() - check if &devname is numbered MD device (md).
+ * @devname: path or name to check.
+ */
+bool is_devname_md_numbered(const char *devname)
+{
+       return is_devname_numbered(devname, DEV_NUM_PREF, DEV_NUM_PREF_LEN);
+}
+
+/**
+ * is_devname_md_d_numbered() - check if &devname is secondary numbered MD device (md_d).
+ * @devname: path or name to check.
+ */
+bool is_devname_md_d_numbered(const char *devname)
 {
-       /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
-       /* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */
+       static const char d_dev[] = DEV_NUM_PREF "_d";
 
-       static char devname[50];
+       return is_devname_numbered(devname, d_dev, sizeof(d_dev) - 1);
+}
+
+/**
+ * get_md_name() - Get main dev node of the md device.
+ * @devnm: Md device name or path.
+ *
+ * Function checks if the full name was passed and returns md name
+ * if it is the MD device.
+ *
+ * Return: Main dev node of the md device or NULL if not found.
+ */
+char *get_md_name(char *devnm)
+{
+       static char devname[NAME_MAX];
        struct stat stb;
-       dev_t rdev = devnm2devid(devnm);
-       char *dn;
 
-       if (rdev == 0)
-               return 0;
-       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))
-                       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))
-               return devname;
+       if (strncmp(devnm, "/dev/", 5) == 0)
+               snprintf(devname, sizeof(devname), "%s", devnm);
+       else
+               snprintf(devname, sizeof(devname), "/dev/%s", devnm);
 
-       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 (!is_mddev(devname))
+               return NULL;
+       if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK)
                return devname;
 
-       dn = map_dev(major(rdev), minor(rdev), 0);
-       if (dn)
-               return dn;
-       snprintf(devname, sizeof(devname), "/dev/.tmp.%s", devnm);
-       if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
-               if (errno != EEXIST)
-                       return NULL;
-
-       if (stat(devname, &stb) == 0
-           && (S_IFMT&stb.st_mode) == S_IFBLK
-           && (stb.st_rdev == rdev))
-               return devname;
-       unlink(devname);
        return NULL;
 }
 
@@ -1037,7 +1061,6 @@ void put_md_name(char *name)
        if (strncmp(name, "/dev/.tmp.md", 12) == 0)
                unlink(name);
 }
-#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
 
 int get_maj_min(char *dev, int *major, int *minor)
 {
@@ -1048,6 +1071,20 @@ int get_maj_min(char *dev, int *major, int *minor)
                *e == 0);
 }
 
+/**
+ * is_bit_set() - get bit value by index.
+ * @val: value.
+ * @index: index of the bit (LSB numbering).
+ *
+ * Return: bit value.
+ */
+bool is_bit_set(int *val, unsigned char index)
+{
+       if ((*val) & (1 << index))
+               return true;
+       return false;
+}
+
 int dev_open(char *dev, int flags)
 {
        /* like 'open', but if 'dev' matches %d:%d, create a temp
@@ -1071,9 +1108,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);
                        }
@@ -1104,7 +1143,7 @@ int open_dev_excl(char *devnm)
        int i;
        int flags = O_RDWR;
        dev_t devid = devnm2devid(devnm);
-       long delay = 1000;
+       unsigned int delay = 1; // miliseconds
 
        sprintf(buf, "%d:%d", major(devid), minor(devid));
        for (i = 0; i < 25; i++) {
@@ -1117,8 +1156,8 @@ int open_dev_excl(char *devnm)
                }
                if (errno != EBUSY)
                        return fd;
-               usleep(delay);
-               if (delay < 200000)
+               sleep_for(0, MSEC_TO_NSEC(delay), true);
+               if (delay < 200)
                        delay *= 2;
        }
        return -1;
@@ -1142,7 +1181,7 @@ void wait_for(char *dev, int fd)
 {
        int i;
        struct stat stb_want;
-       long delay = 1000;
+       unsigned int delay = 1; // miliseconds
 
        if (fstat(fd, &stb_want) != 0 ||
            (stb_want.st_mode & S_IFMT) != S_IFBLK)
@@ -1154,12 +1193,12 @@ void wait_for(char *dev, int fd)
                    (stb.st_mode & S_IFMT) == S_IFBLK &&
                    (stb.st_rdev == stb_want.st_rdev))
                        return;
-               usleep(delay);
-               if (delay < 200000)
+               sleep_for(0, MSEC_TO_NSEC(delay), true);
+               if (delay < 200)
                        delay *= 2;
        }
        if (i == 25)
-               dprintf("timeout waiting for %s\n", dev);
+               pr_err("timeout waiting for %s\n", dev);
 }
 
 struct superswitch *superlist[] =
@@ -1167,9 +1206,8 @@ struct superswitch *superlist[] =
        &super0, &super1,
        &super_ddf, &super_imsm,
        &mbr, &gpt,
-       NULL };
-
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
+       NULL
+};
 
 struct supertype *super_by_fd(int fd, char **subarrayp)
 {
@@ -1183,6 +1221,11 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
        int i;
        char *subarray = NULL;
        char container[32] = "";
+       char *devnm = NULL;
+
+       devnm = fd2devnm(fd);
+       if (!devnm)
+               return NULL;
 
        sra = sysfs_read(fd, NULL, GET_VERSION);
 
@@ -1228,30 +1271,12 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
                if (subarrayp)
                        *subarrayp = subarray;
                strcpy(st->container_devnm, container);
-               strcpy(st->devnm, fd2devnm(fd));
+               strncpy(st->devnm, devnm, MD_NAME_MAX - 1);
        } else
                free(subarray);
 
        return st;
 }
-#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
-
-int dev_size_from_id(dev_t id, unsigned long long *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_size(fd, NULL, size)) {
-               close(fd);
-               return 1;
-       }
-       close(fd);
-       return 0;
-}
 
 struct supertype *dup_super(struct supertype *orig)
 {
@@ -1368,9 +1393,14 @@ int get_dev_sector_size(int fd, char *dname, unsigned int *sectsizep)
  */
 int must_be_container(int fd)
 {
+       struct mdinfo *mdi;
        unsigned long long size;
-       if (md_get_version(fd) < 0)
+
+       mdi = sysfs_read(fd, NULL, GET_VERSION);
+       if (!mdi)
                return 0;
+       sysfs_free(mdi);
+
        if (get_dev_size(fd, NULL, &size) == 0)
                return 1;
        if (size == 0)
@@ -1532,7 +1562,7 @@ int open_container(int fd)
        /* 'fd' is a block device.  Find out if it is in use
         * by a container, and return an open fd on that container.
         */
-       char path[256];
+       char path[288];
        char *e;
        DIR *dir;
        struct dirent *de;
@@ -1769,7 +1799,7 @@ int add_disk(int mdfd, struct supertype *st,
 {
        /* Add a device to an array, in one of 2 ways. */
        int rv;
-#ifndef MDASSEMBLE
+
        if (st->ss->external) {
                if (info->disk.state & (1<<MD_DISK_SYNC))
                        info->recovery_start = MaxSector;
@@ -1789,7 +1819,6 @@ int add_disk(int mdfd, struct supertype *st,
                        }
                }
        } else
-#endif
                rv = ioctl(mdfd, ADD_NEW_DISK, &info->disk);
        return rv;
 }
@@ -1798,12 +1827,11 @@ int remove_disk(int mdfd, struct supertype *st,
                struct mdinfo *sra, struct mdinfo *info)
 {
        int rv;
+
        /* Remove the disk given by 'info' from the array */
-#ifndef MDASSEMBLE
        if (st->ss->external)
-               rv = sysfs_set_str(sra, info, "slot", "none");
+               rv = sysfs_set_str(sra, info, "slot", STR_COMMON_NONE);
        else
-#endif
                rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major,
                                                          info->disk.minor));
        return rv;
@@ -1822,7 +1850,7 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force)
        while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 &&
               errno == EBUSY &&
               cnt-- > 0)
-               usleep(10000);
+               sleep_for(0, MSEC_TO_NSEC(10), true);
 
        return ret;
 }
@@ -1835,7 +1863,7 @@ int sys_hot_remove_disk(int statefd, int force)
        while ((ret = write(statefd, "remove", 6)) == -1 &&
               errno == EBUSY &&
               cnt-- > 0)
-               usleep(10000);
+               sleep_for(0, MSEC_TO_NSEC(10), true);
        return ret == 6 ? 0 : -1;
 }
 
@@ -1845,22 +1873,17 @@ int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
         * This varies between externally managed arrays
         * and older kernels
         */
-       int vers = md_get_version(mdfd);
+       mdu_array_info_t inf;
        int rv;
 
-#ifndef MDASSEMBLE
        if (st->ss->external)
-               rv = sysfs_set_array(info, vers);
-       else
-#endif
-               if ((vers % 100) >= 1) { /* can use different versions */
-               mdu_array_info_t inf;
-               memset(&inf, 0, sizeof(inf));
-               inf.major_version = info->array.major_version;
-               inf.minor_version = info->array.minor_version;
-               rv = ioctl(mdfd, SET_ARRAY_INFO, &inf);
-       } else
-               rv = ioctl(mdfd, SET_ARRAY_INFO, NULL);
+               return sysfs_set_array(info);
+
+       memset(&inf, 0, sizeof(inf));
+       inf.major_version = info->array.major_version;
+       inf.minor_version = info->array.minor_version;
+       rv = md_set_array_info(mdfd, &inf);
+
        return rv;
 }
 
@@ -1911,10 +1934,11 @@ int mdmon_running(char *devnm)
 
 int start_mdmon(char *devnm)
 {
-       int i, skipped;
+       int i;
        int len;
        pid_t pid;
        int status;
+       char *prefix = in_initrd() ? "initrd-" : "";
        char pathbuf[1024];
        char *paths[4] = {
                pathbuf,
@@ -1925,7 +1949,10 @@ int start_mdmon(char *devnm)
 
        if (check_env("MDADM_NO_MDMON"))
                return 0;
+       if (continue_via_systemd(devnm, MDMON_SERVICE, prefix))
+               return 0;
 
+       /* That failed, try running mdmon directly */
        len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf)-1);
        if (len > 0) {
                char *sl;
@@ -1939,51 +1966,9 @@ int start_mdmon(char *devnm)
        } else
                pathbuf[0] = '\0';
 
-       /* First try to run systemctl */
-       if (!check_env("MDADM_NO_SYSTEMCTL"))
-               switch(fork()) {
-               case 0:
-                       /* FIXME yuk. CLOSE_EXEC?? */
-                       skipped = 0;
-                       for (i = 3; skipped < 20; i++)
-                               if (close(i) < 0)
-                                       skipped++;
-                               else
-                                       skipped = 0;
-
-                       /* Don't want to see error messages from
-                        * systemctl.  If the service doesn't exist,
-                        * we start mdmon ourselves.
-                        */
-                       close(2);
-                       open("/dev/null", O_WRONLY);
-                       snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service",
-                                devnm);
-                       status = execl("/usr/bin/systemctl", "systemctl",
-                                      "start",
-                                      pathbuf, NULL);
-                       status = execl("/bin/systemctl", "systemctl", "start",
-                                      pathbuf, NULL);
-                       exit(1);
-               case -1: pr_err("cannot run mdmon. Array remains readonly\n");
-                       return -1;
-               default: /* parent - good */
-                       pid = wait(&status);
-                       if (pid >= 0 && status == 0)
-                               return 0;
-               }
-
-       /* That failed, try running mdmon directly */
        switch(fork()) {
        case 0:
-               /* FIXME yuk. CLOSE_EXEC?? */
-               skipped = 0;
-               for (i = 3; skipped < 20; i++)
-                       if (close(i) < 0)
-                               skipped++;
-                       else
-                               skipped = 0;
-
+               manage_fork_fds(1);
                for (i = 0; paths[i]; i++)
                        if (paths[i][0]) {
                                execl(paths[i], paths[i],
@@ -2034,7 +2019,6 @@ use_random:
        memcpy(buf, r, 16);
 }
 
-#ifndef MDASSEMBLE
 int flush_metadata_updates(struct supertype *st)
 {
        int sfd;
@@ -2076,21 +2060,69 @@ void append_metadata_update(struct supertype *st, void *buf, int len)
        *st->update_tail = mu;
        st->update_tail = &mu->next;
 }
-#endif /* MDASSEMBLE */
 
 #ifdef __TINYC__
 /* tinyc doesn't optimize this check in ioctl.h out ... */
 unsigned int __invalid_size_argument_for_IOC = 0;
 #endif
 
-int experimental(void)
+/**
+ * disk_fd_matches_criteria() - check if device matches spare criteria.
+ * @st: supertype, not NULL.
+ * @disk_fd: file descriptor of the disk.
+ * @sc: criteria to test.
+ *
+ * Return: true if disk matches criteria, false otherwise.
+ */
+bool disk_fd_matches_criteria(struct supertype *st, int disk_fd, struct spare_criteria *sc)
 {
-       if (check_env("MDADM_EXPERIMENTAL"))
-               return 1;
-       else {
-               pr_err("To use this feature MDADM_EXPERIMENTAL environment variable has to be defined.\n");
-               return 0;
-       }
+       unsigned int dev_sector_size = 0;
+       unsigned long long dev_size = 0;
+
+       if (!sc->criteria_set)
+               return true;
+
+       if (!get_dev_size(disk_fd, NULL, &dev_size) || dev_size < sc->min_size)
+               return false;
+
+       if (!get_dev_sector_size(disk_fd, NULL, &dev_sector_size) ||
+           sc->sector_size != dev_sector_size)
+               return false;
+
+       if (drive_test_and_add_policies(st, &sc->pols, disk_fd, 0))
+               return false;
+
+       return true;
+}
+
+/**
+ * devid_matches_criteria() - check if device referenced by devid matches spare criteria.
+ * @st: supertype, not NULL.
+ * @devid: devid of the device to check.
+ * @sc: criteria to test.
+ *
+ * Return: true if disk matches criteria, false otherwise.
+ */
+bool devid_matches_criteria(struct supertype *st, dev_t devid, struct spare_criteria *sc)
+{
+       char buf[NAME_MAX];
+       bool ret;
+       int fd;
+
+       if (!sc->criteria_set)
+               return true;
+
+       snprintf(buf, NAME_MAX, "%d:%d", major(devid), minor(devid));
+
+       fd = dev_open(buf, O_RDONLY);
+       if (!is_fd_valid(fd))
+               return false;
+
+       /* Error code inherited */
+       ret = disk_fd_matches_criteria(st, fd, sc);
+
+       close(fd);
+       return ret;
 }
 
 /* Pick all spares matching given criteria from a container
@@ -2099,7 +2131,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)
@@ -2116,17 +2148,14 @@ struct mdinfo *container_choose_spares(struct supertype *st,
        dp = &disks->devs;
        disks->array.spare_disks = 0;
        while (*dp) {
-               int found = 0;
+               bool found = false;
+
                d = *dp;
                if (d->disk.state == 0) {
-                       /* check if size is acceptable */
-                       unsigned long long dev_size;
                        dev_t dev = makedev(d->disk.major,d->disk.minor);
 
-                       if (!min_size ||
-                          (dev_size_from_id(dev,  &dev_size) &&
-                           dev_size >= min_size))
-                               found = 1;
+                       found = devid_matches_criteria(st, dev, criteria);
+
                        /* check if domain matches */
                        if (found && domlist) {
                                struct dev_policy *pol = devid_policy(dev);
@@ -2134,7 +2163,8 @@ struct mdinfo *container_choose_spares(struct supertype *st,
                                        pol_add(&pol, pol_domain,
                                                spare_group, NULL);
                                if (domain_test(domlist, pol, metadata) != 1)
-                                       found = 0;
+                                       found = false;
+
                                dev_policy_free(pol);
                        }
                }
@@ -2180,8 +2210,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;
@@ -2189,17 +2218,84 @@ void enable_fds(int devices)
        setrlimit(RLIMIT_NOFILE, &lim);
 }
 
+/* Close all opened descriptors if needed and redirect
+ * streams to /dev/null.
+ * For debug purposed, leave STDOUT and STDERR untouched
+ * Returns:
+ *     1- if any error occurred
+ *     0- otherwise
+ */
+void manage_fork_fds(int close_all)
+{
+       DIR *dir;
+       struct dirent *dirent;
+
+       close(0);
+       open("/dev/null", O_RDWR);
+
+#ifndef DEBUG
+       dup2(0, 1);
+       dup2(0, 2);
+#endif
+
+       if (close_all == 0)
+               return;
+
+       dir = opendir("/proc/self/fd");
+       if (!dir) {
+               pr_err("Cannot open /proc/self/fd directory.\n");
+               return;
+       }
+       for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
+               int fd = -1;
+
+               if ((strcmp(dirent->d_name, ".") == 0) ||
+                   (strcmp(dirent->d_name, "..")) == 0)
+                       continue;
+
+               fd = strtol(dirent->d_name, NULL, 10);
+               if (fd > 2)
+                       close(fd);
+       }
+}
+
+/* In a systemd/udev world, it is best to get systemd to
+ * run daemon rather than running in the background.
+ * Returns:
+ *     1- if systemd service has been started
+ *     0- otherwise
+ */
+int continue_via_systemd(char *devnm, char *service_name, char *prefix)
+{
+       int pid, status;
+       char pathbuf[1024];
+
+       /* Simply return that service cannot be started */
+       if (check_env("MDADM_NO_SYSTEMCTL"))
+               return 0;
+       switch (fork()) {
+       case  0:
+               manage_fork_fds(1);
+               snprintf(pathbuf, sizeof(pathbuf),
+                        "%s@%s%s.service", service_name, prefix ?: "", devnm);
+               status = execl("/usr/bin/systemctl", "systemctl", "restart",
+                              pathbuf, NULL);
+               status = execl("/bin/systemctl", "systemctl", "restart",
+                              pathbuf, NULL);
+               exit(1);
+       case -1: /* Just do it ourselves. */
+               break;
+       default: /* parent - good */
+               pid = wait(&status);
+               if (pid >= 0 && status == 0)
+                       return 1;
+       }
+       return 0;
+}
+
 int in_initrd(void)
 {
-       /* This is based on similar function in systemd. */
-       struct statfs s;
-       /* statfs.f_type is signed long on s390x and MIPS, causing all
-          sorts of sign extension problems with RAMFS_MAGIC being
-          defined as 0x858458f6 */
-       return  statfs("/", &s) >= 0 &&
-               ((unsigned long)s.f_type == TMPFS_MAGIC ||
-                ((unsigned long)s.f_type & 0xFFFFFFFFUL) ==
-                ((unsigned long)RAMFS_MAGIC & 0xFFFFFFFFUL));
+       return access("/etc/initrd-release", F_OK) >= 0;
 }
 
 void reopen_mddev(int mdfd)
@@ -2216,7 +2312,6 @@ void reopen_mddev(int mdfd)
                dup2(fd, mdfd);
 }
 
-#ifndef MDASSEMBLE
 static struct cmap_hooks *cmap_hooks = NULL;
 static int is_cmap_hooks_ready = 0;
 
@@ -2227,8 +2322,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 ||
@@ -2271,16 +2368,22 @@ 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->open_lockspace =
+               dlsym(dlm_hooks->dlm_handle, "dlm_open_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_unlock_wait =
+               dlsym(dlm_hooks->dlm_handle, "dlm_ls_unlock_wait");
        dlm_hooks->ls_get_fd = dlsym(dlm_hooks->dlm_handle, "dlm_ls_get_fd");
        dlm_hooks->dispatch = dlsym(dlm_hooks->dlm_handle, "dlm_dispatch");
 
-       if (!dlm_hooks->create_lockspace || !dlm_hooks->ls_lock ||
-           !dlm_hooks->ls_unlock || !dlm_hooks->release_lockspace ||
-           !dlm_hooks->ls_get_fd || !dlm_hooks->dispatch)
+       if (!dlm_hooks->open_lockspace || !dlm_hooks->create_lockspace ||
+           !dlm_hooks->ls_lock || !dlm_hooks->ls_unlock_wait ||
+           !dlm_hooks->release_lockspace || !dlm_hooks->ls_get_fd ||
+           !dlm_hooks->dispatch)
                dlclose(dlm_hooks->dlm_handle);
        else
                is_dlm_hooks_ready = 1;
@@ -2291,4 +2394,120 @@ void set_hooks(void)
        set_dlm_hooks();
        set_cmap_hooks();
 }
-#endif
+
+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;
+}
+
+/**
+ * sleep_for() - Sleeps for specified time.
+ * @sec: Seconds to sleep for.
+ * @nsec: Nanoseconds to sleep for, has to be less than one second.
+ * @wake_after_interrupt: If set, wake up if interrupted.
+ *
+ * Function immediately returns if error different than EINTR occurs.
+ */
+void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt)
+{
+       struct timespec delay = {.tv_sec = sec, .tv_nsec = nsec};
+
+       assert(nsec < MSEC_TO_NSEC(1000));
+
+       do {
+               errno = 0;
+               nanosleep(&delay, &delay);
+               if (errno != 0 && errno != EINTR) {
+                       pr_err("Error sleeping for %us %ldns: %s\n", sec, nsec, strerror(errno));
+                       return;
+               }
+       } while (!wake_after_interrupt && errno == EINTR);
+}
+
+/* is_directory() - Checks if directory provided by path is indeed a regular directory.
+ * @path: directory path to be checked
+ *
+ * Doesn't accept symlinks.
+ *
+ * Return: true if is a directory, false if not
+ */
+bool is_directory(const char *path)
+{
+       struct stat st;
+
+       if (lstat(path, &st) != 0) {
+               pr_err("%s: %s\n", strerror(errno), path);
+               return false;
+       }
+
+       if (!S_ISDIR(st.st_mode))
+               return false;
+
+       return true;
+}
+
+/*
+ * is_file() - Checks if file provided by path is indeed a regular file.
+ * @path: file path to be checked
+ *
+ * Doesn't accept symlinks.
+ *
+ * Return: true if is  a file, false if not
+ */
+bool is_file(const char *path)
+{
+       struct stat st;
+
+       if (lstat(path, &st) != 0) {
+               pr_err("%s: %s\n", strerror(errno), path);
+               return false;
+       }
+
+       if (!S_ISREG(st.st_mode))
+               return false;
+
+       return true;
+}