Blame view

fs/dlm/user.c 24.5 KB
2522fe45a   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
597d0cae0   David Teigland   [DLM] dlm: user l...
2
  /*
7fe2b3190   David Teigland   dlm: fix ordering...
3
   * Copyright (C) 2006-2010 Red Hat, Inc.  All rights reserved.
597d0cae0   David Teigland   [DLM] dlm: user l...
4
5
6
7
8
   */
  
  #include <linux/miscdevice.h>
  #include <linux/init.h>
  #include <linux/wait.h>
597d0cae0   David Teigland   [DLM] dlm: user l...
9
10
11
12
13
14
15
  #include <linux/file.h>
  #include <linux/fs.h>
  #include <linux/poll.h>
  #include <linux/signal.h>
  #include <linux/spinlock.h>
  #include <linux/dlm.h>
  #include <linux/dlm_device.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
17
  #include <linux/sched/signal.h>
597d0cae0   David Teigland   [DLM] dlm: user l...
18
19
20
21
22
  
  #include "dlm_internal.h"
  #include "lockspace.h"
  #include "lock.h"
  #include "lvb_table.h"
84c6e8cd3   Adrian Bunk   [DLM] fs/dlm/user...
23
  #include "user.h"
8304d6f24   David Teigland   dlm: record full ...
24
  #include "ast.h"
3595c5593   David Teigland   dlm: fix invalid ...
25
  #include "config.h"
597d0cae0   David Teigland   [DLM] dlm: user l...
26

0fe410d3f   Denis Cheng   dlm: static initi...
27
  static const char name_prefix[] = "dlm";
00977a59b   Arjan van de Ven   [PATCH] mark stru...
28
  static const struct file_operations device_fops;
dc68c7ed3   David Teigland   dlm: detect avail...
29
30
  static atomic_t dlm_monitor_opened;
  static int dlm_monitor_unused = 1;
597d0cae0   David Teigland   [DLM] dlm: user l...
31
32
33
34
35
36
  
  #ifdef CONFIG_COMPAT
  
  struct dlm_lock_params32 {
  	__u8 mode;
  	__u8 namelen;
d7db923ea   David Teigland   [DLM] dlm_device ...
37
38
  	__u16 unused;
  	__u32 flags;
597d0cae0   David Teigland   [DLM] dlm: user l...
39
40
  	__u32 lkid;
  	__u32 parent;
d7db923ea   David Teigland   [DLM] dlm_device ...
41
42
  	__u64 xid;
  	__u64 timeout;
597d0cae0   David Teigland   [DLM] dlm: user l...
43
44
45
46
47
  	__u32 castparam;
  	__u32 castaddr;
  	__u32 bastparam;
  	__u32 bastaddr;
  	__u32 lksb;
597d0cae0   David Teigland   [DLM] dlm: user l...
48
49
50
51
52
53
54
55
56
57
58
59
60
  	char lvb[DLM_USER_LVB_LEN];
  	char name[0];
  };
  
  struct dlm_write_request32 {
  	__u32 version[3];
  	__u8 cmd;
  	__u8 is64bit;
  	__u8 unused[2];
  
  	union  {
  		struct dlm_lock_params32 lock;
  		struct dlm_lspace_params lspace;
72c2be776   David Teigland   [DLM] interface f...
61
  		struct dlm_purge_params purge;
597d0cae0   David Teigland   [DLM] dlm: user l...
62
63
64
65
66
67
68
69
70
71
72
  	} i;
  };
  
  struct dlm_lksb32 {
  	__u32 sb_status;
  	__u32 sb_lkid;
  	__u8 sb_flags;
  	__u32 sb_lvbptr;
  };
  
  struct dlm_lock_result32 {
d7db923ea   David Teigland   [DLM] dlm_device ...
73
  	__u32 version[3];
597d0cae0   David Teigland   [DLM] dlm: user l...
74
75
76
77
78
79
80
81
82
83
84
85
  	__u32 length;
  	__u32 user_astaddr;
  	__u32 user_astparam;
  	__u32 user_lksb;
  	struct dlm_lksb32 lksb;
  	__u8 bast_mode;
  	__u8 unused[3];
  	/* Offsets may be zero if no data is present */
  	__u32 lvb_offset;
  };
  
  static void compat_input(struct dlm_write_request *kb,
2a79289e8   Patrick Caulfeld   dlm: Sanity check...
86
  			 struct dlm_write_request32 *kb32,
1fecb1c4b   David Teigland   dlm: fix length c...
87
  			 int namelen)
597d0cae0   David Teigland   [DLM] dlm: user l...
88
89
90
91
92
93
94
95
96
97
98
  {
  	kb->version[0] = kb32->version[0];
  	kb->version[1] = kb32->version[1];
  	kb->version[2] = kb32->version[2];
  
  	kb->cmd = kb32->cmd;
  	kb->is64bit = kb32->is64bit;
  	if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
  	    kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
  		kb->i.lspace.flags = kb32->i.lspace.flags;
  		kb->i.lspace.minor = kb32->i.lspace.minor;
1fecb1c4b   David Teigland   dlm: fix length c...
99
  		memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);
72c2be776   David Teigland   [DLM] interface f...
100
101
102
  	} else if (kb->cmd == DLM_USER_PURGE) {
  		kb->i.purge.nodeid = kb32->i.purge.nodeid;
  		kb->i.purge.pid = kb32->i.purge.pid;
597d0cae0   David Teigland   [DLM] dlm: user l...
103
104
105
106
107
108
  	} else {
  		kb->i.lock.mode = kb32->i.lock.mode;
  		kb->i.lock.namelen = kb32->i.lock.namelen;
  		kb->i.lock.flags = kb32->i.lock.flags;
  		kb->i.lock.lkid = kb32->i.lock.lkid;
  		kb->i.lock.parent = kb32->i.lock.parent;
d7db923ea   David Teigland   [DLM] dlm_device ...
109
110
  		kb->i.lock.xid = kb32->i.lock.xid;
  		kb->i.lock.timeout = kb32->i.lock.timeout;
597d0cae0   David Teigland   [DLM] dlm: user l...
111
112
113
114
115
116
  		kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
  		kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
  		kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
  		kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
  		kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
  		memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
1fecb1c4b   David Teigland   dlm: fix length c...
117
  		memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);
