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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [lockd/] [svclock.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/fs/lockd/svclock.c
3
 *
4
 * Handling of server-side locks, mostly of the blocked variety.
5
 * This is the ugliest part of lockd because we tread on very thin ice.
6
 * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
7
 * IMNSHO introducing the grant callback into the NLM protocol was one
8
 * of the worst ideas Sun ever had. Except maybe for the idea of doing
9
 * NFS file locking at all.
10
 *
11
 * I'm trying hard to avoid race conditions by protecting most accesses
12
 * to a file's list of blocked locks through a semaphore. The global
13
 * list of blocked locks is not protected in this fashion however.
14
 * Therefore, some functions (such as the RPC callback for the async grant
15
 * call) move blocked locks towards the head of the list *while some other
16
 * process might be traversing it*. This should not be a problem in
17
 * practice, because this will only cause functions traversing the list
18
 * to visit some blocks twice.
19
 *
20
 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
21
 */
22
 
23
#include <linux/config.h>
24
#include <linux/types.h>
25
#include <linux/errno.h>
26
#include <linux/kernel.h>
27
#include <linux/sched.h>
28
#include <linux/smp_lock.h>
29
#include <linux/sunrpc/clnt.h>
30
#include <linux/sunrpc/svc.h>
31
#include <linux/lockd/nlm.h>
32
#include <linux/lockd/lockd.h>
33
 
34
#define NLMDBG_FACILITY         NLMDBG_SVCLOCK
35
 
36
#ifdef CONFIG_LOCKD_V4
37
#define nlm_deadlock    nlm4_deadlock
38
#else
39
#define nlm_deadlock    nlm_lck_denied
40
#endif
41
 
42
static void     nlmsvc_insert_block(struct nlm_block *block, unsigned long);
43
static int      nlmsvc_remove_block(struct nlm_block *block);
44
static void     nlmsvc_grant_callback(struct rpc_task *task);
45
static void     nlmsvc_notify_blocked(struct file_lock *);
46
 
47
/*
48
 * The list of blocked locks to retry
49
 */
50
static struct nlm_block *       nlm_blocked;
51
 
52
/*
53
 * Insert a blocked lock into the global list
54
 */
55
static void
56
nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
57
{
58
        struct nlm_block **bp, *b;
59
 
60
        dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
61
        if (block->b_queued)
62
                nlmsvc_remove_block(block);
63
        bp = &nlm_blocked;
64
        if (when != NLM_NEVER) {
65
                if ((when += jiffies) == NLM_NEVER)
66
                        when ++;
67
                while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
68
                        bp = &b->b_next;
69
        } else
70
                while ((b = *bp))
71
                        bp = &b->b_next;
72
 
73
        block->b_queued = 1;
74
        block->b_when = when;
75
        block->b_next = b;
76
        *bp = block;
77
}
78
 
79
/*
80
 * Remove a block from the global list
81
 */
82
static int
83
nlmsvc_remove_block(struct nlm_block *block)
84
{
85
        struct nlm_block **bp, *b;
86
 
87
        if (!block->b_queued)
88
                return 1;
89
        for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next) {
90
                if (b == block) {
91
                        *bp = block->b_next;
92
                        block->b_queued = 0;
93
                        return 1;
94
                }
95
        }
96
 
97
        return 0;
98
}
99
 
100
/*
101
 * Find a block for a given lock and optionally remove it from
102
 * the list.
103
 */
104
static struct nlm_block *
105
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
106
{
107
        struct nlm_block        **head, *block;
108
        struct file_lock        *fl;
109
 
110
        dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
111
                                file, lock->fl.fl_pid,
112
                                (long long)lock->fl.fl_start,
113
                                (long long)lock->fl.fl_end, lock->fl.fl_type);
114
        for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
115
                fl = &block->b_call.a_args.lock.fl;
116
                dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
117
                                block->b_file, fl->fl_pid,
118
                                (long long)fl->fl_start,
119
                                (long long)fl->fl_end, fl->fl_type,
120
                                nlmdbg_cookie2a(&block->b_call.a_args.cookie));
121
                if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
122
                        if (remove) {
123
                                *head = block->b_next;
124
                                block->b_queued = 0;
125
                        }
126
                        return block;
127
                }
128
        }
129
 
130
        return NULL;
131
}
132
 
133
static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
134
{
135
        if(a->len != b->len)
136
                return 0;
137
        if(memcmp(a->data,b->data,a->len))
138
                return 0;
139
        return 1;
140
}
141
 
142
/*
143
 * Find a block with a given NLM cookie.
144
 */
