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