Blame view

fs/dlm/user.c 24.4 KB
597d0cae0   David Teigland   [DLM] dlm: user l...
1
  /*
7fe2b3190   David Teigland   dlm: fix ordering...
2
   * Copyright (C) 2006-2010 Red Hat, Inc.  All rights reserved.
597d0cae0   David Teigland   [DLM] dlm: user l...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   * This copyrighted material is made available to anyone wishing to use,
   * modify, copy, or redistribute it subject to the terms and conditions
   * of the GNU General Public License v.2.
   */
  
  #include <linux/miscdevice.h>
  #include <linux/init.h>
  #include <linux/wait.h>
  #include <linux/module.h>
  #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: ...
20
  #include <linux/slab.h>
597d0cae0   David Teigland   [DLM] dlm: user l...
21
22
23
24
25
  
  #include "dlm_internal.h"
  #include "lockspace.h"
  #include "lock.h"
  #include "lvb_table.h"
84c6e8cd3   Adrian Bunk   [DLM] fs/dlm/user...
26
  #include "user.h"
8304d6f24   David Teigland   dlm: record full ...
27
  #include "ast.h"
597d0cae0   David Teigland   [DLM] dlm: user l...
28

0fe410d3f   Denis Cheng   dlm: static initi...
29
  static const char name_prefix[] = "dlm";
00977a59b   Arjan van de Ven   [PATCH] mark stru...
30
  static const struct file_operations device_fops;
dc68c7ed3   David Teigland   dlm: detect avail...
31
32
  static atomic_t dlm_monitor_opened;
  static int dlm_monitor_unused = 1;
597d0cae0   David Teigland   [DLM] dlm: user l...
33
34
35
36
37
38
  
  #ifdef CONFIG_COMPAT
  
  struct dlm_lock_params32 {
  	__u8 mode;
  	__u8 namelen;
d7db923ea   David Teigland   [DLM] dlm_device ...
39
40
  	__u16 unused;
  	__u32 flags;
597d0cae0   David Teigland   [DLM] dlm: user l...
41
42
  	__u32 lkid;
  	__u32 parent;
d7db923ea   David Teigland   [DLM] dlm_device ...
43
44
  	__u64 xid;
  	__u64 timeout;
597d0cae0   David Teigland   [DLM] dlm: user l...
45
46
47
48
49
  	__u32 castparam;
  	__u32 castaddr;
  	__u32 bastparam;
  	__u32 bastaddr;
  	__u32 lksb;
597d0cae0   David Teigland   [DLM] dlm: user l...
50
51
52
53
54
55
56
57
58
59
60
61
62
  	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...
63
  		struct dlm_purge_params purge;
597d0cae0   David Teigland   [DLM] dlm: user l...
64
65
66
67
68
69
70
71
72
73
74
  	} 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 ...
75
  	__u32 version[3];
597d0cae0   David Teigland   [DLM] dlm: user l...
76
77
78
79
80
81
82
83
84
85
86
87
  	__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...
88
  			 struct dlm_write_request32 *kb32,
1fecb1c4b   David Teigland   dlm: fix length c...
89
  			 int namelen)
597d0cae0   David Teigland   [DLM] dlm: user l...
90
91
92
93
94
95
96
97
98
99
100
  {
  	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...
101
  		memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);
72c2be776   David Teigland   [DLM] interface f...
102
103
104
  	} 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...
105
106
107
108
109
110
  	} 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 ...
111
112
  		kb->i.lock.xid = kb32->i.lock.xid;
  		kb->i.lock.timeout = kb32->i.lock.timeout;
597d0cae0   David Teigland   [DLM] dlm: user l...
113
114
115
116
117
118
  		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...
119
  		memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);