597d0cae0   David Teigland   [DLM] dlm: user l...
118
119
120
121
122
123
  	}
  }
  
  static void compat_output(struct dlm_lock_result *res,
  			  struct dlm_lock_result32 *res32)
  {
8286d6b14   Vlad Tsyrklevich   dlm: Fix kernel m...
124
  	memset(res32, 0, sizeof(*res32));
d7db923ea   David Teigland   [DLM] dlm_device ...
125
126
127
  	res32->version[0] = res->version[0];
  	res32->version[1] = res->version[1];
  	res32->version[2] = res->version[2];
597d0cae0   David Teigland   [DLM] dlm: user l...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  	res32->user_astaddr = (__u32)(long)res->user_astaddr;
  	res32->user_astparam = (__u32)(long)res->user_astparam;
  	res32->user_lksb = (__u32)(long)res->user_lksb;
  	res32->bast_mode = res->bast_mode;
  
  	res32->lvb_offset = res->lvb_offset;
  	res32->length = res->length;
  
  	res32->lksb.sb_status = res->lksb.sb_status;
  	res32->lksb.sb_flags = res->lksb.sb_flags;
  	res32->lksb.sb_lkid = res->lksb.sb_lkid;
  	res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
  }
  #endif
84d8cd69a   David Teigland   [DLM] timeout fixes
142
143
144
145
146
147
148
149
150
151
  /* Figure out if this lock is at the end of its life and no longer
     available for the application to use.  The lkb still exists until
     the final ast is read.  A lock becomes EOL in three situations:
       1. a noqueue request fails with EAGAIN
       2. an unlock completes with EUNLOCK
       3. a cancel of a waiting request completes with ECANCEL/EDEADLK
     An EOL lock needs to be removed from the process's list of locks.
     And we can't allow any new operation on an EOL lock.  This is
     not related to the lifetime of the lkb struct which is managed
     entirely by refcount. */
8304d6f24   David Teigland   dlm: record full ...
152
  static int lkb_is_endoflife(int mode, int status)
84d8cd69a   David Teigland   [DLM] timeout fixes
153
  {
8304d6f24   David Teigland   dlm: record full ...
154
  	switch (status) {
84d8cd69a   David Teigland   [DLM] timeout fixes
155
156
157
158
  	case -DLM_EUNLOCK:
  		return 1;
  	case -DLM_ECANCEL:
  	case -ETIMEDOUT:
8b4021fa4   David Teigland   [DLM] canceling d...
159
  	case -EDEADLK:
84d8cd69a   David Teigland   [DLM] timeout fixes
160
  	case -EAGAIN:
8304d6f24   David Teigland   dlm: record full ...
161
  		if (mode == DLM_LOCK_IV)
84d8cd69a   David Teigland   [DLM] timeout fixes
162
163
164
165
166
  			return 1;
  		break;
  	}
  	return 0;
  }
ef0c2bb05   David Teigland   [DLM] overlapping...
167
168
  /* we could possibly check if the cancel of an orphan has resulted in the lkb
     being removed and then remove that lkb from the orphans list and free it */
597d0cae0   David Teigland   [DLM] dlm: user l...
169

8304d6f24   David Teigland   dlm: record full ...
170
171
  void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
  		      int status, uint32_t sbflags, uint64_t seq)
597d0cae0   David Teigland   [DLM] dlm: user l...
172
173
174
175
  {
  	struct dlm_ls *ls;
  	struct dlm_user_args *ua;
  	struct dlm_user_proc *proc;
8304d6f24   David Teigland   dlm: record full ...
176
  	int rv;
597d0cae0   David Teigland   [DLM] dlm: user l...
177

ef0c2bb05   David Teigland   [DLM] overlapping...
178
  	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
597d0cae0   David Teigland   [DLM] dlm: user l...
179
  		return;
597d0cae0   David Teigland   [DLM] dlm: user l...
180
181
182
183
184
185
  
  	ls = lkb->lkb_resource->res_ls;
  	mutex_lock(&ls->ls_clear_proc_locks);
  
  	/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
  	   can't be delivered.  For ORPHAN's, dlm_clear_proc_locks() freed
ef0c2bb05   David Teigland   [DLM] overlapping...
186
187
188
  	   lkb->ua so we can't try to use it.  This second check is necessary
  	   for cases where a completion ast is received for an operation that
  	   began before clear_proc_locks did its cancel/unlock. */
597d0cae0   David Teigland   [DLM] dlm: user l...
189

ef0c2bb05   David Teigland   [DLM] overlapping...
190
  	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
597d0cae0   David Teigland   [DLM] dlm: user l...
191
  		goto out;
597d0cae0   David Teigland   [DLM] dlm: user l...
192

d292c0cc4   David Teigland   dlm: eliminate as...
193
194
  	DLM_ASSERT(lkb->lkb_ua, dlm_print_lkb(lkb););
  	ua = lkb->lkb_ua;
597d0cae0   David Teigland   [DLM] dlm: user l...
195
  	proc = ua->proc;
8304d6f24   David Teigland   dlm: record full ...
196
  	if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL)
597d0cae0   David Teigland   [DLM] dlm: user l...
197
  		goto out;
8304d6f24   David Teigland   dlm: record full ...
198
199
  	if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status))
  		lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
597d0cae0   David Teigland   [DLM] dlm: user l...
200
  	spin_lock(&proc->asts_spin);
ef0c2bb05   David Teigland   [DLM] overlapping...
201

8304d6f24   David Teigland   dlm: record full ...
202
203
204
205
206
  	rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
  	if (rv < 0) {
  		spin_unlock(&proc->asts_spin);
  		goto out;
  	}
ef0c2bb05   David Teigland   [DLM] overlapping...
207