145
static inline struct nlm_block *
146
nlmsvc_find_block(struct nlm_cookie *cookie,  struct sockaddr_in *sin)
147
{
148
        struct nlm_block *block;
149
 
150
        for (block = nlm_blocked; block; block = block->b_next) {
151
                dprintk("cookie: head of blocked queue %p, block %p\n",
152
                        nlm_blocked, block);
153
                if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)
154
                                && nlm_cmp_addr(sin, &block->b_host->h_addr))
155
                        break;
156
        }
157
 
158
        return block;
159
}
160
 
161
/*
162
 * Create a block and initialize it.
163
 *
164
 * Note: we explicitly set the cookie of the grant reply to that of
165
 * the blocked lock request. The spec explicitly mentions that the client
166
 * should _not_ rely on the callback containing the same cookie as the
167
 * request, but (as I found out later) that's because some implementations
168
 * do just this. Never mind the standards comittees, they support our
169
 * logging industries.
170
 */
171
static inline struct nlm_block *
172
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
173
                                struct nlm_lock *lock, struct nlm_cookie *cookie)
174
{
175
        struct nlm_block        *block;
176
        struct nlm_host         *host;
177
        struct nlm_rqst         *call;
178
 
179
        /* Create host handle for callback */
180
        host = nlmclnt_lookup_host(&rqstp->rq_addr,
181
                                rqstp->rq_prot, rqstp->rq_vers);
182
        if (host == NULL)
183
                return NULL;
184
 
185
        /* Allocate memory for block, and initialize arguments */
186
        if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))
187
                goto failed;
188
        memset(block, 0, sizeof(*block));
189
        locks_init_lock(&block->b_call.a_args.lock.fl);
190
        locks_init_lock(&block->b_call.a_res.lock.fl);
191
 
192
        block->b_host = nlmsvc_lookup_host(rqstp);
193
        if (block->b_host == NULL) {
194
                goto failed_free;
195
        }
196
 
197
        if (!nlmclnt_setgrantargs(&block->b_call, lock))
198
                goto failed_free;
199
 
200
        /* Set notifier function for VFS, and init args */
201
        block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;
202
        block->b_call.a_args.cookie = *cookie;  /* see above */
203
 
204
        dprintk("lockd: created block %p...\n", block);
205
 
206
        /* Create and initialize the block */
207
        block->b_daemon = rqstp->rq_server;
208
        block->b_file   = file;
209
 
210
        /* Add to file's list of blocks */
211
        block->b_fnext  = file->f_blocks;
212
        file->f_blocks  = block;
213
 
214
        /* Set up RPC arguments for callback */
215
        call = &block->b_call;
216
        call->a_host    = host;
217
        call->a_flags   = RPC_TASK_ASYNC;
218
 
219
        return block;
220
 
221
failed_free:
222
        kfree(block);
223
failed:
224
        nlm_release_host(host);
225
        return NULL;
226
}
227
 
228
/*
229
 * Delete a block. If the lock was cancelled or the grant callback
230
 * failed, unlock is set to 1.
231
 * It is the caller's responsibility to check whether the file
232
 * can be closed hereafter.
233
 */
234
static void
235
nlmsvc_delete_block(struct nlm_block *block, int unlock)
236
{
237
        struct file_lock        *fl = &block->b_call.a_args.lock.fl;
238
        struct nlm_file         *file = block->b_file;
239
        struct nlm_block        **bp;
240
 
241
        dprintk("lockd: deleting block %p...\n", block);
242
 
243
        /* Remove block from list */
244
        nlmsvc_remove_block(block);
245
 
246
        /* If granted, unlock it, else remove from inode block list */
247
        if (unlock && block->b_granted) {
248
                dprintk("lockd: deleting granted lock\n");
249
                fl->fl_type = F_UNLCK;
250
                posix_lock_file(&block->b_file->f_file, fl, 0);
251
                block->b_granted = 0;
252
        } else {
253
                dprintk("lockd: unblocking blocked lock\n");
254
                posix_unblock_lock(fl);
255
        }
256
 
257
        /* If the block is in the middle of a GRANT callback,
258
         * don't kill it yet. */
259
        if (block->b_incall) {
260
                nlmsvc_insert_block(block, NLM_NEVER);
261
                block->b_done = 1;
262
                return;
263
        }
264
 
265
        /* Remove block from file's list of blocks */
266
        for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
267
                if (*bp == block) {
268
                        *bp = block->b_fnext;
269
                        break;
270
                }
271
        }
272
 
273
        nlm_release_host(block->b_host);
274
        nlmclnt_freegrantargs(&block->b_call);
275
        kfree(block);
