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
;
33 struct dlm_lock_resource
*sb_lock
;
34 struct mutex sb_mutex
;
37 static void sync_ast(void *arg
)
39 struct dlm_lock_resource
*res
;
41 res
= (struct dlm_lock_resource
*) arg
;
42 complete(&res
->completion
);
45 static int dlm_lock_sync(struct dlm_lock_resource
*res
, int mode
)
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
);
55 wait_for_completion(&res
->completion
);
56 return res
->lksb
.sb_status
;
59 static int dlm_unlock_sync(struct dlm_lock_resource
*res
)
61 return dlm_lock_sync(res
, DLM_LOCK_NL
);
64 static struct dlm_lock_resource
*lockres_init(struct mddev
*mddev
,
65 char *name
, void (*bastfn
)(void *arg
, int mode
), int with_lvb
)
67 struct dlm_lock_resource
*res
= NULL
;
69 struct md_cluster_info
*cinfo
= mddev
->cluster_info
;
71 res
= kzalloc(sizeof(struct dlm_lock_resource
), GFP_KERNEL
);
74 res
->ls
= cinfo
->lockspace
;
76 namelen
= strlen(name
);
77 res
->name
= kzalloc(namelen
+ 1, GFP_KERNEL
);
79 pr_err("md-cluster: Unable to allocate resource name for resource %s\n", name
);
82 strlcpy(res
->name
, name
, namelen
+ 1);
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
);
89 res
->flags
= DLM_LKF_VALBLK
;
95 res
->flags
|= DLM_LKF_EXPEDITE
;
97 ret
= dlm_lock_sync(res
, DLM_LOCK_NL
);
99 pr_err("md-cluster: Unable to lock NL on new lock resource %s\n", name
);
102 res
->flags
&= ~DLM_LKF_EXPEDITE
;
103 res
->flags
|= DLM_LKF_CONVERT
;
107 kfree(res
->lksb
.sb_lvbptr
);
113 static void lockres_free(struct dlm_lock_resource
*res
)
118 init_completion(&res
->completion
);
119 dlm_unlock(res
->ls
, res
->lksb
.sb_lkid
, 0, &res
->lksb
, res
);
120 wait_for_completion(&res
->completion
);
123 kfree(res
->lksb
.sb_lvbptr
);
127 static char *pretty_uuid(char *dest
, char *src
)
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
]);
139 static int join(struct mddev
*mddev
, int nodes
)
141 struct md_cluster_info
*cinfo
;
145 if (!try_module_get(THIS_MODULE
))
148 cinfo
= kzalloc(sizeof(struct md_cluster_info
), GFP_KERNEL
);
153 pretty_uuid(str
, mddev
->uuid
);
154 ret
= dlm_new_lockspace(str
, NULL
, DLM_LSFL_FS
, LVB_SIZE
,
155 NULL
, NULL
, NULL
, &cinfo
->lockspace
);
158 cinfo
->sb_lock
= lockres_init(mddev
, "cmd-super",
160 if (!cinfo
->sb_lock
) {
164 mutex_init(&cinfo
->sb_mutex
);
165 mddev
->cluster_info
= cinfo
;
168 if (cinfo
->lockspace
)
169 dlm_release_lockspace(cinfo
->lockspace
, 2);
171 module_put(THIS_MODULE
);
175 static int leave(struct mddev
*mddev
)
177 struct md_cluster_info
*cinfo
= mddev
->cluster_info
;
181 lockres_free(cinfo
->sb_lock
);
182 dlm_release_lockspace(cinfo
->lockspace
, 2);
186 static struct md_cluster_operations cluster_ops
= {
191 static int __init
cluster_init(void)
193 pr_warn("md-cluster: EXPERIMENTAL. Use with caution\n");
194 pr_info("Registering Cluster MD functions\n");
195 register_md_cluster_operations(&cluster_ops
, THIS_MODULE
);
199 static void cluster_exit(void)
201 unregister_md_cluster_operations();
204 module_init(cluster_init
);
205 module_exit(cluster_exit
);
206 MODULE_LICENSE("GPL");
207 MODULE_DESCRIPTION("Clustering support for MD");