597d0cae0   David Teigland   [DLM] dlm: user l...
120
121
122
123
124
125
  	}
  }
  
  static void compat_output(struct dlm_lock_result *res,
  			  struct dlm_lock_result32 *res32)
  {
d7db923ea   David Teigland   [DLM] dlm_device ...
126
127
128
  	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...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	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
143
144
145
146
147
148
149
150
151
152
  /* 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 ...
153
  static int lkb_is_endoflife(int mode, int status)
84d8cd69a   David Teigland   [DLM] timeout fixes
154
  {
8304d6f24   David Teigland   dlm: record full ...
155
  	switch (status) {
84d8cd69a   David Teigland   [DLM] timeout fixes
156
157
158
159
  	case -DLM_EUNLOCK:
  		return 1;
  	case -DLM_ECANCEL:
  	case -ETIMEDOUT:
8b4021fa4   David Teigland   [DLM] canceling d...
160
  	case -EDEADLK:
84d8cd69a   David Teigland   [DLM] timeout fixes
161
  	case -EAGAIN:
8304d6f24   David Teigland   dlm: record full ...
162
  		if (mode == DLM_LOCK_IV)
84d8cd69a   David Teigland   [DLM] timeout fixes
163
164
165
166
167
  			return 1;
  		break;
  	}
  	return 0;
  }
ef0c2bb05   David Teigland   [DLM] overlapping...
168
169
  /* 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...
170

8304d6f24   David Teigland   dlm: record full ...
171
172
  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...
173
174
175
176
  {
  	struct dlm_ls *ls;
  	struct dlm_user_args *ua;
  	struct dlm_user_proc *proc;
8304d6f24   David Teigland   dlm: record full ...
177
  	int rv;
597d0cae0   David Teigland   [DLM] dlm: user l...
178

ef0c2bb05   David Teigland   [DLM] overlapping...
179
  	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
597d0cae0   David Teigland   [DLM] dlm: user l...
180
  		return;
597d0cae0   David Teigland   [DLM] dlm: user l...
181
182
183
184
185
186
  
  	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...
187
188
189
  	   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...
190

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

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

8304d6f24   David Teigland   dlm: record full ...
203
204
205
206
207
  	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...
208

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

8304d6f24   David Teigland   dlm: record full ...
216
217
  	if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
  		/* N.B. spin_lock locks_spin, not asts_spin */
ce5246b97   David Teigland   dlm: fix possible...
218
  		spin_lock(&proc->locks_spin);
ef0c2bb05   David Teigland   [DLM] overlapping...
219
220
221
222
  		if (!list_empty(&lkb->lkb_ownqueue)) {
  			list_del_init(&lkb->lkb_ownqueue);
  			dlm_put_lkb(lkb);
  		}
ce5246b97   David Teigland   dlm: fix possible...
223
  		spin_unlock(&proc->locks_spin);
34e22bed1   David Teigland   [DLM] fix leaking...
224
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
225
226
227
228
229
230
231
232
233
   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...
234
  	uint32_t lkid;
597d0cae0   David Teigland   [DLM] dlm: user l...
235
236
237
238
239
240
241
242
243
244
  	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...
245
  	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
246
247
248
249
250
251
252
253
  	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 ...
254
  	ua->xid = params->xid;
597d0cae0   David Teigland   [DLM] dlm: user l...
255

2ab4bd8ea   David Teigland   dlm: adopt orphan...
256
  	if (params->flags & DLM_LKF_CONVERT) {
597d0cae0   David Teigland   [DLM] dlm: user l...
257
258
  		error = dlm_user_convert(ls, ua,
  				         params->mode, params->flags,
d7db923ea   David Teigland   [DLM] dlm_device ...
259
260
  				         params->lkid, params->lvb,
  					 (unsigned long) params->timeout);
2ab4bd8ea   David Teigland   dlm: adopt orphan...
261
262
263
264
265
266
267
268
269
  	} 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...
270
271
272
  		error = dlm_user_request(ls, ua,
  					 params->mode, params->flags,
  					 params->name, params->namelen,
d7db923ea   David Teigland   [DLM] dlm_device ...
273
  					 (unsigned long) params->timeout);
597d0cae0   David Teigland   [DLM] dlm: user l...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  		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...
292
  	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  	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...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  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...
324
  static int dlm_device_register(struct dlm_ls *ls, char *name)
254da030d   Patrick Caulfield   [DLM] Don't delet...
325
326
  {
  	int error, len;
0f8e0d9a3   David Teigland   dlm: allow multip...
327
328
329
330
  	/* 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...
331
332
  	error = -ENOMEM;
  	len = strlen(name) + strlen(name_prefix) + 2;
573c24c4a   David Teigland   dlm: always use G...
333
  	ls->ls_device.name = kzalloc(len, GFP_NOFS);
254da030d   Patrick Caulfield   [DLM] Don't delet...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  	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);
  	}
  fail:
  	return error;
  }
0f8e0d9a3   David Teigland   dlm: allow multip...
349
350
  int dlm_device_deregister(struct dlm_ls *ls)
  {
0f8e0d9a3   David Teigland   dlm: allow multip...
351
352
353
354
355
  	/* 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...
356
357
358
  	misc_deregister(&ls->ls_device);
  	kfree(ls->ls_device.name);
  	return 0;
0f8e0d9a3   David Teigland   dlm: allow multip...
359
  }
72c2be776   David Teigland   [DLM] interface f...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
  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...
375
376
377
378
  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...
379
  	int error;
597d0cae0   David Teigland   [DLM] dlm: user l...
380
381
382
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
60f98d183   David Teigland   dlm: add recovery...
383
384
385
  	error = dlm_new_lockspace(params->name, NULL, params->flags,
  				  DLM_USER_LVB_LEN, NULL, NULL, NULL,
  				  &lockspace);
597d0cae0   David Teigland   [DLM] dlm: user l...
386
387
388
389
390
391
  	if (error)
  		return error;
  
  	ls = dlm_find_lockspace_local(lockspace);
  	if (!ls)
  		return -ENOENT;
0f8e0d9a3   David Teigland   dlm: allow multip...
392
  	error = dlm_device_register(ls, params->name);
597d0cae0   David Teigland   [DLM] dlm: user l...
393
  	dlm_put_lockspace(ls);
597d0cae0   David Teigland   [DLM] dlm: user l...
394

254da030d   Patrick Caulfield   [DLM] Don't delet...
395
396
397
398
  	if (error)
  		dlm_release_lockspace(lockspace, 0);
  	else
  		error = ls->ls_device.minor;
597d0cae0   David Teigland   [DLM] dlm: user l...
399
400
401
402
403
404
405
  	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...
406
  	int error, force = 0;
597d0cae0   David Teigland   [DLM] dlm: user l...
407
408
409
410
411
412
413
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	ls = dlm_find_lockspace_device(params->minor);
  	if (!ls)
  		return -ENOENT;
c6e6f0ba8   David Teigland   [DLM] force remov...
414
415
  	if (params->flags & DLM_USER_LSFLG_FORCEFREE)
  		force = 2;
597d0cae0   David Teigland   [DLM] dlm: user l...
416
  	lockspace = ls->ls_local_handle;
0f8e0d9a3   David Teigland   dlm: allow multip...
417
  	dlm_put_lockspace(ls);
597d0cae0   David Teigland   [DLM] dlm: user l...
418

0f8e0d9a3   David Teigland   dlm: allow multip...
419
420
421
422
423
424
  	/* 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...
425

c6e6f0ba8   David Teigland   [DLM] force remov...
426
  	error = dlm_release_lockspace(lockspace, force);
0f8e0d9a3   David Teigland   dlm: allow multip...
427
428
  	if (error > 0)
  		error = 0;
597d0cae0   David Teigland   [DLM] dlm: user l...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  	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...
443
  		       task_pid_nr(current),
597d0cae0   David Teigland   [DLM] dlm: user l...
444
445
446
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
  		       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...
481
482
483
484
485
486
487
488
  	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...
489
490
491
492
  	/*
  	 * 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...
493
  	if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
2b75bc912   Sasha Levin   dlm: check the ma...
494
  		return -EINVAL;
16e5c1fc3   Al Viro   convert a bunch o...
495
  	kbuf = memdup_user_nul(buf, count);
117aa41e8   Al Viro   [regression] fix ...
496
  	if (IS_ERR(kbuf))
16e5c1fc3   Al Viro   convert a bunch o...
497
  		return PTR_ERR(kbuf);
597d0cae0   David Teigland   [DLM] dlm: user l...
498
499
500
501
502
503
504
505
506
  
  	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...
507
508
509
510
  		int namelen = 0;
  
  		if (count > sizeof(struct dlm_write_request32))
  			namelen = count - sizeof(struct dlm_write_request32);
597d0cae0   David Teigland   [DLM] dlm: user l...
511
  		k32buf = (struct dlm_write_request32 *)kbuf;
1fecb1c4b   David Teigland   dlm: fix length c...
512
513
514
  
  		/* 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...
515
  			       GFP_NOFS);
cb980d9a3   David Teigland   dlm: add missing ...
516
517
  		if (!kbuf) {
  			kfree(k32buf);
597d0cae0   David Teigland   [DLM] dlm: user l...
518
  			return -ENOMEM;
cb980d9a3   David Teigland   dlm: add missing ...
519
  		}
597d0cae0   David Teigland   [DLM] dlm: user l...
520
521
522
  
  		if (proc)
  			set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
1fecb1c4b   David Teigland   dlm: fix length c...
523
524
  
  		compat_input(kbuf, k32buf, namelen);
597d0cae0   David Teigland   [DLM] dlm: user l...
525
526
527
528
529
530
  		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 ...
531
532
533
534
  	    (proc && test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))) {
  		error = -EINVAL;
  		goto out_free;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
535

597d0cae0   David Teigland   [DLM] dlm: user l...
536
537
538
539
540
541
542
  	error = -EINVAL;
  
  	switch (kbuf->cmd)
  	{
  	case DLM_USER_LOCK:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
543
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
544
545
546
547
548
549
550
  		}
  		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...
551
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
552
553
554
  		}
  		error = device_user_unlock(proc, &kbuf->i.lock);
  		break;
8b4021fa4   David Teigland   [DLM] canceling d...
555
556
557
  	case DLM_USER_DEADLOCK:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
558
  			goto out_free;
8b4021fa4   David Teigland   [DLM] canceling d...
559
560
561
  		}
  		error = device_user_deadlock(proc, &kbuf->i.lock);
  		break;
597d0cae0   David Teigland   [DLM] dlm: user l...
562
563
564
  	case DLM_USER_CREATE_LOCKSPACE:
  		if (proc) {
  			log_print("create/remove only on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
565
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
566
567
568
569
570
571
572
  		}
  		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...
573
  			goto out_free;
597d0cae0   David Teigland   [DLM] dlm: user l...
574
575
576
  		}
  		error = device_remove_lockspace(&kbuf->i.lspace);
  		break;
72c2be776   David Teigland   [DLM] interface f...
577
578
579
  	case DLM_USER_PURGE:
  		if (!proc) {
  			log_print("no locking on control device");
c6ca7bc91   David Teigland   dlm: remove signa...
580
  			goto out_free;
72c2be776   David Teigland   [DLM] interface f...
581
582
583
  		}
  		error = device_user_purge(proc, &kbuf->i.purge);
  		break;
597d0cae0   David Teigland   [DLM] dlm: user l...
584
585
586
587
588
  	default:
  		log_print("Unknown command passed to DLM device : %d
  ",
  			  kbuf->cmd);
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
   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
604
  	if (!ls)
597d0cae0   David Teigland   [DLM] dlm: user l...
605
  		return -ENOENT;
573c24c4a   David Teigland   dlm: always use G...
606
  	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_NOFS);
597d0cae0   David Teigland   [DLM] dlm: user l...
607
608
609
610
611
612
613
614
  	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...
615
  	INIT_LIST_HEAD(&proc->unlocking);
597d0cae0   David Teigland   [DLM] dlm: user l...
616
617
618
619
620
621
622
623
624
625
626
627
  	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...
628
629
630
631
  
  	ls = dlm_find_lockspace_local(proc->lockspace);
  	if (!ls)
  		return -ENOENT;
597d0cae0   David Teigland   [DLM] dlm: user l...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  	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...
648
649
  	return 0;
  }
8304d6f24   David Teigland   dlm: record full ...
650
651
652
  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...
653
654
655
656
657
658
659
660
661
662
663
  {
  #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 ...
664
665
666
  	result.version[0] = DLM_DEVICE_VERSION_MAJOR;
  	result.version[1] = DLM_DEVICE_VERSION_MINOR;
  	result.version[2] = DLM_DEVICE_VERSION_PATCH;
597d0cae0   David Teigland   [DLM] dlm: user l...
667
668
669
670
671
672
673
674
  	memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
  	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 ...
675
  	if (flags & DLM_CB_BAST) {
597d0cae0   David Teigland   [DLM] dlm: user l...
676
677
  		result.user_astaddr = ua->bastaddr;
  		result.user_astparam = ua->bastparam;
89d799d00   David Teigland   dlm: fix ast orde...
678
  		result.bast_mode = mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  	} 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 ...
694
  	if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
597d0cae0   David Teigland   [DLM] dlm: user l...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  		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 ...
721
722
723
724
725
726
727
728
729
730
731
732
733
  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...
734
735
736
737
738
739
740
  /* 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...
741
  	DECLARE_WAITQUEUE(wait, current);
8304d6f24   David Teigland   dlm: record full ...
742
743
  	struct dlm_callback cb;
  	int rv, resid, copy_lvb = 0;
b96f46503   David Teigland   dlm: fix lvb copy...
744
  	int old_mode, new_mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
745

d7db923ea   David Teigland   [DLM] dlm_device ...
746
  	if (count == sizeof(struct dlm_device_version)) {
8304d6f24   David Teigland   dlm: record full ...
747
748
  		rv = copy_version_to_user(buf, count);
  		return rv;
d7db923ea   David Teigland   [DLM] dlm_device ...
749
750
751
752
753
754
  	}
  
  	if (!proc) {
  		log_print("non-version read from control device %zu", count);
  		return -EINVAL;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
755
756
757
758
759
760
  #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...
761
   try_another:
597d0cae0   David Teigland   [DLM] dlm: user l...
762
763
764
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
  	/* 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 ...
791
  	/* if we empty lkb_callbacks, we don't want to unlock the spinlock
23e8e1aaa   David Teigland   dlm: use workqueu...
792
  	   without removing lkb_cb_list; so empty lkb_cb_list is always
8304d6f24   David Teigland   dlm: record full ...
793
  	   consistent with empty lkb_callbacks */
597d0cae0   David Teigland   [DLM] dlm: user l...
794

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

b96f46503   David Teigland   dlm: fix lvb copy...
797
798
  	/* rem_lkb_callback sets a new lkb_last_cast */
  	old_mode = lkb->lkb_last_cast.mode;
8304d6f24   David Teigland   dlm: record full ...
799
800
801
802
803
  	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...
804
  		list_del_init(&lkb->lkb_cb_list);
8304d6f24   David Teigland   dlm: record full ...
805
806
807
808
  		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...
809
  	}
8304d6f24   David Teigland   dlm: record full ...
810
  	if (!resid)
23e8e1aaa   David Teigland   dlm: use workqueu...
811
  		list_del_init(&lkb->lkb_cb_list);
8304d6f24   David Teigland   dlm: record full ...
812
  	spin_unlock(&proc->asts_spin);
89d799d00   David Teigland   dlm: fix ast orde...
813

8304d6f24   David Teigland   dlm: record full ...
814
815
816
817
818
  	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...
819
  	}