23e8e1aaa   David Teigland   dlm: use workqueu...
208
  	if (list_empty(&lkb->lkb_cb_list)) {
597d0cae0   David Teigland   [DLM] dlm: user l...
209
  		kref_get(&lkb->lkb_ref);
23e8e1aaa   David Teigland   dlm: use workqueu...
210
  		list_add_tail(&lkb->lkb_cb_list, &proc->asts);
597d0cae0   David Teigland   [DLM] dlm: user l...
211
212
  		wake_up_interruptible(&proc->wait);
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
213
  	spin_unlock(&proc->asts_spin);
34e22bed1   David Teigland   [DLM] fix leaking...
214

8304d6f24   David Teigland   dlm: record full ...
215
216
  	if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
  		/* N.B. spin_lock locks_spin, not asts_spin */
ce5246b97   David Teigland   dlm: fix possible...
217
  		spin_lock(&proc->locks_spin);
ef0c2bb05   David Teigland   [DLM] overlapping...
218
219
220
221
  		if (!list_empty(&lkb->lkb_ownqueue)) {
  			list_del_init(&lkb->lkb_ownqueue);
  			dlm_put_lkb(lkb);
  		}
ce5246b97   David Teigland   dlm: fix possible...
222
  		spin_unlock(&proc->locks_spin);
34e22bed1   David Teigland   [DLM] fix leaking...
223
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
224
225
226
227
228
229
230
231
232
   out:
  	mutex_unlock(&ls->ls_clear_proc_locks);
  }
  
  static int device_user_lock(struct dlm_user_proc *proc,
  			    struct dlm_lock_params *params)
  {
  	struct dlm_ls *ls;
  	struct dlm_user_args *ua;
2ab4bd8ea   David Teigland   dlm: adopt orphan...
233
  	uint32_t lkid;
597d0cae0   David Teigland   [DLM] dlm: user l...
234
235
236
237
238
239
240
241
242
243
  	int error = -ENOMEM;
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
  
  	if (!params->castaddr || !params->lksb) {
  		error = -EINVAL;
  		goto out;
  	}
573c24c4a   David Teigland   dlm: always use G...
244
  	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
245
246
247
248
249
250
251
252
  	if (!ua)
  		goto out;
  	ua->proc = proc;
  	ua->user_lksb = params->lksb;
  	ua->castparam = params->castparam;
  	ua->castaddr = params->castaddr;
  	ua->bastparam = params->bastparam;
  	ua->bastaddr = params->bastaddr;
d7db923ea   David Teigland   [DLM] dlm_device ...
253
  	ua->xid = params->xid;
597d0cae0   David Teigland   [DLM] dlm: user l...
254

2ab4bd8ea   David Teigland   dlm: adopt orphan...
255
  	if (params->flags & DLM_LKF_CONVERT) {
597d0cae0   David Teigland   [DLM] dlm: user l...
256
257
  		error = dlm_user_convert(ls, ua,
  				         params->mode, params->flags,
d7db923ea   David Teigland   [DLM] dlm_device ...
258
259
  				         params->lkid, params->lvb,
  					 (unsigned long) params->timeout);
2ab4bd8ea   David Teigland   dlm: adopt orphan...
260
261
262
263
264
265
266
267
268
  	} else if (params->flags & DLM_LKF_ORPHAN) {
  		error = dlm_user_adopt_orphan(ls, ua,
  					 params->mode, params->flags,
  					 params->name, params->namelen,
  					 (unsigned long) params->timeout,
  					 &lkid);
  		if (!error)
  			error = lkid;
  	} else {
597d0cae0   David Teigland   [DLM] dlm: user l...
269
270
271
  		error = dlm_user_request(ls, ua,
  					 params->mode, params->flags,
  					 params->name, params->namelen,
d7db923ea   David Teigland   [DLM] dlm_device ...
272
  					 (unsigned long) params->timeout);
597d0cae0   David Teigland   [DLM] dlm: user l...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  		if (!error)
  			error = ua->lksb.sb_lkid;
  	}
   out:
  	dlm_put_lockspace(ls);
  	return error;
  }
  
  static int device_user_unlock(struct dlm_user_proc *proc,
  			      struct dlm_lock_params *params)
  {
  	struct dlm_ls *ls;
  	struct dlm_user_args *ua;
  	int error = -ENOMEM;
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
573c24c4a   David Teigland   dlm: always use G...
291
  	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  	if (!ua)
  		goto out;
  	ua->proc = proc;
  	ua->user_lksb = params->lksb;
  	ua->castparam = params->castparam;
  	ua->castaddr = params->castaddr;
  
  	if (params->flags & DLM_LKF_CANCEL)
  		error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
  	else
  		error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
  					params->lvb);
   out:
  	dlm_put_lockspace(ls);
  	return error;
  }
8b4021fa4   David Teigland   [DLM] canceling d...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  static int device_user_deadlock(struct dlm_user_proc *proc,
  				struct dlm_lock_params *params)
  {
  	struct dlm_ls *ls;
  	int error;
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
  
  	error = dlm_user_deadlock(ls, params->flags, params->lkid);
  
  	dlm_put_lockspace(ls);
  	return error;
  }
0f8e0d9a3   David Teigland   dlm: allow multip...
323
  static int dlm_device_register(struct dlm_ls *ls, char *name)