276
}
277
 
278
/*
279
 * Loop over all blocks and perform the action specified.
280
 * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
281
 */
282
int
283
nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
284
{
285
        struct nlm_block        *block, *next;
286
 
287
        down(&file->f_sema);
288
        for (block = file->f_blocks; block; block = next) {
289
                next = block->b_fnext;
290
                if (action == NLM_ACT_MARK)
291
                        block->b_host->h_inuse = 1;
292
                else if (action == NLM_ACT_UNLOCK) {
293
                        if (host == NULL || host == block->b_host)
294
                                nlmsvc_delete_block(block, 1);
295
                }
296
        }
297
        up(&file->f_sema);
298
        return 0;
299
}
300
 
301
/*
302
 * Attempt to establish a lock, and if it can't be granted, block it
303
 * if required.
304
 */
305
u32
306
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
307
                        struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
308
{
309
        struct file_lock        *conflock;
310
        struct nlm_block        *block;
311
        int                     error;
312
 
313
        dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
314
                                file->f_file.f_dentry->d_inode->i_dev,
315
                                file->f_file.f_dentry->d_inode->i_ino,
316
                                lock->fl.fl_type, lock->fl.fl_pid,
317
                                (long long)lock->fl.fl_start,
318
                                (long long)lock->fl.fl_end,
319
                                wait);
320
 
321
 
322
        /* Get existing block (in case client is busy-waiting) */
323
        block = nlmsvc_lookup_block(file, lock, 0);
324
 
325
        lock->fl.fl_flags |= FL_LOCKD;
326
 
327
again:
328
        /* Lock file against concurrent access */
329
        down(&file->f_sema);
330
 
331
        if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
332
                error = posix_lock_file(&file->f_file, &lock->fl, 0);
333
 
334
                if (block)
335
                        nlmsvc_delete_block(block, 0);
336
                up(&file->f_sema);
337
 
338
                dprintk("lockd: posix_lock_file returned %d\n", -error);
339
                switch(-error) {
340
                case 0:
341
                        return nlm_granted;
342
                case EDEADLK:
343
                        return nlm_deadlock;
344
                case EAGAIN:
345
                        return nlm_lck_denied;
346
                default:                        /* includes ENOLCK */
347
                        return nlm_lck_denied_nolocks;
348
                }
349
        }
350
 
351
        if (!wait) {
352
                up(&file->f_sema);
353
                return nlm_lck_denied;
354
        }
355
 
356
        if (posix_locks_deadlock(&lock->fl, conflock)) {
357
                up(&file->f_sema);
358
                return nlm_deadlock;
359
        }
360
 
361
        /* If we don't have a block, create and initialize it. Then
362
         * retry because we may have slept in kmalloc. */
363
        /* We have to release f_sema as nlmsvc_create_block may try to
364
         * claim it while doing host garbage collection */
365
        if (block == NULL) {
366
                up(&file->f_sema);
367
                dprintk("lockd: blocking on this lock (allocating).\n");
368
                if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
369
                        return nlm_lck_denied_nolocks;
370
                goto again;
371
        }
372
 
373
        /* Append to list of blocked */
374
        nlmsvc_insert_block(block, NLM_NEVER);
375
 
376
        if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
377
                /* Now add block to block list of the conflicting lock
378
                   if we haven't done so. */
379
                dprintk("lockd: blocking on this lock.\n");
380
                posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
381
        }
382
 
383
        up(&file->f_sema);
384
        return nlm_lck_blocked;
385
}
386
 
387
/*
388
 * Test for presence of a conflicting lock.
389
 */
390
u32
391
nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
392
                                       struct nlm_lock *conflock)
393
{
394
        struct file_lock        *fl;
395
 
396
        dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
397
                                file->f_file.f_dentry->d_inode->i_dev,
398
                                file->f_file.f_dentry->d_inode->i_ino,
399
                                lock->fl.fl_type,
400
                                (long long)lock->fl.fl_start,
401
                                (long long)lock->fl.fl_end);
402
 
403
        if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
404
                dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
405
                                fl->fl_type, (long long)fl->fl_start,
406
                                (long long)fl->fl_end);
407
                conflock->caller = "somehost";  /* FIXME */
408
                conflock->oh.len = 0;            /* don't return OH info */
409
                conflock->fl = *fl;
410
                return nlm_lck_denied;
411
        }
412
 
413
        return nlm_granted;
414
}
415
 
416
/*
417
 * Remove a lock.
418
 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
419
 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
420
 * afterwards. In this case the block will still be there, and hence
421
 * must be removed.
422
 */
