+static int is_dlm_hooks_ready = 0;
+
+int dlm_funs_ready(void)
+{
+ return is_dlm_hooks_ready ? 1 : 0;
+}
+
+static struct dlm_hooks *dlm_hooks = NULL;
+struct dlm_lock_resource *dlm_lock_res = NULL;
+static int ast_called = 0;
+
+struct dlm_lock_resource {
+ dlm_lshandle_t *ls;
+ struct dlm_lksb lksb;
+};
+
+/* Using poll(2) to wait for and dispatch ASTs */
+static int poll_for_ast(dlm_lshandle_t ls)
+{
+ struct pollfd pfd;
+
+ pfd.fd = dlm_hooks->ls_get_fd(ls);
+ pfd.events = POLLIN;
+
+ while (!ast_called)
+ {
+ if (poll(&pfd, 1, 0) < 0)
+ {
+ perror("poll");
+ return -1;
+ }
+ dlm_hooks->dispatch(dlm_hooks->ls_get_fd(ls));
+ }
+ ast_called = 0;
+
+ return 0;
+}
+
+static void dlm_ast(void *arg)
+{
+ ast_called = 1;
+}
+
+static char *cluster_name = NULL;
+/* Create the lockspace, take bitmapXXX locks on all the bitmaps. */
+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) {
+ pr_err("The md can't get cluster name\n");
+ return -1;
+ }
+
+ dlm_lock_res = xmalloc(sizeof(struct dlm_lock_resource));
+ dlm_lock_res->ls = dlm_hooks->open_lockspace(cluster_name);
+ if (!dlm_lock_res->ls) {
+ 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);
+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);
+
+ if (dlm_lock_res->lksb.sb_status) {
+ pr_err("failed to lock cluster\n");
+ return -1;
+ }
+ return 1;
+}
+
+int cluster_release_dlmlock(void)
+{
+ int ret = -1;
+
+ if (!cluster_name)
+ goto out;
+
+ if (!dlm_lock_res->lksb.sb_lkid)
+ goto out;
+
+ 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 */
+ goto out;
+ }
+
+ /* Wait for it to complete */
+ poll_for_ast(dlm_lock_res->ls);
+
+ errno = dlm_lock_res->lksb.sb_status;
+ if (errno != EUNLOCK) {
+ pr_err("error %d happened in ast when unlock lockspace\n",
+ errno);
+ /* XXX make sure the lockspace is unlocked eventually */
+ goto out;
+ }
+
+ ret = dlm_hooks->release_lockspace(cluster_name, dlm_lock_res->ls, 1);
+ if (ret) {
+ pr_err("error %d happened when release lockspace\n", errno);
+ /* XXX make sure the lockspace is released eventually */
+ goto out;
+ }
+ free(dlm_lock_res);
+
+out:
+ return ret;
+}
+
+int md_array_valid(int fd)
+{
+ 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 md_array_active(int fd)
+{
+ 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);
+}
+
+/*
+ * Get array info from the kernel. Longer term we want to deprecate the
+ * ioctl and get it from sysfs.
+ */
+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.
+ */
+int md_get_disk_info(int fd, struct mdu_disk_info_s *disk)
+{
+ return ioctl(fd, GET_DISK_INFO, disk);
+}
+