254da030d   Patrick Caulfield   [DLM] Don't delet...
324
325
  {
  	int error, len;
0f8e0d9a3   David Teigland   dlm: allow multip...
326
327
328
329
  	/* The device is already registered.  This happens when the
  	   lockspace is created multiple times from userspace. */
  	if (ls->ls_device.name)
  		return 0;
254da030d   Patrick Caulfield   [DLM] Don't delet...
330
331
  	error = -ENOMEM;
  	len = strlen(name) + strlen(name_prefix) + 2;
573c24c4a   David Teigland   dlm: always use G...
332
  	ls->ls_device.name = kzalloc(len, GFP_NOFS);
254da030d   Patrick Caulfield   [DLM] Don't delet...
333
334
335
336
337
338
339
340
341
342
343
  	if (!ls->ls_device.name)
  		goto fail;
  
  	snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
  		 name);
  	ls->ls_device.fops = &device_fops;
  	ls->ls_device.minor = MISC_DYNAMIC_MINOR;
  
  	error = misc_register(&ls->ls_device);
  	if (error) {
  		kfree(ls->ls_device.name);
55acdd926   Edwin Török   dlm: avoid double...
344
345
346
347
  		/* this has to be set to NULL
  		 * to avoid a double-free in dlm_device_deregister
  		 */
  		ls->ls_device.name = NULL;
254da030d   Patrick Caulfield   [DLM] Don't delet...
348
349
350
351
  	}
  fail:
  	return error;
  }
0f8e0d9a3   David Teigland   dlm: allow multip...
352
353
  int dlm_device_deregister(struct dlm_ls *ls)
  {
0f8e0d9a3   David Teigland   dlm: allow multip...
354
355
356
357
358
  	/* The device is not registered.  This happens when the lockspace
  	   was never used from userspace, or when device_create_lockspace()
  	   calls dlm_release_lockspace() after the register fails. */
  	if (!ls->ls_device.name)
  		return 0;
f368ed608   Greg Kroah-Hartman   char: make misc_d...
359
360
361
  	misc_deregister(&ls->ls_device);
  	kfree(ls->ls_device.name);
  	return 0;
0f8e0d9a3   David Teigland   dlm: allow multip...
362
  }
72c2be776   David Teigland   [DLM] interface f...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  static int device_user_purge(struct dlm_user_proc *proc,
  			     struct dlm_purge_params *params)
  {
  	struct dlm_ls *ls;
  	int error;
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
  
  	error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
  
  	dlm_put_lockspace(ls);
  	return error;
  }
597d0cae0   David Teigland   [DLM] dlm: user l...
378
379
380
381
  static int device_create_lockspace(struct dlm_lspace_params *params)
  {
  	dlm_lockspace_t *lockspace;
  	struct dlm_ls *ls;
254da030d   Patrick Caulfield   [DLM] Don't delet...
382
  	int error;
597d0cae0   David Teigland   [DLM] dlm: user l...
383
384
385
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
3595c5593   David Teigland   dlm: fix invalid ...
386
  	error = dlm_new_lockspace(params->name, dlm_config.ci_cluster_name, params->flags,
60f98d183   David Teigland   dlm: add recovery...
387
388
  				  DLM_USER_LVB_LEN, NULL, NULL, NULL,
  				  &lockspace);
597d0cae0   David Teigland   [DLM] dlm: user l...
389
390
391
392
393
394
  	if (error)
  		return error;
  
  	ls = dlm_find_lockspace_local(lockspace);
  	if (!ls)
  		return -ENOENT;
0f8e0d9a3   David Teigland   dlm: allow multip...
395
  	error = dlm_device_register(ls, params->name);
597d0cae0   David Teigland   [DLM] dlm: user l...
396
  	dlm_put_lockspace(ls);
597d0cae0   David Teigland   [DLM] dlm: user l...
397

254da030d   Patrick Caulfield   [DLM] Don't delet...
398
399
400
401
  	if (error)
  		dlm_release_lockspace(lockspace, 0);
  	else
  		error = ls->ls_device.minor;
597d0cae0   David Teigland   [DLM] dlm: user l...
402
403
404
405
406
407
408
  	return error;
  }
  
  static int device_remove_lockspace(struct dlm_lspace_params *params)
  {
  	dlm_lockspace_t *lockspace;
  	struct dlm_ls *ls;
c6e6f0ba8   David Teigland   [DLM] force remov...
409
  	int error, force = 0;
597d0cae0   David Teigland   [DLM] dlm: user l...
410
411
412
413
414
415
416
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	ls = dlm_find_lockspace_device(params->minor);
  	if (!ls)
  		return -ENOENT;
c6e6f0ba8   David Teigland   [DLM] force remov...
417
418
  	if (params->flags & DLM_USER_LSFLG_FORCEFREE)
  		force = 2;
597d0cae0   David Teigland   [DLM] dlm: user l...
419
  	lockspace = ls->ls_local_handle;
0f8e0d9a3   David Teigland   dlm: allow multip...
420
  	dlm_put_lockspace(ls);
597d0cae0   David Teigland   [DLM] dlm: user l...
421

0f8e0d9a3   David Teigland   dlm: allow multip...
422
423
424
425
426
427
  	/* The final dlm_release_lockspace waits for references to go to
  	   zero, so all processes will need to close their device for the
  	   ls before the release will proceed.  release also calls the
  	   device_deregister above.  Converting a positive return value
  	   from release to zero means that userspace won't know when its
  	   release was the final one, but it shouldn't need to know. */
597d0cae0   David Teigland   [DLM] dlm: user l...
428

c6e6f0ba8   David Teigland   [DLM] force remov...
429
  	error = dlm_release_lockspace(lockspace, force);
0f8e0d9a3   David Teigland   dlm: allow multip...
430
431
  	if (error > 0)
  		error = 0;
597d0cae0   David Teigland   [DLM] dlm: user l...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  	return error;
  }
  
  /* Check the user's version matches ours */
  static int check_version(struct dlm_write_request *req)
  {
  	if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
  	    (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
  	     req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
  
  		printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
  		       "user (%d.%d.%d) kernel (%d.%d.%d)
  ",
  		       current->comm,
ba25f9dcc   Pavel Emelyanov   Use helpers to ob...
446
  		       task_pid_nr(current),
597d0cae0   David Teigland   [DLM] dlm: user l...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  		       req->version[0],
  		       req->version[1],
  		       req->version[2],
  		       DLM_DEVICE_VERSION_MAJOR,
  		       DLM_DEVICE_VERSION_MINOR,
  		       DLM_DEVICE_VERSION_PATCH);
  		return -EINVAL;
  	}
  	return 0;
  }
  
  /*
   * device_write
   *
   *   device_user_lock
   *     dlm_user_request -> request_lock
   *     dlm_user_convert -> convert_lock
   *
   *   device_user_unlock
   *     dlm_user_unlock -> unlock_lock
   *     dlm_user_cancel -> cancel_lock
   *
   *   device_create_lockspace
   *     dlm_new_lockspace
   *
   *   device_remove_lockspace
   *     dlm_release_lockspace
   */
  
  /* a write to a lockspace device is a lock or unlock request, a write
     to the control device is to create/remove a lockspace */
  
  static ssize_t device_write(struct file *file, const char __user *buf,
  			    size_t count, loff_t *ppos)
  {
  	struct dlm_user_proc *proc = file->private_data;
  	struct dlm_write_request *kbuf;
597d0cae0   David Teigland   [DLM] dlm: user l...
484
485
486
487
488
489
490
491
  	int error;
  
  #ifdef CONFIG_COMPAT
  	if (count < sizeof(struct dlm_write_request32))
  #else
  	if (count < sizeof(struct dlm_write_request))
  #endif
  		return -EINVAL;
d4b0bcf32   David Teigland   dlm: check the wr...
492
493
494
495
  	/*
  	 * can't compare against COMPAT/dlm_write_request32 because
  	 * we don't yet know if is64bit is zero
  	 */
2b75bc912   Sasha Levin   dlm: check the ma...
496
  	if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
2b75bc912   Sasha Levin   dlm: check the ma...
497
  		return -EINVAL;
16e5c1fc3   Al Viro   convert a bunch o...
498
  	kbuf = memdup_user_nul(buf, count);
117aa41e8   Al Viro   [regression] fix ...
499
  	if (IS_ERR(kbuf))
16e5c1fc3   Al Viro   convert a bunch o...
500
  		return PTR_ERR(kbuf);
597d0cae0   David Teigland   [DLM] dlm: user l...
501
502
503
504
505
506
507
508
509
  
  	if (check_version(kbuf)) {
  		error = -EBADE;
  		goto out_free;
  	}
  
  #ifdef CONFIG_COMPAT
  	if (!kbuf->is64bit) {
  		struct dlm_write_request32 *k32buf;
1fecb1c4b   David Teigland   dlm: fix length c...
510
511
512
513
  		int namelen = 0;
  
  		if (count > sizeof(struct dlm_write_request32))
  			namelen = count - sizeof(struct dlm_write_request32);
597d0cae0   David Teigland   [DLM] dlm: user l...
514
  		k32buf = (struct dlm_write_request32 *)kbuf;
1fecb1c4b   David Teigland   dlm: fix length c...
515
516
517
  
  		/* add 1 after namelen so that the name string is terminated */
  		kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1,
573c24c4a   David Teigland   dlm: always use G...
518
  			       GFP_NOFS);
cb980d9a3   David Teigland   dlm: add missing ...
519
520
  		if (!kbuf) {
  			kfree(k32buf);
597d0cae0   David Teigland   [DLM] dlm: user l...
521
  			return -ENOMEM;
cb980d9a3   David Teigland   dlm: add missing ...
522
  		}
597d0cae0   David Teigland   [DLM] dlm: user l...
523
524
525
  
  		if (proc)
  			set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
1fecb1c4b   David Teigland   dlm: fix length c...
526
527
  
  		compat_input(kbuf, k32buf, namelen);
597d0cae0   David Teigland   [DLM] dlm: user l...
528
529
530
531
532
533
  		kfree(k32buf);
  	}
  #endif
  
  	/* do we really need this? can a write happen after a close? */
  	if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