423
u32
424
nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
425
{
426
        int     error;
427
 
428
        dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
429
                                file->f_file.f_dentry->d_inode->i_dev,
430
                                file->f_file.f_dentry->d_inode->i_ino,
431
                                lock->fl.fl_pid,
432
                                (long long)lock->fl.fl_start,
433
                                (long long)lock->fl.fl_end);
434
 
435
        /* First, cancel any lock that might be there */
436
        nlmsvc_cancel_blocked(file, lock);
437
 
438
        lock->fl.fl_type = F_UNLCK;
439
        error = posix_lock_file(&file->f_file, &lock->fl, 0);
440
 
441
        return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
442
}
443
 
444
/*
445
 * Cancel a previously blocked request.
446
 *
447
 * A cancel request always overrides any grant that may currently
448
 * be in progress.
449
 * The calling procedure must check whether the file can be closed.
450
 */
451
u32
452
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
453
{
454
        struct nlm_block        *block;
455
 
456
        dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
457
                                file->f_file.f_dentry->d_inode->i_dev,
458
                                file->f_file.f_dentry->d_inode->i_ino,
459
                                lock->fl.fl_pid,
460
                                (long long)lock->fl.fl_start,
461
                                (long long)lock->fl.fl_end);
462
 
463
        down(&file->f_sema);
464
        if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
465
                nlmsvc_delete_block(block, 1);
466
        up(&file->f_sema);
467
        return nlm_granted;
468
}
469
 
470
/*
471
 * Unblock a blocked lock request. This is a callback invoked from the
472
 * VFS layer when a lock on which we blocked is removed.
473
 *
474
 * This function doesn't grant the blocked lock instantly, but rather moves
475
 * the block to the head of nlm_blocked where it can be picked up by lockd.
476
 */
477
static void
478
nlmsvc_notify_blocked(struct file_lock *fl)
479
{
480
        struct nlm_block        **bp, *block;
481
 
482
        dprintk("lockd: VFS unblock notification for block %p\n", fl);
483
        posix_unblock_lock(fl);
484
        for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
485
                if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
486
                        nlmsvc_insert_block(block, 0);
487
                        svc_wake_up(block->b_daemon);
488
                        return;
489
                }
490
        }
491
 
492
        printk(KERN_WARNING "lockd: notification for unknown block!\n");
493
}
494
 
495
/*
496
 * Try to claim a lock that was previously blocked.
497
 *
498
 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
499
 * RPC thread when notifying the client. This seems like overkill...
500
 * Here's why:
501
 *  -   we don't want to use a synchronous RPC thread, otherwise
502
 *      we might find ourselves hanging on a dead portmapper.
503
 *  -   Some lockd implementations (e.g. HP) don't react to
504
 *      RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
505
 */
506
static void
507
nlmsvc_grant_blocked(struct nlm_block *block)
508
{
509
        struct nlm_file         *file = block->b_file;
510
        struct nlm_lock         *lock = &block->b_call.a_args.lock;
511
        struct file_lock        *conflock;
512
        int                     error;
513
 
514
        dprintk("lockd: grant blocked lock %p\n", block);
515
 
516
        /* First thing is lock the file */
517
        down(&file->f_sema);
518
 
519
        /* Unlink block request from list */
520
        nlmsvc_remove_block(block);
521
 
522
        /* If b_granted is true this means we've been here before.
523
         * Just retry the grant callback, possibly refreshing the RPC
524
         * binding */
525
        if (block->b_granted) {
526
                nlm_rebind_host(block->b_call.a_host);
527
                goto callback;
528
        }
529
 
530
        /* Try the lock operation again */
531
        if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
532
                /* Bummer, we blocked again */
533
                dprintk("lockd: lock still blocked\n");
534
                nlmsvc_insert_block(block, NLM_NEVER);
535
                posix_block_lock(conflock, &lock->fl);
536
                up(&file->f_sema);
537
                return;
538
        }
539
 
540
        /* Alright, no conflicting lock. Now lock it for real. If the
541
         * following yields an error, this is most probably due to low
542
         * memory. Retry the lock in a few seconds.
543
         */
544
        if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
545
                printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
546
                                -error, __FUNCTION__);
547
                nlmsvc_insert_block(block, 10 * HZ);
548
                up(&file->f_sema);
549
                return;
550
        }
551
 
552
callback:
553
        /* Lock was granted by VFS. */
554
        dprintk("lockd: GRANTing blocked lock.\n");
555
        block->b_granted = 1;
556
        block->b_incall  = 1;
557
 
558
        /* Schedule next grant callback in 30 seconds */
