blob: c978c67b1effd3958aab99d66247abde50d68111 [file] [log] [blame]
David Teigland597d0ca2006-07-12 16:44:04 -05001/*
David Teiglandef0c2bb2007-03-28 09:56:46 -05002 * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved.
David Teigland597d0ca2006-07-12 16:44:04 -05003 *
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"
Adrian Bunk84c6e8c2007-02-26 00:18:42 +010025#include "user.h"
David Teigland597d0ca2006-07-12 16:44:04 -050026
27static const char *name_prefix="dlm";
28static struct miscdevice ctl_device;
Arjan van de Ven00977a52007-02-12 00:55:34 -080029static const struct file_operations device_fops;
David Teigland597d0ca2006-07-12 16:44:04 -050030
31#ifdef CONFIG_COMPAT
32
33struct dlm_lock_params32 {
34 __u8 mode;
35 __u8 namelen;
36 __u16 flags;
37 __u32 lkid;
38 __u32 parent;
39
40 __u32 castparam;
41 __u32 castaddr;
42 __u32 bastparam;
43 __u32 bastaddr;
44 __u32 lksb;
45
46 char lvb[DLM_USER_LVB_LEN];
47 char name[0];
48};
49
50struct dlm_write_request32 {
51 __u32 version[3];
52 __u8 cmd;
53 __u8 is64bit;
54 __u8 unused[2];
55
56 union {
57 struct dlm_lock_params32 lock;
58 struct dlm_lspace_params lspace;
59 } i;
60};
61
62struct dlm_lksb32 {
63 __u32 sb_status;
64 __u32 sb_lkid;
65 __u8 sb_flags;
66 __u32 sb_lvbptr;
67};
68
69struct dlm_lock_result32 {
70 __u32 length;
71 __u32 user_astaddr;
72 __u32 user_astparam;
73 __u32 user_lksb;
74 struct dlm_lksb32 lksb;
75 __u8 bast_mode;
76 __u8 unused[3];
77 /* Offsets may be zero if no data is present */
78 __u32 lvb_offset;
79};
80
81static void compat_input(struct dlm_write_request *kb,
82 struct dlm_write_request32 *kb32)
83{
84 kb->version[0] = kb32->version[0];
85 kb->version[1] = kb32->version[1];
86 kb->version[2] = kb32->version[2];
87
88 kb->cmd = kb32->cmd;
89 kb->is64bit = kb32->is64bit;
90 if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
91 kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
92 kb->i.lspace.flags = kb32->i.lspace.flags;
93 kb->i.lspace.minor = kb32->i.lspace.minor;
94 strcpy(kb->i.lspace.name, kb32->i.lspace.name);
95 } else {
96 kb->i.lock.mode = kb32->i.lock.mode;
97 kb->i.lock.namelen = kb32->i.lock.namelen;
98 kb->i.lock.flags = kb32->i.lock.flags;
99 kb->i.lock.lkid = kb32->i.lock.lkid;
100 kb->i.lock.parent = kb32->i.lock.parent;
101 kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
102 kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
103 kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
104 kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
105 kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
106 memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
107 memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen);
108 }
109}
110
111static void compat_output(struct dlm_lock_result *res,
112 struct dlm_lock_result32 *res32)
113{
114 res32->length = res->length - (sizeof(struct dlm_lock_result) -
115 sizeof(struct dlm_lock_result32));
116 res32->user_astaddr = (__u32)(long)res->user_astaddr;
117 res32->user_astparam = (__u32)(long)res->user_astparam;
118 res32->user_lksb = (__u32)(long)res->user_lksb;
119 res32->bast_mode = res->bast_mode;
120
121 res32->lvb_offset = res->lvb_offset;
122 res32->length = res->length;
123
124 res32->lksb.sb_status = res->lksb.sb_status;
125 res32->lksb.sb_flags = res->lksb.sb_flags;
126 res32->lksb.sb_lkid = res->lksb.sb_lkid;
127 res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
128}
129#endif
130
David Teiglandef0c2bb2007-03-28 09:56:46 -0500131/* we could possibly check if the cancel of an orphan has resulted in the lkb
132 being removed and then remove that lkb from the orphans list and free it */
David Teigland597d0ca2006-07-12 16:44:04 -0500133
134void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
135{
136 struct dlm_ls *ls;
137 struct dlm_user_args *ua;
138 struct dlm_user_proc *proc;
David Teiglandef0c2bb2007-03-28 09:56:46 -0500139 int eol = 0, ast_type;
David Teigland597d0ca2006-07-12 16:44:04 -0500140
David Teiglandef0c2bb2007-03-28 09:56:46 -0500141 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
David Teigland597d0ca2006-07-12 16:44:04 -0500142 return;
David Teigland597d0ca2006-07-12 16:44:04 -0500143
144 ls = lkb->lkb_resource->res_ls;
145 mutex_lock(&ls->ls_clear_proc_locks);
146
147 /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
148 can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
David Teiglandef0c2bb2007-03-28 09:56:46 -0500149 lkb->ua so we can't try to use it. This second check is necessary
150 for cases where a completion ast is received for an operation that
151 began before clear_proc_locks did its cancel/unlock. */
David Teigland597d0ca2006-07-12 16:44:04 -0500152
David Teiglandef0c2bb2007-03-28 09:56:46 -0500153 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
David Teigland597d0ca2006-07-12 16:44:04 -0500154 goto out;
David Teigland597d0ca2006-07-12 16:44:04 -0500155
156 DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
157 ua = (struct dlm_user_args *)lkb->lkb_astparam;
158 proc = ua->proc;
159
160 if (type == AST_BAST && ua->bastaddr == NULL)
161 goto out;
162
163 spin_lock(&proc->asts_spin);
David Teiglandef0c2bb2007-03-28 09:56:46 -0500164
165 ast_type = lkb->lkb_ast_type;
166 lkb->lkb_ast_type |= type;
167
168 if (!ast_type) {
David Teigland597d0ca2006-07-12 16:44:04 -0500169 kref_get(&lkb->lkb_ref);
170 list_add_tail(&lkb->lkb_astqueue, &proc->asts);
David Teigland597d0ca2006-07-12 16:44:04 -0500171 wake_up_interruptible(&proc->wait);
172 }
David Teiglandef0c2bb2007-03-28 09:56:46 -0500173 if (type == AST_COMP && (ast_type & AST_COMP))
174 log_debug(ls, "ast overlap %x status %x %x",
175 lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
David Teigland597d0ca2006-07-12 16:44:04 -0500176
David Teiglandef0c2bb2007-03-28 09:56:46 -0500177 /* Figure out if this lock is at the end of its life and no longer
178 available for the application to use. The lkb still exists until
179 the final ast is read. A lock becomes EOL in three situations:
180 1. a noqueue request fails with EAGAIN
181 2. an unlock completes with EUNLOCK
182 3. a cancel of a waiting request completes with ECANCEL
183 An EOL lock needs to be removed from the process's list of locks.
184 And we can't allow any new operation on an EOL lock. This is
185 not related to the lifetime of the lkb struct which is managed
186 entirely by refcount. */
David Teigland36098192006-07-20 08:35:39 -0500187
David Teiglandef0c2bb2007-03-28 09:56:46 -0500188 if (type == AST_COMP &&
189 lkb->lkb_grmode == DLM_LOCK_IV &&
190 ua->lksb.sb_status == -EAGAIN)
191 eol = 1;
192 else if (ua->lksb.sb_status == -DLM_EUNLOCK ||
David Teiglanda1bc86e2007-01-15 10:34:52 -0600193 (ua->lksb.sb_status == -DLM_ECANCEL &&
194 lkb->lkb_grmode == DLM_LOCK_IV))
David Teiglandef0c2bb2007-03-28 09:56:46 -0500195 eol = 1;
196 if (eol) {
197 lkb->lkb_ast_type &= ~AST_BAST;
198 lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
199 }
David Teiglanda1bc86e2007-01-15 10:34:52 -0600200
David Teigland597d0ca2006-07-12 16:44:04 -0500201 /* We want to copy the lvb to userspace when the completion
202 ast is read if the status is 0, the lock has an lvb and
203 lvb_ops says we should. We could probably have set_lvb_lock()
204 set update_user_lvb instead and not need old_mode */
205
206 if ((lkb->lkb_ast_type & AST_COMP) &&
207 (lkb->lkb_lksb->sb_status == 0) &&
208 lkb->lkb_lksb->sb_lvbptr &&
209 dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
210 ua->update_user_lvb = 1;
211 else
212 ua->update_user_lvb = 0;
213
214 spin_unlock(&proc->asts_spin);
David Teigland34e22be2006-07-18 11:24:04 -0500215
David Teiglandef0c2bb2007-03-28 09:56:46 -0500216 if (eol) {
David Teigland34e22be2006-07-18 11:24:04 -0500217 spin_lock(&ua->proc->locks_spin);
David Teiglandef0c2bb2007-03-28 09:56:46 -0500218 if (!list_empty(&lkb->lkb_ownqueue)) {
219 list_del_init(&lkb->lkb_ownqueue);
220 dlm_put_lkb(lkb);
221 }
David Teigland34e22be2006-07-18 11:24:04 -0500222 spin_unlock(&ua->proc->locks_spin);
David Teigland34e22be2006-07-18 11:24:04 -0500223 }
David Teigland597d0ca2006-07-12 16:44:04 -0500224 out:
225 mutex_unlock(&ls->ls_clear_proc_locks);
226}
227
228static int device_user_lock(struct dlm_user_proc *proc,
229 struct dlm_lock_params *params)
230{
231 struct dlm_ls *ls;
232 struct dlm_user_args *ua;
233 int error = -ENOMEM;
234
235 ls = dlm_find_lockspace_local(proc->lockspace);
236 if (!ls)
237 return -ENOENT;
238
239 if (!params->castaddr || !params->lksb) {
240 error = -EINVAL;
241 goto out;
242 }
243
244 ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
245 if (!ua)
246 goto out;
247 ua->proc = proc;
248 ua->user_lksb = params->lksb;
249 ua->castparam = params->castparam;
250 ua->castaddr = params->castaddr;
251 ua->bastparam = params->bastparam;
252 ua->bastaddr = params->bastaddr;
253
254 if (params->flags & DLM_LKF_CONVERT)
255 error = dlm_user_convert(ls, ua,
256 params->mode, params->flags,
257 params->lkid, params->lvb);
258 else {
259 error = dlm_user_request(ls, ua,
260 params->mode, params->flags,
261 params->name, params->namelen,
262 params->parent);
263 if (!error)
264 error = ua->lksb.sb_lkid;
265 }
266 out:
267 dlm_put_lockspace(ls);
268 return error;
269}
270
271static int device_user_unlock(struct dlm_user_proc *proc,
272 struct dlm_lock_params *params)
273{
274 struct dlm_ls *ls;
275 struct dlm_user_args *ua;
276 int error = -ENOMEM;
277
278 ls = dlm_find_lockspace_local(proc->lockspace);
279 if (!ls)
280 return -ENOENT;
281
282 ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
283 if (!ua)
284 goto out;
285 ua->proc = proc;
286 ua->user_lksb = params->lksb;
287 ua->castparam = params->castparam;
288 ua->castaddr = params->castaddr;
289
290 if (params->flags & DLM_LKF_CANCEL)
291 error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
292 else
293 error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
294 params->lvb);
295 out:
296 dlm_put_lockspace(ls);
297 return error;
298}
299
Patrick Caulfield254da032007-03-21 09:23:53 +0000300static int create_misc_device(struct dlm_ls *ls, char *name)
301{
302 int error, len;
303
304 error = -ENOMEM;
305 len = strlen(name) + strlen(name_prefix) + 2;
306 ls->ls_device.name = kzalloc(len, GFP_KERNEL);
307 if (!ls->ls_device.name)
308 goto fail;
309
310 snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
311 name);
312 ls->ls_device.fops = &device_fops;
313 ls->ls_device.minor = MISC_DYNAMIC_MINOR;
314
315 error = misc_register(&ls->ls_device);
316 if (error) {
317 kfree(ls->ls_device.name);
318 }
319fail:
320 return error;
321}
322
David Teigland597d0ca2006-07-12 16:44:04 -0500323static int device_create_lockspace(struct dlm_lspace_params *params)
324{
325 dlm_lockspace_t *lockspace;
326 struct dlm_ls *ls;
Patrick Caulfield254da032007-03-21 09:23:53 +0000327 int error;
David Teigland597d0ca2006-07-12 16:44:04 -0500328
329 if (!capable(CAP_SYS_ADMIN))
330 return -EPERM;
331
332 error = dlm_new_lockspace(params->name, strlen(params->name),
333 &lockspace, 0, DLM_USER_LVB_LEN);
334 if (error)
335 return error;
336
337 ls = dlm_find_lockspace_local(lockspace);
338 if (!ls)
339 return -ENOENT;
340
Patrick Caulfield254da032007-03-21 09:23:53 +0000341 error = create_misc_device(ls, params->name);
David Teigland597d0ca2006-07-12 16:44:04 -0500342 dlm_put_lockspace(ls);
David Teigland597d0ca2006-07-12 16:44:04 -0500343
Patrick Caulfield254da032007-03-21 09:23:53 +0000344 if (error)
345 dlm_release_lockspace(lockspace, 0);
346 else
347 error = ls->ls_device.minor;
348
David Teigland597d0ca2006-07-12 16:44:04 -0500349 return error;
350}
351
352static int device_remove_lockspace(struct dlm_lspace_params *params)
353{
354 dlm_lockspace_t *lockspace;
355 struct dlm_ls *ls;
David Teiglandc6e6f0b2006-08-30 10:50:18 -0500356 int error, force = 0;
David Teigland597d0ca2006-07-12 16:44:04 -0500357
358 if (!capable(CAP_SYS_ADMIN))
359 return -EPERM;
360
361 ls = dlm_find_lockspace_device(params->minor);
362 if (!ls)
363 return -ENOENT;
364
Patrick Caulfield254da032007-03-21 09:23:53 +0000365 /* Deregister the misc device first, so we don't have
366 * a device that's not attached to a lockspace. If
367 * dlm_release_lockspace fails then we can recreate it
368 */
David Teigland597d0ca2006-07-12 16:44:04 -0500369 error = misc_deregister(&ls->ls_device);
370 if (error) {
371 dlm_put_lockspace(ls);
372 goto out;
373 }
374 kfree(ls->ls_device.name);
375
David Teiglandc6e6f0b2006-08-30 10:50:18 -0500376 if (params->flags & DLM_USER_LSFLG_FORCEFREE)
377 force = 2;
378
David Teigland597d0ca2006-07-12 16:44:04 -0500379 lockspace = ls->ls_local_handle;
380
381 /* dlm_release_lockspace waits for references to go to zero,
382 so all processes will need to close their device for the ls
383 before the release will procede */
384
385 dlm_put_lockspace(ls);
David Teiglandc6e6f0b2006-08-30 10:50:18 -0500386 error = dlm_release_lockspace(lockspace, force);
Patrick Caulfield254da032007-03-21 09:23:53 +0000387 if (error)
388 create_misc_device(ls, ls->ls_name);
David Teiglandc6e6f0b2006-08-30 10:50:18 -0500389 out:
David Teigland597d0ca2006-07-12 16:44:04 -0500390 return error;
391}
392
393/* Check the user's version matches ours */
394static int check_version(struct dlm_write_request *req)
395{
396 if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
397 (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
398 req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
399
400 printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
401 "user (%d.%d.%d) kernel (%d.%d.%d)\n",
402 current->comm,
403 current->pid,
404 req->version[0],
405 req->version[1],
406 req->version[2],
407 DLM_DEVICE_VERSION_MAJOR,
408 DLM_DEVICE_VERSION_MINOR,
409 DLM_DEVICE_VERSION_PATCH);
410 return -EINVAL;
411 }
412 return 0;
413}
414
415/*
416 * device_write
417 *
418 * device_user_lock
419 * dlm_user_request -> request_lock
420 * dlm_user_convert -> convert_lock
421 *
422 * device_user_unlock
423 * dlm_user_unlock -> unlock_lock
424 * dlm_user_cancel -> cancel_lock
425 *
426 * device_create_lockspace
427 * dlm_new_lockspace
428 *
429 * device_remove_lockspace
430 * dlm_release_lockspace
431 */
432
433/* a write to a lockspace device is a lock or unlock request, a write
434 to the control device is to create/remove a lockspace */
435
436static ssize_t device_write(struct file *file, const char __user *buf,
437 size_t count, loff_t *ppos)
438{
439 struct dlm_user_proc *proc = file->private_data;
440 struct dlm_write_request *kbuf;
441 sigset_t tmpsig, allsigs;
442 int error;
443
444#ifdef CONFIG_COMPAT
445 if (count < sizeof(struct dlm_write_request32))
446#else
447 if (count < sizeof(struct dlm_write_request))
448#endif
449 return -EINVAL;
450
451 kbuf = kmalloc(count, GFP_KERNEL);
452 if (!kbuf)
453 return -ENOMEM;
454
455 if (copy_from_user(kbuf, buf, count)) {
456 error = -EFAULT;
457 goto out_free;
458 }
459
460 if (check_version(kbuf)) {
461 error = -EBADE;
462 goto out_free;
463 }
464
465#ifdef CONFIG_COMPAT
466 if (!kbuf->is64bit) {
467 struct dlm_write_request32 *k32buf;
468 k32buf = (struct dlm_write_request32 *)kbuf;
469 kbuf = kmalloc(count + (sizeof(struct dlm_write_request) -
470 sizeof(struct dlm_write_request32)), GFP_KERNEL);
471 if (!kbuf)
472 return -ENOMEM;
473
474 if (proc)
475 set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
476 compat_input(kbuf, k32buf);
477 kfree(k32buf);
478 }
479#endif
480
481 /* do we really need this? can a write happen after a close? */
482 if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
483 test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
484 return -EINVAL;
485
486 sigfillset(&allsigs);
487 sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
488
489 error = -EINVAL;
490
491 switch (kbuf->cmd)
492 {
493 case DLM_USER_LOCK:
494 if (!proc) {
495 log_print("no locking on control device");
496 goto out_sig;
497 }
498 error = device_user_lock(proc, &kbuf->i.lock);
499 break;
500
501 case DLM_USER_UNLOCK:
502 if (!proc) {
503 log_print("no locking on control device");
504 goto out_sig;
505 }
506 error = device_user_unlock(proc, &kbuf->i.lock);
507 break;
508
509 case DLM_USER_CREATE_LOCKSPACE:
510 if (proc) {
511 log_print("create/remove only on control device");
512 goto out_sig;
513 }
514 error = device_create_lockspace(&kbuf->i.lspace);
515 break;
516
517 case DLM_USER_REMOVE_LOCKSPACE:
518 if (proc) {
519 log_print("create/remove only on control device");
520 goto out_sig;
521 }
522 error = device_remove_lockspace(&kbuf->i.lspace);
523 break;
524
525 default:
526 log_print("Unknown command passed to DLM device : %d\n",
527 kbuf->cmd);
528 }
529
530 out_sig:
531 sigprocmask(SIG_SETMASK, &tmpsig, NULL);
532 recalc_sigpending();
533 out_free:
534 kfree(kbuf);
535 return error;
536}
537
538/* Every process that opens the lockspace device has its own "proc" structure
539 hanging off the open file that's used to keep track of locks owned by the
540 process and asts that need to be delivered to the process. */
541
542static int device_open(struct inode *inode, struct file *file)
543{
544 struct dlm_user_proc *proc;
545 struct dlm_ls *ls;
546
547 ls = dlm_find_lockspace_device(iminor(inode));
548 if (!ls)
549 return -ENOENT;
550
551 proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
552 if (!proc) {
553 dlm_put_lockspace(ls);
554 return -ENOMEM;
555 }
556
557 proc->lockspace = ls->ls_local_handle;
558 INIT_LIST_HEAD(&proc->asts);
559 INIT_LIST_HEAD(&proc->locks);
David Teiglanda1bc86e2007-01-15 10:34:52 -0600560 INIT_LIST_HEAD(&proc->unlocking);
David Teigland597d0ca2006-07-12 16:44:04 -0500561 spin_lock_init(&proc->asts_spin);
562 spin_lock_init(&proc->locks_spin);
563 init_waitqueue_head(&proc->wait);
564 file->private_data = proc;
565
566 return 0;
567}
568
569static int device_close(struct inode *inode, struct file *file)
570{
571 struct dlm_user_proc *proc = file->private_data;
572 struct dlm_ls *ls;
573 sigset_t tmpsig, allsigs;
574
575 ls = dlm_find_lockspace_local(proc->lockspace);
576 if (!ls)
577 return -ENOENT;
578
579 sigfillset(&allsigs);
580 sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
581
582 set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
583
584 dlm_clear_proc_locks(ls, proc);
585
586 /* at this point no more lkb's should exist for this lockspace,
587 so there's no chance of dlm_user_add_ast() being called and
588 looking for lkb->ua->proc */
589
590 kfree(proc);
591 file->private_data = NULL;
592
593 dlm_put_lockspace(ls);
594 dlm_put_lockspace(ls); /* for the find in device_open() */
595
596 /* FIXME: AUTOFREE: if this ls is no longer used do
597 device_remove_lockspace() */
598
599 sigprocmask(SIG_SETMASK, &tmpsig, NULL);
600 recalc_sigpending();
601
602 return 0;
603}
604
605static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
606 int bmode, char __user *buf, size_t count)
607{
608#ifdef CONFIG_COMPAT
609 struct dlm_lock_result32 result32;
610#endif
611 struct dlm_lock_result result;
612 void *resultptr;
613 int error=0;
614 int len;
615 int struct_len;
616
617 memset(&result, 0, sizeof(struct dlm_lock_result));
618 memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
619 result.user_lksb = ua->user_lksb;
620
621 /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
622 in a conversion unless the conversion is successful. See code
623 in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though,
624 notes that a new blocking AST address and parameter are set even if
625 the conversion fails, so maybe we should just do that. */
626
627 if (type == AST_BAST) {
628 result.user_astaddr = ua->bastaddr;
629 result.user_astparam = ua->bastparam;
630 result.bast_mode = bmode;
631 } else {
632 result.user_astaddr = ua->castaddr;
633 result.user_astparam = ua->castparam;
634 }
635
636#ifdef CONFIG_COMPAT
637 if (compat)
638 len = sizeof(struct dlm_lock_result32);
639 else
640#endif
641 len = sizeof(struct dlm_lock_result);
642 struct_len = len;
643
644 /* copy lvb to userspace if there is one, it's been updated, and
645 the user buffer has space for it */
646
647 if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
648 count >= len + DLM_USER_LVB_LEN) {
649 if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
650 DLM_USER_LVB_LEN)) {
651 error = -EFAULT;
652 goto out;
653 }
654
655 result.lvb_offset = len;
656 len += DLM_USER_LVB_LEN;
657 }
658
659 result.length = len;
660 resultptr = &result;
661#ifdef CONFIG_COMPAT
662 if (compat) {
663 compat_output(&result, &result32);
664 resultptr = &result32;
665 }
666#endif
667
668 if (copy_to_user(buf, resultptr, struct_len))
669 error = -EFAULT;
670 else
671 error = len;
672 out:
673 return error;
674}
675
676/* a read returns a single ast described in a struct dlm_lock_result */
677
678static ssize_t device_read(struct file *file, char __user *buf, size_t count,
679 loff_t *ppos)
680{
681 struct dlm_user_proc *proc = file->private_data;
682 struct dlm_lkb *lkb;
683 struct dlm_user_args *ua;
684 DECLARE_WAITQUEUE(wait, current);
685 int error, type=0, bmode=0, removed = 0;
686
687#ifdef CONFIG_COMPAT
688 if (count < sizeof(struct dlm_lock_result32))
689#else
690 if (count < sizeof(struct dlm_lock_result))
691#endif
692 return -EINVAL;
693
694 /* do we really need this? can a read happen after a close? */
695 if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
696 return -EINVAL;
697
698 spin_lock(&proc->asts_spin);
699 if (list_empty(&proc->asts)) {
700 if (file->f_flags & O_NONBLOCK) {
701 spin_unlock(&proc->asts_spin);
702 return -EAGAIN;
703 }
704
705 add_wait_queue(&proc->wait, &wait);
706
707 repeat:
708 set_current_state(TASK_INTERRUPTIBLE);
709 if (list_empty(&proc->asts) && !signal_pending(current)) {
710 spin_unlock(&proc->asts_spin);
711 schedule();
712 spin_lock(&proc->asts_spin);
713 goto repeat;
714 }
715 set_current_state(TASK_RUNNING);
716 remove_wait_queue(&proc->wait, &wait);
717
718 if (signal_pending(current)) {
719 spin_unlock(&proc->asts_spin);
720 return -ERESTARTSYS;
721 }
722 }
723
724 if (list_empty(&proc->asts)) {
725 spin_unlock(&proc->asts_spin);
726 return -EAGAIN;
727 }
728
729 /* there may be both completion and blocking asts to return for
730 the lkb, don't remove lkb from asts list unless no asts remain */
731
732 lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
733
734 if (lkb->lkb_ast_type & AST_COMP) {
735 lkb->lkb_ast_type &= ~AST_COMP;
736 type = AST_COMP;
737 } else if (lkb->lkb_ast_type & AST_BAST) {
738 lkb->lkb_ast_type &= ~AST_BAST;
739 type = AST_BAST;
740 bmode = lkb->lkb_bastmode;
741 }
742
743 if (!lkb->lkb_ast_type) {
744 list_del(&lkb->lkb_astqueue);
745 removed = 1;
746 }
747 spin_unlock(&proc->asts_spin);
748
749 ua = (struct dlm_user_args *)lkb->lkb_astparam;
750 error = copy_result_to_user(ua,
751 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
752 type, bmode, buf, count);
753
754 /* removes reference for the proc->asts lists added by
755 dlm_user_add_ast() and may result in the lkb being freed */
756 if (removed)
757 dlm_put_lkb(lkb);
758
759 return error;
760}
761
762static unsigned int device_poll(struct file *file, poll_table *wait)
763{
764 struct dlm_user_proc *proc = file->private_data;
765
766 poll_wait(file, &proc->wait, wait);
767
768 spin_lock(&proc->asts_spin);
769 if (!list_empty(&proc->asts)) {
770 spin_unlock(&proc->asts_spin);
771 return POLLIN | POLLRDNORM;
772 }
773 spin_unlock(&proc->asts_spin);
774 return 0;
775}
776
777static int ctl_device_open(struct inode *inode, struct file *file)
778{
779 file->private_data = NULL;
780 return 0;
781}
782
783static int ctl_device_close(struct inode *inode, struct file *file)
784{
785 return 0;
786}
787
Arjan van de Ven00977a52007-02-12 00:55:34 -0800788static const struct file_operations device_fops = {
David Teigland597d0ca2006-07-12 16:44:04 -0500789 .open = device_open,
790 .release = device_close,
791 .read = device_read,
792 .write = device_write,
793 .poll = device_poll,
794 .owner = THIS_MODULE,
795};
796
Arjan van de Ven00977a52007-02-12 00:55:34 -0800797static const struct file_operations ctl_device_fops = {
David Teigland597d0ca2006-07-12 16:44:04 -0500798 .open = ctl_device_open,
799 .release = ctl_device_close,
800 .write = device_write,
801 .owner = THIS_MODULE,
802};
803
804int dlm_user_init(void)
805{
806 int error;
807
808 ctl_device.name = "dlm-control";
809 ctl_device.fops = &ctl_device_fops;
810 ctl_device.minor = MISC_DYNAMIC_MINOR;
811
812 error = misc_register(&ctl_device);
813 if (error)
814 log_print("misc_register failed for control device");
815
816 return error;
817}
818
819void dlm_user_exit(void)
820{
821 misc_deregister(&ctl_device);
822}
823