cb980d9a3   David Teigland   dlm: add missing ...
534
535
536
537
  	    (proc && test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))) {
  		error = -EINVAL;
  		goto out_free;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
538

597d0cae0   David Teigland   [DLM] dlm: user l...
539
540
541
542
543
544
545
  	error = -EINVAL;
  
  	switch (kbuf->cmd)
  	{
  	case DLM_USER_LOCK:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
546
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
547
548
549
550
551
552
553
  		}
  		error = device_user_lock(proc, &kbuf->i.lock);
  		break;
  
  	case DLM_USER_UNLOCK:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
554
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
555
556
557
  		}
  		error = device_user_unlock(proc, &kbuf->i.lock);
  		break;
8b4021fa4   David Teigland   [DLM] canceling d...
558
559
560
  	case DLM_USER_DEADLOCK:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
561
  			goto out_free;
8b4021fa4   David Teigland   [DLM] canceling d...
562
563
564
  		}
  		error = device_user_deadlock(proc, &kbuf->i.lock);
  		break;
597d0cae0   David Teigland   [DLM] dlm: user l...
565
566
567
  	case DLM_USER_CREATE_LOCKSPACE:
  		if (proc) {
  			log_print("create/remove only on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
568
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
569
570
571
572
573
574
575
  		}
  		error = device_create_lockspace(&kbuf->i.lspace);
  		break;
  
  	case DLM_USER_REMOVE_LOCKSPACE:
  		if (proc) {
  			log_print("create/remove only on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
576
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
577
578
579
  		}
  		error = device_remove_lockspace(&kbuf->i.lspace);
  		break;
72c2be776   David Teigland   [DLM] interface f...
580
581
582
  	case DLM_USER_PURGE:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
583
  			goto out_free;
72c2be776   David Teigland   [DLM] interface f...
584
585
586
  		}
  		error = device_user_purge(proc, &kbuf->i.purge);
  		break;
597d0cae0   David Teigland   [DLM] dlm: user l...
587
588
589
590
591
  	default:
  		log_print("Unknown command passed to DLM device : %d
  ",
  			  kbuf->cmd);
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
   out_free:
  	kfree(kbuf);
  	return error;
  }
  
  /* Every process that opens the lockspace device has its own "proc" structure
     hanging off the open file that's used to keep track of locks owned by the
     process and asts that need to be delivered to the process. */
  
  static int device_open(struct inode *inode, struct file *file)
  {
  	struct dlm_user_proc *proc;
  	struct dlm_ls *ls;
  
  	ls = dlm_find_lockspace_device(iminor(inode));
f9f2ed486   David Teigland   dlm: remove bkl
607
  	if (!ls)
597d0cae0   David Teigland   [DLM] dlm: user l...
608
  		return -ENOENT;
573c24c4a   David Teigland   dlm: always use G...
609
  	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
610
611
612
613
614
615
616
617
  	if (!proc) {
  		dlm_put_lockspace(ls);
  		return -ENOMEM;
  	}
  
  	proc->lockspace = ls->ls_local_handle;
  	INIT_LIST_HEAD(&proc->asts);
  	INIT_LIST_HEAD(&proc->locks);
a1bc86e6b   David Teigland   [DLM] fix user un...
618
  	INIT_LIST_HEAD(&proc->unlocking);
597d0cae0   David Teigland   [DLM] dlm: user l...
619
620
621
622
623
624
625
626
627
628
629
630
  	spin_lock_init(&proc->asts_spin);
  	spin_lock_init(&proc->locks_spin);
  	init_waitqueue_head(&proc->wait);
  	file->private_data = proc;
  
  	return 0;
  }
  
  static int device_close(struct inode *inode, struct file *file)
  {
  	struct dlm_user_proc *proc = file->private_data;
  	struct dlm_ls *ls;
597d0cae0   David Teigland   [DLM] dlm: user l...
631
632
633
634
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
597d0cae0   David Teigland   [DLM] dlm: user l...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  	set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
  
  	dlm_clear_proc_locks(ls, proc);
  
  	/* at this point no more lkb's should exist for this lockspace,
  	   so there's no chance of dlm_user_add_ast() being called and
  	   looking for lkb->ua->proc */
  
  	kfree(proc);
  	file->private_data = NULL;
  
  	dlm_put_lockspace(ls);
  	dlm_put_lockspace(ls);  /* for the find in device_open() */
  
  	/* FIXME: AUTOFREE: if this ls is no longer used do
  	   device_remove_lockspace() */
597d0cae0   David Teigland   [DLM] dlm: user l...
651
652
  	return 0;
  }
