2 * Copyright (C) 2015, SUSE
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
12 #include <linux/module.h>
13 #include <linux/dlm.h>
14 #include <linux/sched.h>
16 #include "md-cluster.h"
20 struct dlm_lock_resource {
23 char *name; /* lock name. */
24 uint32_t flags; /* flags to pass to dlm_lock() */
25 struct completion completion; /* completion for synchronized locking */
26 void (*bast)(void *arg, int mode); /* blocking AST function pointer*/
27 struct mddev *mddev; /* pointing back to mddev. */
30 struct md_cluster_info {
31 /* dlm lock space and resources for clustered raid. */
32 dlm_lockspace_t *lockspace;
34 struct completion completion;
35 struct dlm_lock_resource *sb_lock;
36 struct mutex sb_mutex;
39 static void sync_ast(void *arg)
41 struct dlm_lock_resource *res;
43 res = (struct dlm_lock_resource *) arg;
44 complete(&res->completion);
47 static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
51 init_completion(&res->completion);
52 ret = dlm_lock(res->ls, mode, &res->lksb,
53 res->flags, res->name, strlen(res->name),
54 0, sync_ast, res, res->bast);
57 wait_for_completion(&res->completion);
58 return res->lksb.sb_status;
61 static int dlm_unlock_sync(struct dlm_lock_resource *res)
63 return dlm_lock_sync(res, DLM_LOCK_NL);
66 static struct dlm_lock_resource *lockres_init(struct mddev *mddev,
67 char *name, void (*bastfn)(void *arg, int mode), int with_lvb)
69 struct dlm_lock_resource *res = NULL;
71 struct md_cluster_info *cinfo = mddev->cluster_info;
73 res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL);
76 res->ls = cinfo->lockspace;
78 namelen = strlen(name);
79 res->name = kzalloc(namelen + 1, GFP_KERNEL);
81 pr_err("md-cluster: Unable to allocate resource name for resource %s\n", name);
84 strlcpy(res->name, name, namelen + 1);
86 res->lksb.sb_lvbptr = kzalloc(LVB_SIZE, GFP_KERNEL);
87 if (!res->lksb.sb_lvbptr) {
88 pr_err("md-cluster: Unable to allocate LVB for resource %s\n", name);
91 res->flags = DLM_LKF_VALBLK;
97 res->flags |= DLM_LKF_EXPEDITE;
99 ret = dlm_lock_sync(res, DLM_LOCK_NL);
101 pr_err("md-cluster: Unable to lock NL on new lock resource %s\n", name);
104 res->flags &= ~DLM_LKF_EXPEDITE;
105 res->flags |= DLM_LKF_CONVERT;
109 kfree(res->lksb.sb_lvbptr);
115 static void lockres_free(struct dlm_lock_resource *res)
120 init_completion(&res->completion);
121 dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res);
122 wait_for_completion(&res->completion);
125 kfree(res->lksb.sb_lvbptr);
129 static char *pretty_uuid(char *dest, char *src)
133 for (i = 0; i < 16; i++) {
134 if (i == 4 || i == 6 || i == 8 || i == 10)
135 len += sprintf(dest + len, "-");
136 len += sprintf(dest + len, "%02x", (__u8)src[i]);
141 static void recover_prep(void *arg)
145 static void recover_slot(void *arg, struct dlm_slot *slot)
147 struct mddev *mddev = arg;
148 struct md_cluster_info *cinfo = mddev->cluster_info;
150 pr_info("md-cluster: %s Node %d/%d down. My slot: %d. Initiating recovery.\n",
151 mddev->bitmap_info.cluster_name,
152 slot->nodeid, slot->slot,
156 static void recover_done(void *arg, struct dlm_slot *slots,
157 int num_slots, int our_slot,
160 struct mddev *mddev = arg;
161 struct md_cluster_info *cinfo = mddev->cluster_info;
163 cinfo->slot_number = our_slot;
164 complete(&cinfo->completion);
167 static const struct dlm_lockspace_ops md_ls_ops = {
168 .recover_prep = recover_prep,
169 .recover_slot = recover_slot,
170 .recover_done = recover_done,
173 static int join(struct mddev *mddev, int nodes)
175 struct md_cluster_info *cinfo;
179 if (!try_module_get(THIS_MODULE))
182 cinfo = kzalloc(sizeof(struct md_cluster_info), GFP_KERNEL);
186 init_completion(&cinfo->completion);
188 mutex_init(&cinfo->sb_mutex);
189 mddev->cluster_info = cinfo;
192 pretty_uuid(str, mddev->uuid);
193 ret = dlm_new_lockspace(str, mddev->bitmap_info.cluster_name,
194 DLM_LSFL_FS, LVB_SIZE,
195 &md_ls_ops, mddev, &ops_rv, &cinfo->lockspace);
198 wait_for_completion(&cinfo->completion);
199 cinfo->sb_lock = lockres_init(mddev, "cmd-super",
201 if (!cinfo->sb_lock) {
207 if (cinfo->lockspace)
208 dlm_release_lockspace(cinfo->lockspace, 2);
209 mddev->cluster_info = NULL;
211 module_put(THIS_MODULE);
215 static int leave(struct mddev *mddev)
217 struct md_cluster_info *cinfo = mddev->cluster_info;
221 lockres_free(cinfo->sb_lock);
222 dlm_release_lockspace(cinfo->lockspace, 2);
226 /* slot_number(): Returns the MD slot number to use
227 * DLM starts the slot numbers from 1, wheras cluster-md
228 * wants the number to be from zero, so we deduct one
230 static int slot_number(struct mddev *mddev)
232 struct md_cluster_info *cinfo = mddev->cluster_info;
234 return cinfo->slot_number - 1;
237 static struct md_cluster_operations cluster_ops = {
240 .slot_number = slot_number,
243 static int __init cluster_init(void)
245 pr_warn("md-cluster: EXPERIMENTAL. Use with caution\n");
246 pr_info("Registering Cluster MD functions\n");
247 register_md_cluster_operations(&cluster_ops, THIS_MODULE);
251 static void cluster_exit(void)
253 unregister_md_cluster_operations();
256 module_init(cluster_init);
257 module_exit(cluster_exit);
258 MODULE_LICENSE("GPL");
259 MODULE_DESCRIPTION("Clustering support for MD");