8304d6f24   David Teigland   dlm: record full ...
820
  	if (cb.flags & DLM_CB_CAST) {
8304d6f24   David Teigland   dlm: record full ...
821
  		new_mode = cb.mode;
597d0cae0   David Teigland   [DLM] dlm: user l...
822

8304d6f24   David Teigland   dlm: record full ...
823
824
825
  		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...
826

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

8304d6f24   David Teigland   dlm: record full ...
831
832
833
  	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...
834

8304d6f24   David Teigland   dlm: record full ...
835
836
  	/* removes ref for proc->asts, may cause lkb to be freed */
  	if (!resid)
597d0cae0   David Teigland   [DLM] dlm: user l...
837
  		dlm_put_lkb(lkb);
8304d6f24   David Teigland   dlm: record full ...
838
  	return rv;
597d0cae0   David Teigland   [DLM] dlm: user l...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  }
  
  static unsigned int device_poll(struct file *file, poll_table *wait)
  {
  	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);
  		return POLLIN | POLLRDNORM;
  	}
  	spin_unlock(&proc->asts_spin);
  	return 0;
  }
dc68c7ed3   David Teigland   dlm: detect avail...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  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...
874
875
876
877
878
879
880
881
882
883
  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...
884
885
886
887
888
889
890
891
892
893
894
895
896
  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...
