xref: /openbmc/linux/fs/dlm/lockspace.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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