1/* 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 3 * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 4 * 5 * This copyrighted material is made available to anyone wishing to use, 6 * modify, copy, or redistribute it subject to the terms and conditions 7 * of the GNU General Public License version 2. 8 */ 9 10#include "lock_dlm.h" 11 12const struct lm_lockops gdlm_ops; 13 14 15static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, 16 int flags, char *table_name) 17{ 18 struct gdlm_ls *ls; 19 char buf[256], *p; 20 21 ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL); 22 if (!ls) 23 return NULL; 24 25 ls->drop_locks_count = GDLM_DROP_COUNT; 26 ls->drop_locks_period = GDLM_DROP_PERIOD; 27 ls->fscb = cb; 28 ls->sdp = sdp; 29 ls->fsflags = flags; 30 spin_lock_init(&ls->async_lock); 31 INIT_LIST_HEAD(&ls->complete); 32 INIT_LIST_HEAD(&ls->blocking); 33 INIT_LIST_HEAD(&ls->delayed); 34 INIT_LIST_HEAD(&ls->submit); 35 INIT_LIST_HEAD(&ls->all_locks); 36 init_waitqueue_head(&ls->thread_wait); 37 init_waitqueue_head(&ls->wait_control); 38 ls->thread1 = NULL; 39 ls->thread2 = NULL; 40 ls->drop_time = jiffies; 41 ls->jid = -1; 42 43 strncpy(buf, table_name, 256); 44 buf[255] = '\0'; 45 46 p = strchr(buf, ':'); 47 if (!p) { 48 log_info("invalid table_name \"%s\"", table_name); 49 kfree(ls); 50 return NULL; 51 } 52 *p = '\0'; 53 p++; 54 55 strncpy(ls->clustername, buf, GDLM_NAME_LEN); 56 strncpy(ls->fsname, p, GDLM_NAME_LEN); 57 58 return ls; 59} 60 61static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) 62{ 63 char data[256]; 64 char *options, *x, *y; 65 int error = 0; 66 67 memset(data, 0, 256); 68 strncpy(data, data_arg, 255); 69 70 for (options = data; (x = strsep(&options, ":")); ) { 71 if (!*x) 72 continue; 73 74 y = strchr(x, '='); 75 if (y) 76 *y++ = 0; 77 78 if (!strcmp(x, "jid")) { 79 if (!y) { 80 log_error("need argument to jid"); 81 error = -EINVAL; 82 break; 83 } 84 sscanf(y, "%u", &ls->jid); 85 86 } else if (!strcmp(x, "first")) { 87 if (!y) { 88 log_error("need argument to first"); 89 error = -EINVAL; 90 break; 91 } 92 sscanf(y, "%u", &ls->first); 93 94 } else if (!strcmp(x, "id")) { 95 if (!y) { 96 log_error("need argument to id"); 97 error = -EINVAL; 98 break; 99 } 100 sscanf(y, "%u", &ls->id); 101 102 } else if (!strcmp(x, "nodir")) { 103 if (!y) { 104 log_error("need argument to nodir"); 105 error = -EINVAL; 106 break; 107 } 108 sscanf(y, "%u", nodir); 109 110 } else { 111 log_error("unkonwn option: %s", x); 112 error = -EINVAL; 113 break; 114 } 115 } 116 117 return error; 118} 119 120static int gdlm_mount(char *table_name, char *host_data, 121 lm_callback_t cb, void *cb_data, 122 unsigned int min_lvb_size, int flags, 123 struct lm_lockstruct *lockstruct, 124 struct kobject *fskobj) 125{ 126 struct gdlm_ls *ls; 127 int error = -ENOMEM, nodir = 0; 128 129 if (min_lvb_size > GDLM_LVB_SIZE) 130 goto out; 131 132 ls = init_gdlm(cb, cb_data, flags, table_name); 133 if (!ls) 134 goto out; 135 136 error = make_args(ls, host_data, &nodir); 137 if (error) 138 goto out; 139 140 error = gdlm_init_threads(ls); 141 if (error) 142 goto out_free; 143 144 error = gdlm_kobject_setup(ls, fskobj); 145 if (error) 146 goto out_thread; 147 148 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), 149 &ls->dlm_lockspace, 150 nodir ? DLM_LSFL_NODIR : 0, 151 GDLM_LVB_SIZE); 152 if (error) { 153 log_error("dlm_new_lockspace error %d", error); 154 goto out_kobj; 155 } 156 157 lockstruct->ls_jid = ls->jid; 158 lockstruct->ls_first = ls->first; 159 lockstruct->ls_lockspace = ls; 160 lockstruct->ls_ops = &gdlm_ops; 161 lockstruct->ls_flags = 0; 162 lockstruct->ls_lvb_size = GDLM_LVB_SIZE; 163 return 0; 164 165out_kobj: 166 gdlm_kobject_release(ls); 167out_thread: 168 gdlm_release_threads(ls); 169out_free: 170 kfree(ls); 171out: 172 return error; 173} 174 175static void gdlm_unmount(void *lockspace) 176{ 177 struct gdlm_ls *ls = lockspace; 178 int rv; 179 180 log_debug("unmount flags %lx", ls->flags); 181 182 183 if (test_bit(DFL_WITHDRAW, &ls->flags)) 184 goto out; 185 186 gdlm_kobject_release(ls); 187 dlm_release_lockspace(ls->dlm_lockspace, 2); 188 gdlm_release_threads(ls); 189 rv = gdlm_release_all_locks(ls); 190 if (rv) 191 log_info("gdlm_unmount: %d stray locks freed", rv); 192out: 193 kfree(ls); 194} 195 196static void gdlm_recovery_done(void *lockspace, unsigned int jid, 197 unsigned int message) 198{ 199 struct gdlm_ls *ls = lockspace; 200 ls->recover_jid_done = jid; 201 ls->recover_jid_status = message; 202 kobject_uevent(&ls->kobj, KOBJ_CHANGE); 203} 204 205static void gdlm_others_may_mount(void *lockspace) 206{ 207 struct gdlm_ls *ls = lockspace; 208 ls->first_done = 1; 209 kobject_uevent(&ls->kobj, KOBJ_CHANGE); 210} 211 212/* Userspace gets the offline uevent, blocks new gfs locks on 213 other mounters, and lets us know (sets WITHDRAW flag). Then, 214 userspace leaves the mount group while we leave the lockspace. */ 215 216static void gdlm_withdraw(void *lockspace) 217{ 218 struct gdlm_ls *ls = lockspace; 219 220 kobject_uevent(&ls->kobj, KOBJ_OFFLINE); 221 222 wait_event_interruptible(ls->wait_control, 223 test_bit(DFL_WITHDRAW, &ls->flags)); 224 225 dlm_release_lockspace(ls->dlm_lockspace, 2); 226 gdlm_release_threads(ls); 227 gdlm_release_all_locks(ls); 228 gdlm_kobject_release(ls); 229} 230 231const struct lm_lockops gdlm_ops = { 232 .lm_proto_name = "lock_dlm", 233 .lm_mount = gdlm_mount, 234 .lm_others_may_mount = gdlm_others_may_mount, 235 .lm_unmount = gdlm_unmount, 236 .lm_withdraw = gdlm_withdraw, 237 .lm_get_lock = gdlm_get_lock, 238 .lm_put_lock = gdlm_put_lock, 239 .lm_lock = gdlm_lock, 240 .lm_unlock = gdlm_unlock, 241 .lm_plock = gdlm_plock, 242 .lm_punlock = gdlm_punlock, 243 .lm_plock_get = gdlm_plock_get, 244 .lm_cancel = gdlm_cancel, 245 .lm_hold_lvb = gdlm_hold_lvb, 246 .lm_unhold_lvb = gdlm_unhold_lvb, 247 .lm_recovery_done = gdlm_recovery_done, 248 .lm_owner = THIS_MODULE, 249}; 250