12522fe45SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e7fd4179SDavid Teigland /******************************************************************************
3e7fd4179SDavid Teigland *******************************************************************************
4e7fd4179SDavid Teigland **
5e7fd4179SDavid Teigland ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
660f98d18SDavid Teigland ** Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
7e7fd4179SDavid Teigland **
8e7fd4179SDavid Teigland **
9e7fd4179SDavid Teigland *******************************************************************************
10e7fd4179SDavid Teigland ******************************************************************************/
11e7fd4179SDavid Teigland
127963b8a5SPaul Gortmaker #include <linux/module.h>
137963b8a5SPaul Gortmaker
14e7fd4179SDavid Teigland #include "dlm_internal.h"
15e7fd4179SDavid Teigland #include "lockspace.h"
16e7fd4179SDavid Teigland #include "member.h"
17e7fd4179SDavid Teigland #include "recoverd.h"
18e7fd4179SDavid Teigland #include "dir.h"
19a070a91cSAlexander Aring #include "midcomms.h"
20e7fd4179SDavid Teigland #include "config.h"
21e7fd4179SDavid Teigland #include "memory.h"
22e7fd4179SDavid Teigland #include "lock.h"
23c56b39cdSDavid Teigland #include "recover.h"
242896ee37SDavid Teigland #include "requestqueue.h"
250f8e0d9aSDavid Teigland #include "user.h"
2623e8e1aaSDavid Teigland #include "ast.h"
27e7fd4179SDavid Teigland
28e7fd4179SDavid Teigland static int ls_count;
2990135925SDavid Teigland static struct mutex ls_lock;
30e7fd4179SDavid Teigland static struct list_head lslist;
31e7fd4179SDavid Teigland static spinlock_t lslist_lock;
32e7fd4179SDavid Teigland static struct task_struct * scand_task;
33e7fd4179SDavid Teigland
34e7fd4179SDavid Teigland
dlm_control_store(struct dlm_ls * ls,const char * buf,size_t len)35e7fd4179SDavid Teigland static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)
36e7fd4179SDavid Teigland {
37e7fd4179SDavid Teigland ssize_t ret = len;
386edb5687SFabian Frederick int n;
396edb5687SFabian Frederick int rc = kstrtoint(buf, 0, &n);
40e7fd4179SDavid Teigland
416edb5687SFabian Frederick if (rc)
426edb5687SFabian Frederick return rc;
43e2de7f56SPatrick Caulfield ls = dlm_find_lockspace_local(ls->ls_local_handle);
44e2de7f56SPatrick Caulfield if (!ls)
45e2de7f56SPatrick Caulfield return -EINVAL;
46e2de7f56SPatrick Caulfield
47e7fd4179SDavid Teigland switch (n) {
48e7fd4179SDavid Teigland case 0:
49e7fd4179SDavid Teigland dlm_ls_stop(ls);
50e7fd4179SDavid Teigland break;
51e7fd4179SDavid Teigland case 1:
52e7fd4179SDavid Teigland dlm_ls_start(ls);
53e7fd4179SDavid Teigland break;
54e7fd4179SDavid Teigland default:
55e7fd4179SDavid Teigland ret = -EINVAL;
56e7fd4179SDavid Teigland }
57e2de7f56SPatrick Caulfield dlm_put_lockspace(ls);
58e7fd4179SDavid Teigland return ret;
59e7fd4179SDavid Teigland }
60e7fd4179SDavid Teigland
dlm_event_store(struct dlm_ls * ls,const char * buf,size_t len)61e7fd4179SDavid Teigland static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)
62e7fd4179SDavid Teigland {
636edb5687SFabian Frederick int rc = kstrtoint(buf, 0, &ls->ls_uevent_result);
646edb5687SFabian Frederick
656edb5687SFabian Frederick if (rc)
666edb5687SFabian Frederick return rc;
67e7fd4179SDavid Teigland set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags);
68e7fd4179SDavid Teigland wake_up(&ls->ls_uevent_wait);
69e7fd4179SDavid Teigland return len;
70e7fd4179SDavid Teigland }
71e7fd4179SDavid Teigland
dlm_id_show(struct dlm_ls * ls,char * buf)72e7fd4179SDavid Teigland static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)
73e7fd4179SDavid Teigland {
74a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id);
75e7fd4179SDavid Teigland }
76e7fd4179SDavid Teigland
dlm_id_store(struct dlm_ls * ls,const char * buf,size_t len)77e7fd4179SDavid Teigland static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
78e7fd4179SDavid Teigland {
796edb5687SFabian Frederick int rc = kstrtouint(buf, 0, &ls->ls_global_id);
806edb5687SFabian Frederick
816edb5687SFabian Frederick if (rc)
826edb5687SFabian Frederick return rc;
83e7fd4179SDavid Teigland return len;
84e7fd4179SDavid Teigland }
85e7fd4179SDavid Teigland
dlm_nodir_show(struct dlm_ls * ls,char * buf)864875647aSDavid Teigland static ssize_t dlm_nodir_show(struct dlm_ls *ls, char *buf)
874875647aSDavid Teigland {
884875647aSDavid Teigland return snprintf(buf, PAGE_SIZE, "%u\n", dlm_no_directory(ls));
894875647aSDavid Teigland }
904875647aSDavid Teigland
dlm_nodir_store(struct dlm_ls * ls,const char * buf,size_t len)914875647aSDavid Teigland static ssize_t dlm_nodir_store(struct dlm_ls *ls, const char *buf, size_t len)
924875647aSDavid Teigland {
936edb5687SFabian Frederick int val;
946edb5687SFabian Frederick int rc = kstrtoint(buf, 0, &val);
956edb5687SFabian Frederick
966edb5687SFabian Frederick if (rc)
976edb5687SFabian Frederick return rc;
984875647aSDavid Teigland if (val == 1)
994875647aSDavid Teigland set_bit(LSFL_NODIR, &ls->ls_flags);
1004875647aSDavid Teigland return len;
1014875647aSDavid Teigland }
1024875647aSDavid Teigland
dlm_recover_status_show(struct dlm_ls * ls,char * buf)103c56b39cdSDavid Teigland static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
104c56b39cdSDavid Teigland {
105c56b39cdSDavid Teigland uint32_t status = dlm_recover_status(ls);
106a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%x\n", status);
107c56b39cdSDavid Teigland }
108c56b39cdSDavid Teigland
dlm_recover_nodeid_show(struct dlm_ls * ls,char * buf)109faa0f267SDavid Teigland static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf)
110faa0f267SDavid Teigland {
111a1d144c7SDavid Teigland return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid);
112faa0f267SDavid Teigland }
113faa0f267SDavid Teigland
114e7fd4179SDavid Teigland struct dlm_attr {
115e7fd4179SDavid Teigland struct attribute attr;
116e7fd4179SDavid Teigland ssize_t (*show)(struct dlm_ls *, char *);
117e7fd4179SDavid Teigland ssize_t (*store)(struct dlm_ls *, const char *, size_t);
118e7fd4179SDavid Teigland };
119e7fd4179SDavid Teigland
120e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_control = {
121e7fd4179SDavid Teigland .attr = {.name = "control", .mode = S_IWUSR},
122e7fd4179SDavid Teigland .store = dlm_control_store
123e7fd4179SDavid Teigland };
124e7fd4179SDavid Teigland
125e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_event = {
126e7fd4179SDavid Teigland .attr = {.name = "event_done", .mode = S_IWUSR},
127e7fd4179SDavid Teigland .store = dlm_event_store
128e7fd4179SDavid Teigland };
129e7fd4179SDavid Teigland
130e7fd4179SDavid Teigland static struct dlm_attr dlm_attr_id = {
131e7fd4179SDavid Teigland .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR},
132e7fd4179SDavid Teigland .show = dlm_id_show,
133e7fd4179SDavid Teigland .store = dlm_id_store
134e7fd4179SDavid Teigland };
135e7fd4179SDavid Teigland
1364875647aSDavid Teigland static struct dlm_attr dlm_attr_nodir = {
1374875647aSDavid Teigland .attr = {.name = "nodir", .mode = S_IRUGO | S_IWUSR},
1384875647aSDavid Teigland .show = dlm_nodir_show,
1394875647aSDavid Teigland .store = dlm_nodir_store
1404875647aSDavid Teigland };
1414875647aSDavid Teigland
142c56b39cdSDavid Teigland static struct dlm_attr dlm_attr_recover_status = {
143c56b39cdSDavid Teigland .attr = {.name = "recover_status", .mode = S_IRUGO},
144c56b39cdSDavid Teigland .show = dlm_recover_status_show
145c56b39cdSDavid Teigland };
146c56b39cdSDavid Teigland
147faa0f267SDavid Teigland static struct dlm_attr dlm_attr_recover_nodeid = {
148faa0f267SDavid Teigland .attr = {.name = "recover_nodeid", .mode = S_IRUGO},
149faa0f267SDavid Teigland .show = dlm_recover_nodeid_show
150faa0f267SDavid Teigland };
151faa0f267SDavid Teigland
152e7fd4179SDavid Teigland static struct attribute *dlm_attrs[] = {
153e7fd4179SDavid Teigland &dlm_attr_control.attr,
154e7fd4179SDavid Teigland &dlm_attr_event.attr,
155e7fd4179SDavid Teigland &dlm_attr_id.attr,
1564875647aSDavid Teigland &dlm_attr_nodir.attr,
157c56b39cdSDavid Teigland &dlm_attr_recover_status.attr,
158faa0f267SDavid Teigland &dlm_attr_recover_nodeid.attr,
159e7fd4179SDavid Teigland NULL,
160e7fd4179SDavid Teigland };
161c9c5b5e1SKimberly Brown ATTRIBUTE_GROUPS(dlm);
162e7fd4179SDavid Teigland
dlm_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)163e7fd4179SDavid Teigland static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
164e7fd4179SDavid Teigland char *buf)
165e7fd4179SDavid Teigland {
166e7fd4179SDavid Teigland struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
167e7fd4179SDavid Teigland struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
168e7fd4179SDavid Teigland return a->show ? a->show(ls, buf) : 0;
169e7fd4179SDavid Teigland }
170e7fd4179SDavid Teigland
dlm_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t len)171e7fd4179SDavid Teigland static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,
172e7fd4179SDavid Teigland const char *buf, size_t len)
173e7fd4179SDavid Teigland {
174e7fd4179SDavid Teigland struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
175e7fd4179SDavid Teigland struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
176e7fd4179SDavid Teigland return a->store ? a->store(ls, buf, len) : len;
177e7fd4179SDavid Teigland }
178e7fd4179SDavid Teigland
lockspace_kobj_release(struct kobject * k)179ba542e3bSPatrick Caulfield static void lockspace_kobj_release(struct kobject *k)
180ba542e3bSPatrick Caulfield {
181ba542e3bSPatrick Caulfield struct dlm_ls *ls = container_of(k, struct dlm_ls, ls_kobj);
182ba542e3bSPatrick Caulfield kfree(ls);
183ba542e3bSPatrick Caulfield }
184ba542e3bSPatrick Caulfield
18552cf25d0SEmese Revfy static const struct sysfs_ops dlm_attr_ops = {
186e7fd4179SDavid Teigland .show = dlm_attr_show,
187e7fd4179SDavid Teigland .store = dlm_attr_store,
188e7fd4179SDavid Teigland };
189e7fd4179SDavid Teigland
190e7fd4179SDavid Teigland static struct kobj_type dlm_ktype = {
191c9c5b5e1SKimberly Brown .default_groups = dlm_groups,
192e7fd4179SDavid Teigland .sysfs_ops = &dlm_attr_ops,
193ba542e3bSPatrick Caulfield .release = lockspace_kobj_release,
194e7fd4179SDavid Teigland };
195e7fd4179SDavid Teigland
196d405936bSGreg Kroah-Hartman static struct kset *dlm_kset;
197e7fd4179SDavid Teigland
do_uevent(struct dlm_ls * ls,int in)198e7fd4179SDavid Teigland static int do_uevent(struct dlm_ls *ls, int in)
199e7fd4179SDavid Teigland {
200e7fd4179SDavid Teigland if (in)
201e7fd4179SDavid Teigland kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE);
202e7fd4179SDavid Teigland else
203e7fd4179SDavid Teigland kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE);
204e7fd4179SDavid Teigland
205075f0177SDavid Teigland log_rinfo(ls, "%s the lockspace group...", in ? "joining" : "leaving");
2068b0e7b2cSDavid Teigland
2078b0e7b2cSDavid Teigland /* dlm_controld will see the uevent, do the necessary group management
2088b0e7b2cSDavid Teigland and then write to sysfs to wake us */
2098b0e7b2cSDavid Teigland
210f084a4f4SRoss Lagerwall wait_event(ls->ls_uevent_wait,
211e7fd4179SDavid Teigland test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags));
2128b0e7b2cSDavid Teigland
213f084a4f4SRoss Lagerwall log_rinfo(ls, "group event done %d", ls->ls_uevent_result);
2148b0e7b2cSDavid Teigland
215f084a4f4SRoss Lagerwall return ls->ls_uevent_result;
216e7fd4179SDavid Teigland }
217e7fd4179SDavid Teigland
dlm_uevent(const struct kobject * kobj,struct kobj_uevent_env * env)21856d5f362SGreg Kroah-Hartman static int dlm_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
219b4a5d4bcSSteven Whitehouse {
22056d5f362SGreg Kroah-Hartman const struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
221b4a5d4bcSSteven Whitehouse
222b4a5d4bcSSteven Whitehouse add_uevent_var(env, "LOCKSPACE=%s", ls->ls_name);
223b4a5d4bcSSteven Whitehouse return 0;
224b4a5d4bcSSteven Whitehouse }
225b4a5d4bcSSteven Whitehouse
226417f7c59SBhumika Goyal static const struct kset_uevent_ops dlm_uevent_ops = {
227b4a5d4bcSSteven Whitehouse .uevent = dlm_uevent,
228b4a5d4bcSSteven Whitehouse };
229e7fd4179SDavid Teigland
dlm_lockspace_init(void)23030727174SDenis Cheng int __init dlm_lockspace_init(void)
231e7fd4179SDavid Teigland {
232e7fd4179SDavid Teigland ls_count = 0;
23390135925SDavid Teigland mutex_init(&ls_lock);
234e7fd4179SDavid Teigland INIT_LIST_HEAD(&lslist);
235e7fd4179SDavid Teigland spin_lock_init(&lslist_lock);
236e7fd4179SDavid Teigland
237b4a5d4bcSSteven Whitehouse dlm_kset = kset_create_and_add("dlm", &dlm_uevent_ops, kernel_kobj);
238d405936bSGreg Kroah-Hartman if (!dlm_kset) {
2398e24eea7SHarvey Harrison printk(KERN_WARNING "%s: can not create kset\n", __func__);
240d405936bSGreg Kroah-Hartman return -ENOMEM;
241d405936bSGreg Kroah-Hartman }
242d405936bSGreg Kroah-Hartman return 0;
243e7fd4179SDavid Teigland }
244e7fd4179SDavid Teigland
dlm_lockspace_exit(void)245e7fd4179SDavid Teigland void dlm_lockspace_exit(void)
246e7fd4179SDavid Teigland {
247d405936bSGreg Kroah-Hartman kset_unregister(dlm_kset);
248e7fd4179SDavid Teigland }
249e7fd4179SDavid Teigland
find_ls_to_scan(void)250c1dcf65fSDavid Teigland static struct dlm_ls *find_ls_to_scan(void)
251e7fd4179SDavid Teigland {
252e7fd4179SDavid Teigland struct dlm_ls *ls;
253e7fd4179SDavid Teigland
254c1dcf65fSDavid Teigland spin_lock(&lslist_lock);
25585e86edfSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
256c1dcf65fSDavid Teigland if (time_after_eq(jiffies, ls->ls_scan_time +
257c1dcf65fSDavid Teigland dlm_config.ci_scan_secs * HZ)) {
258c1dcf65fSDavid Teigland spin_unlock(&lslist_lock);
259c1dcf65fSDavid Teigland return ls;
260c1dcf65fSDavid Teigland }
261c1dcf65fSDavid Teigland }
262c1dcf65fSDavid Teigland spin_unlock(&lslist_lock);
263c1dcf65fSDavid Teigland return NULL;
264c1dcf65fSDavid Teigland }
265c1dcf65fSDavid Teigland
dlm_scand(void * data)266c1dcf65fSDavid Teigland static int dlm_scand(void *data)
267c1dcf65fSDavid Teigland {
268c1dcf65fSDavid Teigland struct dlm_ls *ls;
269c1dcf65fSDavid Teigland
270c1dcf65fSDavid Teigland while (!kthread_should_stop()) {
271c1dcf65fSDavid Teigland ls = find_ls_to_scan();
272c1dcf65fSDavid Teigland if (ls) {
27385e86edfSDavid Teigland if (dlm_lock_recovery_try(ls)) {
274c1dcf65fSDavid Teigland ls->ls_scan_time = jiffies;
275e7fd4179SDavid Teigland dlm_scan_rsbs(ls);
27685e86edfSDavid Teigland dlm_unlock_recovery(ls);
277c1dcf65fSDavid Teigland } else {
278c1dcf65fSDavid Teigland ls->ls_scan_time += HZ;
27985e86edfSDavid Teigland }
280c6ff669bSDavid Teigland continue;
28185e86edfSDavid Teigland }
282c6ff669bSDavid Teigland schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
283e7fd4179SDavid Teigland }
284e7fd4179SDavid Teigland return 0;
285e7fd4179SDavid Teigland }
286e7fd4179SDavid Teigland
dlm_scand_start(void)287e7fd4179SDavid Teigland static int dlm_scand_start(void)
288e7fd4179SDavid Teigland {
289e7fd4179SDavid Teigland struct task_struct *p;
290e7fd4179SDavid Teigland int error = 0;
291e7fd4179SDavid Teigland
292e7fd4179SDavid Teigland p = kthread_run(dlm_scand, NULL, "dlm_scand");
293e7fd4179SDavid Teigland if (IS_ERR(p))
294e7fd4179SDavid Teigland error = PTR_ERR(p);
295e7fd4179SDavid Teigland else
296e7fd4179SDavid Teigland scand_task = p;
297e7fd4179SDavid Teigland return error;
298e7fd4179SDavid Teigland }
299e7fd4179SDavid Teigland
dlm_scand_stop(void)300e7fd4179SDavid Teigland static void dlm_scand_stop(void)
301e7fd4179SDavid Teigland {
302e7fd4179SDavid Teigland kthread_stop(scand_task);
303e7fd4179SDavid Teigland }
304e7fd4179SDavid Teigland
dlm_find_lockspace_global(uint32_t id)305e7fd4179SDavid Teigland struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
306e7fd4179SDavid Teigland {
307e7fd4179SDavid Teigland struct dlm_ls *ls;
308e7fd4179SDavid Teigland
309e7fd4179SDavid Teigland spin_lock(&lslist_lock);
310e7fd4179SDavid Teigland
311e7fd4179SDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
312e7fd4179SDavid Teigland if (ls->ls_global_id == id) {
3133cb5977cSAlexander Aring atomic_inc(&ls->ls_count);
314e7fd4179SDavid Teigland goto out;
315e7fd4179SDavid Teigland }
316e7fd4179SDavid Teigland }
317e7fd4179SDavid Teigland ls = NULL;
318e7fd4179SDavid Teigland out:
319e7fd4179SDavid Teigland spin_unlock(&lslist_lock);
320e7fd4179SDavid Teigland return ls;
321e7fd4179SDavid Teigland }
322e7fd4179SDavid Teigland
dlm_find_lockspace_local(dlm_lockspace_t * lockspace)323597d0caeSDavid Teigland struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace)
324e7fd4179SDavid Teigland {
325597d0caeSDavid Teigland struct dlm_ls *ls;
326e7fd4179SDavid Teigland
327e7fd4179SDavid Teigland spin_lock(&lslist_lock);
328597d0caeSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
329597d0caeSDavid Teigland if (ls->ls_local_handle == lockspace) {
3303cb5977cSAlexander Aring atomic_inc(&ls->ls_count);
331597d0caeSDavid Teigland goto out;
332597d0caeSDavid Teigland }
333597d0caeSDavid Teigland }
334597d0caeSDavid Teigland ls = NULL;
335597d0caeSDavid Teigland out:
336597d0caeSDavid Teigland spin_unlock(&lslist_lock);
337597d0caeSDavid Teigland return ls;
338597d0caeSDavid Teigland }
339597d0caeSDavid Teigland
dlm_find_lockspace_device(int minor)340597d0caeSDavid Teigland struct dlm_ls *dlm_find_lockspace_device(int minor)
341597d0caeSDavid Teigland {
342597d0caeSDavid Teigland struct dlm_ls *ls;
343597d0caeSDavid Teigland
344597d0caeSDavid Teigland spin_lock(&lslist_lock);
345597d0caeSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
346597d0caeSDavid Teigland if (ls->ls_device.minor == minor) {
3473cb5977cSAlexander Aring atomic_inc(&ls->ls_count);
348597d0caeSDavid Teigland goto out;
349597d0caeSDavid Teigland }
350597d0caeSDavid Teigland }
351597d0caeSDavid Teigland ls = NULL;
352597d0caeSDavid Teigland out:
353e7fd4179SDavid Teigland spin_unlock(&lslist_lock);
354e7fd4179SDavid Teigland return ls;
355e7fd4179SDavid Teigland }
356e7fd4179SDavid Teigland
dlm_put_lockspace(struct dlm_ls * ls)357e7fd4179SDavid Teigland void dlm_put_lockspace(struct dlm_ls *ls)
358e7fd4179SDavid Teigland {
3593cb5977cSAlexander Aring if (atomic_dec_and_test(&ls->ls_count))
3603cb5977cSAlexander Aring wake_up(&ls->ls_count_wait);
361e7fd4179SDavid Teigland }
362e7fd4179SDavid Teigland
remove_lockspace(struct dlm_ls * ls)363e7fd4179SDavid Teigland static void remove_lockspace(struct dlm_ls *ls)
364e7fd4179SDavid Teigland {
3653cb5977cSAlexander Aring retry:
3663cb5977cSAlexander Aring wait_event(ls->ls_count_wait, atomic_read(&ls->ls_count) == 0);
3673cb5977cSAlexander Aring
368e7fd4179SDavid Teigland spin_lock(&lslist_lock);
3693cb5977cSAlexander Aring if (atomic_read(&ls->ls_count) != 0) {
3703cb5977cSAlexander Aring spin_unlock(&lslist_lock);
3713cb5977cSAlexander Aring goto retry;
3723cb5977cSAlexander Aring }
3733cb5977cSAlexander Aring
3740f8e0d9aSDavid Teigland WARN_ON(ls->ls_create_count != 0);
375e7fd4179SDavid Teigland list_del(&ls->ls_list);
376e7fd4179SDavid Teigland spin_unlock(&lslist_lock);
377e7fd4179SDavid Teigland }
378e7fd4179SDavid Teigland
threads_start(void)379e7fd4179SDavid Teigland static int threads_start(void)
380e7fd4179SDavid Teigland {
381e7fd4179SDavid Teigland int error;
382e7fd4179SDavid Teigland
383e7fd4179SDavid Teigland /* Thread for sending/receiving messages for all lockspace's */
384a070a91cSAlexander Aring error = dlm_midcomms_start();
385e7fd4179SDavid Teigland if (error) {
3863e54c9e8SAlexander Aring log_print("cannot start dlm midcomms %d", error);
387aad633dcSAlexander Aring goto fail;
388aad633dcSAlexander Aring }
389aad633dcSAlexander Aring
390aad633dcSAlexander Aring error = dlm_scand_start();
391aad633dcSAlexander Aring if (error) {
392aad633dcSAlexander Aring log_print("cannot start dlm_scand thread %d", error);
393aad633dcSAlexander Aring goto midcomms_fail;
394e7fd4179SDavid Teigland }
395e7fd4179SDavid Teigland
396e7fd4179SDavid Teigland return 0;
397e7fd4179SDavid Teigland
398aad633dcSAlexander Aring midcomms_fail:
399aad633dcSAlexander Aring dlm_midcomms_stop();
400e7fd4179SDavid Teigland fail:
401e7fd4179SDavid Teigland return error;
402e7fd4179SDavid Teigland }
403e7fd4179SDavid Teigland
new_lockspace(const char * name,const char * cluster,uint32_t flags,int lvblen,const struct dlm_lockspace_ops * ops,void * ops_arg,int * ops_result,dlm_lockspace_t ** lockspace)40460f98d18SDavid Teigland static int new_lockspace(const char *name, const char *cluster,
40560f98d18SDavid Teigland uint32_t flags, int lvblen,
40660f98d18SDavid Teigland const struct dlm_lockspace_ops *ops, void *ops_arg,
40760f98d18SDavid Teigland int *ops_result, dlm_lockspace_t **lockspace)
408e7fd4179SDavid Teigland {
409e7fd4179SDavid Teigland struct dlm_ls *ls;
4100f8e0d9aSDavid Teigland int i, size, error;
41179d72b54SDavid Teigland int do_unreg = 0;
41260f98d18SDavid Teigland int namelen = strlen(name);
413e7fd4179SDavid Teigland
4143f0806d2STycho Andersen if (namelen > DLM_LOCKSPACE_LEN || namelen == 0)
415e7fd4179SDavid Teigland return -EINVAL;
416e7fd4179SDavid Teigland
417b5c9d37cSAlexander Aring if (lvblen % 8)
418e7fd4179SDavid Teigland return -EINVAL;
419e7fd4179SDavid Teigland
420e7fd4179SDavid Teigland if (!try_module_get(THIS_MODULE))
421e7fd4179SDavid Teigland return -EINVAL;
422e7fd4179SDavid Teigland
423dc68c7edSDavid Teigland if (!dlm_user_daemon_available()) {
42460f98d18SDavid Teigland log_print("dlm user daemon not available");
42560f98d18SDavid Teigland error = -EUNATCH;
42660f98d18SDavid Teigland goto out;
42760f98d18SDavid Teigland }
42860f98d18SDavid Teigland
42960f98d18SDavid Teigland if (ops && ops_result) {
43060f98d18SDavid Teigland if (!dlm_config.ci_recover_callbacks)
43160f98d18SDavid Teigland *ops_result = -EOPNOTSUPP;
43260f98d18SDavid Teigland else
43360f98d18SDavid Teigland *ops_result = 0;
43460f98d18SDavid Teigland }
43560f98d18SDavid Teigland
4363b0e761bSZhu Lingshan if (!cluster)
4373b0e761bSZhu Lingshan log_print("dlm cluster name '%s' is being used without an application provided cluster name",
4383b0e761bSZhu Lingshan dlm_config.ci_cluster_name);
4393b0e761bSZhu Lingshan
44060f98d18SDavid Teigland if (dlm_config.ci_recover_callbacks && cluster &&
44160f98d18SDavid Teigland strncmp(cluster, dlm_config.ci_cluster_name, DLM_LOCKSPACE_LEN)) {
4428e174374SGang He log_print("dlm cluster name '%s' does not match "
4438e174374SGang He "the application cluster name '%s'",
44460f98d18SDavid Teigland dlm_config.ci_cluster_name, cluster);
44560f98d18SDavid Teigland error = -EBADR;
44660f98d18SDavid Teigland goto out;
447dc68c7edSDavid Teigland }
448dc68c7edSDavid Teigland
4490f8e0d9aSDavid Teigland error = 0;
4500f8e0d9aSDavid Teigland
4510f8e0d9aSDavid Teigland spin_lock(&lslist_lock);
4520f8e0d9aSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
4530f8e0d9aSDavid Teigland WARN_ON(ls->ls_create_count <= 0);
4540f8e0d9aSDavid Teigland if (ls->ls_namelen != namelen)
4550f8e0d9aSDavid Teigland continue;
4560f8e0d9aSDavid Teigland if (memcmp(ls->ls_name, name, namelen))
4570f8e0d9aSDavid Teigland continue;
4580f8e0d9aSDavid Teigland if (flags & DLM_LSFL_NEWEXCL) {
4590f8e0d9aSDavid Teigland error = -EEXIST;
4600f8e0d9aSDavid Teigland break;
461e7fd4179SDavid Teigland }
4620f8e0d9aSDavid Teigland ls->ls_create_count++;
4638511a272SDavid Teigland *lockspace = ls;
4648511a272SDavid Teigland error = 1;
4650f8e0d9aSDavid Teigland break;
4660f8e0d9aSDavid Teigland }
4670f8e0d9aSDavid Teigland spin_unlock(&lslist_lock);
4680f8e0d9aSDavid Teigland
4690f8e0d9aSDavid Teigland if (error)
4708511a272SDavid Teigland goto out;
4710f8e0d9aSDavid Teigland
4720f8e0d9aSDavid Teigland error = -ENOMEM;
473e7fd4179SDavid Teigland
474d96d0f96SPaulo Miguel Almeida ls = kzalloc(sizeof(*ls), GFP_NOFS);
475e7fd4179SDavid Teigland if (!ls)
476e7fd4179SDavid Teigland goto out;
477e7fd4179SDavid Teigland memcpy(ls->ls_name, name, namelen);
478e7fd4179SDavid Teigland ls->ls_namelen = namelen;
479e7fd4179SDavid Teigland ls->ls_lvblen = lvblen;
4803cb5977cSAlexander Aring atomic_set(&ls->ls_count, 0);
4813cb5977cSAlexander Aring init_waitqueue_head(&ls->ls_count_wait);
482e7fd4179SDavid Teigland ls->ls_flags = 0;
483c1dcf65fSDavid Teigland ls->ls_scan_time = jiffies;
484e7fd4179SDavid Teigland
48560f98d18SDavid Teigland if (ops && dlm_config.ci_recover_callbacks) {
48660f98d18SDavid Teigland ls->ls_ops = ops;
48760f98d18SDavid Teigland ls->ls_ops_arg = ops_arg;
48860f98d18SDavid Teigland }
48960f98d18SDavid Teigland
4906b0afc0cSAlexander Aring /* ls_exflags are forced to match among nodes, and we don't
4916b0afc0cSAlexander Aring * need to require all nodes to have some flags set
4926b0afc0cSAlexander Aring */
4936b0afc0cSAlexander Aring ls->ls_exflags = (flags & ~(DLM_LSFL_FS | DLM_LSFL_NEWEXCL));
494fad59c13SDavid Teigland
495d921a23fSAlexander Aring size = READ_ONCE(dlm_config.ci_rsbtbl_size);
496e7fd4179SDavid Teigland ls->ls_rsbtbl_size = size;
497e7fd4179SDavid Teigland
49842bc47b3SKees Cook ls->ls_rsbtbl = vmalloc(array_size(size, sizeof(struct dlm_rsbtable)));
499e7fd4179SDavid Teigland if (!ls->ls_rsbtbl)
500e7fd4179SDavid Teigland goto out_lsfree;
501e7fd4179SDavid Teigland for (i = 0; i < size; i++) {
5029beb3bf5SBob Peterson ls->ls_rsbtbl[i].keep.rb_node = NULL;
5039beb3bf5SBob Peterson ls->ls_rsbtbl[i].toss.rb_node = NULL;
504c7be761aSDavid Teigland spin_lock_init(&ls->ls_rsbtbl[i].lock);
505e7fd4179SDavid Teigland }
506e7fd4179SDavid Teigland
50705c32f47SDavid Teigland for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) {
50805c32f47SDavid Teigland ls->ls_remove_names[i] = kzalloc(DLM_RESNAME_MAXLEN+1,
50905c32f47SDavid Teigland GFP_KERNEL);
51005c32f47SDavid Teigland if (!ls->ls_remove_names[i])
51105c32f47SDavid Teigland goto out_rsbtbl;
51205c32f47SDavid Teigland }
51305c32f47SDavid Teigland
5143d6aa675SDavid Teigland idr_init(&ls->ls_lkbidr);
5153d6aa675SDavid Teigland spin_lock_init(&ls->ls_lkbidr_spin);
516e7fd4179SDavid Teigland
517e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_waiters);
51890135925SDavid Teigland mutex_init(&ls->ls_waiters_mutex);
519ef0c2bb0SDavid Teigland INIT_LIST_HEAD(&ls->ls_orphans);
520ef0c2bb0SDavid Teigland mutex_init(&ls->ls_orphans_mutex);
521e7fd4179SDavid Teigland
5223881ac04SDavid Teigland INIT_LIST_HEAD(&ls->ls_new_rsb);
5233881ac04SDavid Teigland spin_lock_init(&ls->ls_new_rsb_spin);
5243881ac04SDavid Teigland
525e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_nodes);
526e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_nodes_gone);
527e7fd4179SDavid Teigland ls->ls_num_nodes = 0;
528e7fd4179SDavid Teigland ls->ls_low_nodeid = 0;
529e7fd4179SDavid Teigland ls->ls_total_weight = 0;
530e7fd4179SDavid Teigland ls->ls_node_array = NULL;
531e7fd4179SDavid Teigland
532a7e7ffacSAlexander Aring memset(&ls->ls_local_rsb, 0, sizeof(struct dlm_rsb));
533a7e7ffacSAlexander Aring ls->ls_local_rsb.res_ls = ls;
534e7fd4179SDavid Teigland
5355de6319bSDavid Teigland ls->ls_debug_rsb_dentry = NULL;
5365de6319bSDavid Teigland ls->ls_debug_waiters_dentry = NULL;
537e7fd4179SDavid Teigland
538e7fd4179SDavid Teigland init_waitqueue_head(&ls->ls_uevent_wait);
539e7fd4179SDavid Teigland ls->ls_uevent_result = 0;
540682bb91bSAlexander Aring init_completion(&ls->ls_recovery_done);
541682bb91bSAlexander Aring ls->ls_recovery_result = -1;
542e7fd4179SDavid Teigland
543a4c0352bSAlexander Aring spin_lock_init(&ls->ls_cb_lock);
54423e8e1aaSDavid Teigland INIT_LIST_HEAD(&ls->ls_cb_delay);
54523e8e1aaSDavid Teigland
546e7fd4179SDavid Teigland ls->ls_recoverd_task = NULL;
54790135925SDavid Teigland mutex_init(&ls->ls_recoverd_active);
548e7fd4179SDavid Teigland spin_lock_init(&ls->ls_recover_lock);
54998f176fbSDavid Teigland spin_lock_init(&ls->ls_rcom_spin);
55098f176fbSDavid Teigland get_random_bytes(&ls->ls_rcom_seq, sizeof(uint64_t));
551e7fd4179SDavid Teigland ls->ls_recover_status = 0;
552317dd6baSAlexander Aring ls->ls_recover_seq = get_random_u64();
553e7fd4179SDavid Teigland ls->ls_recover_args = NULL;
554e7fd4179SDavid Teigland init_rwsem(&ls->ls_in_recovery);
555c36258b5SDavid Teigland init_rwsem(&ls->ls_recv_active);
556e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_requestqueue);
557164d88abSAlexander Aring atomic_set(&ls->ls_requestqueue_cnt, 0);
558164d88abSAlexander Aring init_waitqueue_head(&ls->ls_requestqueue_wait);
55990135925SDavid Teigland mutex_init(&ls->ls_requestqueue_mutex);
560296d9d1eSAlexander Aring spin_lock_init(&ls->ls_clear_proc_locks);
561e7fd4179SDavid Teigland
562489d8e55SAlexander Aring /* Due backwards compatibility with 3.1 we need to use maximum
563489d8e55SAlexander Aring * possible dlm message size to be sure the message will fit and
564489d8e55SAlexander Aring * not having out of bounds issues. However on sending side 3.2
565489d8e55SAlexander Aring * might send less.
566489d8e55SAlexander Aring */
567d10a0b88SAlexander Aring ls->ls_recover_buf = kmalloc(DLM_MAX_SOCKET_BUFSIZE, GFP_NOFS);
568e7fd4179SDavid Teigland if (!ls->ls_recover_buf)
56905c32f47SDavid Teigland goto out_lkbidr;
570e7fd4179SDavid Teigland
571757a4271SDavid Teigland ls->ls_slot = 0;
572757a4271SDavid Teigland ls->ls_num_slots = 0;
573757a4271SDavid Teigland ls->ls_slots_size = 0;
574757a4271SDavid Teigland ls->ls_slots = NULL;
575757a4271SDavid Teigland
576e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_recover_list);
577e7fd4179SDavid Teigland spin_lock_init(&ls->ls_recover_list_lock);
5781d7c484eSDavid Teigland idr_init(&ls->ls_recover_idr);
5791d7c484eSDavid Teigland spin_lock_init(&ls->ls_recover_idr_lock);
580e7fd4179SDavid Teigland ls->ls_recover_list_count = 0;
581597d0caeSDavid Teigland ls->ls_local_handle = ls;
582e7fd4179SDavid Teigland init_waitqueue_head(&ls->ls_wait_general);
583e7fd4179SDavid Teigland INIT_LIST_HEAD(&ls->ls_root_list);
584e7fd4179SDavid Teigland init_rwsem(&ls->ls_root_sem);
585e7fd4179SDavid Teigland
5865f88f1eaSDavid Teigland spin_lock(&lslist_lock);
5870f8e0d9aSDavid Teigland ls->ls_create_count = 1;
5885f88f1eaSDavid Teigland list_add(&ls->ls_list, &lslist);
5895f88f1eaSDavid Teigland spin_unlock(&lslist_lock);
5905f88f1eaSDavid Teigland
59123e8e1aaSDavid Teigland if (flags & DLM_LSFL_FS) {
59223e8e1aaSDavid Teigland error = dlm_callback_start(ls);
59323e8e1aaSDavid Teigland if (error) {
59423e8e1aaSDavid Teigland log_error(ls, "can't start dlm_callback %d", error);
59523e8e1aaSDavid Teigland goto out_delist;
59623e8e1aaSDavid Teigland }
59723e8e1aaSDavid Teigland }
59823e8e1aaSDavid Teigland
599475f230cSDavid Teigland init_waitqueue_head(&ls->ls_recover_lock_wait);
600475f230cSDavid Teigland
601475f230cSDavid Teigland /*
602475f230cSDavid Teigland * Once started, dlm_recoverd first looks for ls in lslist, then
603475f230cSDavid Teigland * initializes ls_in_recovery as locked in "down" mode. We need
604475f230cSDavid Teigland * to wait for the wakeup from dlm_recoverd because in_recovery
605475f230cSDavid Teigland * has to start out in down mode.
606475f230cSDavid Teigland */
607475f230cSDavid Teigland
608e7fd4179SDavid Teigland error = dlm_recoverd_start(ls);
609e7fd4179SDavid Teigland if (error) {
610e7fd4179SDavid Teigland log_error(ls, "can't start dlm_recoverd %d", error);
61123e8e1aaSDavid Teigland goto out_callback;
612e7fd4179SDavid Teigland }
613e7fd4179SDavid Teigland
614475f230cSDavid Teigland wait_event(ls->ls_recover_lock_wait,
615475f230cSDavid Teigland test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
616475f230cSDavid Teigland
6170ffddafcSWang Hai /* let kobject handle freeing of ls if there's an error */
6180ffddafcSWang Hai do_unreg = 1;
6190ffddafcSWang Hai
620901195edSGreg Kroah-Hartman ls->ls_kobj.kset = dlm_kset;
621901195edSGreg Kroah-Hartman error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
622901195edSGreg Kroah-Hartman "%s", ls->ls_name);
623e7fd4179SDavid Teigland if (error)
62423e8e1aaSDavid Teigland goto out_recoverd;
625901195edSGreg Kroah-Hartman kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
62679d72b54SDavid Teigland
6278b0e7b2cSDavid Teigland /* This uevent triggers dlm_controld in userspace to add us to the
6288b0e7b2cSDavid Teigland group of nodes that are members of this lockspace (managed by the
6298b0e7b2cSDavid Teigland cluster infrastructure.) Once it's done that, it tells us who the
6308b0e7b2cSDavid Teigland current lockspace members are (via configfs) and then tells the
6318b0e7b2cSDavid Teigland lockspace to start running (via sysfs) in dlm_ls_start(). */
6328b0e7b2cSDavid Teigland
633e7fd4179SDavid Teigland error = do_uevent(ls, 1);
634e7fd4179SDavid Teigland if (error)
63523e8e1aaSDavid Teigland goto out_recoverd;
63679d72b54SDavid Teigland
637682bb91bSAlexander Aring /* wait until recovery is successful or failed */
638682bb91bSAlexander Aring wait_for_completion(&ls->ls_recovery_done);
639682bb91bSAlexander Aring error = ls->ls_recovery_result;
6408b0e7b2cSDavid Teigland if (error)
6418b0e7b2cSDavid Teigland goto out_members;
6428b0e7b2cSDavid Teigland
64379d72b54SDavid Teigland dlm_create_debug_file(ls);
64479d72b54SDavid Teigland
645075f0177SDavid Teigland log_rinfo(ls, "join complete");
646e7fd4179SDavid Teigland *lockspace = ls;
647e7fd4179SDavid Teigland return 0;
648e7fd4179SDavid Teigland
6498b0e7b2cSDavid Teigland out_members:
6508b0e7b2cSDavid Teigland do_uevent(ls, 0);
6518b0e7b2cSDavid Teigland dlm_clear_members(ls);
6528b0e7b2cSDavid Teigland kfree(ls->ls_node_array);
65323e8e1aaSDavid Teigland out_recoverd:
6545f88f1eaSDavid Teigland dlm_recoverd_stop(ls);
65523e8e1aaSDavid Teigland out_callback:
65623e8e1aaSDavid Teigland dlm_callback_stop(ls);
65779d72b54SDavid Teigland out_delist:
658e7fd4179SDavid Teigland spin_lock(&lslist_lock);
659e7fd4179SDavid Teigland list_del(&ls->ls_list);
660e7fd4179SDavid Teigland spin_unlock(&lslist_lock);
6611d7c484eSDavid Teigland idr_destroy(&ls->ls_recover_idr);
662e7fd4179SDavid Teigland kfree(ls->ls_recover_buf);
66305c32f47SDavid Teigland out_lkbidr:
6643d6aa675SDavid Teigland idr_destroy(&ls->ls_lkbidr);
665b982896cSVasily Averin out_rsbtbl:
6663456880fSThomas Meyer for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++)
66705c32f47SDavid Teigland kfree(ls->ls_remove_names[i]);
668c282af49SBryn M. Reeves vfree(ls->ls_rsbtbl);
669e7fd4179SDavid Teigland out_lsfree:
67079d72b54SDavid Teigland if (do_unreg)
671197b12d6SGreg Kroah-Hartman kobject_put(&ls->ls_kobj);
67279d72b54SDavid Teigland else
673e7fd4179SDavid Teigland kfree(ls);
674e7fd4179SDavid Teigland out:
675e7fd4179SDavid Teigland module_put(THIS_MODULE);
676e7fd4179SDavid Teigland return error;
677e7fd4179SDavid Teigland }
678e7fd4179SDavid Teigland
__dlm_new_lockspace(const char * name,const char * cluster,uint32_t flags,int lvblen,const struct dlm_lockspace_ops * ops,void * ops_arg,int * ops_result,dlm_lockspace_t ** lockspace)67912cda13cSAlexander Aring static int __dlm_new_lockspace(const char *name, const char *cluster,
68060f98d18SDavid Teigland uint32_t flags, int lvblen,
68112cda13cSAlexander Aring const struct dlm_lockspace_ops *ops,
68212cda13cSAlexander Aring void *ops_arg, int *ops_result,
68312cda13cSAlexander Aring dlm_lockspace_t **lockspace)
684e7fd4179SDavid Teigland {
685e7fd4179SDavid Teigland int error = 0;
686e7fd4179SDavid Teigland
68790135925SDavid Teigland mutex_lock(&ls_lock);
688e7fd4179SDavid Teigland if (!ls_count)
689e7fd4179SDavid Teigland error = threads_start();
690e7fd4179SDavid Teigland if (error)
691e7fd4179SDavid Teigland goto out;
692e7fd4179SDavid Teigland
69360f98d18SDavid Teigland error = new_lockspace(name, cluster, flags, lvblen, ops, ops_arg,
69460f98d18SDavid Teigland ops_result, lockspace);
695e7fd4179SDavid Teigland if (!error)
696e7fd4179SDavid Teigland ls_count++;
6978511a272SDavid Teigland if (error > 0)
6988511a272SDavid Teigland error = 0;
6999d232469SAlexander Aring if (!ls_count) {
7009d232469SAlexander Aring dlm_scand_stop();
701a070a91cSAlexander Aring dlm_midcomms_shutdown();
7028b0188b0SAlexander Aring dlm_midcomms_stop();
7039d232469SAlexander Aring }
704e7fd4179SDavid Teigland out:
70590135925SDavid Teigland mutex_unlock(&ls_lock);
706e7fd4179SDavid Teigland return error;
707e7fd4179SDavid Teigland }
708e7fd4179SDavid Teigland
dlm_new_lockspace(const char * name,const char * cluster,uint32_t flags,int lvblen,const struct dlm_lockspace_ops * ops,void * ops_arg,int * ops_result,dlm_lockspace_t ** lockspace)70912cda13cSAlexander Aring int dlm_new_lockspace(const char *name, const char *cluster, uint32_t flags,
71012cda13cSAlexander Aring int lvblen, const struct dlm_lockspace_ops *ops,
71112cda13cSAlexander Aring void *ops_arg, int *ops_result,
71212cda13cSAlexander Aring dlm_lockspace_t **lockspace)
71312cda13cSAlexander Aring {
71412cda13cSAlexander Aring return __dlm_new_lockspace(name, cluster, flags | DLM_LSFL_FS, lvblen,
71512cda13cSAlexander Aring ops, ops_arg, ops_result, lockspace);
71612cda13cSAlexander Aring }
71712cda13cSAlexander Aring
dlm_new_user_lockspace(const char * name,const char * cluster,uint32_t flags,int lvblen,const struct dlm_lockspace_ops * ops,void * ops_arg,int * ops_result,dlm_lockspace_t ** lockspace)71812cda13cSAlexander Aring int dlm_new_user_lockspace(const char *name, const char *cluster,
71912cda13cSAlexander Aring uint32_t flags, int lvblen,
72012cda13cSAlexander Aring const struct dlm_lockspace_ops *ops,
72112cda13cSAlexander Aring void *ops_arg, int *ops_result,
72212cda13cSAlexander Aring dlm_lockspace_t **lockspace)
72312cda13cSAlexander Aring {
72412cda13cSAlexander Aring return __dlm_new_lockspace(name, cluster, flags, lvblen, ops,
72512cda13cSAlexander Aring ops_arg, ops_result, lockspace);
72612cda13cSAlexander Aring }
72712cda13cSAlexander Aring
lkb_idr_is_local(int id,void * p,void * data)7283d6aa675SDavid Teigland static int lkb_idr_is_local(int id, void *p, void *data)
729e7fd4179SDavid Teigland {
7303d6aa675SDavid Teigland struct dlm_lkb *lkb = p;
731e7fd4179SDavid Teigland
732a97f4a66SBart Van Assche return lkb->lkb_nodeid == 0 && lkb->lkb_grmode != DLM_LOCK_IV;
7333d6aa675SDavid Teigland }
734e7fd4179SDavid Teigland
lkb_idr_is_any(int id,void * p,void * data)7353d6aa675SDavid Teigland static int lkb_idr_is_any(int id, void *p, void *data)
7363d6aa675SDavid Teigland {
7373d6aa675SDavid Teigland return 1;
738e7fd4179SDavid Teigland }
7393d6aa675SDavid Teigland
lkb_idr_free(int id,void * p,void * data)7403d6aa675SDavid Teigland static int lkb_idr_free(int id, void *p, void *data)
7413d6aa675SDavid Teigland {
7423d6aa675SDavid Teigland struct dlm_lkb *lkb = p;
7433d6aa675SDavid Teigland
744*e1af8728SAlexander Aring if (lkb->lkb_lvbptr && test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags))
7453d6aa675SDavid Teigland dlm_free_lvb(lkb->lkb_lvbptr);
7463d6aa675SDavid Teigland
7473d6aa675SDavid Teigland dlm_free_lkb(lkb);
7483d6aa675SDavid Teigland return 0;
749e7fd4179SDavid Teigland }
7503d6aa675SDavid Teigland
7513d6aa675SDavid Teigland /* NOTE: We check the lkbidr here rather than the resource table.
7523d6aa675SDavid Teigland This is because there may be LKBs queued as ASTs that have been unlinked
7533d6aa675SDavid Teigland from their RSBs and are pending deletion once the AST has been delivered */
7543d6aa675SDavid Teigland
lockspace_busy(struct dlm_ls * ls,int force)7553d6aa675SDavid Teigland static int lockspace_busy(struct dlm_ls *ls, int force)
7563d6aa675SDavid Teigland {
7573d6aa675SDavid Teigland int rv;
7583d6aa675SDavid Teigland
7593d6aa675SDavid Teigland spin_lock(&ls->ls_lkbidr_spin);
7603d6aa675SDavid Teigland if (force == 0) {
7613d6aa675SDavid Teigland rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_any, ls);
7623d6aa675SDavid Teigland } else if (force == 1) {
7633d6aa675SDavid Teigland rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_local, ls);
7643d6aa675SDavid Teigland } else {
7653d6aa675SDavid Teigland rv = 0;
766e7fd4179SDavid Teigland }
7673d6aa675SDavid Teigland spin_unlock(&ls->ls_lkbidr_spin);
7683d6aa675SDavid Teigland return rv;
769e7fd4179SDavid Teigland }
770e7fd4179SDavid Teigland
release_lockspace(struct dlm_ls * ls,int force)771e7fd4179SDavid Teigland static int release_lockspace(struct dlm_ls *ls, int force)
772e7fd4179SDavid Teigland {
773e7fd4179SDavid Teigland struct dlm_rsb *rsb;
7749beb3bf5SBob Peterson struct rb_node *n;
7750f8e0d9aSDavid Teigland int i, busy, rv;
776e7fd4179SDavid Teigland
7773d6aa675SDavid Teigland busy = lockspace_busy(ls, force);
7780f8e0d9aSDavid Teigland
7790f8e0d9aSDavid Teigland spin_lock(&lslist_lock);
7800f8e0d9aSDavid Teigland if (ls->ls_create_count == 1) {
7813d6aa675SDavid Teigland if (busy) {
7820f8e0d9aSDavid Teigland rv = -EBUSY;
7833d6aa675SDavid Teigland } else {
7840f8e0d9aSDavid Teigland /* remove_lockspace takes ls off lslist */
7850f8e0d9aSDavid Teigland ls->ls_create_count = 0;
7860f8e0d9aSDavid Teigland rv = 0;
7870f8e0d9aSDavid Teigland }
7880f8e0d9aSDavid Teigland } else if (ls->ls_create_count > 1) {
7890f8e0d9aSDavid Teigland rv = --ls->ls_create_count;
7900f8e0d9aSDavid Teigland } else {
7910f8e0d9aSDavid Teigland rv = -EINVAL;
7920f8e0d9aSDavid Teigland }
7930f8e0d9aSDavid Teigland spin_unlock(&lslist_lock);
7940f8e0d9aSDavid Teigland
7950f8e0d9aSDavid Teigland if (rv) {
7960f8e0d9aSDavid Teigland log_debug(ls, "release_lockspace no remove %d", rv);
7970f8e0d9aSDavid Teigland return rv;
7980f8e0d9aSDavid Teigland }
7990f8e0d9aSDavid Teigland
800b8b750e0SAlexander Aring if (ls_count == 1)
801b8b750e0SAlexander Aring dlm_midcomms_version_wait();
802b8b750e0SAlexander Aring
8030f8e0d9aSDavid Teigland dlm_device_deregister(ls);
804e7fd4179SDavid Teigland
805dc68c7edSDavid Teigland if (force < 3 && dlm_user_daemon_available())
806e7fd4179SDavid Teigland do_uevent(ls, 0);
807e7fd4179SDavid Teigland
808e7fd4179SDavid Teigland dlm_recoverd_stop(ls);
809e7fd4179SDavid Teigland
8109d232469SAlexander Aring if (ls_count == 1) {
8119d232469SAlexander Aring dlm_scand_stop();
812ecd95673SAlexander Aring dlm_clear_members(ls);
813a070a91cSAlexander Aring dlm_midcomms_shutdown();
8149d232469SAlexander Aring }
8159d232469SAlexander Aring
81623e8e1aaSDavid Teigland dlm_callback_stop(ls);
81723e8e1aaSDavid Teigland
818e7fd4179SDavid Teigland remove_lockspace(ls);
819e7fd4179SDavid Teigland
820e7fd4179SDavid Teigland dlm_delete_debug_file(ls);
821e7fd4179SDavid Teigland
8228fc6ed9aSDavid Teigland idr_destroy(&ls->ls_recover_idr);
823e7fd4179SDavid Teigland kfree(ls->ls_recover_buf);
824e7fd4179SDavid Teigland
825e7fd4179SDavid Teigland /*
8263d6aa675SDavid Teigland * Free all lkb's in idr
827e7fd4179SDavid Teigland */
828e7fd4179SDavid Teigland
8293d6aa675SDavid Teigland idr_for_each(&ls->ls_lkbidr, lkb_idr_free, ls);
8303d6aa675SDavid Teigland idr_destroy(&ls->ls_lkbidr);
831e7fd4179SDavid Teigland
832e7fd4179SDavid Teigland /*
833e7fd4179SDavid Teigland * Free all rsb's on rsbtbl[] lists
834e7fd4179SDavid Teigland */
835e7fd4179SDavid Teigland
836e7fd4179SDavid Teigland for (i = 0; i < ls->ls_rsbtbl_size; i++) {
8379beb3bf5SBob Peterson while ((n = rb_first(&ls->ls_rsbtbl[i].keep))) {
8389beb3bf5SBob Peterson rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
8399beb3bf5SBob Peterson rb_erase(n, &ls->ls_rsbtbl[i].keep);
84052bda2b5SDavid Teigland dlm_free_rsb(rsb);
841e7fd4179SDavid Teigland }
842e7fd4179SDavid Teigland
8439beb3bf5SBob Peterson while ((n = rb_first(&ls->ls_rsbtbl[i].toss))) {
8449beb3bf5SBob Peterson rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
8459beb3bf5SBob Peterson rb_erase(n, &ls->ls_rsbtbl[i].toss);
84652bda2b5SDavid Teigland dlm_free_rsb(rsb);
847e7fd4179SDavid Teigland }
848e7fd4179SDavid Teigland }
849e7fd4179SDavid Teigland
850c282af49SBryn M. Reeves vfree(ls->ls_rsbtbl);
851e7fd4179SDavid Teigland
85205c32f47SDavid Teigland for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++)
85305c32f47SDavid Teigland kfree(ls->ls_remove_names[i]);
85405c32f47SDavid Teigland
8553881ac04SDavid Teigland while (!list_empty(&ls->ls_new_rsb)) {
8563881ac04SDavid Teigland rsb = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb,
8573881ac04SDavid Teigland res_hashchain);
8583881ac04SDavid Teigland list_del(&rsb->res_hashchain);
8593881ac04SDavid Teigland dlm_free_rsb(rsb);
8603881ac04SDavid Teigland }
8613881ac04SDavid Teigland
862e7fd4179SDavid Teigland /*
863e7fd4179SDavid Teigland * Free structures on any other lists
864e7fd4179SDavid Teigland */
865e7fd4179SDavid Teigland
8662896ee37SDavid Teigland dlm_purge_requestqueue(ls);
867e7fd4179SDavid Teigland kfree(ls->ls_recover_args);
868e7fd4179SDavid Teigland dlm_clear_members(ls);
869e7fd4179SDavid Teigland dlm_clear_members_gone(ls);
870e7fd4179SDavid Teigland kfree(ls->ls_node_array);
871075f0177SDavid Teigland log_rinfo(ls, "release_lockspace final free");
872197b12d6SGreg Kroah-Hartman kobject_put(&ls->ls_kobj);
873ba542e3bSPatrick Caulfield /* The ls structure will be freed when the kobject is done with */
874e7fd4179SDavid Teigland
875e7fd4179SDavid Teigland module_put(THIS_MODULE);
876e7fd4179SDavid Teigland return 0;
877e7fd4179SDavid Teigland }
878e7fd4179SDavid Teigland
879e7fd4179SDavid Teigland /*
880e7fd4179SDavid Teigland * Called when a system has released all its locks and is not going to use the
881e7fd4179SDavid Teigland * lockspace any longer. We free everything we're managing for this lockspace.
882e7fd4179SDavid Teigland * Remaining nodes will go through the recovery process as if we'd died. The
883e7fd4179SDavid Teigland * lockspace must continue to function as usual, participating in recoveries,
884e7fd4179SDavid Teigland * until this returns.
885e7fd4179SDavid Teigland *
886e7fd4179SDavid Teigland * Force has 4 possible values:
887bb6866a5SAlexander Aring * 0 - don't destroy lockspace if it has any LKBs
888e7fd4179SDavid Teigland * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs
889e7fd4179SDavid Teigland * 2 - destroy lockspace regardless of LKBs
890e7fd4179SDavid Teigland * 3 - destroy lockspace as part of a forced shutdown
891e7fd4179SDavid Teigland */
892e7fd4179SDavid Teigland
dlm_release_lockspace(void * lockspace,int force)893e7fd4179SDavid Teigland int dlm_release_lockspace(void *lockspace, int force)
894e7fd4179SDavid Teigland {
895e7fd4179SDavid Teigland struct dlm_ls *ls;
8960f8e0d9aSDavid Teigland int error;
897e7fd4179SDavid Teigland
898e7fd4179SDavid Teigland ls = dlm_find_lockspace_local(lockspace);
899e7fd4179SDavid Teigland if (!ls)
900e7fd4179SDavid Teigland return -EINVAL;
901e7fd4179SDavid Teigland dlm_put_lockspace(ls);
9020f8e0d9aSDavid Teigland
9030f8e0d9aSDavid Teigland mutex_lock(&ls_lock);
9040f8e0d9aSDavid Teigland error = release_lockspace(ls, force);
9050f8e0d9aSDavid Teigland if (!error)
9060f8e0d9aSDavid Teigland ls_count--;
907278afcbfSDavid Teigland if (!ls_count)
9088b0188b0SAlexander Aring dlm_midcomms_stop();
9090f8e0d9aSDavid Teigland mutex_unlock(&ls_lock);
9100f8e0d9aSDavid Teigland
9110f8e0d9aSDavid Teigland return error;
912e7fd4179SDavid Teigland }
913e7fd4179SDavid Teigland
dlm_stop_lockspaces(void)914dc68c7edSDavid Teigland void dlm_stop_lockspaces(void)
915dc68c7edSDavid Teigland {
916dc68c7edSDavid Teigland struct dlm_ls *ls;
917696b3d84SDavid Teigland int count;
918dc68c7edSDavid Teigland
919dc68c7edSDavid Teigland restart:
920696b3d84SDavid Teigland count = 0;
921dc68c7edSDavid Teigland spin_lock(&lslist_lock);
922dc68c7edSDavid Teigland list_for_each_entry(ls, &lslist, ls_list) {
923696b3d84SDavid Teigland if (!test_bit(LSFL_RUNNING, &ls->ls_flags)) {
924696b3d84SDavid Teigland count++;
925dc68c7edSDavid Teigland continue;
926696b3d84SDavid Teigland }
927dc68c7edSDavid Teigland spin_unlock(&lslist_lock);
928dc68c7edSDavid Teigland log_error(ls, "no userland control daemon, stopping lockspace");
929dc68c7edSDavid Teigland dlm_ls_stop(ls);
930dc68c7edSDavid Teigland goto restart;
931dc68c7edSDavid Teigland }
932dc68c7edSDavid Teigland spin_unlock(&lslist_lock);
933696b3d84SDavid Teigland
934696b3d84SDavid Teigland if (count)
935696b3d84SDavid Teigland log_print("dlm user daemon left %d lockspaces", count);
936dc68c7edSDavid Teigland }
937dc68c7edSDavid Teigland
9382c3fa6aeSAlexander Aring