1e7fd4179SDavid Teigland /****************************************************************************** 2e7fd4179SDavid Teigland ******************************************************************************* 3e7fd4179SDavid Teigland ** 4e7fd4179SDavid Teigland ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 5ef0c2bb0SDavid Teigland ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6e7fd4179SDavid Teigland ** 7e7fd4179SDavid Teigland ** This copyrighted material is made available to anyone wishing to use, 8e7fd4179SDavid Teigland ** modify, copy, or redistribute it subject to the terms and conditions 9e7fd4179SDavid Teigland ** of the GNU General Public License v.2. 10e7fd4179SDavid Teigland ** 11e7fd4179SDavid Teigland ******************************************************************************* 12e7fd4179SDavid Teigland ******************************************************************************/ 13e7fd4179SDavid Teigland 14e7fd4179SDavid Teigland #include "dlm_internal.h" 15e7fd4179SDavid Teigland #include "lockspace.h" 16e7fd4179SDavid Teigland #include "member.h" 17e7fd4179SDavid Teigland #include "recoverd.h" 18e7fd4179SDavid Teigland #include "ast.h" 19e7fd4179SDavid Teigland #include "dir.h" 20e7fd4179SDavid Teigland #include "lowcomms.h" 21e7fd4179SDavid Teigland #include "config.h" 22e7fd4179SDavid Teigland #include "memory.h" 23e7fd4179SDavid Teigland #include "lock.h" 24c56b39cdSDavid Teigland #include "recover.h" 252896ee37SDavid Teigland #include "requestqueue.h" 26e7fd4179SDavid Teigland 27e7fd4179SDavid Teigland #ifdef CONFIG_DLM_DEBUG 28e7fd4179SDavid Teigland int dlm_create_debug_file(struct dlm_ls *ls); 29e7fd4179SDavid Teigland void dlm_delete_debug_file(struct dlm_ls *ls); 30e7fd4179SDavid Teigland #else 31e7fd4179SDavid Teigland static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; } 32e7fd4179SDavid Teigland static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } 33e7fd4179SDavid Teigland #endif 34e7fd4179SDavid Teigland 35e7fd4179SDavid Teigland static int ls_count; 3690135925SDavid Teigland static struct mutex ls_lock; 37e7fd4179SDavid Teigland static struct list_head lslist; 38e7fd4179SDavid Teigland static spinlock_t lslist_lock; 39e7fd4179SDavid Teigland static struct task_struct * scand_task; 40e7fd4179SDavid Teigland 41e7fd4179SDavid Teigland 42e7fd4179SDavid Teigland static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len) 43e7fd4179SDavid Teigland { 44e7fd4179SDavid Teigland ssize_t ret = len; 45e7fd4179SDavid Teigland int n = simple_strtol(buf, NULL, 0); 46e7fd4179SDavid Teigland 47e2de7f56SPatrick Caulfield ls = dlm_find_lockspace_local(ls->ls_local_handle); 48e2de7f56SPatrick Caulfield if (!ls) 49e2de7f56SPatrick Caulfield return -EINVAL; 50e2de7f56SPatrick Caulfield 51e7fd4179SDavid Teigland switch (n) { 52e7fd4179SDavid Teigland case 0: 53e7fd4179SDavid Teigland dlm_ls_stop(ls); 54e7fd4179SDavid Teigland break; 55e7fd4179SDavid Teigland case 1: 56e7fd4179SDavid Teigland dlm_ls_start(ls); 57e7fd4179SDavid Teigland break; 58e7fd4179SDavid Teigland default: 59e7fd4179SDavid Teigland ret = -EINVAL; 60e7fd4179SDavid Teigland } 61e2de7f56SPatrick Caulfield dlm_put_lockspace(ls); 62e7fd4179SDavid Teigland return ret; 63e7fd4179SDavid Teigland } 64e7fd4179SDavid Teigland 65e7fd4179SDavid Teigland static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len) 66e7fd4179SDavid Teigland { 67e7fd4179SDavid Teigland ls->ls_uevent_result = simple_strtol(buf, NULL, 0); 68e7fd4179SDavid Teigland set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags); 69e7fd4179SDavid Teigland wake_up(&ls->ls_uevent_wait); 70e7fd4179SDavid Teigland return len; 71e7fd4179SDavid Teigland } 72e7fd4179SDavid Teigland 73e7fd4179SDavid Teigland static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf) 74e7fd4179SDavid Teigland { 75a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id); 76e7fd4179SDavid Teigland } 77e7fd4179SDavid Teigland 78e7fd4179SDavid Teigland static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) 79e7fd4179SDavid Teigland { 80e7fd4179SDavid Teigland ls->ls_global_id = simple_strtoul(buf, NULL, 0); 81e7fd4179SDavid Teigland return len; 82e7fd4179SDavid Teigland } 83e7fd4179SDavid Teigland 84c56b39cdSDavid Teigland static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) 85c56b39cdSDavid Teigland { 86c56b39cdSDavid Teigland uint32_t status = dlm_recover_status(ls); 87a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%x\n", status); 88c56b39cdSDavid Teigland } 89c56b39cdSDavid Teigland 90faa0f267SDavid Teigland static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf) 91faa0f267SDavid Teigland { 92a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid); 93faa0f267SDavid Teigland } 94faa0f267SDavid Teigland 95e7fd4179SDavid Teigland struct dlm_attr { 96e7fd4179SDavid Teigland struct attribute attr; 97e7fd4179SDavid Teigland ssize_t (*show)(struct dlm_ls *, char *); 98e7fd4179SDavid Teigland ssize_t (*store)(struct dlm_ls *, const char *, size_t); 99e7fd4179SDavid Teigland }; 100e7fd4179SDavid Teigland 101e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_control = { 102e7fd4179SDavid Teigland .attr = {.name = "control", .mode = S_IWUSR}, 103e7fd4179SDavid Teigland .store = dlm_control_store 104e7fd4179SDavid Teigland }; 105e7fd4179SDavid Teigland 106e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_event = { 107e7fd4179SDavid Teigland .attr = {.name = "event_done", .mode = S_IWUSR}, 108e7fd4179SDavid Teigland .store = dlm_event_store 109e7fd4179SDavid Teigland }; 110e7fd4179SDavid Teigland 111e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_id = { 112e7fd4179SDavid Teigland .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR}, 113e7fd4179SDavid Teigland .show = dlm_id_show, 114e7fd4179SDavid Teigland .store = dlm_id_store 115e7fd4179SDavid Teigland }; 116e7fd4179SDavid Teigland 117c56b39cdSDavid Teigland static struct dlm_attr dlm_attr_recover_status = { 118c56b39cdSDavid Teigland .attr = {.name = "recover_status", .mode = S_IRUGO}, 119c56b39cdSDavid Teigland .show = dlm_recover_status_show 120c56b39cdSDavid Teigland }; 121c56b39cdSDavid Teigland 122faa0f267SDavid Teigland static struct dlm_attr dlm_attr_recover_nodeid = { 123faa0f267SDavid Teigland .attr = {.name = "recover_nodeid", .mode = S_IRUGO}, 124faa0f267SDavid Teigland .show = dlm_recover_nodeid_show 125faa0f267SDavid Teigland }; 126faa0f267SDavid Teigland 127e7fd4179SDavid Teigland static struct attribute *dlm_attrs[] = { 128e7fd4179SDavid Teigland &dlm_attr_control.attr, 129e7fd4179SDavid Teigland &dlm_attr_event.attr, 130e7fd4179SDavid Teigland &dlm_attr_id.attr, 131c56b39cdSDavid Teigland &dlm_attr_recover_status.attr, 132faa0f267SDavid Teigland &dlm_attr_recover_nodeid.attr, 133e7fd4179SDavid Teigland NULL, 134e7fd4179SDavid Teigland }; 135e7fd4179SDavid Teigland 136e7fd4179SDavid Teigland static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr, 137e7fd4179SDavid Teigland char *buf) 138e7fd4179SDavid Teigland { 139e7fd4179SDavid Teigland struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); 140e7fd4179SDavid Teigland struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); 141e7fd4179SDavid Teigland return a->show ? a->show(ls, buf) : 0; 142e7fd4179SDavid Teigland } 143e7fd4179SDavid Teigland 144e7fd4179SDavid Teigland static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr, 145e7fd4179SDavid Teigland const char *buf, size_t len) 146e7fd4179SDavid Teigland { 147e7fd4179SDavid Teigland struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); 148e7fd4179SDavid Teigland struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); 149e7fd4179SDavid Teigland return a->store ? a->store(ls, buf, len) : len; 150e7fd4179SDavid Teigland } 151e7fd4179SDavid Teigland 152ba542e3bSPatrick Caulfield static void lockspace_kobj_release(struct kobject *k) 153ba542e3bSPatrick Caulfield { 154ba542e3bSPatrick Caulfield struct dlm_ls *ls = container_of(k, struct dlm_ls, ls_kobj); 155ba542e3bSPatrick Caulfield kfree(ls); 156ba542e3bSPatrick Caulfield } 157ba542e3bSPatrick Caulfield 158e7fd4179SDavid Teigland static struct sysfs_ops dlm_attr_ops = { 159e7fd4179SDavid Teigland .show = dlm_attr_show, 160e7fd4179SDavid Teigland .store = dlm_attr_store, 161e7fd4179SDavid Teigland }; 162e7fd4179SDavid Teigland 163e7fd4179SDavid Teigland static struct kobj_type dlm_ktype = { 164e7fd4179SDavid Teigland .default_attrs = dlm_attrs, 165e7fd4179SDavid Teigland .sysfs_ops = &dlm_attr_ops, 166ba542e3bSPatrick Caulfield .release = lockspace_kobj_release, 167e7fd4179SDavid Teigland }; 168e7fd4179SDavid Teigland 169e7fd4179SDavid Teigland static struct kset dlm_kset = { 170e7fd4179SDavid Teigland .kobj = {.name = "dlm",}, 171e7fd4179SDavid Teigland .ktype = &dlm_ktype, 172e7fd4179SDavid Teigland }; 173e7fd4179SDavid Teigland 174e7fd4179SDavid Teigland static int kobject_setup(struct dlm_ls *ls) 175e7fd4179SDavid Teigland { 176e7fd4179SDavid Teigland char lsname[DLM_LOCKSPACE_LEN]; 177e7fd4179SDavid Teigland int error; 178e7fd4179SDavid Teigland 179e7fd4179SDavid Teigland memset(lsname, 0, DLM_LOCKSPACE_LEN); 180e7fd4179SDavid Teigland snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name); 181e7fd4179SDavid Teigland 182e7fd4179SDavid Teigland error = kobject_set_name(&ls->ls_kobj, "%s", lsname); 183e7fd4179SDavid Teigland if (error) 184e7fd4179SDavid Teigland return error; 185e7fd4179SDavid Teigland 186e7fd4179SDavid Teigland ls->ls_kobj.kset = &dlm_kset; 187e7fd4179SDavid Teigland ls->ls_kobj.ktype = &dlm_ktype; 188e7fd4179SDavid Teigland return 0; 189e7fd4179SDavid Teigland } 190e7fd4179SDavid Teigland 191e7fd4179SDavid Teigland static int do_uevent(struct dlm_ls *ls, int in) 192e7fd4179SDavid Teigland { 193e7fd4179SDavid Teigland int error; 194e7fd4179SDavid Teigland 195e7fd4179SDavid Teigland if (in) 196e7fd4179SDavid Teigland kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE); 197e7fd4179SDavid Teigland else 198e7fd4179SDavid Teigland kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE); 199e7fd4179SDavid Teigland 200e7fd4179SDavid Teigland error = wait_event_interruptible(ls->ls_uevent_wait, 201e7fd4179SDavid Teigland test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags)); 202e7fd4179SDavid Teigland if (error) 203e7fd4179SDavid Teigland goto out; 204e7fd4179SDavid Teigland 205e7fd4179SDavid Teigland error = ls->ls_uevent_result; 206e7fd4179SDavid Teigland out: 207e7fd4179SDavid Teigland return error; 208e7fd4179SDavid Teigland } 209e7fd4179SDavid Teigland 210e7fd4179SDavid Teigland 211e7fd4179SDavid Teigland int dlm_lockspace_init(void) 212e7fd4179SDavid Teigland { 213e7fd4179SDavid Teigland int error; 214e7fd4179SDavid Teigland 215e7fd4179SDavid Teigland ls_count = 0; 21690135925SDavid Teigland mutex_init(&ls_lock); 217e7fd4179SDavid Teigland INIT_LIST_HEAD(&lslist); 218e7fd4179SDavid Teigland spin_lock_init(&lslist_lock); 219e7fd4179SDavid Teigland 220823bccfcSGreg Kroah-Hartman kobj_set_kset_s(&dlm_kset, kernel_subsys); 221e7fd4179SDavid Teigland error = kset_register(&dlm_kset); 222e7fd4179SDavid Teigland if (error) 223e7fd4179SDavid Teigland printk("dlm_lockspace_init: cannot register kset %d\n", error); 224e7fd4179SDavid Teigland return error; 225e7fd4179SDavid Teigland } 226e7fd4179SDavid Teigland 227e7fd4179SDavid Teigland void dlm_lockspace_exit(void) 228e7fd4179SDavid Teigland { 229e7fd4179SDavid Teigland kset_unregister(&dlm_kset); 230e7fd4179SDavid Teigland } 231e7fd4179SDavid Teigland 232e7fd4179SDavid Teigland static int dlm_scand(void *data) 233e7fd4179SDavid Teigland { 234e7fd4179SDavid Teigland struct dlm_ls *ls; 235e7fd4179SDavid Teigland 236e7fd4179SDavid Teigland while (!kthread_should_stop()) { 237*85e86edfSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) { 238*85e86edfSDavid Teigland if (dlm_lock_recovery_try(ls)) { 239e7fd4179SDavid Teigland dlm_scan_rsbs(ls); 240*85e86edfSDavid Teigland dlm_unlock_recovery(ls); 241*85e86edfSDavid Teigland } 242*85e86edfSDavid Teigland } 24368c817a1SDavid Teigland schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ); 244e7fd4179SDavid Teigland } 245e7fd4179SDavid Teigland return 0; 246e7fd4179SDavid Teigland } 247e7fd4179SDavid Teigland 248e7fd4179SDavid Teigland static int dlm_scand_start(void) 249e7fd4179SDavid Teigland { 250e7fd4179SDavid Teigland struct task_struct *p; 251e7fd4179SDavid Teigland int error = 0; 252e7fd4179SDavid Teigland 253e7fd4179SDavid Teigland p = kthread_run(dlm_scand, NULL, "dlm_scand"); 254e7fd4179SDavid Teigland if (IS_ERR(p)) 255e7fd4179SDavid Teigland error = PTR_ERR(p); 256e7fd4179SDavid Teigland else 257e7fd4179SDavid Teigland scand_task = p; 258e7fd4179SDavid Teigland return error; 259e7fd4179SDavid Teigland } 260e7fd4179SDavid Teigland 261e7fd4179SDavid Teigland static void dlm_scand_stop(void) 262e7fd4179SDavid Teigland { 263e7fd4179SDavid Teigland kthread_stop(scand_task); 264e7fd4179SDavid Teigland } 265e7fd4179SDavid Teigland 266e7fd4179SDavid Teigland static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen) 267e7fd4179SDavid Teigland { 268e7fd4179SDavid Teigland struct dlm_ls *ls; 269e7fd4179SDavid Teigland 270e7fd4179SDavid Teigland spin_lock(&lslist_lock); 271e7fd4179SDavid Teigland 272e7fd4179SDavid Teigland list_for_each_entry(ls, &lslist, ls_list) { 273e7fd4179SDavid Teigland if (ls->ls_namelen == namelen && 274e7fd4179SDavid Teigland memcmp(ls->ls_name, name, namelen) == 0) 275e7fd4179SDavid Teigland goto out; 276e7fd4179SDavid Teigland } 277e7fd4179SDavid Teigland ls = NULL; 278e7fd4179SDavid Teigland out: 279e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 280e7fd4179SDavid Teigland return ls; 281e7fd4179SDavid Teigland } 282e7fd4179SDavid Teigland 283e7fd4179SDavid Teigland struct dlm_ls *dlm_find_lockspace_global(uint32_t id) 284e7fd4179SDavid Teigland { 285e7fd4179SDavid Teigland struct dlm_ls *ls; 286e7fd4179SDavid Teigland 287e7fd4179SDavid Teigland spin_lock(&lslist_lock); 288e7fd4179SDavid Teigland 289e7fd4179SDavid Teigland list_for_each_entry(ls, &lslist, ls_list) { 290e7fd4179SDavid Teigland if (ls->ls_global_id == id) { 291e7fd4179SDavid Teigland ls->ls_count++; 292e7fd4179SDavid Teigland goto out; 293e7fd4179SDavid Teigland } 294e7fd4179SDavid Teigland } 295e7fd4179SDavid Teigland ls = NULL; 296e7fd4179SDavid Teigland out: 297e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 298e7fd4179SDavid Teigland return ls; 299e7fd4179SDavid Teigland } 300e7fd4179SDavid Teigland 301597d0caeSDavid Teigland struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace) 302e7fd4179SDavid Teigland { 303597d0caeSDavid Teigland struct dlm_ls *ls; 304e7fd4179SDavid Teigland 305e7fd4179SDavid Teigland spin_lock(&lslist_lock); 306597d0caeSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) { 307597d0caeSDavid Teigland if (ls->ls_local_handle == lockspace) { 308e7fd4179SDavid Teigland ls->ls_count++; 309597d0caeSDavid Teigland goto out; 310597d0caeSDavid Teigland } 311597d0caeSDavid Teigland } 312597d0caeSDavid Teigland ls = NULL; 313597d0caeSDavid Teigland out: 314597d0caeSDavid Teigland spin_unlock(&lslist_lock); 315597d0caeSDavid Teigland return ls; 316597d0caeSDavid Teigland } 317597d0caeSDavid Teigland 318597d0caeSDavid Teigland struct dlm_ls *dlm_find_lockspace_device(int minor) 319597d0caeSDavid Teigland { 320597d0caeSDavid Teigland struct dlm_ls *ls; 321597d0caeSDavid Teigland 322597d0caeSDavid Teigland spin_lock(&lslist_lock); 323597d0caeSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) { 324597d0caeSDavid Teigland if (ls->ls_device.minor == minor) { 325597d0caeSDavid Teigland ls->ls_count++; 326597d0caeSDavid Teigland goto out; 327597d0caeSDavid Teigland } 328597d0caeSDavid Teigland } 329597d0caeSDavid Teigland ls = NULL; 330597d0caeSDavid Teigland out: 331e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 332e7fd4179SDavid Teigland return ls; 333e7fd4179SDavid Teigland } 334e7fd4179SDavid Teigland 335e7fd4179SDavid Teigland void dlm_put_lockspace(struct dlm_ls *ls) 336e7fd4179SDavid Teigland { 337e7fd4179SDavid Teigland spin_lock(&lslist_lock); 338e7fd4179SDavid Teigland ls->ls_count--; 339e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 340e7fd4179SDavid Teigland } 341e7fd4179SDavid Teigland 342e7fd4179SDavid Teigland static void remove_lockspace(struct dlm_ls *ls) 343e7fd4179SDavid Teigland { 344e7fd4179SDavid Teigland for (;;) { 345e7fd4179SDavid Teigland spin_lock(&lslist_lock); 346e7fd4179SDavid Teigland if (ls->ls_count == 0) { 347e7fd4179SDavid Teigland list_del(&ls->ls_list); 348e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 349e7fd4179SDavid Teigland return; 350e7fd4179SDavid Teigland } 351e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 352e7fd4179SDavid Teigland ssleep(1); 353e7fd4179SDavid Teigland } 354e7fd4179SDavid Teigland } 355e7fd4179SDavid Teigland 356e7fd4179SDavid Teigland static int threads_start(void) 357e7fd4179SDavid Teigland { 358e7fd4179SDavid Teigland int error; 359e7fd4179SDavid Teigland 360e7fd4179SDavid Teigland /* Thread which process lock requests for all lockspace's */ 361e7fd4179SDavid Teigland error = dlm_astd_start(); 362e7fd4179SDavid Teigland if (error) { 363e7fd4179SDavid Teigland log_print("cannot start dlm_astd thread %d", error); 364e7fd4179SDavid Teigland goto fail; 365e7fd4179SDavid Teigland } 366e7fd4179SDavid Teigland 367e7fd4179SDavid Teigland error = dlm_scand_start(); 368e7fd4179SDavid Teigland if (error) { 369e7fd4179SDavid Teigland log_print("cannot start dlm_scand thread %d", error); 370e7fd4179SDavid Teigland goto astd_fail; 371e7fd4179SDavid Teigland } 372e7fd4179SDavid Teigland 373e7fd4179SDavid Teigland /* Thread for sending/receiving messages for all lockspace's */ 374e7fd4179SDavid Teigland error = dlm_lowcomms_start(); 375e7fd4179SDavid Teigland if (error) { 376e7fd4179SDavid Teigland log_print("cannot start dlm lowcomms %d", error); 377e7fd4179SDavid Teigland goto scand_fail; 378e7fd4179SDavid Teigland } 379e7fd4179SDavid Teigland 380e7fd4179SDavid Teigland return 0; 381e7fd4179SDavid Teigland 382e7fd4179SDavid Teigland scand_fail: 383e7fd4179SDavid Teigland dlm_scand_stop(); 384e7fd4179SDavid Teigland astd_fail: 385e7fd4179SDavid Teigland dlm_astd_stop(); 386e7fd4179SDavid Teigland fail: 387e7fd4179SDavid Teigland return error; 388e7fd4179SDavid Teigland } 389e7fd4179SDavid Teigland 390e7fd4179SDavid Teigland static void threads_stop(void) 391e7fd4179SDavid Teigland { 392e7fd4179SDavid Teigland dlm_scand_stop(); 393e7fd4179SDavid Teigland dlm_lowcomms_stop(); 394e7fd4179SDavid Teigland dlm_astd_stop(); 395e7fd4179SDavid Teigland } 396e7fd4179SDavid Teigland 397e7fd4179SDavid Teigland static int new_lockspace(char *name, int namelen, void **lockspace, 398e7fd4179SDavid Teigland uint32_t flags, int lvblen) 399e7fd4179SDavid Teigland { 400e7fd4179SDavid Teigland struct dlm_ls *ls; 401e7fd4179SDavid Teigland int i, size, error = -ENOMEM; 402e7fd4179SDavid Teigland 403e7fd4179SDavid Teigland if (namelen > DLM_LOCKSPACE_LEN) 404e7fd4179SDavid Teigland return -EINVAL; 405e7fd4179SDavid Teigland 406e7fd4179SDavid Teigland if (!lvblen || (lvblen % 8)) 407e7fd4179SDavid Teigland return -EINVAL; 408e7fd4179SDavid Teigland 409e7fd4179SDavid Teigland if (!try_module_get(THIS_MODULE)) 410e7fd4179SDavid Teigland return -EINVAL; 411e7fd4179SDavid Teigland 412e7fd4179SDavid Teigland ls = dlm_find_lockspace_name(name, namelen); 413e7fd4179SDavid Teigland if (ls) { 414e7fd4179SDavid Teigland *lockspace = ls; 415e7fd4179SDavid Teigland module_put(THIS_MODULE); 416e7fd4179SDavid Teigland return -EEXIST; 417e7fd4179SDavid Teigland } 418e7fd4179SDavid Teigland 41990135925SDavid Teigland ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); 420e7fd4179SDavid Teigland if (!ls) 421e7fd4179SDavid Teigland goto out; 422e7fd4179SDavid Teigland memcpy(ls->ls_name, name, namelen); 423e7fd4179SDavid Teigland ls->ls_namelen = namelen; 424e7fd4179SDavid Teigland ls->ls_exflags = flags; 425e7fd4179SDavid Teigland ls->ls_lvblen = lvblen; 426e7fd4179SDavid Teigland ls->ls_count = 0; 427e7fd4179SDavid Teigland ls->ls_flags = 0; 428e7fd4179SDavid Teigland 42968c817a1SDavid Teigland size = dlm_config.ci_rsbtbl_size; 430e7fd4179SDavid Teigland ls->ls_rsbtbl_size = size; 431e7fd4179SDavid Teigland 432e7fd4179SDavid Teigland ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL); 433e7fd4179SDavid Teigland if (!ls->ls_rsbtbl) 434e7fd4179SDavid Teigland goto out_lsfree; 435e7fd4179SDavid Teigland for (i = 0; i < size; i++) { 436e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list); 437e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss); 438e7fd4179SDavid Teigland rwlock_init(&ls->ls_rsbtbl[i].lock); 439e7fd4179SDavid Teigland } 440e7fd4179SDavid Teigland 44168c817a1SDavid Teigland size = dlm_config.ci_lkbtbl_size; 442e7fd4179SDavid Teigland ls->ls_lkbtbl_size = size; 443e7fd4179SDavid Teigland 444e7fd4179SDavid Teigland ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL); 445e7fd4179SDavid Teigland if (!ls->ls_lkbtbl) 446e7fd4179SDavid Teigland goto out_rsbfree; 447e7fd4179SDavid Teigland for (i = 0; i < size; i++) { 448e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list); 449e7fd4179SDavid Teigland rwlock_init(&ls->ls_lkbtbl[i].lock); 450e7fd4179SDavid Teigland ls->ls_lkbtbl[i].counter = 1; 451e7fd4179SDavid Teigland } 452e7fd4179SDavid Teigland 45368c817a1SDavid Teigland size = dlm_config.ci_dirtbl_size; 454e7fd4179SDavid Teigland ls->ls_dirtbl_size = size; 455e7fd4179SDavid Teigland 456e7fd4179SDavid Teigland ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL); 457e7fd4179SDavid Teigland if (!ls->ls_dirtbl) 458e7fd4179SDavid Teigland goto out_lkbfree; 459e7fd4179SDavid Teigland for (i = 0; i < size; i++) { 460e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_dirtbl[i].list); 461e7fd4179SDavid Teigland rwlock_init(&ls->ls_dirtbl[i].lock); 462e7fd4179SDavid Teigland } 463e7fd4179SDavid Teigland 464e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_waiters); 46590135925SDavid Teigland mutex_init(&ls->ls_waiters_mutex); 466ef0c2bb0SDavid Teigland INIT_LIST_HEAD(&ls->ls_orphans); 467ef0c2bb0SDavid Teigland mutex_init(&ls->ls_orphans_mutex); 468e7fd4179SDavid Teigland 469e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_nodes); 470e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_nodes_gone); 471e7fd4179SDavid Teigland ls->ls_num_nodes = 0; 472e7fd4179SDavid Teigland ls->ls_low_nodeid = 0; 473e7fd4179SDavid Teigland ls->ls_total_weight = 0; 474e7fd4179SDavid Teigland ls->ls_node_array = NULL; 475e7fd4179SDavid Teigland 476e7fd4179SDavid Teigland memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb)); 477e7fd4179SDavid Teigland ls->ls_stub_rsb.res_ls = ls; 478e7fd4179SDavid Teigland 4795de6319bSDavid Teigland ls->ls_debug_rsb_dentry = NULL; 4805de6319bSDavid Teigland ls->ls_debug_waiters_dentry = NULL; 481e7fd4179SDavid Teigland 482e7fd4179SDavid Teigland init_waitqueue_head(&ls->ls_uevent_wait); 483e7fd4179SDavid Teigland ls->ls_uevent_result = 0; 484e7fd4179SDavid Teigland 485e7fd4179SDavid Teigland ls->ls_recoverd_task = NULL; 48690135925SDavid Teigland mutex_init(&ls->ls_recoverd_active); 487e7fd4179SDavid Teigland spin_lock_init(&ls->ls_recover_lock); 48898f176fbSDavid Teigland spin_lock_init(&ls->ls_rcom_spin); 48998f176fbSDavid Teigland get_random_bytes(&ls->ls_rcom_seq, sizeof(uint64_t)); 490e7fd4179SDavid Teigland ls->ls_recover_status = 0; 491e7fd4179SDavid Teigland ls->ls_recover_seq = 0; 492e7fd4179SDavid Teigland ls->ls_recover_args = NULL; 493e7fd4179SDavid Teigland init_rwsem(&ls->ls_in_recovery); 494e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_requestqueue); 49590135925SDavid Teigland mutex_init(&ls->ls_requestqueue_mutex); 496597d0caeSDavid Teigland mutex_init(&ls->ls_clear_proc_locks); 497e7fd4179SDavid Teigland 49868c817a1SDavid Teigland ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); 499e7fd4179SDavid Teigland if (!ls->ls_recover_buf) 500e7fd4179SDavid Teigland goto out_dirfree; 501e7fd4179SDavid Teigland 502e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_recover_list); 503e7fd4179SDavid Teigland spin_lock_init(&ls->ls_recover_list_lock); 504e7fd4179SDavid Teigland ls->ls_recover_list_count = 0; 505597d0caeSDavid Teigland ls->ls_local_handle = ls; 506e7fd4179SDavid Teigland init_waitqueue_head(&ls->ls_wait_general); 507e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_root_list); 508e7fd4179SDavid Teigland init_rwsem(&ls->ls_root_sem); 509e7fd4179SDavid Teigland 510e7fd4179SDavid Teigland down_write(&ls->ls_in_recovery); 511e7fd4179SDavid Teigland 5125f88f1eaSDavid Teigland spin_lock(&lslist_lock); 5135f88f1eaSDavid Teigland list_add(&ls->ls_list, &lslist); 5145f88f1eaSDavid Teigland spin_unlock(&lslist_lock); 5155f88f1eaSDavid Teigland 5165f88f1eaSDavid Teigland /* needs to find ls in lslist */ 517e7fd4179SDavid Teigland error = dlm_recoverd_start(ls); 518e7fd4179SDavid Teigland if (error) { 519e7fd4179SDavid Teigland log_error(ls, "can't start dlm_recoverd %d", error); 520e7fd4179SDavid Teigland goto out_rcomfree; 521e7fd4179SDavid Teigland } 522e7fd4179SDavid Teigland 523e7fd4179SDavid Teigland dlm_create_debug_file(ls); 524e7fd4179SDavid Teigland 525e7fd4179SDavid Teigland error = kobject_setup(ls); 526e7fd4179SDavid Teigland if (error) 527e7fd4179SDavid Teigland goto out_del; 528e7fd4179SDavid Teigland 529e7fd4179SDavid Teigland error = kobject_register(&ls->ls_kobj); 530e7fd4179SDavid Teigland if (error) 531e7fd4179SDavid Teigland goto out_del; 532e7fd4179SDavid Teigland 533e7fd4179SDavid Teigland error = do_uevent(ls, 1); 534e7fd4179SDavid Teigland if (error) 535e7fd4179SDavid Teigland goto out_unreg; 536e7fd4179SDavid Teigland 537e7fd4179SDavid Teigland *lockspace = ls; 538e7fd4179SDavid Teigland return 0; 539e7fd4179SDavid Teigland 540e7fd4179SDavid Teigland out_unreg: 541e7fd4179SDavid Teigland kobject_unregister(&ls->ls_kobj); 542e7fd4179SDavid Teigland out_del: 543e7fd4179SDavid Teigland dlm_delete_debug_file(ls); 5445f88f1eaSDavid Teigland dlm_recoverd_stop(ls); 5455f88f1eaSDavid Teigland out_rcomfree: 546e7fd4179SDavid Teigland spin_lock(&lslist_lock); 547e7fd4179SDavid Teigland list_del(&ls->ls_list); 548e7fd4179SDavid Teigland spin_unlock(&lslist_lock); 549e7fd4179SDavid Teigland kfree(ls->ls_recover_buf); 550e7fd4179SDavid Teigland out_dirfree: 551e7fd4179SDavid Teigland kfree(ls->ls_dirtbl); 552e7fd4179SDavid Teigland out_lkbfree: 553e7fd4179SDavid Teigland kfree(ls->ls_lkbtbl); 554e7fd4179SDavid Teigland out_rsbfree: 555e7fd4179SDavid Teigland kfree(ls->ls_rsbtbl); 556e7fd4179SDavid Teigland out_lsfree: 557e7fd4179SDavid Teigland kfree(ls); 558e7fd4179SDavid Teigland out: 559e7fd4179SDavid Teigland module_put(THIS_MODULE); 560e7fd4179SDavid Teigland return error; 561e7fd4179SDavid Teigland } 562e7fd4179SDavid Teigland 563e7fd4179SDavid Teigland int dlm_new_lockspace(char *name, int namelen, void **lockspace, 564e7fd4179SDavid Teigland uint32_t flags, int lvblen) 565e7fd4179SDavid Teigland { 566e7fd4179SDavid Teigland int error = 0; 567e7fd4179SDavid Teigland 56890135925SDavid Teigland mutex_lock(&ls_lock); 569e7fd4179SDavid Teigland if (!ls_count) 570e7fd4179SDavid Teigland error = threads_start(); 571e7fd4179SDavid Teigland if (error) 572e7fd4179SDavid Teigland goto out; 573e7fd4179SDavid Teigland 574e7fd4179SDavid Teigland error = new_lockspace(name, namelen, lockspace, flags, lvblen); 575e7fd4179SDavid Teigland if (!error) 576e7fd4179SDavid Teigland ls_count++; 577e7fd4179SDavid Teigland out: 57890135925SDavid Teigland mutex_unlock(&ls_lock); 579e7fd4179SDavid Teigland return error; 580e7fd4179SDavid Teigland } 581e7fd4179SDavid Teigland 582e7fd4179SDavid Teigland /* Return 1 if the lockspace still has active remote locks, 583e7fd4179SDavid Teigland * 2 if the lockspace still has active local locks. 584e7fd4179SDavid Teigland */ 585e7fd4179SDavid Teigland static int lockspace_busy(struct dlm_ls *ls) 586e7fd4179SDavid Teigland { 587e7fd4179SDavid Teigland int i, lkb_found = 0; 588e7fd4179SDavid Teigland struct dlm_lkb *lkb; 589e7fd4179SDavid Teigland 590e7fd4179SDavid Teigland /* NOTE: We check the lockidtbl here rather than the resource table. 591e7fd4179SDavid Teigland This is because there may be LKBs queued as ASTs that have been 592e7fd4179SDavid Teigland unlinked from their RSBs and are pending deletion once the AST has 593e7fd4179SDavid Teigland been delivered */ 594e7fd4179SDavid Teigland 595e7fd4179SDavid Teigland for (i = 0; i < ls->ls_lkbtbl_size; i++) { 596e7fd4179SDavid Teigland read_lock(&ls->ls_lkbtbl[i].lock); 597e7fd4179SDavid Teigland if (!list_empty(&ls->ls_lkbtbl[i].list)) { 598e7fd4179SDavid Teigland lkb_found = 1; 599e7fd4179SDavid Teigland list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list, 600e7fd4179SDavid Teigland lkb_idtbl_list) { 601e7fd4179SDavid Teigland if (!lkb->lkb_nodeid) { 602e7fd4179SDavid Teigland read_unlock(&ls->ls_lkbtbl[i].lock); 603e7fd4179SDavid Teigland return 2; 604e7fd4179SDavid Teigland } 605e7fd4179SDavid Teigland } 606e7fd4179SDavid Teigland } 607e7fd4179SDavid Teigland read_unlock(&ls->ls_lkbtbl[i].lock); 608e7fd4179SDavid Teigland } 609e7fd4179SDavid Teigland return lkb_found; 610e7fd4179SDavid Teigland } 611e7fd4179SDavid Teigland 612e7fd4179SDavid Teigland static int release_lockspace(struct dlm_ls *ls, int force) 613e7fd4179SDavid Teigland { 614e7fd4179SDavid Teigland struct dlm_lkb *lkb; 615e7fd4179SDavid Teigland struct dlm_rsb *rsb; 616e7fd4179SDavid Teigland struct list_head *head; 617e7fd4179SDavid Teigland int i; 618e7fd4179SDavid Teigland int busy = lockspace_busy(ls); 619e7fd4179SDavid Teigland 620e7fd4179SDavid Teigland if (busy > force) 621e7fd4179SDavid Teigland return -EBUSY; 622e7fd4179SDavid Teigland 623e7fd4179SDavid Teigland if (force < 3) 624e7fd4179SDavid Teigland do_uevent(ls, 0); 625e7fd4179SDavid Teigland 626e7fd4179SDavid Teigland dlm_recoverd_stop(ls); 627e7fd4179SDavid Teigland 628e7fd4179SDavid Teigland remove_lockspace(ls); 629e7fd4179SDavid Teigland 630e7fd4179SDavid Teigland dlm_delete_debug_file(ls); 631e7fd4179SDavid Teigland 632e7fd4179SDavid Teigland dlm_astd_suspend(); 633e7fd4179SDavid Teigland 634e7fd4179SDavid Teigland kfree(ls->ls_recover_buf); 635e7fd4179SDavid Teigland 636e7fd4179SDavid Teigland /* 637e7fd4179SDavid Teigland * Free direntry structs. 638e7fd4179SDavid Teigland */ 639e7fd4179SDavid Teigland 640e7fd4179SDavid Teigland dlm_dir_clear(ls); 641e7fd4179SDavid Teigland kfree(ls->ls_dirtbl); 642e7fd4179SDavid Teigland 643e7fd4179SDavid Teigland /* 644e7fd4179SDavid Teigland * Free all lkb's on lkbtbl[] lists. 645e7fd4179SDavid Teigland */ 646e7fd4179SDavid Teigland 647e7fd4179SDavid Teigland for (i = 0; i < ls->ls_lkbtbl_size; i++) { 648e7fd4179SDavid Teigland head = &ls->ls_lkbtbl[i].list; 649e7fd4179SDavid Teigland while (!list_empty(head)) { 650e7fd4179SDavid Teigland lkb = list_entry(head->next, struct dlm_lkb, 651e7fd4179SDavid Teigland lkb_idtbl_list); 652e7fd4179SDavid Teigland 653e7fd4179SDavid Teigland list_del(&lkb->lkb_idtbl_list); 654e7fd4179SDavid Teigland 655e7fd4179SDavid Teigland dlm_del_ast(lkb); 656e7fd4179SDavid Teigland 657e7fd4179SDavid Teigland if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY) 658e7fd4179SDavid Teigland free_lvb(lkb->lkb_lvbptr); 659e7fd4179SDavid Teigland 660e7fd4179SDavid Teigland free_lkb(lkb); 661e7fd4179SDavid Teigland } 662e7fd4179SDavid Teigland } 663e7fd4179SDavid Teigland dlm_astd_resume(); 664e7fd4179SDavid Teigland 665e7fd4179SDavid Teigland kfree(ls->ls_lkbtbl); 666e7fd4179SDavid Teigland 667e7fd4179SDavid Teigland /* 668e7fd4179SDavid Teigland * Free all rsb's on rsbtbl[] lists 669e7fd4179SDavid Teigland */ 670e7fd4179SDavid Teigland 671e7fd4179SDavid Teigland for (i = 0; i < ls->ls_rsbtbl_size; i++) { 672e7fd4179SDavid Teigland head = &ls->ls_rsbtbl[i].list; 673e7fd4179SDavid Teigland while (!list_empty(head)) { 674e7fd4179SDavid Teigland rsb = list_entry(head->next, struct dlm_rsb, 675e7fd4179SDavid Teigland res_hashchain); 676e7fd4179SDavid Teigland 677e7fd4179SDavid Teigland list_del(&rsb->res_hashchain); 678e7fd4179SDavid Teigland free_rsb(rsb); 679e7fd4179SDavid Teigland } 680e7fd4179SDavid Teigland 681e7fd4179SDavid Teigland head = &ls->ls_rsbtbl[i].toss; 682e7fd4179SDavid Teigland while (!list_empty(head)) { 683e7fd4179SDavid Teigland rsb = list_entry(head->next, struct dlm_rsb, 684e7fd4179SDavid Teigland res_hashchain); 685e7fd4179SDavid Teigland list_del(&rsb->res_hashchain); 686e7fd4179SDavid Teigland free_rsb(rsb); 687e7fd4179SDavid Teigland } 688e7fd4179SDavid Teigland } 689e7fd4179SDavid Teigland 690e7fd4179SDavid Teigland kfree(ls->ls_rsbtbl); 691e7fd4179SDavid Teigland 692e7fd4179SDavid Teigland /* 693e7fd4179SDavid Teigland * Free structures on any other lists 694e7fd4179SDavid Teigland */ 695e7fd4179SDavid Teigland 6962896ee37SDavid Teigland dlm_purge_requestqueue(ls); 697e7fd4179SDavid Teigland kfree(ls->ls_recover_args); 698e7fd4179SDavid Teigland dlm_clear_free_entries(ls); 699e7fd4179SDavid Teigland dlm_clear_members(ls); 700e7fd4179SDavid Teigland dlm_clear_members_gone(ls); 701e7fd4179SDavid Teigland kfree(ls->ls_node_array); 702e7fd4179SDavid Teigland kobject_unregister(&ls->ls_kobj); 703ba542e3bSPatrick Caulfield /* The ls structure will be freed when the kobject is done with */ 704e7fd4179SDavid Teigland 70590135925SDavid Teigland mutex_lock(&ls_lock); 706e7fd4179SDavid Teigland ls_count--; 707e7fd4179SDavid Teigland if (!ls_count) 708e7fd4179SDavid Teigland threads_stop(); 70990135925SDavid Teigland mutex_unlock(&ls_lock); 710e7fd4179SDavid Teigland 711e7fd4179SDavid Teigland module_put(THIS_MODULE); 712e7fd4179SDavid Teigland return 0; 713e7fd4179SDavid Teigland } 714e7fd4179SDavid Teigland 715e7fd4179SDavid Teigland /* 716e7fd4179SDavid Teigland * Called when a system has released all its locks and is not going to use the 717e7fd4179SDavid Teigland * lockspace any longer. We free everything we're managing for this lockspace. 718e7fd4179SDavid Teigland * Remaining nodes will go through the recovery process as if we'd died. The 719e7fd4179SDavid Teigland * lockspace must continue to function as usual, participating in recoveries, 720e7fd4179SDavid Teigland * until this returns. 721e7fd4179SDavid Teigland * 722e7fd4179SDavid Teigland * Force has 4 possible values: 723e7fd4179SDavid Teigland * 0 - don't destroy locksapce if it has any LKBs 724e7fd4179SDavid Teigland * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs 725e7fd4179SDavid Teigland * 2 - destroy lockspace regardless of LKBs 726e7fd4179SDavid Teigland * 3 - destroy lockspace as part of a forced shutdown 727e7fd4179SDavid Teigland */ 728e7fd4179SDavid Teigland 729e7fd4179SDavid Teigland int dlm_release_lockspace(void *lockspace, int force) 730e7fd4179SDavid Teigland { 731e7fd4179SDavid Teigland struct dlm_ls *ls; 732e7fd4179SDavid Teigland 733e7fd4179SDavid Teigland ls = dlm_find_lockspace_local(lockspace); 734e7fd4179SDavid Teigland if (!ls) 735e7fd4179SDavid Teigland return -EINVAL; 736e7fd4179SDavid Teigland dlm_put_lockspace(ls); 737e7fd4179SDavid Teigland return release_lockspace(ls, force); 738e7fd4179SDavid Teigland } 739e7fd4179SDavid Teigland 740