]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
mdadm: improve the dlm locking mechanism for clustered raid
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index aa27e59de7b8807c0664e04b829f6bb47a21e0f0..4adbbff0295e30c984f59b5c5a5c4bfe024e1d60 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>
@@ -89,7 +90,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 +128,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 +147,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(10);
+                       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 +209,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 +226,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 = ioctl(fd, GET_ARRAY_INFO, &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
@@ -220,6 +290,14 @@ int md_get_array_info(int fd, struct mdu_array_info_s *array)
        return ioctl(fd, GET_ARRAY_INFO, array);
 }
 
+/*
+ * Set array info
+ */
+int md_set_array_info(int fd, struct mdu_array_info_s *array)
+{
+       return ioctl(fd, SET_ARRAY_INFO, array);
+}
+
 /*
  * Get disk info from the kernel.
  */
@@ -265,35 +343,6 @@ int parse_uuid(char *str, int uuid[4])
        return 0;
 }
 
-/*
- * 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
- */
-
-int md_get_version(int fd)
-{
-       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;
-}
-
 int get_linux_version()
 {
        struct utsname name;
@@ -312,7 +361,6 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
-#ifndef MDASSEMBLE
 int mdadm_version(char *version)
 {
        int a, b, c;
@@ -374,6 +422,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;
@@ -418,7 +477,6 @@ long parse_num(char *num)
        else
                return rv;
 }
-#endif
 
 int parse_cluster_confirm_arg(char *input, char **devname, int *slot)
 {
@@ -549,37 +607,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)
@@ -650,17 +677,18 @@ 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);
 }
 
-#ifndef MDASSEMBLE
 int check_ext2(int fd, char *name)
 {
        /*
@@ -745,6 +773,40 @@ 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;
+}
+
 int ask(char *mesg)
 {
        char *add = "";
@@ -764,7 +826,6 @@ int ask(char *mesg)
        pr_err("assuming 'no'\n");
        return 0;
 }
-#endif /* MDASSEMBLE */
 
 int is_standard(char *dev, int *nump)
 {
@@ -824,7 +885,6 @@ unsigned long calc_csum(void *super, int bytes)
        return csum;
 }
 
-#ifndef MDASSEMBLE
 char *human_size(long long bytes)
 {
        static char buf[47];
@@ -916,7 +976,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)
@@ -983,7 +1042,6 @@ dev_t devnm2devid(char *devnm)
        return 0;
 }
 
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
 char *get_md_name(char *devnm)
 {
        /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
@@ -999,21 +1057,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);
@@ -1024,9 +1079,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;
@@ -1037,7 +1091,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)
 {
@@ -1071,9 +1124,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);
                        }
@@ -1159,7 +1214,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[] =
@@ -1167,9 +1222,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)
 {
@@ -1234,7 +1288,6 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
 
        return st;
 }
-#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
 
 int dev_size_from_id(dev_t id, unsigned long long *size)
 {
@@ -1253,6 +1306,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;
@@ -1368,9 +1438,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)
@@ -1769,7 +1844,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 +1864,6 @@ int add_disk(int mdfd, struct supertype *st,
                        }
                }
        } else
-#endif
                rv = ioctl(mdfd, ADD_NEW_DISK, &info->disk);
        return rv;
 }
@@ -1798,12 +1872,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");
        else
-#endif
                rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major,
                                                          info->disk.minor));
        return rv;
@@ -1845,22 +1918,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, 9003);
+               
+       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;
 }
 
@@ -2034,7 +2102,6 @@ use_random:
        memcpy(buf, r, 16);
 }
 
-#ifndef MDASSEMBLE
 int flush_metadata_updates(struct supertype *st)
 {
        int sfd;
@@ -2076,7 +2143,6 @@ 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 ... */
@@ -2099,7 +2165,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)
@@ -2121,12 +2187,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);
@@ -2180,8 +2258,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;
@@ -2216,7 +2293,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 +2303,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 +2349,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 +2375,51 @@ 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;
+}