blob: fd19caf9af973b888750b0ca0dc7080c232974ab [file] [log] [blame]
David Teigland597d0ca2006-07-12 16:44:04 -05001/*
2 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
3 *
4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions
6 * of the GNU General Public License v.2.
7 */
8
9#include <linux/miscdevice.h>
10#include <linux/init.h>
11#include <linux/wait.h>
12#include <linux/module.h>
13#include <linux/file.h>
14#include <linux/fs.h>
15#include <linux/poll.h>
16#include <linux/signal.h>
17#include <linux/spinlock.h>
18#include <linux/dlm.h>
19#include <linux/dlm_device.h>
20
21#include "dlm_internal.h"
22#include "lockspace.h"
23#include "lock.h"
24#include "lvb_table.h"
25
26static const char *name_prefix="dlm";
27static struct miscdevice ctl_device;
28static struct file_operations device_fops;
29
30#ifdef CONFIG_COMPAT
31
32struct dlm_lock_params32 {
33 __u8 mode;
34 __u8 namelen;
35 __u16 flags;
36 __u32 lkid;
37 __u32 parent;
38
39 __u32 castparam;
40 __u32 castaddr;
41 __u32 bastparam;
42 __u32 bastaddr;
43 __u32 lksb;
44
45 char lvb[DLM_USER_LVB_LEN];
46 char name[0];
47};
48
49struct dlm_write_request32 {
50 __u32 version[3];
51 __u8 cmd;
52 __u8 is64bit;
53 __u8 unused[2];
54
55 union {
56 struct dlm_lock_params32 lock;
57 struct dlm_lspace_params lspace;
58 } i;
59};
60
61struct dlm_lksb32 {
62 __u32 sb_status;
63 __u32 sb_lkid;
64 __u8 sb_flags;
65 __u32 sb_lvbptr;
66};
67
68struct dlm_lock_result32 {
69 __u32 length;
70 __u32 user_astaddr;
71 __u32 user_astparam;
72 __u32 user_lksb;
73 struct dlm_lksb32 lksb;
74 __u8 bast_mode;
75 __u8 unused[3];
76 /* Offsets may be zero if no data is present */
77 __u32 lvb_offset;
78};
79
80static void compat_input(struct dlm_write_request *kb,
81 struct dlm_write_request32 *kb32)
82{
83 kb->version[0] = kb32->version[0];
84 kb->version[1] = kb32->version[1];
85 kb->version[2] = kb32->version[2];
86
87 kb->cmd = kb32->cmd;
88 kb->is64bit = kb32->is64bit;
89 if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
90 kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
91 kb->i.lspace.flags = kb32->i.lspace.flags;
92 kb->i.lspace.minor = kb32->i.lspace.minor;
93 strcpy(kb->i.lspace.name, kb32->i.lspace.name);
94 } else {
95 kb->i.lock.mode = kb32->i.lock.mode;
96 kb->i.lock.namelen = kb32->i.lock.namelen;
97 kb->i.lock.flags = kb32->i.lock.flags;
98 kb->i.lock.lkid = kb32->i.lock.lkid;
99 kb->i.lock.parent = kb32->i.lock.parent;
100 kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
101 kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
102 kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
103 kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
104 kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
105 memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
106 memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen);
107 }
108}
109
110static void compat_output(struct dlm_lock_result *res,
111 struct dlm_lock_result32 *res32)
112{
113 res32->length = res->length - (sizeof(struct dlm_lock_result) -
114 sizeof(struct dlm_lock_result32));
115 res32->user_astaddr = (__u32)(long)res->user_astaddr;
116 res32->user_astparam = (__u32)(long)res->user_astparam;
117 res32->user_lksb = (__u32)(long)res->user_lksb;
118 res32->bast_mode = res->bast_mode;
119
120 res32->lvb_offset = res->lvb_offset;
121 res32->length = res->length;
122
123 res32->lksb.sb_status = res->lksb.sb_status;
124 res32->lksb.sb_flags = res->lksb.sb_flags;
125 res32->lksb.sb_lkid = res->lksb.sb_lkid;
126 res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
127}
128#endif
129
130
131void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
132{
133 struct dlm_ls *ls;
134 struct dlm_user_args *ua;
135 struct dlm_user_proc *proc;
David Teigland34e22be2006-07-18 11:24:04 -0500136 int remove_ownqueue = 0;
David Teigland597d0ca2006-07-12 16:44:04 -0500137
138 /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
139 lkb before dealing with it. We need to check this
140 flag before taking ls_clear_proc_locks mutex because if
141 it's set, dlm_clear_proc_locks() holds the mutex. */
142
143 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
144 /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
145 return;
146 }
147
148 ls = lkb->lkb_resource->res_ls;
149 mutex_lock(&ls->ls_clear_proc_locks);
150
151 /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
152 can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
153 lkb->ua so we can't try to use it. */
154
155 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
156 /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
157 goto out;
158 }
159
160 DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
161 ua = (struct dlm_user_args *)lkb->lkb_astparam;
162 proc = ua->proc;
163
164 if (type == AST_BAST && ua->bastaddr == NULL)
165 goto out;
166
167 spin_lock(&proc->asts_spin);
168 if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
169 kref_get(&lkb->lkb_ref);
170 list_add_tail(&lkb->lkb_astqueue, &proc->asts);
171 lkb->lkb_ast_type |= type;
172 wake_up_interruptible(&proc->wait);
173 }
174
David Teigland34e22be2006-07-18 11:24:04 -0500175 /* noqueue requests that fail may need to be removed from the
176 proc's locks list, there should be a better way of detecting
177 this situation than checking all these things... */
178
179 if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
180 ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
181 remove_ownqueue = 1;
182
David Teigland597d0ca2006-07-12 16:44:04 -0500183 /* We want to copy the lvb to userspace when the completion
184 ast is read if the status is 0, the lock has an lvb and
185 lvb_ops says we should. We could probably have set_lvb_lock()
186 set update_user_lvb instead and not need old_mode */
187
188 if ((lkb->lkb_ast_type & AST_COMP) &&
189 (lkb->lkb_lksb->sb_status == 0) &&
190 lkb->lkb_lksb->sb_lvbptr &&
191 dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
192 ua->update_user_lvb = 1;
193 else
194 ua->update_user_lvb = 0;
195
196 spin_unlock(&proc->asts_spin);
David Teigland34e22be2006-07-18 11:24:04 -0500197
198 if (remove_ownqueue) {
199 spin_lock(&ua->proc->locks_spin);
200 list_del_init(&lkb->lkb_ownqueue);
201 spin_unlock(&ua->proc->locks_spin);
202 dlm_put_lkb(lkb);
203 }
David Teigland597d0ca2006-07-12 16:44:04 -0500204 out:
205 mutex_unlock(&ls->ls_clear_proc_locks);
206}
207
208static int device_user_lock(struct dlm_user_proc *proc,
209 struct dlm_lock_params *params)
210{
211 struct dlm_ls *ls;
212 struct dlm_user_args *ua;
213 int error = -ENOMEM;
214
215 ls = dlm_find_lockspace_local(proc->lockspace);
216 if (!ls)
217 return -ENOENT;
218
219 if (!params->castaddr || !params->lksb) {
220 error = -EINVAL;
221 goto out;
222 }
223
224 ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
225 if (!ua)
226 goto out;
227 ua->proc = proc;
228 ua->user_lksb = params->lksb;
229 ua->castparam = params->castparam;
230 ua->castaddr = params->castaddr;
231 ua->bastparam = params->bastparam;
232 ua->bastaddr = params->bastaddr;
233
234 if (params->flags & DLM_LKF_CONVERT)
235 error = dlm_user_convert(ls, ua,
236 params->mode, params->flags,
237 params->lkid, params->lvb);
238 else {
239 error = dlm_user_request(ls, ua,
240 params->mode, params->flags,
241 params->name, params->namelen,
242 params->parent);
243 if (!error)
244 error = ua->lksb.sb_lkid;
245 }
246 out:
247 dlm_put_lockspace(ls);
248 return error;
249}
250
251static int device_user_unlock(struct dlm_user_proc *proc,
252 struct dlm_lock_params *params)
253{
254 struct dlm_ls *ls;
255 struct dlm_user_args *ua;
256 int error = -ENOMEM;
257
258 ls = dlm_find_lockspace_local(proc->lockspace);
259 if (!ls)
260 return -ENOENT;
261
262 ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
263 if (!ua)
264 goto out;
265 ua->proc = proc;
266 ua->user_lksb = params->lksb;
267 ua->castparam = params->castparam;
268 ua->castaddr = params->castaddr;
269
270 if (params->flags & DLM_LKF_CANCEL)
271 error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
272 else
273 error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
274 params->lvb);
275 out:
276 dlm_put_lockspace(ls);
277 return error;
278}
279
280static int device_create_lockspace(struct dlm_lspace_params *params)
281{
282 dlm_lockspace_t *lockspace;
283 struct dlm_ls *ls;
284 int error, len;
285
286 if (!capable(CAP_SYS_ADMIN))
287 return -EPERM;
288
289 error = dlm_new_lockspace(params->name, strlen(params->name),
290 &lockspace, 0, DLM_USER_LVB_LEN);
291 if (error)
292 return error;
293
294 ls = dlm_find_lockspace_local(lockspace);
295 if (!ls)
296 return -ENOENT;
297
298 error = -ENOMEM;
299 len = strlen(params->name) + strlen(name_prefix) + 2;
300 ls->ls_device.name = kzalloc(len, GFP_KERNEL);
301 if (!ls->ls_device.name)
302 goto fail;
303 snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
304 params->name);
305 ls->ls_device.fops = &device_fops;
306 ls->ls_device.minor = MISC_DYNAMIC_MINOR;
307
308 error = misc_register(&ls->ls_device);
309 if (error) {
310 kfree(ls->ls_device.name);
311 goto fail;
312 }
313
314 error = ls->ls_device.minor;
315 dlm_put_lockspace(ls);
316 return error;
317
318 fail:
319 dlm_put_lockspace(ls);
320 dlm_release_lockspace(lockspace, 0);
321 return error;
322}
323
324static int device_remove_lockspace(struct dlm_lspace_params *params)
325{
326 dlm_lockspace_t *lockspace;
327 struct dlm_ls *ls;
328 int error;
329
330 if (!capable(CAP_SYS_ADMIN))
331 return -EPERM;
332
333 ls = dlm_find_lockspace_device(params->minor);
334 if (!ls)
335 return -ENOENT;
336
337 error = misc_deregister(&ls->ls_device);
338 if (error) {
339 dlm_put_lockspace(ls);
340 goto out;
341 }
342 kfree(ls->ls_device.name);
343
344 lockspace = ls->ls_local_handle;
345
346 /* dlm_release_lockspace waits for references to go to zero,
347 so all processes will need to close their device for the ls
348 before the release will procede */
349
350 dlm_put_lockspace(ls);
351 error = dlm_release_lockspace(lockspace, 0);
352out:
353 return error;
354}
355
356/* Check the user's version matches ours */
357static int check_version(struct dlm_write_request *req)
358{
359 if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
360 (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
361 req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
362
363 printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
364 "user (%d.%d.%d) kernel (%d.%d.%d)\n",
365 current->comm,
366 current->pid,
367 req->version[0],
368 req->version[1],
369 req->version[2],
370 DLM_DEVICE_VERSION_MAJOR,
371 DLM_DEVICE_VERSION_MINOR,
372 DLM_DEVICE_VERSION_PATCH);
373 return -EINVAL;
374 }
375 return 0;
376}
377
378/*
379 * device_write
380 *
381 * device_user_lock
382 * dlm_user_request -> request_lock
383 * dlm_user_convert -> convert_lock
384 *
385 * device_user_unlock
386 * dlm_user_unlock -> unlock_lock
387 * dlm_user_cancel -> cancel_lock
388 *
389 * device_create_lockspace
390 * dlm_new_lockspace
391 *
392 * device_remove_lockspace
393 * dlm_release_lockspace
394 */
395
396/* a write to a lockspace device is a lock or unlock request, a write
397 to the control device is to create/remove a lockspace */
398
399static ssize_t device_write(struct file *file, const char __user *buf,
400 size_t count, loff_t *ppos)
401{
402 struct dlm_user_proc *proc = file->private_data;
403 struct dlm_write_request *kbuf;
404 sigset_t tmpsig, allsigs;
405 int error;
406
407#ifdef CONFIG_COMPAT
408 if (count < sizeof(struct dlm_write_request32))
409#else
410 if (count < sizeof(struct dlm_write_request))
411#endif
412 return -EINVAL;
413
414 kbuf = kmalloc(count, GFP_KERNEL);
415 if (!kbuf)
416 return -ENOMEM;
417
418 if (copy_from_user(kbuf, buf, count)) {
419 error = -EFAULT;
420 goto out_free;
421 }
422
423 if (check_version(kbuf)) {
424 error = -EBADE;
425 goto out_free;
426 }
427
428#ifdef CONFIG_COMPAT
429 if (!kbuf->is64bit) {
430 struct dlm_write_request32 *k32buf;
431 k32buf = (struct dlm_write_request32 *)kbuf;
432 kbuf = kmalloc(count + (sizeof(struct dlm_write_request) -
433 sizeof(struct dlm_write_request32)), GFP_KERNEL);
434 if (!kbuf)
435 return -ENOMEM;
436
437 if (proc)
438 set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
439 compat_input(kbuf, k32buf);
440 kfree(k32buf);
441 }
442#endif
443
444 /* do we really need this? can a write happen after a close? */
445 if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
446 test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
447 return -EINVAL;
448
449 sigfillset(&allsigs);
450 sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
451
452 error = -EINVAL;
453
454 switch (kbuf->cmd)
455 {
456 case DLM_USER_LOCK:
457 if (!proc) {
458 log_print("no locking on control device");
459 goto out_sig;
460 }
461 error = device_user_lock(proc, &kbuf->i.lock);
462 break;
463
464 case DLM_USER_UNLOCK:
465 if (!proc) {
466 log_print("no locking on control device");
467 goto out_sig;
468 }
469 error = device_user_unlock(proc, &kbuf->i.lock);
470 break;
471
472 case DLM_USER_CREATE_LOCKSPACE:
473 if (proc) {
474 log_print("create/remove only on control device");
475 goto out_sig;
476 }
477 error = device_create_lockspace(&kbuf->i.lspace);
478 break;
479
480 case DLM_USER_REMOVE_LOCKSPACE:
481 if (proc) {
482 log_print("create/remove only on control device");
483 goto out_sig;
484 }
485 error = device_remove_lockspace(&kbuf->i.lspace);
486 break;
487
488 default:
489 log_print("Unknown command passed to DLM device : %d\n",
490 kbuf->cmd);
491 }
492
493 out_sig:
494 sigprocmask(SIG_SETMASK, &tmpsig, NULL);
495 recalc_sigpending();
496 out_free:
497 kfree(kbuf);
498 return error;
499}
500
501/* Every process that opens the lockspace device has its own "proc" structure
502 hanging off the open file that's used to keep track of locks owned by the
503 process and asts that need to be delivered to the process. */
504
505static int device_open(struct inode *inode, struct file *file)
506{
507 struct dlm_user_proc *proc;
508 struct dlm_ls *ls;
509
510 ls = dlm_find_lockspace_device(iminor(inode));
511 if (!ls)
512 return -ENOENT;
513
514 proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
515 if (!proc) {
516 dlm_put_lockspace(ls);
517 return -ENOMEM;
518 }
519
520 proc->lockspace = ls->ls_local_handle;
521 INIT_LIST_HEAD(&proc->asts);
522 INIT_LIST_HEAD(&proc->locks);
523 spin_lock_init(&proc->asts_spin);
524 spin_lock_init(&proc->locks_spin);
525 init_waitqueue_head(&proc->wait);
526 file->private_data = proc;
527
528 return 0;
529}
530
531static int device_close(struct inode *inode, struct file *file)
532{
533 struct dlm_user_proc *proc = file->private_data;
534 struct dlm_ls *ls;
535 sigset_t tmpsig, allsigs;
536
537 ls = dlm_find_lockspace_local(proc->lockspace);
538 if (!ls)
539 return -ENOENT;
540
541 sigfillset(&allsigs);
542 sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
543
544 set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
545
546 dlm_clear_proc_locks(ls, proc);
547
548 /* at this point no more lkb's should exist for this lockspace,
549 so there's no chance of dlm_user_add_ast() being called and
550 looking for lkb->ua->proc */
551
552 kfree(proc);
553 file->private_data = NULL;
554
555 dlm_put_lockspace(ls);
556 dlm_put_lockspace(ls); /* for the find in device_open() */
557
558 /* FIXME: AUTOFREE: if this ls is no longer used do
559 device_remove_lockspace() */
560
561 sigprocmask(SIG_SETMASK, &tmpsig, NULL);
562 recalc_sigpending();
563
564 return 0;
565}
566
567static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
568 int bmode, char __user *buf, size_t count)
569{
570#ifdef CONFIG_COMPAT
571 struct dlm_lock_result32 result32;
572#endif
573 struct dlm_lock_result result;
574 void *resultptr;
575 int error=0;
576 int len;
577 int struct_len;
578
579 memset(&result, 0, sizeof(struct dlm_lock_result));
580 memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
581 result.user_lksb = ua->user_lksb;
582
583 /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
584 in a conversion unless the conversion is successful. See code
585 in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though,
586 notes that a new blocking AST address and parameter are set even if
587 the conversion fails, so maybe we should just do that. */
588
589 if (type == AST_BAST) {
590 result.user_astaddr = ua->bastaddr;
591 result.user_astparam = ua->bastparam;
592 result.bast_mode = bmode;
593 } else {
594 result.user_astaddr = ua->castaddr;
595 result.user_astparam = ua->castparam;
596 }
597
598#ifdef CONFIG_COMPAT
599 if (compat)
600 len = sizeof(struct dlm_lock_result32);
601 else
602#endif
603 len = sizeof(struct dlm_lock_result);
604 struct_len = len;
605
606 /* copy lvb to userspace if there is one, it's been updated, and
607 the user buffer has space for it */
608
609 if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
610 count >= len + DLM_USER_LVB_LEN) {
611 if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
612 DLM_USER_LVB_LEN)) {
613 error = -EFAULT;
614 goto out;
615 }
616
617 result.lvb_offset = len;
618 len += DLM_USER_LVB_LEN;
619 }
620
621 result.length = len;
622 resultptr = &result;
623#ifdef CONFIG_COMPAT
624 if (compat) {
625 compat_output(&result, &result32);
626 resultptr = &result32;
627 }
628#endif
629
630 if (copy_to_user(buf, resultptr, struct_len))
631 error = -EFAULT;
632 else
633 error = len;
634 out:
635 return error;
636}
637
638/* a read returns a single ast described in a struct dlm_lock_result */
639
640static ssize_t device_read(struct file *file, char __user *buf, size_t count,
641 loff_t *ppos)
642{
643 struct dlm_user_proc *proc = file->private_data;
644 struct dlm_lkb *lkb;
645 struct dlm_user_args *ua;
646 DECLARE_WAITQUEUE(wait, current);
647 int error, type=0, bmode=0, removed = 0;
648
649#ifdef CONFIG_COMPAT
650 if (count < sizeof(struct dlm_lock_result32))
651#else
652 if (count < sizeof(struct dlm_lock_result))
653#endif
654 return -EINVAL;
655
656 /* do we really need this? can a read happen after a close? */
657 if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
658 return -EINVAL;
659
660 spin_lock(&proc->asts_spin);
661 if (list_empty(&proc->asts)) {
662 if (file->f_flags & O_NONBLOCK) {
663 spin_unlock(&proc->asts_spin);
664 return -EAGAIN;
665 }
666
667 add_wait_queue(&proc->wait, &wait);
668
669 repeat:
670 set_current_state(TASK_INTERRUPTIBLE);
671 if (list_empty(&proc->asts) && !signal_pending(current)) {
672 spin_unlock(&proc->asts_spin);
673 schedule();
674 spin_lock(&proc->asts_spin);
675 goto repeat;
676 }
677 set_current_state(TASK_RUNNING);
678 remove_wait_queue(&proc->wait, &wait);
679
680 if (signal_pending(current)) {
681 spin_unlock(&proc->asts_spin);
682 return -ERESTARTSYS;
683 }
684 }
685
686 if (list_empty(&proc->asts)) {
687 spin_unlock(&proc->asts_spin);
688 return -EAGAIN;
689 }
690
691 /* there may be both completion and blocking asts to return for
692 the lkb, don't remove lkb from asts list unless no asts remain */
693
694 lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
695
696 if (lkb->lkb_ast_type & AST_COMP) {
697 lkb->lkb_ast_type &= ~AST_COMP;
698 type = AST_COMP;
699 } else if (lkb->lkb_ast_type & AST_BAST) {
700 lkb->lkb_ast_type &= ~AST_BAST;
701 type = AST_BAST;
702 bmode = lkb->lkb_bastmode;
703 }
704
705 if (!lkb->lkb_ast_type) {
706 list_del(&lkb->lkb_astqueue);
707 removed = 1;
708 }
709 spin_unlock(&proc->asts_spin);
710
711 ua = (struct dlm_user_args *)lkb->lkb_astparam;
712 error = copy_result_to_user(ua,
713 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
714 type, bmode, buf, count);
715
716 /* removes reference for the proc->asts lists added by
717 dlm_user_add_ast() and may result in the lkb being freed */
718 if (removed)
719 dlm_put_lkb(lkb);
720
721 return error;
722}
723
724static unsigned int device_poll(struct file *file, poll_table *wait)
725{
726 struct dlm_user_proc *proc = file->private_data;
727
728 poll_wait(file, &proc->wait, wait);
729
730 spin_lock(&proc->asts_spin);
731 if (!list_empty(&proc->asts)) {
732 spin_unlock(&proc->asts_spin);
733 return POLLIN | POLLRDNORM;
734 }
735 spin_unlock(&proc->asts_spin);
736 return 0;
737}
738
739static int ctl_device_open(struct inode *inode, struct file *file)
740{
741 file->private_data = NULL;
742 return 0;
743}
744
745static int ctl_device_close(struct inode *inode, struct file *file)
746{
747 return 0;
748}
749
750static struct file_operations device_fops = {
751 .open = device_open,
752 .release = device_close,
753 .read = device_read,
754 .write = device_write,
755 .poll = device_poll,
756 .owner = THIS_MODULE,
757};
758
759static struct file_operations ctl_device_fops = {
760 .open = ctl_device_open,
761 .release = ctl_device_close,
762 .write = device_write,
763 .owner = THIS_MODULE,
764};
765
766int dlm_user_init(void)
767{
768 int error;
769
770 ctl_device.name = "dlm-control";
771 ctl_device.fops = &ctl_device_fops;
772 ctl_device.minor = MISC_DYNAMIC_MINOR;
773
774 error = misc_register(&ctl_device);
775 if (error)
776 log_print("misc_register failed for control device");
777
778 return error;
779}
780
781void dlm_user_exit(void)
782{
783 misc_deregister(&ctl_device);
784}
785