897
  static const struct file_operations device_fops = {
597d0cae0   David Teigland   [DLM] dlm: user l...
898
899
900
901
902
903
  	.open    = device_open,
  	.release = device_close,
  	.read    = device_read,
  	.write   = device_write,
  	.poll    = device_poll,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
904
  	.llseek  = noop_llseek,
597d0cae0   David Teigland   [DLM] dlm: user l...
905
  };
00977a59b   Arjan van de Ven   [PATCH] mark stru...
906
  static const struct file_operations ctl_device_fops = {
597d0cae0   David Teigland   [DLM] dlm: user l...
907
908
  	.open    = ctl_device_open,
  	.release = ctl_device_close,
d7db923ea   David Teigland   [DLM] dlm_device ...
909
  	.read    = device_read,
597d0cae0   David Teigland   [DLM] dlm: user l...
910
911
  	.write   = device_write,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
912
  	.llseek  = noop_llseek,
597d0cae0   David Teigland   [DLM] dlm: user l...
913
  };
0fe410d3f   Denis Cheng   dlm: static initi...
914
915
916
917
918
  static struct miscdevice ctl_device = {
  	.name  = "dlm-control",
  	.fops  = &ctl_device_fops,
  	.minor = MISC_DYNAMIC_MINOR,
  };
