xref: /openbmc/linux/drivers/md/md-cluster.c (revision edb39c9d)
1 /*
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>
13 #include <linux/dlm.h>
14 #include <linux/sched.h>
15 #include "md.h"
16 #include "md-cluster.h"
17 
18 #define LVB_SIZE	64
19 
20 struct 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() */
25 	void (*bast)(void *arg, int mode); /* blocking AST function pointer*/
26 	struct completion completion; /* completion for synchronized locking */
27 };
28 
29 static void sync_ast(void *arg)
30 {
31 	struct dlm_lock_resource *res;
32 
33 	res = (struct dlm_lock_resource *) arg;
34 	complete(&res->completion);
35 }
36 
37 static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
38 {
39 	int ret = 0;
40 
41 	init_completion(&res->completion);
42 	ret = dlm_lock(res->ls, mode, &res->lksb,
43 			res->flags, res->name, strlen(res->name),
44 			0, sync_ast, res, res->bast);
45 	if (ret)
46 		return ret;
47 	wait_for_completion(&res->completion);
48 	return res->lksb.sb_status;
49 }
50 
51 static int dlm_unlock_sync(struct dlm_lock_resource *res)
52 {
53 	return dlm_lock_sync(res, DLM_LOCK_NL);
54 }
55 
56 static struct dlm_lock_resource *lockres_init(dlm_lockspace_t *lockspace,
57 		char *name, void (*bastfn)(void *arg, int mode), int with_lvb)
58 {
59 	struct dlm_lock_resource *res = NULL;
60 	int ret, namelen;
61 
62 	res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL);
63 	if (!res)
64 		return NULL;
65 	res->ls = lockspace;
66 	namelen = strlen(name);
67 	res->name = kzalloc(namelen + 1, GFP_KERNEL);
68 	if (!res->name) {
69 		pr_err("md-cluster: Unable to allocate resource name for resource %s\n", name);
70 		goto out_err;
71 	}
72 	strlcpy(res->name, name, namelen + 1);
73 	if (with_lvb) {
74 		res->lksb.sb_lvbptr = kzalloc(LVB_SIZE, GFP_KERNEL);
75 		if (!res->lksb.sb_lvbptr) {
76 			pr_err("md-cluster: Unable to allocate LVB for resource %s\n", name);
77 			goto out_err;
78 		}
79 		res->flags = DLM_LKF_VALBLK;
80 	}
81 
82 	if (bastfn)
83 		res->bast = bastfn;
84 
85 	res->flags |= DLM_LKF_EXPEDITE;
86 
87 	ret = dlm_lock_sync(res, DLM_LOCK_NL);
88 	if (ret) {
89 		pr_err("md-cluster: Unable to lock NL on new lock resource %s\n", name);
90 		goto out_err;
91 	}
92 	res->flags &= ~DLM_LKF_EXPEDITE;
93 	res->flags |= DLM_LKF_CONVERT;
94 
95 	return res;
96 out_err:
97 	kfree(res->lksb.sb_lvbptr);
98 	kfree(res->name);
99 	kfree(res);
100 	return NULL;
101 }
102 
103 static void lockres_free(struct dlm_lock_resource *res)
104 {
105 	if (!res)
106 		return;
107 
108 	init_completion(&res->completion);
109 	dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res);
110 	wait_for_completion(&res->completion);
111 
112 	kfree(res->name);
113 	kfree(res->lksb.sb_lvbptr);
114 	kfree(res);
115 }
116 
117 static int join(struct mddev *mddev, int nodes)
118 {
119 	return 0;
120 }
121 
122 static int leave(struct mddev *mddev)
123 {
124 	return 0;
125 }
126 
127 static struct md_cluster_operations cluster_ops = {
128 	.join   = join,
129 	.leave  = leave,
130 };
131 
132 static int __init cluster_init(void)
133 {
134 	pr_warn("md-cluster: EXPERIMENTAL. Use with caution\n");
135 	pr_info("Registering Cluster MD functions\n");
136 	register_md_cluster_operations(&cluster_ops, THIS_MODULE);
137 	return 0;
138 }
139 
140 static void cluster_exit(void)
141 {
142 	unregister_md_cluster_operations();
143 }
144 
145 module_init(cluster_init);
146 module_exit(cluster_exit);
147 MODULE_LICENSE("GPL");
148 MODULE_DESCRIPTION("Clustering support for MD");
149