8304d6f24   David Teigland   dlm: record full ...
653
654
655
  static int copy_result_to_user(struct dlm_user_args *ua, int compat,
  			       uint32_t flags, int mode, int copy_lvb,
  			       char __user *buf, size_t count)
597d0cae0   David Teigland   [DLM] dlm: user l...
656
657
658
659
660
661
662
663
664
665
666
  {
  #ifdef CONFIG_COMPAT
  	struct dlm_lock_result32 result32;
  #endif
  	struct dlm_lock_result result;
  	void *resultptr;
  	int error=0;
  	int len;
  	int struct_len;
  
  	memset(&result, 0, sizeof(struct dlm_lock_result));
d7db923ea   David Teigland   [DLM] dlm_device ...
667
668
669
  	result.version[0] = DLM_DEVICE_VERSION_MAJOR;
  	result.version[1] = DLM_DEVICE_VERSION_MINOR;
  	result.version[2] = DLM_DEVICE_VERSION_PATCH;
9de30f3f7   Tycho Andersen   dlm: don't leak k...
670
  	memcpy(&result.lksb, &ua->lksb, offsetof(struct dlm_lksb, sb_lvbptr));
597d0cae0   David Teigland   [DLM] dlm: user l...
671
672
673
674
675
676
677
  	result.user_lksb = ua->user_lksb;
  
  	/* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
  	   in a conversion unless the conversion is successful.  See code
  	   in dlm_user_convert() for updating ua from ua_tmp.  OpenVMS, though,
  	   notes that a new blocking AST address and parameter are set even if
  	   the conversion fails, so maybe we should just do that. */
8304d6f24   David Teigland   dlm: record full ...
678
  	if (flags & DLM_CB_BAST) {
597d0cae0   David Teigland   [DLM] dlm: user l...
679
680
  		result.user_astaddr = ua->bastaddr;
  		result.user_astparam = ua->bastparam;
89d799d00   David Teigland   dlm: fix ast orde...
681
  		result.bast_mode = mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  	} else {
  		result.user_astaddr = ua->castaddr;
  		result.user_astparam = ua->castparam;
  	}
  
  #ifdef CONFIG_COMPAT
  	if (compat)
  		len = sizeof(struct dlm_lock_result32);
  	else
  #endif
  		len = sizeof(struct dlm_lock_result);
  	struct_len = len;
  
  	/* copy lvb to userspace if there is one, it's been updated, and
  	   the user buffer has space for it */
8304d6f24   David Teigland   dlm: record full ...
697
  	if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
597d0cae0   David Teigland   [DLM] dlm: user l...
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
  		if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
  				 DLM_USER_LVB_LEN)) {
  			error = -EFAULT;
  			goto out;
  		}
  
  		result.lvb_offset = len;
  		len += DLM_USER_LVB_LEN;
  	}
  
  	result.length = len;
  	resultptr = &result;
  #ifdef CONFIG_COMPAT
  	if (compat) {
  		compat_output(&result, &result32);
  		resultptr = &result32;
  	}
  #endif
  
  	if (copy_to_user(buf, resultptr, struct_len))
  		error = -EFAULT;
  	else
  		error = len;
   out:
  	return error;
  }
d7db923ea   David Teigland   [DLM] dlm_device ...
724
725
726
727
728
729
730
731
732
733
734
735
736
  static int copy_version_to_user(char __user *buf, size_t count)
  {
  	struct dlm_device_version ver;
  
  	memset(&ver, 0, sizeof(struct dlm_device_version));
  	ver.version[0] = DLM_DEVICE_VERSION_MAJOR;
  	ver.version[1] = DLM_DEVICE_VERSION_MINOR;
  	ver.version[2] = DLM_DEVICE_VERSION_PATCH;
  
  	if (copy_to_user(buf, &ver, sizeof(struct dlm_device_version)))
  		return -EFAULT;
  	return sizeof(struct dlm_device_version);
  }
