blob: 1f3c8f39ecb2a2b4dcd12b936983b47bbc10e0de [file] [log] [blame]
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -06001/*
2 * Copyright (C) 2015, SUSE
3 *
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)
7 * any later version.
8 *
9 */
10
11
12#include <linux/module.h>
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060013#include <linux/dlm.h>
14#include <linux/sched.h>
15#include "md.h"
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -050016#include "md-cluster.h"
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060017
18#define LVB_SIZE 64
19
20struct dlm_lock_resource {
21 dlm_lockspace_t *ls;
22 struct dlm_lksb lksb;
23 char *name; /* lock name. */
24 uint32_t flags; /* flags to pass to dlm_lock() */
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060025 struct completion completion; /* completion for synchronized locking */
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050026 void (*bast)(void *arg, int mode); /* blocking AST function pointer*/
27 struct mddev *mddev; /* pointing back to mddev. */
28};
29
30struct md_cluster_info {
31 /* dlm lock space and resources for clustered raid. */
32 dlm_lockspace_t *lockspace;
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -050033 int slot_number;
34 struct completion completion;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050035 struct dlm_lock_resource *sb_lock;
36 struct mutex sb_mutex;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060037};
38
39static void sync_ast(void *arg)
40{
41 struct dlm_lock_resource *res;
42
43 res = (struct dlm_lock_resource *) arg;
44 complete(&res->completion);
45}
46
47static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
48{
49 int ret = 0;
50
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);
55 if (ret)
56 return ret;
57 wait_for_completion(&res->completion);
58 return res->lksb.sb_status;
59}
60
61static int dlm_unlock_sync(struct dlm_lock_resource *res)
62{
63 return dlm_lock_sync(res, DLM_LOCK_NL);
64}
65
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050066static struct dlm_lock_resource *lockres_init(struct mddev *mddev,
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060067 char *name, void (*bastfn)(void *arg, int mode), int with_lvb)
68{
69 struct dlm_lock_resource *res = NULL;
70 int ret, namelen;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050071 struct md_cluster_info *cinfo = mddev->cluster_info;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060072
73 res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL);
74 if (!res)
75 return NULL;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050076 res->ls = cinfo->lockspace;
77 res->mddev = mddev;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060078 namelen = strlen(name);
79 res->name = kzalloc(namelen + 1, GFP_KERNEL);
80 if (!res->name) {
81 pr_err("md-cluster: Unable to allocate resource name for resource %s\n", name);
82 goto out_err;
83 }
84 strlcpy(res->name, name, namelen + 1);
85 if (with_lvb) {
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);
89 goto out_err;
90 }
91 res->flags = DLM_LKF_VALBLK;
92 }
93
94 if (bastfn)
95 res->bast = bastfn;
96
97 res->flags |= DLM_LKF_EXPEDITE;
98
99 ret = dlm_lock_sync(res, DLM_LOCK_NL);
100 if (ret) {
101 pr_err("md-cluster: Unable to lock NL on new lock resource %s\n", name);
102 goto out_err;
103 }
104 res->flags &= ~DLM_LKF_EXPEDITE;
105 res->flags |= DLM_LKF_CONVERT;
106
107 return res;
108out_err:
109 kfree(res->lksb.sb_lvbptr);
110 kfree(res->name);
111 kfree(res);
112 return NULL;
113}
114
115static void lockres_free(struct dlm_lock_resource *res)
116{
117 if (!res)
118 return;
119
120 init_completion(&res->completion);
121 dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res);
122 wait_for_completion(&res->completion);
123
124 kfree(res->name);
125 kfree(res->lksb.sb_lvbptr);
126 kfree(res);
127}
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600128
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500129static char *pretty_uuid(char *dest, char *src)
130{
131 int i, len = 0;
132
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]);
137 }
138 return dest;
139}
140
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500141static void recover_prep(void *arg)
142{
143}
144
145static void recover_slot(void *arg, struct dlm_slot *slot)
146{
147 struct mddev *mddev = arg;
148 struct md_cluster_info *cinfo = mddev->cluster_info;
149
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,
153 cinfo->slot_number);
154}
155
156static void recover_done(void *arg, struct dlm_slot *slots,
157 int num_slots, int our_slot,
158 uint32_t generation)
159{
160 struct mddev *mddev = arg;
161 struct md_cluster_info *cinfo = mddev->cluster_info;
162
163 cinfo->slot_number = our_slot;
164 complete(&cinfo->completion);
165}
166
167static const struct dlm_lockspace_ops md_ls_ops = {
168 .recover_prep = recover_prep,
169 .recover_slot = recover_slot,
170 .recover_done = recover_done,
171};
172
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500173static int join(struct mddev *mddev, int nodes)
174{
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500175 struct md_cluster_info *cinfo;
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500176 int ret, ops_rv;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500177 char str[64];
178
179 if (!try_module_get(THIS_MODULE))
180 return -ENOENT;
181
182 cinfo = kzalloc(sizeof(struct md_cluster_info), GFP_KERNEL);
183 if (!cinfo)
184 return -ENOMEM;
185
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500186 init_completion(&cinfo->completion);
187
188 mutex_init(&cinfo->sb_mutex);
189 mddev->cluster_info = cinfo;
190
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500191 memset(str, 0, 64);
192 pretty_uuid(str, mddev->uuid);
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500193 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);
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500196 if (ret)
197 goto err;
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500198 wait_for_completion(&cinfo->completion);
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500199 cinfo->sb_lock = lockres_init(mddev, "cmd-super",
200 NULL, 0);
201 if (!cinfo->sb_lock) {
202 ret = -ENOMEM;
203 goto err;
204 }
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500205 return 0;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500206err:
207 if (cinfo->lockspace)
208 dlm_release_lockspace(cinfo->lockspace, 2);
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500209 mddev->cluster_info = NULL;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500210 kfree(cinfo);
211 module_put(THIS_MODULE);
212 return ret;
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500213}
214
215static int leave(struct mddev *mddev)
216{
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500217 struct md_cluster_info *cinfo = mddev->cluster_info;
218
219 if (!cinfo)
220 return 0;
221 lockres_free(cinfo->sb_lock);
222 dlm_release_lockspace(cinfo->lockspace, 2);
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500223 return 0;
224}
225
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500226/* 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
229 */
230static int slot_number(struct mddev *mddev)
231{
232 struct md_cluster_info *cinfo = mddev->cluster_info;
233
234 return cinfo->slot_number - 1;
235}
236
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500237static struct md_cluster_operations cluster_ops = {
238 .join = join,
239 .leave = leave,
Goldwyn Rodriguescf921cc2014-03-30 00:42:49 -0500240 .slot_number = slot_number,
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500241};
242
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600243static int __init cluster_init(void)
244{
245 pr_warn("md-cluster: EXPERIMENTAL. Use with caution\n");
246 pr_info("Registering Cluster MD functions\n");
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500247 register_md_cluster_operations(&cluster_ops, THIS_MODULE);
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600248 return 0;
249}
250
251static void cluster_exit(void)
252{
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500253 unregister_md_cluster_operations();
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600254}
255
256module_init(cluster_init);
257module_exit(cluster_exit);
258MODULE_LICENSE("GPL");
259MODULE_DESCRIPTION("Clustering support for MD");