559
        nlmsvc_insert_block(block, 30 * HZ);
560
 
561
        /* Call the client */
562
        nlm_get_host(block->b_call.a_host);
563
        if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
564
                                                nlmsvc_grant_callback) < 0)
565
                nlm_release_host(block->b_call.a_host);
566
        up(&file->f_sema);
567
}
568
 
569
/*
570
 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
571
 * RPC call has succeeded or timed out.
572
 * Like all RPC callbacks, it is invoked by the rpciod process, so it
573
 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
574
 * chain once more in order to have it removed by lockd itself (which can
575
 * then sleep on the file semaphore without disrupting e.g. the nfs client).
576
 */
577
static void
578
nlmsvc_grant_callback(struct rpc_task *task)
579
{
580
        struct nlm_rqst         *call = (struct nlm_rqst *) task->tk_calldata;
581
        struct nlm_block        *block;
582
        unsigned long           timeout;
583
        struct sockaddr_in      *peer_addr = RPC_PEERADDR(task->tk_client);
584
 
585
        dprintk("lockd: GRANT_MSG RPC callback\n");
586
        dprintk("callback: looking for cookie %s, host %u.%u.%u.%u\n",
587
                nlmdbg_cookie2a(&call->a_args.cookie),
588
                NIPQUAD(peer_addr->sin_addr.s_addr));
589
        if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) {
590
                dprintk("lockd: no block for cookie %s, host %u.%u.%u.%u\n",
591
                                nlmdbg_cookie2a(&call->a_args.cookie),
592
                                NIPQUAD(peer_addr->sin_addr.s_addr));
593
                return;
594
        }
595
 
596
        /* Technically, we should down the file semaphore here. Since we
597
         * move the block towards the head of the queue only, no harm
598
         * can be done, though. */
599
        if (task->tk_status < 0) {
600
                /* RPC error: Re-insert for retransmission */
601
                timeout = 10 * HZ;
602
        } else if (block->b_done) {
603
                /* Block already removed, kill it for real */
604
                timeout = 0;
605
        } else {
606
                /* Call was successful, now wait for client callback */
607
                timeout = 60 * HZ;
608
        }
609
        nlmsvc_insert_block(block, timeout);
610
        svc_wake_up(block->b_daemon);
611
        block->b_incall = 0;
612
 
613
        nlm_release_host(call->a_host);
614
}
615
 
616
/*
617
 * We received a GRANT_RES callback. Try to find the corresponding
618
 * block.
619
 */
620
void
621
nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
622
{
623
        struct nlm_block        *block;
624
        struct nlm_file         *file;
625
 
626
        dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n",
627
                *(unsigned int *)(cookie->data),
628
                ntohl(rqstp->rq_addr.sin_addr.s_addr), status);
629
        if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr)))
630
                return;
631
        file = block->b_file;
632
 
633
        file->f_count++;
634
        down(&file->f_sema);
635
        if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) {
636
                if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
637
                        /* Try again in a couple of seconds */
638
                        nlmsvc_insert_block(block, 10 * HZ);
639
                        block = NULL;
640
                } else {
641
                        /* Lock is now held by client, or has been rejected.
642
                         * In both cases, the block should be removed. */
643
                        file->f_count++;
644
                        up(&file->f_sema);
645
                        if (status == NLM_LCK_GRANTED)
646
                                nlmsvc_delete_block(block, 0);
647
                        else
648
                                nlmsvc_delete_block(block, 1);
649
                }
650
        }
651
        if (!block)
652
                up(&file->f_sema);
653
        nlm_release_file(file);
654
}
655
 
656
/*
657
 * Retry all blocked locks that have been notified. This is where lockd
658
 * picks up locks that can be granted, or grant notifications that must
659
 * be retransmitted.
660
 */
661
unsigned long
662
nlmsvc_retry_blocked(void)
663
{
664
        struct nlm_block        *block;
665
 
666
        dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
667
                        nlm_blocked,
668
                        nlm_blocked? nlm_blocked->b_when : 0);
669
        while ((block = nlm_blocked)) {
670
                if (block->b_when == NLM_NEVER)
671
                        break;
672
                if (time_after(block->b_when,jiffies))
673
                        break;
674
                dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
675
                        block, block->b_when, block->b_done);
676
                if (block->b_done)
677
                        nlmsvc_delete_block(block, 0);
678
                else
679
                        nlmsvc_grant_blocked(block);
680
        }
681
 
682
        if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
683
                return (block->b_when - jiffies);
684
 
685
        return MAX_SCHEDULE_TIMEOUT;
686
}

powered by: WebSVN 2.1.0

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