dc68c7ed3   David Teigland   dlm: detect avail...
919
920
921
922
  static const struct file_operations monitor_device_fops = {
  	.open    = monitor_device_open,
  	.release = monitor_device_close,
  	.owner   = THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
923
  	.llseek  = noop_llseek,
dc68c7ed3   David Teigland   dlm: detect avail...
924
925
926
927
928
929
930
  };
  
  static struct miscdevice monitor_device = {
  	.name  = "dlm-monitor",
  	.fops  = &monitor_device_fops,
  	.minor = MISC_DYNAMIC_MINOR,
  };
30727174b   Denis Cheng   dlm: add __init a...
931
  int __init dlm_user_init(void)
597d0cae0   David Teigland   [DLM] dlm: user l...
932
933
  {
  	int error;
dc68c7ed3   David Teigland   dlm: detect avail...
934
  	atomic_set(&dlm_monitor_opened, 0);
597d0cae0   David Teigland   [DLM] dlm: user l...
935
  	error = misc_register(&ctl_device);
dc68c7ed3   David Teigland   dlm: detect avail...
936
  	if (error) {
597d0cae0   David Teigland   [DLM] dlm: user l...
937
  		log_print("misc_register failed for control device");
dc68c7ed3   David Teigland   dlm: detect avail...
938
939
  		goto out;
  	}
597d0cae0   David Teigland   [DLM] dlm: user l...
940

dc68c7ed3   David Teigland   dlm: detect avail...
941
942
943
944
945
946
  	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...
947
948
949
950
951
952
  	return error;
  }
  
  void dlm_user_exit(void)
  {
  	misc_deregister(&ctl_device);
dc68c7ed3   David Teigland   dlm: detect avail...
953
  	misc_deregister(&monitor_device);
597d0cae0   David Teigland   [DLM] dlm: user l...
954
  }