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