OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [dlm/] [user.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.