597d0cae0   David Teigland   [DLM] dlm: user l...
737
738
739
740
741
742
743
  /* a read returns a single ast described in a struct dlm_lock_result */
  
  static ssize_t device_read(struct file *file, char __user *buf, size_t count,
  			   loff_t *ppos)
  {
  	struct dlm_user_proc *proc = file->private_data;
  	struct dlm_lkb *lkb;
597d0cae0   David Teigland   [DLM] dlm: user l...
744
  	DECLARE_WAITQUEUE(wait, current);
8304d6f24   David Teigland   dlm: record full ...
745
746
  	struct dlm_callback cb;
  	int rv, resid, copy_lvb = 0;
b96f46503   David Teigland   dlm: fix lvb copy...
747
  	int old_mode, new_mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
748

d7db923ea   David Teigland   [DLM] dlm_device ...
749
  	if (count == sizeof(struct dlm_device_version)) {
8304d6f24   David Teigland   dlm: record full ...
750
751
  		rv = copy_version_to_user(buf, count);
  		return rv;
d7db923ea   David Teigland   [DLM] dlm_device ...
752
753
754
755
756
757
  	}
  
  	if (!proc) {
  		log_print("non-version read from control device %zu", count);
  		return -EINVAL;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
758
759
760
761
762
763
  #ifdef CONFIG_COMPAT
  	if (count < sizeof(struct dlm_lock_result32))
  #else
  	if (count < sizeof(struct dlm_lock_result))
  #endif
  		return -EINVAL;
89d799d00   David Teigland   dlm: fix ast orde...
764
   try_another:
597d0cae0   David Teigland   [DLM] dlm: user l...
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  	/* do we really need this? can a read happen after a close? */
  	if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
  		return -EINVAL;
  
  	spin_lock(&proc->asts_spin);
  	if (list_empty(&proc->asts)) {
  		if (file->f_flags & O_NONBLOCK) {
  			spin_unlock(&proc->asts_spin);
  			return -EAGAIN;
  		}
  
  		add_wait_queue(&proc->wait, &wait);
  
  	repeat:
  		set_current_state(TASK_INTERRUPTIBLE);
  		if (list_empty(&proc->asts) && !signal_pending(current)) {
  			spin_unlock(&proc->asts_spin);
  			schedule();
  			spin_lock(&proc->asts_spin);
  			goto repeat;
  		}
  		set_current_state(TASK_RUNNING);
  		remove_wait_queue(&proc->wait, &wait);
  
  		if (signal_pending(current)) {
  			spin_unlock(&proc->asts_spin);
  			return -ERESTARTSYS;
  		}
  	}
8304d6f24   David Teigland   dlm: record full ...
794
  	/* if we empty lkb_callbacks, we don't want to unlock the spinlock
23e8e1aaa   David Teigland   dlm: use workqueu...
795
  	   without removing lkb_cb_list; so empty lkb_cb_list is always
8304d6f24   David Teigland   dlm: record full ...
796
  	   consistent with empty lkb_callbacks */
597d0cae0   David Teigland   [DLM] dlm: user l...
797

23e8e1aaa   David Teigland   dlm: use workqueu...
798
  	lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_cb_list);
597d0cae0   David Teigland   [DLM] dlm: user l...
799

b96f46503   David Teigland   dlm: fix lvb copy...
800
801
  	/* rem_lkb_callback sets a new lkb_last_cast */
  	old_mode = lkb->lkb_last_cast.mode;
8304d6f24   David Teigland   dlm: record full ...
802
803
804
805
806
  	rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid);
  	if (rv < 0) {
  		/* this shouldn't happen; lkb should have been removed from
  		   list when resid was zero */
  		log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id);
23e8e1aaa   David Teigland   dlm: use workqueu...
807
  		list_del_init(&lkb->lkb_cb_list);
8304d6f24   David Teigland   dlm: record full ...
808
809
810
811
  		spin_unlock(&proc->asts_spin);
  		/* removes ref for proc->asts, may cause lkb to be freed */
  		dlm_put_lkb(lkb);
  		goto try_another;
89d799d00   David Teigland   dlm: fix ast orde...
812
  	}
8304d6f24   David Teigland   dlm: record full ...
813
  	if (!resid)
23e8e1aaa   David Teigland   dlm: use workqueu...
814
  		list_del_init(&lkb->lkb_cb_list);
8304d6f24   David Teigland   dlm: record full ...
815
  	spin_unlock(&proc->asts_spin);
89d799d00   David Teigland   dlm: fix ast orde...
816

8304d6f24   David Teigland   dlm: record full ...
817
818
819
820
821
  	if (cb.flags & DLM_CB_SKIP) {
  		/* removes ref for proc->asts, may cause lkb to be freed */
  		if (!resid)
  			dlm_put_lkb(lkb);
  		goto try_another;
89d799d00   David Teigland   dlm: fix ast orde...
822
  	}
8304d6f24   David Teigland   dlm: record full ...
823
  	if (cb.flags & DLM_CB_CAST) {
8304d6f24   David Teigland   dlm: record full ...
824
  		new_mode = cb.mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
825

8304d6f24   David Teigland   dlm: record full ...
826
827
828
  		if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
  		    dlm_lvb_operations[old_mode + 1][new_mode + 1])
  			copy_lvb = 1;
89d799d00   David Teigland   dlm: fix ast orde...
829

8304d6f24   David Teigland   dlm: record full ...
830
831
  		lkb->lkb_lksb->sb_status = cb.sb_status;
  		lkb->lkb_lksb->sb_flags = cb.sb_flags;
89d799d00   David Teigland   dlm: fix ast orde...
832
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
833

8304d6f24   David Teigland   dlm: record full ...
834
835
836
  	rv = copy_result_to_user(lkb->lkb_ua,
  				 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
  				 cb.flags, cb.mode, copy_lvb, buf, count);
89d799d00   David Teigland   dlm: fix ast orde...
837

