blob: d141d4812c8c4fedfaaaf9e8648116fd5ab7d986 [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;
33 struct dlm_lock_resource *sb_lock;
34 struct mutex sb_mutex;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060035};
36
37static void sync_ast(void *arg)
38{
39 struct dlm_lock_resource *res;
40
41 res = (struct dlm_lock_resource *) arg;
42 complete(&res->completion);
43}
44
45static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
46{
47 int ret = 0;
48
49 init_completion(&res->completion);
50 ret = dlm_lock(res->ls, mode, &res->lksb,
51 res->flags, res->name, strlen(res->name),
52 0, sync_ast, res, res->bast);
53 if (ret)
54 return ret;
55 wait_for_completion(&res->completion);
56 return res->lksb.sb_status;
57}
58
59static int dlm_unlock_sync(struct dlm_lock_resource *res)
60{
61 return dlm_lock_sync(res, DLM_LOCK_NL);
62}
63
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050064static struct dlm_lock_resource *lockres_init(struct mddev *mddev,
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060065 char *name, void (*bastfn)(void *arg, int mode), int with_lvb)
66{
67 struct dlm_lock_resource *res = NULL;
68 int ret, namelen;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050069 struct md_cluster_info *cinfo = mddev->cluster_info;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060070
71 res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL);
72 if (!res)
73 return NULL;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -050074 res->ls = cinfo->lockspace;
75 res->mddev = mddev;
Goldwyn Rodrigues47741b72014-03-07 13:49:26 -060076 namelen = strlen(name);
77 res->name = kzalloc(namelen + 1, GFP_KERNEL);
78 if (!res->name) {
79 pr_err("md-cluster: Unable to allocate resource name for resource %s\n", name);
80 goto out_err;
81 }
82 strlcpy(res->name, name, namelen + 1);
83 if (with_lvb) {
84 res->lksb.sb_lvbptr = kzalloc(LVB_SIZE, GFP_KERNEL);
85 if (!res->lksb.sb_lvbptr) {
86 pr_err("md-cluster: Unable to allocate LVB for resource %s\n", name);
87 goto out_err;
88 }
89 res->flags = DLM_LKF_VALBLK;
90 }
91
92 if (bastfn)
93 res->bast = bastfn;
94
95 res->flags |= DLM_LKF_EXPEDITE;
96
97 ret = dlm_lock_sync(res, DLM_LOCK_NL);
98 if (ret) {
99 pr_err("md-cluster: Unable to lock NL on new lock resource %s\n", name);
100 goto out_err;
101 }
102 res->flags &= ~DLM_LKF_EXPEDITE;
103 res->flags |= DLM_LKF_CONVERT;
104
105 return res;
106out_err:
107 kfree(res->lksb.sb_lvbptr);
108 kfree(res->name);
109 kfree(res);
110 return NULL;
111}
112
113static void lockres_free(struct dlm_lock_resource *res)
114{
115 if (!res)
116 return;
117
118 init_completion(&res->completion);
119 dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res);
120 wait_for_completion(&res->completion);
121
122 kfree(res->name);
123 kfree(res->lksb.sb_lvbptr);
124 kfree(res);
125}
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600126
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500127static char *pretty_uuid(char *dest, char *src)
128{
129 int i, len = 0;
130
131 for (i = 0; i < 16; i++) {
132 if (i == 4 || i == 6 || i == 8 || i == 10)
133 len += sprintf(dest + len, "-");
134 len += sprintf(dest + len, "%02x", (__u8)src[i]);
135 }
136 return dest;
137}
138
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500139static int join(struct mddev *mddev, int nodes)
140{
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500141 struct md_cluster_info *cinfo;
142 int ret;
143 char str[64];
144
145 if (!try_module_get(THIS_MODULE))
146 return -ENOENT;
147
148 cinfo = kzalloc(sizeof(struct md_cluster_info), GFP_KERNEL);
149 if (!cinfo)
150 return -ENOMEM;
151
152 memset(str, 0, 64);
153 pretty_uuid(str, mddev->uuid);
154 ret = dlm_new_lockspace(str, NULL, DLM_LSFL_FS, LVB_SIZE,
155 NULL, NULL, NULL, &cinfo->lockspace);
156 if (ret)
157 goto err;
158 cinfo->sb_lock = lockres_init(mddev, "cmd-super",
159 NULL, 0);
160 if (!cinfo->sb_lock) {
161 ret = -ENOMEM;
162 goto err;
163 }
164 mutex_init(&cinfo->sb_mutex);
165 mddev->cluster_info = cinfo;
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500166 return 0;
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500167err:
168 if (cinfo->lockspace)
169 dlm_release_lockspace(cinfo->lockspace, 2);
170 kfree(cinfo);
171 module_put(THIS_MODULE);
172 return ret;
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500173}
174
175static int leave(struct mddev *mddev)
176{
Goldwyn Rodriguesc4ce8672014-03-29 10:20:02 -0500177 struct md_cluster_info *cinfo = mddev->cluster_info;
178
179 if (!cinfo)
180 return 0;
181 lockres_free(cinfo->sb_lock);
182 dlm_release_lockspace(cinfo->lockspace, 2);
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500183 return 0;
184}
185
186static struct md_cluster_operations cluster_ops = {
187 .join = join,
188 .leave = leave,
189};
190
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600191static int __init cluster_init(void)
192{
193 pr_warn("md-cluster: EXPERIMENTAL. Use with caution\n");
194 pr_info("Registering Cluster MD functions\n");
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500195 register_md_cluster_operations(&cluster_ops, THIS_MODULE);
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600196 return 0;
197}
198
199static void cluster_exit(void)
200{
Goldwyn Rodriguesedb39c92014-03-29 10:01:53 -0500201 unregister_md_cluster_operations();
Goldwyn Rodrigues8e854e92014-03-07 11:21:15 -0600202}
203
204module_init(cluster_init);
205module_exit(cluster_exit);
206MODULE_LICENSE("GPL");
207MODULE_DESCRIPTION("Clustering support for MD");