162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci******************************************************************************* 462306a36Sopenharmony_ci** 562306a36Sopenharmony_ci** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 662306a36Sopenharmony_ci** Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. 762306a36Sopenharmony_ci** 862306a36Sopenharmony_ci** 962306a36Sopenharmony_ci******************************************************************************* 1062306a36Sopenharmony_ci******************************************************************************/ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "dlm_internal.h" 1562306a36Sopenharmony_ci#include "lockspace.h" 1662306a36Sopenharmony_ci#include "member.h" 1762306a36Sopenharmony_ci#include "recoverd.h" 1862306a36Sopenharmony_ci#include "dir.h" 1962306a36Sopenharmony_ci#include "midcomms.h" 2062306a36Sopenharmony_ci#include "config.h" 2162306a36Sopenharmony_ci#include "memory.h" 2262306a36Sopenharmony_ci#include "lock.h" 2362306a36Sopenharmony_ci#include "recover.h" 2462306a36Sopenharmony_ci#include "requestqueue.h" 2562306a36Sopenharmony_ci#include "user.h" 2662306a36Sopenharmony_ci#include "ast.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int ls_count; 2962306a36Sopenharmony_cistatic struct mutex ls_lock; 3062306a36Sopenharmony_cistatic struct list_head lslist; 3162306a36Sopenharmony_cistatic spinlock_t lslist_lock; 3262306a36Sopenharmony_cistatic struct task_struct * scand_task; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci ssize_t ret = len; 3862306a36Sopenharmony_ci int n; 3962306a36Sopenharmony_ci int rc = kstrtoint(buf, 0, &n); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (rc) 4262306a36Sopenharmony_ci return rc; 4362306a36Sopenharmony_ci ls = dlm_find_lockspace_local(ls->ls_local_handle); 4462306a36Sopenharmony_ci if (!ls) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci switch (n) { 4862306a36Sopenharmony_ci case 0: 4962306a36Sopenharmony_ci dlm_ls_stop(ls); 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci case 1: 5262306a36Sopenharmony_ci dlm_ls_start(ls); 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci default: 5562306a36Sopenharmony_ci ret = -EINVAL; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci dlm_put_lockspace(ls); 5862306a36Sopenharmony_ci return ret; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int rc = kstrtoint(buf, 0, &ls->ls_uevent_result); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (rc) 6662306a36Sopenharmony_ci return rc; 6762306a36Sopenharmony_ci set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags); 6862306a36Sopenharmony_ci wake_up(&ls->ls_uevent_wait); 6962306a36Sopenharmony_ci return len; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic ssize_t dlm_id_show(struct dlm_ls *ls, char *buf) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci int rc = kstrtouint(buf, 0, &ls->ls_global_id); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (rc) 8262306a36Sopenharmony_ci return rc; 8362306a36Sopenharmony_ci return len; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic ssize_t dlm_nodir_show(struct dlm_ls *ls, char *buf) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%u\n", dlm_no_directory(ls)); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic ssize_t dlm_nodir_store(struct dlm_ls *ls, const char *buf, size_t len) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int val; 9462306a36Sopenharmony_ci int rc = kstrtoint(buf, 0, &val); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (rc) 9762306a36Sopenharmony_ci return rc; 9862306a36Sopenharmony_ci if (val == 1) 9962306a36Sopenharmony_ci set_bit(LSFL_NODIR, &ls->ls_flags); 10062306a36Sopenharmony_ci return len; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci uint32_t status = dlm_recover_status(ls); 10662306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%x\n", status); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct dlm_attr { 11562306a36Sopenharmony_ci struct attribute attr; 11662306a36Sopenharmony_ci ssize_t (*show)(struct dlm_ls *, char *); 11762306a36Sopenharmony_ci ssize_t (*store)(struct dlm_ls *, const char *, size_t); 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_control = { 12162306a36Sopenharmony_ci .attr = {.name = "control", .mode = S_IWUSR}, 12262306a36Sopenharmony_ci .store = dlm_control_store 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_event = { 12662306a36Sopenharmony_ci .attr = {.name = "event_done", .mode = S_IWUSR}, 12762306a36Sopenharmony_ci .store = dlm_event_store 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_id = { 13162306a36Sopenharmony_ci .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR}, 13262306a36Sopenharmony_ci .show = dlm_id_show, 13362306a36Sopenharmony_ci .store = dlm_id_store 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_nodir = { 13762306a36Sopenharmony_ci .attr = {.name = "nodir", .mode = S_IRUGO | S_IWUSR}, 13862306a36Sopenharmony_ci .show = dlm_nodir_show, 13962306a36Sopenharmony_ci .store = dlm_nodir_store 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_recover_status = { 14362306a36Sopenharmony_ci .attr = {.name = "recover_status", .mode = S_IRUGO}, 14462306a36Sopenharmony_ci .show = dlm_recover_status_show 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct dlm_attr dlm_attr_recover_nodeid = { 14862306a36Sopenharmony_ci .attr = {.name = "recover_nodeid", .mode = S_IRUGO}, 14962306a36Sopenharmony_ci .show = dlm_recover_nodeid_show 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic struct attribute *dlm_attrs[] = { 15362306a36Sopenharmony_ci &dlm_attr_control.attr, 15462306a36Sopenharmony_ci &dlm_attr_event.attr, 15562306a36Sopenharmony_ci &dlm_attr_id.attr, 15662306a36Sopenharmony_ci &dlm_attr_nodir.attr, 15762306a36Sopenharmony_ci &dlm_attr_recover_status.attr, 15862306a36Sopenharmony_ci &dlm_attr_recover_nodeid.attr, 15962306a36Sopenharmony_ci NULL, 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ciATTRIBUTE_GROUPS(dlm); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr, 16462306a36Sopenharmony_ci char *buf) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); 16762306a36Sopenharmony_ci struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); 16862306a36Sopenharmony_ci return a->show ? a->show(ls, buf) : 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr, 17262306a36Sopenharmony_ci const char *buf, size_t len) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); 17562306a36Sopenharmony_ci struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); 17662306a36Sopenharmony_ci return a->store ? a->store(ls, buf, len) : len; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void lockspace_kobj_release(struct kobject *k) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct dlm_ls *ls = container_of(k, struct dlm_ls, ls_kobj); 18262306a36Sopenharmony_ci kfree(ls); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct sysfs_ops dlm_attr_ops = { 18662306a36Sopenharmony_ci .show = dlm_attr_show, 18762306a36Sopenharmony_ci .store = dlm_attr_store, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct kobj_type dlm_ktype = { 19162306a36Sopenharmony_ci .default_groups = dlm_groups, 19262306a36Sopenharmony_ci .sysfs_ops = &dlm_attr_ops, 19362306a36Sopenharmony_ci .release = lockspace_kobj_release, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic struct kset *dlm_kset; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int do_uevent(struct dlm_ls *ls, int in) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (in) 20162306a36Sopenharmony_ci kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE); 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci log_rinfo(ls, "%s the lockspace group...", in ? "joining" : "leaving"); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* dlm_controld will see the uevent, do the necessary group management 20862306a36Sopenharmony_ci and then write to sysfs to wake us */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci wait_event(ls->ls_uevent_wait, 21162306a36Sopenharmony_ci test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags)); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci log_rinfo(ls, "group event done %d", ls->ls_uevent_result); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return ls->ls_uevent_result; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int dlm_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci const struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci add_uevent_var(env, "LOCKSPACE=%s", ls->ls_name); 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic const struct kset_uevent_ops dlm_uevent_ops = { 22762306a36Sopenharmony_ci .uevent = dlm_uevent, 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint __init dlm_lockspace_init(void) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci ls_count = 0; 23362306a36Sopenharmony_ci mutex_init(&ls_lock); 23462306a36Sopenharmony_ci INIT_LIST_HEAD(&lslist); 23562306a36Sopenharmony_ci spin_lock_init(&lslist_lock); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci dlm_kset = kset_create_and_add("dlm", &dlm_uevent_ops, kernel_kobj); 23862306a36Sopenharmony_ci if (!dlm_kset) { 23962306a36Sopenharmony_ci printk(KERN_WARNING "%s: can not create kset\n", __func__); 24062306a36Sopenharmony_ci return -ENOMEM; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_civoid dlm_lockspace_exit(void) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci kset_unregister(dlm_kset); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic struct dlm_ls *find_ls_to_scan(void) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct dlm_ls *ls; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci spin_lock(&lslist_lock); 25562306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 25662306a36Sopenharmony_ci if (time_after_eq(jiffies, ls->ls_scan_time + 25762306a36Sopenharmony_ci dlm_config.ci_scan_secs * HZ)) { 25862306a36Sopenharmony_ci spin_unlock(&lslist_lock); 25962306a36Sopenharmony_ci return ls; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci spin_unlock(&lslist_lock); 26362306a36Sopenharmony_ci return NULL; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int dlm_scand(void *data) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct dlm_ls *ls; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci while (!kthread_should_stop()) { 27162306a36Sopenharmony_ci ls = find_ls_to_scan(); 27262306a36Sopenharmony_ci if (ls) { 27362306a36Sopenharmony_ci if (dlm_lock_recovery_try(ls)) { 27462306a36Sopenharmony_ci ls->ls_scan_time = jiffies; 27562306a36Sopenharmony_ci dlm_scan_rsbs(ls); 27662306a36Sopenharmony_ci dlm_unlock_recovery(ls); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci ls->ls_scan_time += HZ; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci continue; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int dlm_scand_start(void) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct task_struct *p; 29062306a36Sopenharmony_ci int error = 0; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci p = kthread_run(dlm_scand, NULL, "dlm_scand"); 29362306a36Sopenharmony_ci if (IS_ERR(p)) 29462306a36Sopenharmony_ci error = PTR_ERR(p); 29562306a36Sopenharmony_ci else 29662306a36Sopenharmony_ci scand_task = p; 29762306a36Sopenharmony_ci return error; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void dlm_scand_stop(void) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci kthread_stop(scand_task); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistruct dlm_ls *dlm_find_lockspace_global(uint32_t id) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct dlm_ls *ls; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci spin_lock(&lslist_lock); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 31262306a36Sopenharmony_ci if (ls->ls_global_id == id) { 31362306a36Sopenharmony_ci atomic_inc(&ls->ls_count); 31462306a36Sopenharmony_ci goto out; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci ls = NULL; 31862306a36Sopenharmony_ci out: 31962306a36Sopenharmony_ci spin_unlock(&lslist_lock); 32062306a36Sopenharmony_ci return ls; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistruct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct dlm_ls *ls; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci spin_lock(&lslist_lock); 32862306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 32962306a36Sopenharmony_ci if (ls->ls_local_handle == lockspace) { 33062306a36Sopenharmony_ci atomic_inc(&ls->ls_count); 33162306a36Sopenharmony_ci goto out; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci ls = NULL; 33562306a36Sopenharmony_ci out: 33662306a36Sopenharmony_ci spin_unlock(&lslist_lock); 33762306a36Sopenharmony_ci return ls; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistruct dlm_ls *dlm_find_lockspace_device(int minor) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct dlm_ls *ls; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci spin_lock(&lslist_lock); 34562306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 34662306a36Sopenharmony_ci if (ls->ls_device.minor == minor) { 34762306a36Sopenharmony_ci atomic_inc(&ls->ls_count); 34862306a36Sopenharmony_ci goto out; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci ls = NULL; 35262306a36Sopenharmony_ci out: 35362306a36Sopenharmony_ci spin_unlock(&lslist_lock); 35462306a36Sopenharmony_ci return ls; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_civoid dlm_put_lockspace(struct dlm_ls *ls) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (atomic_dec_and_test(&ls->ls_count)) 36062306a36Sopenharmony_ci wake_up(&ls->ls_count_wait); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void remove_lockspace(struct dlm_ls *ls) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ciretry: 36662306a36Sopenharmony_ci wait_event(ls->ls_count_wait, atomic_read(&ls->ls_count) == 0); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci spin_lock(&lslist_lock); 36962306a36Sopenharmony_ci if (atomic_read(&ls->ls_count) != 0) { 37062306a36Sopenharmony_ci spin_unlock(&lslist_lock); 37162306a36Sopenharmony_ci goto retry; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci WARN_ON(ls->ls_create_count != 0); 37562306a36Sopenharmony_ci list_del(&ls->ls_list); 37662306a36Sopenharmony_ci spin_unlock(&lslist_lock); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int threads_start(void) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci int error; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Thread for sending/receiving messages for all lockspace's */ 38462306a36Sopenharmony_ci error = dlm_midcomms_start(); 38562306a36Sopenharmony_ci if (error) { 38662306a36Sopenharmony_ci log_print("cannot start dlm midcomms %d", error); 38762306a36Sopenharmony_ci goto fail; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci error = dlm_scand_start(); 39162306a36Sopenharmony_ci if (error) { 39262306a36Sopenharmony_ci log_print("cannot start dlm_scand thread %d", error); 39362306a36Sopenharmony_ci goto midcomms_fail; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci midcomms_fail: 39962306a36Sopenharmony_ci dlm_midcomms_stop(); 40062306a36Sopenharmony_ci fail: 40162306a36Sopenharmony_ci return error; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int new_lockspace(const char *name, const char *cluster, 40562306a36Sopenharmony_ci uint32_t flags, int lvblen, 40662306a36Sopenharmony_ci const struct dlm_lockspace_ops *ops, void *ops_arg, 40762306a36Sopenharmony_ci int *ops_result, dlm_lockspace_t **lockspace) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct dlm_ls *ls; 41062306a36Sopenharmony_ci int i, size, error; 41162306a36Sopenharmony_ci int do_unreg = 0; 41262306a36Sopenharmony_ci int namelen = strlen(name); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (namelen > DLM_LOCKSPACE_LEN || namelen == 0) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (lvblen % 8) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 42162306a36Sopenharmony_ci return -EINVAL; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (!dlm_user_daemon_available()) { 42462306a36Sopenharmony_ci log_print("dlm user daemon not available"); 42562306a36Sopenharmony_ci error = -EUNATCH; 42662306a36Sopenharmony_ci goto out; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (ops && ops_result) { 43062306a36Sopenharmony_ci if (!dlm_config.ci_recover_callbacks) 43162306a36Sopenharmony_ci *ops_result = -EOPNOTSUPP; 43262306a36Sopenharmony_ci else 43362306a36Sopenharmony_ci *ops_result = 0; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!cluster) 43762306a36Sopenharmony_ci log_print("dlm cluster name '%s' is being used without an application provided cluster name", 43862306a36Sopenharmony_ci dlm_config.ci_cluster_name); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (dlm_config.ci_recover_callbacks && cluster && 44162306a36Sopenharmony_ci strncmp(cluster, dlm_config.ci_cluster_name, DLM_LOCKSPACE_LEN)) { 44262306a36Sopenharmony_ci log_print("dlm cluster name '%s' does not match " 44362306a36Sopenharmony_ci "the application cluster name '%s'", 44462306a36Sopenharmony_ci dlm_config.ci_cluster_name, cluster); 44562306a36Sopenharmony_ci error = -EBADR; 44662306a36Sopenharmony_ci goto out; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci error = 0; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci spin_lock(&lslist_lock); 45262306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 45362306a36Sopenharmony_ci WARN_ON(ls->ls_create_count <= 0); 45462306a36Sopenharmony_ci if (ls->ls_namelen != namelen) 45562306a36Sopenharmony_ci continue; 45662306a36Sopenharmony_ci if (memcmp(ls->ls_name, name, namelen)) 45762306a36Sopenharmony_ci continue; 45862306a36Sopenharmony_ci if (flags & DLM_LSFL_NEWEXCL) { 45962306a36Sopenharmony_ci error = -EEXIST; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci ls->ls_create_count++; 46362306a36Sopenharmony_ci *lockspace = ls; 46462306a36Sopenharmony_ci error = 1; 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci spin_unlock(&lslist_lock); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (error) 47062306a36Sopenharmony_ci goto out; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci error = -ENOMEM; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci ls = kzalloc(sizeof(*ls), GFP_NOFS); 47562306a36Sopenharmony_ci if (!ls) 47662306a36Sopenharmony_ci goto out; 47762306a36Sopenharmony_ci memcpy(ls->ls_name, name, namelen); 47862306a36Sopenharmony_ci ls->ls_namelen = namelen; 47962306a36Sopenharmony_ci ls->ls_lvblen = lvblen; 48062306a36Sopenharmony_ci atomic_set(&ls->ls_count, 0); 48162306a36Sopenharmony_ci init_waitqueue_head(&ls->ls_count_wait); 48262306a36Sopenharmony_ci ls->ls_flags = 0; 48362306a36Sopenharmony_ci ls->ls_scan_time = jiffies; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (ops && dlm_config.ci_recover_callbacks) { 48662306a36Sopenharmony_ci ls->ls_ops = ops; 48762306a36Sopenharmony_ci ls->ls_ops_arg = ops_arg; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* ls_exflags are forced to match among nodes, and we don't 49162306a36Sopenharmony_ci * need to require all nodes to have some flags set 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_ci ls->ls_exflags = (flags & ~(DLM_LSFL_FS | DLM_LSFL_NEWEXCL)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci size = READ_ONCE(dlm_config.ci_rsbtbl_size); 49662306a36Sopenharmony_ci ls->ls_rsbtbl_size = size; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ls->ls_rsbtbl = vmalloc(array_size(size, sizeof(struct dlm_rsbtable))); 49962306a36Sopenharmony_ci if (!ls->ls_rsbtbl) 50062306a36Sopenharmony_ci goto out_lsfree; 50162306a36Sopenharmony_ci for (i = 0; i < size; i++) { 50262306a36Sopenharmony_ci ls->ls_rsbtbl[i].keep.rb_node = NULL; 50362306a36Sopenharmony_ci ls->ls_rsbtbl[i].toss.rb_node = NULL; 50462306a36Sopenharmony_ci spin_lock_init(&ls->ls_rsbtbl[i].lock); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) { 50862306a36Sopenharmony_ci ls->ls_remove_names[i] = kzalloc(DLM_RESNAME_MAXLEN+1, 50962306a36Sopenharmony_ci GFP_KERNEL); 51062306a36Sopenharmony_ci if (!ls->ls_remove_names[i]) 51162306a36Sopenharmony_ci goto out_rsbtbl; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci idr_init(&ls->ls_lkbidr); 51562306a36Sopenharmony_ci spin_lock_init(&ls->ls_lkbidr_spin); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_waiters); 51862306a36Sopenharmony_ci mutex_init(&ls->ls_waiters_mutex); 51962306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_orphans); 52062306a36Sopenharmony_ci mutex_init(&ls->ls_orphans_mutex); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_new_rsb); 52362306a36Sopenharmony_ci spin_lock_init(&ls->ls_new_rsb_spin); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_nodes); 52662306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_nodes_gone); 52762306a36Sopenharmony_ci ls->ls_num_nodes = 0; 52862306a36Sopenharmony_ci ls->ls_low_nodeid = 0; 52962306a36Sopenharmony_ci ls->ls_total_weight = 0; 53062306a36Sopenharmony_ci ls->ls_node_array = NULL; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci memset(&ls->ls_local_rsb, 0, sizeof(struct dlm_rsb)); 53362306a36Sopenharmony_ci ls->ls_local_rsb.res_ls = ls; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ls->ls_debug_rsb_dentry = NULL; 53662306a36Sopenharmony_ci ls->ls_debug_waiters_dentry = NULL; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci init_waitqueue_head(&ls->ls_uevent_wait); 53962306a36Sopenharmony_ci ls->ls_uevent_result = 0; 54062306a36Sopenharmony_ci init_completion(&ls->ls_recovery_done); 54162306a36Sopenharmony_ci ls->ls_recovery_result = -1; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci spin_lock_init(&ls->ls_cb_lock); 54462306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_cb_delay); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ls->ls_recoverd_task = NULL; 54762306a36Sopenharmony_ci mutex_init(&ls->ls_recoverd_active); 54862306a36Sopenharmony_ci spin_lock_init(&ls->ls_recover_lock); 54962306a36Sopenharmony_ci spin_lock_init(&ls->ls_rcom_spin); 55062306a36Sopenharmony_ci get_random_bytes(&ls->ls_rcom_seq, sizeof(uint64_t)); 55162306a36Sopenharmony_ci ls->ls_recover_status = 0; 55262306a36Sopenharmony_ci ls->ls_recover_seq = get_random_u64(); 55362306a36Sopenharmony_ci ls->ls_recover_args = NULL; 55462306a36Sopenharmony_ci init_rwsem(&ls->ls_in_recovery); 55562306a36Sopenharmony_ci init_rwsem(&ls->ls_recv_active); 55662306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_requestqueue); 55762306a36Sopenharmony_ci atomic_set(&ls->ls_requestqueue_cnt, 0); 55862306a36Sopenharmony_ci init_waitqueue_head(&ls->ls_requestqueue_wait); 55962306a36Sopenharmony_ci mutex_init(&ls->ls_requestqueue_mutex); 56062306a36Sopenharmony_ci spin_lock_init(&ls->ls_clear_proc_locks); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Due backwards compatibility with 3.1 we need to use maximum 56362306a36Sopenharmony_ci * possible dlm message size to be sure the message will fit and 56462306a36Sopenharmony_ci * not having out of bounds issues. However on sending side 3.2 56562306a36Sopenharmony_ci * might send less. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci ls->ls_recover_buf = kmalloc(DLM_MAX_SOCKET_BUFSIZE, GFP_NOFS); 56862306a36Sopenharmony_ci if (!ls->ls_recover_buf) 56962306a36Sopenharmony_ci goto out_lkbidr; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ls->ls_slot = 0; 57262306a36Sopenharmony_ci ls->ls_num_slots = 0; 57362306a36Sopenharmony_ci ls->ls_slots_size = 0; 57462306a36Sopenharmony_ci ls->ls_slots = NULL; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_recover_list); 57762306a36Sopenharmony_ci spin_lock_init(&ls->ls_recover_list_lock); 57862306a36Sopenharmony_ci idr_init(&ls->ls_recover_idr); 57962306a36Sopenharmony_ci spin_lock_init(&ls->ls_recover_idr_lock); 58062306a36Sopenharmony_ci ls->ls_recover_list_count = 0; 58162306a36Sopenharmony_ci ls->ls_local_handle = ls; 58262306a36Sopenharmony_ci init_waitqueue_head(&ls->ls_wait_general); 58362306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_root_list); 58462306a36Sopenharmony_ci init_rwsem(&ls->ls_root_sem); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci spin_lock(&lslist_lock); 58762306a36Sopenharmony_ci ls->ls_create_count = 1; 58862306a36Sopenharmony_ci list_add(&ls->ls_list, &lslist); 58962306a36Sopenharmony_ci spin_unlock(&lslist_lock); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (flags & DLM_LSFL_FS) { 59262306a36Sopenharmony_ci error = dlm_callback_start(ls); 59362306a36Sopenharmony_ci if (error) { 59462306a36Sopenharmony_ci log_error(ls, "can't start dlm_callback %d", error); 59562306a36Sopenharmony_ci goto out_delist; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci init_waitqueue_head(&ls->ls_recover_lock_wait); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * Once started, dlm_recoverd first looks for ls in lslist, then 60362306a36Sopenharmony_ci * initializes ls_in_recovery as locked in "down" mode. We need 60462306a36Sopenharmony_ci * to wait for the wakeup from dlm_recoverd because in_recovery 60562306a36Sopenharmony_ci * has to start out in down mode. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci error = dlm_recoverd_start(ls); 60962306a36Sopenharmony_ci if (error) { 61062306a36Sopenharmony_ci log_error(ls, "can't start dlm_recoverd %d", error); 61162306a36Sopenharmony_ci goto out_callback; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci wait_event(ls->ls_recover_lock_wait, 61562306a36Sopenharmony_ci test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags)); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* let kobject handle freeing of ls if there's an error */ 61862306a36Sopenharmony_ci do_unreg = 1; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ls->ls_kobj.kset = dlm_kset; 62162306a36Sopenharmony_ci error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL, 62262306a36Sopenharmony_ci "%s", ls->ls_name); 62362306a36Sopenharmony_ci if (error) 62462306a36Sopenharmony_ci goto out_recoverd; 62562306a36Sopenharmony_ci kobject_uevent(&ls->ls_kobj, KOBJ_ADD); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* This uevent triggers dlm_controld in userspace to add us to the 62862306a36Sopenharmony_ci group of nodes that are members of this lockspace (managed by the 62962306a36Sopenharmony_ci cluster infrastructure.) Once it's done that, it tells us who the 63062306a36Sopenharmony_ci current lockspace members are (via configfs) and then tells the 63162306a36Sopenharmony_ci lockspace to start running (via sysfs) in dlm_ls_start(). */ 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci error = do_uevent(ls, 1); 63462306a36Sopenharmony_ci if (error) 63562306a36Sopenharmony_ci goto out_recoverd; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* wait until recovery is successful or failed */ 63862306a36Sopenharmony_ci wait_for_completion(&ls->ls_recovery_done); 63962306a36Sopenharmony_ci error = ls->ls_recovery_result; 64062306a36Sopenharmony_ci if (error) 64162306a36Sopenharmony_ci goto out_members; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci dlm_create_debug_file(ls); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci log_rinfo(ls, "join complete"); 64662306a36Sopenharmony_ci *lockspace = ls; 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci out_members: 65062306a36Sopenharmony_ci do_uevent(ls, 0); 65162306a36Sopenharmony_ci dlm_clear_members(ls); 65262306a36Sopenharmony_ci kfree(ls->ls_node_array); 65362306a36Sopenharmony_ci out_recoverd: 65462306a36Sopenharmony_ci dlm_recoverd_stop(ls); 65562306a36Sopenharmony_ci out_callback: 65662306a36Sopenharmony_ci dlm_callback_stop(ls); 65762306a36Sopenharmony_ci out_delist: 65862306a36Sopenharmony_ci spin_lock(&lslist_lock); 65962306a36Sopenharmony_ci list_del(&ls->ls_list); 66062306a36Sopenharmony_ci spin_unlock(&lslist_lock); 66162306a36Sopenharmony_ci idr_destroy(&ls->ls_recover_idr); 66262306a36Sopenharmony_ci kfree(ls->ls_recover_buf); 66362306a36Sopenharmony_ci out_lkbidr: 66462306a36Sopenharmony_ci idr_destroy(&ls->ls_lkbidr); 66562306a36Sopenharmony_ci out_rsbtbl: 66662306a36Sopenharmony_ci for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) 66762306a36Sopenharmony_ci kfree(ls->ls_remove_names[i]); 66862306a36Sopenharmony_ci vfree(ls->ls_rsbtbl); 66962306a36Sopenharmony_ci out_lsfree: 67062306a36Sopenharmony_ci if (do_unreg) 67162306a36Sopenharmony_ci kobject_put(&ls->ls_kobj); 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci kfree(ls); 67462306a36Sopenharmony_ci out: 67562306a36Sopenharmony_ci module_put(THIS_MODULE); 67662306a36Sopenharmony_ci return error; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int __dlm_new_lockspace(const char *name, const char *cluster, 68062306a36Sopenharmony_ci uint32_t flags, int lvblen, 68162306a36Sopenharmony_ci const struct dlm_lockspace_ops *ops, 68262306a36Sopenharmony_ci void *ops_arg, int *ops_result, 68362306a36Sopenharmony_ci dlm_lockspace_t **lockspace) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int error = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci mutex_lock(&ls_lock); 68862306a36Sopenharmony_ci if (!ls_count) 68962306a36Sopenharmony_ci error = threads_start(); 69062306a36Sopenharmony_ci if (error) 69162306a36Sopenharmony_ci goto out; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci error = new_lockspace(name, cluster, flags, lvblen, ops, ops_arg, 69462306a36Sopenharmony_ci ops_result, lockspace); 69562306a36Sopenharmony_ci if (!error) 69662306a36Sopenharmony_ci ls_count++; 69762306a36Sopenharmony_ci if (error > 0) 69862306a36Sopenharmony_ci error = 0; 69962306a36Sopenharmony_ci if (!ls_count) { 70062306a36Sopenharmony_ci dlm_scand_stop(); 70162306a36Sopenharmony_ci dlm_midcomms_shutdown(); 70262306a36Sopenharmony_ci dlm_midcomms_stop(); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci out: 70562306a36Sopenharmony_ci mutex_unlock(&ls_lock); 70662306a36Sopenharmony_ci return error; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ciint dlm_new_lockspace(const char *name, const char *cluster, uint32_t flags, 71062306a36Sopenharmony_ci int lvblen, const struct dlm_lockspace_ops *ops, 71162306a36Sopenharmony_ci void *ops_arg, int *ops_result, 71262306a36Sopenharmony_ci dlm_lockspace_t **lockspace) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci return __dlm_new_lockspace(name, cluster, flags | DLM_LSFL_FS, lvblen, 71562306a36Sopenharmony_ci ops, ops_arg, ops_result, lockspace); 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ciint dlm_new_user_lockspace(const char *name, const char *cluster, 71962306a36Sopenharmony_ci uint32_t flags, int lvblen, 72062306a36Sopenharmony_ci const struct dlm_lockspace_ops *ops, 72162306a36Sopenharmony_ci void *ops_arg, int *ops_result, 72262306a36Sopenharmony_ci dlm_lockspace_t **lockspace) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci return __dlm_new_lockspace(name, cluster, flags, lvblen, ops, 72562306a36Sopenharmony_ci ops_arg, ops_result, lockspace); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int lkb_idr_is_local(int id, void *p, void *data) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct dlm_lkb *lkb = p; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return lkb->lkb_nodeid == 0 && lkb->lkb_grmode != DLM_LOCK_IV; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic int lkb_idr_is_any(int id, void *p, void *data) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci return 1; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int lkb_idr_free(int id, void *p, void *data) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct dlm_lkb *lkb = p; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (lkb->lkb_lvbptr && test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags)) 74562306a36Sopenharmony_ci dlm_free_lvb(lkb->lkb_lvbptr); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci dlm_free_lkb(lkb); 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* NOTE: We check the lkbidr here rather than the resource table. 75262306a36Sopenharmony_ci This is because there may be LKBs queued as ASTs that have been unlinked 75362306a36Sopenharmony_ci from their RSBs and are pending deletion once the AST has been delivered */ 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int lockspace_busy(struct dlm_ls *ls, int force) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci int rv; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci spin_lock(&ls->ls_lkbidr_spin); 76062306a36Sopenharmony_ci if (force == 0) { 76162306a36Sopenharmony_ci rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_any, ls); 76262306a36Sopenharmony_ci } else if (force == 1) { 76362306a36Sopenharmony_ci rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_local, ls); 76462306a36Sopenharmony_ci } else { 76562306a36Sopenharmony_ci rv = 0; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci spin_unlock(&ls->ls_lkbidr_spin); 76862306a36Sopenharmony_ci return rv; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int release_lockspace(struct dlm_ls *ls, int force) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct dlm_rsb *rsb; 77462306a36Sopenharmony_ci struct rb_node *n; 77562306a36Sopenharmony_ci int i, busy, rv; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci busy = lockspace_busy(ls, force); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci spin_lock(&lslist_lock); 78062306a36Sopenharmony_ci if (ls->ls_create_count == 1) { 78162306a36Sopenharmony_ci if (busy) { 78262306a36Sopenharmony_ci rv = -EBUSY; 78362306a36Sopenharmony_ci } else { 78462306a36Sopenharmony_ci /* remove_lockspace takes ls off lslist */ 78562306a36Sopenharmony_ci ls->ls_create_count = 0; 78662306a36Sopenharmony_ci rv = 0; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } else if (ls->ls_create_count > 1) { 78962306a36Sopenharmony_ci rv = --ls->ls_create_count; 79062306a36Sopenharmony_ci } else { 79162306a36Sopenharmony_ci rv = -EINVAL; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci spin_unlock(&lslist_lock); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (rv) { 79662306a36Sopenharmony_ci log_debug(ls, "release_lockspace no remove %d", rv); 79762306a36Sopenharmony_ci return rv; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (ls_count == 1) 80162306a36Sopenharmony_ci dlm_midcomms_version_wait(); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci dlm_device_deregister(ls); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (force < 3 && dlm_user_daemon_available()) 80662306a36Sopenharmony_ci do_uevent(ls, 0); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci dlm_recoverd_stop(ls); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (ls_count == 1) { 81162306a36Sopenharmony_ci dlm_scand_stop(); 81262306a36Sopenharmony_ci dlm_clear_members(ls); 81362306a36Sopenharmony_ci dlm_midcomms_shutdown(); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci dlm_callback_stop(ls); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci remove_lockspace(ls); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci dlm_delete_debug_file(ls); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci idr_destroy(&ls->ls_recover_idr); 82362306a36Sopenharmony_ci kfree(ls->ls_recover_buf); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* 82662306a36Sopenharmony_ci * Free all lkb's in idr 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci idr_for_each(&ls->ls_lkbidr, lkb_idr_free, ls); 83062306a36Sopenharmony_ci idr_destroy(&ls->ls_lkbidr); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Free all rsb's on rsbtbl[] lists 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci for (i = 0; i < ls->ls_rsbtbl_size; i++) { 83762306a36Sopenharmony_ci while ((n = rb_first(&ls->ls_rsbtbl[i].keep))) { 83862306a36Sopenharmony_ci rsb = rb_entry(n, struct dlm_rsb, res_hashnode); 83962306a36Sopenharmony_ci rb_erase(n, &ls->ls_rsbtbl[i].keep); 84062306a36Sopenharmony_ci dlm_free_rsb(rsb); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci while ((n = rb_first(&ls->ls_rsbtbl[i].toss))) { 84462306a36Sopenharmony_ci rsb = rb_entry(n, struct dlm_rsb, res_hashnode); 84562306a36Sopenharmony_ci rb_erase(n, &ls->ls_rsbtbl[i].toss); 84662306a36Sopenharmony_ci dlm_free_rsb(rsb); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci vfree(ls->ls_rsbtbl); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) 85362306a36Sopenharmony_ci kfree(ls->ls_remove_names[i]); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci while (!list_empty(&ls->ls_new_rsb)) { 85662306a36Sopenharmony_ci rsb = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb, 85762306a36Sopenharmony_ci res_hashchain); 85862306a36Sopenharmony_ci list_del(&rsb->res_hashchain); 85962306a36Sopenharmony_ci dlm_free_rsb(rsb); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* 86362306a36Sopenharmony_ci * Free structures on any other lists 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci dlm_purge_requestqueue(ls); 86762306a36Sopenharmony_ci kfree(ls->ls_recover_args); 86862306a36Sopenharmony_ci dlm_clear_members(ls); 86962306a36Sopenharmony_ci dlm_clear_members_gone(ls); 87062306a36Sopenharmony_ci kfree(ls->ls_node_array); 87162306a36Sopenharmony_ci log_rinfo(ls, "release_lockspace final free"); 87262306a36Sopenharmony_ci kobject_put(&ls->ls_kobj); 87362306a36Sopenharmony_ci /* The ls structure will be freed when the kobject is done with */ 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci module_put(THIS_MODULE); 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci/* 88062306a36Sopenharmony_ci * Called when a system has released all its locks and is not going to use the 88162306a36Sopenharmony_ci * lockspace any longer. We free everything we're managing for this lockspace. 88262306a36Sopenharmony_ci * Remaining nodes will go through the recovery process as if we'd died. The 88362306a36Sopenharmony_ci * lockspace must continue to function as usual, participating in recoveries, 88462306a36Sopenharmony_ci * until this returns. 88562306a36Sopenharmony_ci * 88662306a36Sopenharmony_ci * Force has 4 possible values: 88762306a36Sopenharmony_ci * 0 - don't destroy lockspace if it has any LKBs 88862306a36Sopenharmony_ci * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs 88962306a36Sopenharmony_ci * 2 - destroy lockspace regardless of LKBs 89062306a36Sopenharmony_ci * 3 - destroy lockspace as part of a forced shutdown 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ciint dlm_release_lockspace(void *lockspace, int force) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct dlm_ls *ls; 89662306a36Sopenharmony_ci int error; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci ls = dlm_find_lockspace_local(lockspace); 89962306a36Sopenharmony_ci if (!ls) 90062306a36Sopenharmony_ci return -EINVAL; 90162306a36Sopenharmony_ci dlm_put_lockspace(ls); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci mutex_lock(&ls_lock); 90462306a36Sopenharmony_ci error = release_lockspace(ls, force); 90562306a36Sopenharmony_ci if (!error) 90662306a36Sopenharmony_ci ls_count--; 90762306a36Sopenharmony_ci if (!ls_count) 90862306a36Sopenharmony_ci dlm_midcomms_stop(); 90962306a36Sopenharmony_ci mutex_unlock(&ls_lock); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return error; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_civoid dlm_stop_lockspaces(void) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct dlm_ls *ls; 91762306a36Sopenharmony_ci int count; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci restart: 92062306a36Sopenharmony_ci count = 0; 92162306a36Sopenharmony_ci spin_lock(&lslist_lock); 92262306a36Sopenharmony_ci list_for_each_entry(ls, &lslist, ls_list) { 92362306a36Sopenharmony_ci if (!test_bit(LSFL_RUNNING, &ls->ls_flags)) { 92462306a36Sopenharmony_ci count++; 92562306a36Sopenharmony_ci continue; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci spin_unlock(&lslist_lock); 92862306a36Sopenharmony_ci log_error(ls, "no userland control daemon, stopping lockspace"); 92962306a36Sopenharmony_ci dlm_ls_stop(ls); 93062306a36Sopenharmony_ci goto restart; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci spin_unlock(&lslist_lock); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (count) 93562306a36Sopenharmony_ci log_print("dlm user daemon left %d lockspaces", count); 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 938