8304d6f24   David Teigland   dlm: record full ...
838
839
  	/* removes ref for proc->asts, may cause lkb to be freed */
  	if (!resid)
597d0cae0   David Teigland   [DLM] dlm: user l...
840
  		dlm_put_lkb(lkb);
8304d6f24   David Teigland   dlm: record full ...
841
  	return rv;
597d0cae0   David Teigland   [DLM] dlm: user l...
842
  }
076ccb76e   Al Viro   fs: annotate ->po...
843
  static __poll_t device_poll(struct file *file, poll_table *wait)
597d0cae0   David Teigland   [DLM] dlm: user l...
844
845
846
847
848
849
850
851
  {
  	struct dlm_user_proc *proc = file->private_data;
  
  	poll_wait(file, &proc->wait, wait);
  
  	spin_lock(&proc->asts_spin);
  	if (!list_empty(&proc->asts)) {
  		spin_unlock(&proc->asts_spin);
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
852
  		return EPOLLIN | EPOLLRDNORM;
597d0cae0   David Teigland   [DLM] dlm: user l...
853
854
855
856
  	}
  	spin_unlock(&proc->asts_spin);
  	return 0;
  }
dc68c7ed3   David Teigland   dlm: detect avail...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
  int dlm_user_daemon_available(void)
  {
  	/* dlm_controld hasn't started (or, has started, but not
  	   properly populated configfs) */
  
  	if (!dlm_our_nodeid())
  		return 0;
  
  	/* This is to deal with versions of dlm_controld that don't
  	   know about the monitor device.  We assume that if the
  	   dlm_controld was started (above), but the monitor device
  	   was never opened, that it's an old version.  dlm_controld
  	   should open the monitor device before populating configfs. */
  
  	if (dlm_monitor_unused)
  		return 1;
  
  	return atomic_read(&dlm_monitor_opened) ? 1 : 0;
  }
597d0cae0   David Teigland   [DLM] dlm: user l...
876
877
878
879
880
881
882
883
884
885
  static int ctl_device_open(struct inode *inode, struct file *file)
  {
  	file->private_data = NULL;
  	return 0;
  }
  
  static int ctl_device_close(struct inode *inode, struct file *file)
  {
  	return 0;
  }
dc68c7ed3   David Teigland   dlm: detect avail...
886
887
888
889
890
891
892
893
894
895
896
897
898
  static int monitor_device_open(struct inode *inode, struct file *file)
  {
  	atomic_inc(&dlm_monitor_opened);
  	dlm_monitor_unused = 0;
  	return 0;
  }
  
  static int monitor_device_close(struct inode *inode, struct file *file)
  {
  	if (atomic_dec_and_test(&dlm_monitor_opened))
  		dlm_stop_lockspaces();
  	return 0;
  }
00977a59b   Arjan van de Ven   [PATCH] mark stru...
899
  static const struct file_operations device_fops = {
597d0cae0   David Teigland   [DLM] dlm: user l...
900
901
902
903
904
905
  	.open    = device_open,
  	.release = device_close,
  	.read    = device_read,
  	.write   = device_write,
  	.poll    = device_poll,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
906
  	.llseek  = noop_llseek,
597d0cae0   David Teigland   [DLM] dlm: user l...
907
  };
00977a59b   Arjan van de Ven   [PATCH] mark stru...
908
  static const struct file_operations ctl_device_fops = {
597d0cae0   David Teigland   [DLM] dlm: user l...
909
910
  	.open    = ctl_device_open,
  	.release = ctl_device_close,
d7db923ea   David Teigland   [DLM] dlm_device ...
911
  	.read    = device_read,
597d0cae0   David Teigland   [DLM] dlm: user l...
912
913
  	.write   = device_write,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
914
  	.llseek  = noop_llseek,
597d0cae0   David Teigland   [DLM] dlm: user l...
915
  };
0fe410d3f   Denis Cheng   dlm: static initi...
916
917
918
919
920
  static struct miscdevice ctl_device = {
  	.name  = "dlm-control",
  	.fops  = &ctl_device_fops,
  	.minor = MISC_DYNAMIC_MINOR,
  };
dc68c7ed3   David Teigland   dlm: detect avail...
921
922
923
924
  static const struct file_operations monitor_device_fops = {
  	.open    = monitor_device_open,
  	.release = monitor_device_close,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
925
  	.llseek  = noop_llseek,
dc68c7ed3   David Teigland   dlm: detect avail...
926
927
928
929
930
931
932
  };
  
  static struct miscdevice monitor_device = {
  	.name  = "dlm-monitor",
  	.fops  = &monitor_device_fops,
  	.minor = MISC_DYNAMIC_MINOR,
  };
30727174b   Denis Cheng   dlm: add __init a...
933
  int __init dlm_user_init(void)
597d0cae0   David Teigland   [DLM] dlm: user l...
934
935
  {
  	int error;
dc68c7ed3   David Teigland   dlm: detect avail...
936
  	atomic_set(&dlm_monitor_opened, 0);
597d0cae0   David Teigland   [DLM] dlm: user l...
937
  	error = misc_register(&ctl_device);
dc68c7ed3   David Teigland   dlm: detect avail...
938
  	if (error) {
597d0cae0   David Teigland   [DLM] dlm: user l...
939
  		log_print("misc_register failed for control device");
dc68c7ed3   David Teigland   dlm: detect avail...
940
941
  		goto out;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
942

dc68c7ed3   David Teigland   dlm: detect avail...
943
944
945
946
947
948
  	error = misc_register(&monitor_device);
  	if (error) {
  		log_print("misc_register failed for monitor device");
  		misc_deregister(&ctl_device);
  	}
   out:
597d0cae0   David Teigland   [DLM] dlm: user l...
949
950
951
952
953
954
  	return error;
  }
  
  void dlm_user_exit(void)
  {
  	misc_deregister(&ctl_device);
dc68c7ed3   David Teigland   dlm: detect avail...
955
  	misc_deregister(&monitor_device);
597d0cae0   David Teigland   [DLM] dlm: user l...
956
  }