- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / fs / lockd / clntproc.c
1 /*
2  * linux/fs/lockd/clntproc.c
3  *
4  * RPC procedures for the client side NLM implementation
5  *
6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/errno.h>
12 #include <linux/fs.h>
13 #include <linux/nfs_fs.h>
14 #include <linux/utsname.h>
15 #include <linux/freezer.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/sunrpc/svc.h>
18 #include <linux/lockd/lockd.h>
19 #include <linux/lockd/sm_inter.h>
20
21 #define NLMDBG_FACILITY         NLMDBG_CLIENT
22 #define NLMCLNT_GRACE_WAIT      (5*HZ)
23 #define NLMCLNT_POLL_TIMEOUT    (30*HZ)
24 #define NLMCLNT_MAX_RETRIES     3
25
26 static int      nlmclnt_test(struct nlm_rqst *, struct file_lock *);
27 static int      nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
28 static int      nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
29 static int      nlm_stat_to_errno(__be32 stat);
30 static void     nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
31 static int      nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
32
33 static const struct rpc_call_ops nlmclnt_unlock_ops;
34 static const struct rpc_call_ops nlmclnt_cancel_ops;
35
36 /*
37  * Cookie counter for NLM requests
38  */
39 static atomic_t nlm_cookie = ATOMIC_INIT(0x1234);
40
41 void nlmclnt_next_cookie(struct nlm_cookie *c)
42 {
43         u32     cookie = atomic_inc_return(&nlm_cookie);
44
45         memcpy(c->data, &cookie, 4);
46         c->len=4;
47 }
48
49 static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
50 {
51         atomic_inc(&lockowner->count);
52         return lockowner;
53 }
54
55 static void nlm_put_lockowner(struct nlm_lockowner *lockowner)
56 {
57         if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
58                 return;
59         list_del(&lockowner->list);
60         spin_unlock(&lockowner->host->h_lock);
61         nlm_release_host(lockowner->host);
62         kfree(lockowner);
63 }
64
65 static inline int nlm_pidbusy(struct nlm_host *host, uint32_t pid)
66 {
67         struct nlm_lockowner *lockowner;
68         list_for_each_entry(lockowner, &host->h_lockowners, list) {
69                 if (lockowner->pid == pid)
70                         return -EBUSY;
71         }
72         return 0;
73 }
74
75 static inline uint32_t __nlm_alloc_pid(struct nlm_host *host)
76 {
77         uint32_t res;
78         do {
79                 res = host->h_pidcount++;
80         } while (nlm_pidbusy(host, res) < 0);
81         return res;
82 }
83
84 static struct nlm_lockowner *__nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
85 {
86         struct nlm_lockowner *lockowner;
87         list_for_each_entry(lockowner, &host->h_lockowners, list) {
88                 if (lockowner->owner != owner)
89                         continue;
90                 return nlm_get_lockowner(lockowner);
91         }
92         return NULL;
93 }
94
95 static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
96 {
97         struct nlm_lockowner *res, *new = NULL;
98
99         spin_lock(&host->h_lock);
100         res = __nlm_find_lockowner(host, owner);
101         if (res == NULL) {
102                 spin_unlock(&host->h_lock);
103                 new = kmalloc(sizeof(*new), GFP_KERNEL);
104                 spin_lock(&host->h_lock);
105                 res = __nlm_find_lockowner(host, owner);
106                 if (res == NULL && new != NULL) {
107                         res = new;
108                         atomic_set(&new->count, 1);
109                         new->owner = owner;
110                         new->pid = __nlm_alloc_pid(host);
111                         new->host = nlm_get_host(host);
112                         list_add(&new->list, &host->h_lockowners);
113                         new = NULL;
114                 }
115         }
116         spin_unlock(&host->h_lock);
117         kfree(new);
118         return res;
119 }
120
121 /*
122  * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
123  */
124 static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
125 {
126         struct nlm_args *argp = &req->a_args;
127         struct nlm_lock *lock = &argp->lock;
128
129         nlmclnt_next_cookie(&argp->cookie);
130         argp->state   = nsm_local_state;
131         memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
132         lock->caller  = utsname()->nodename;
133         lock->oh.data = req->a_owner;
134         lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
135                                 (unsigned int)fl->fl_u.nfs_fl.owner->pid,
136                                 utsname()->nodename);
137         lock->svid = fl->fl_u.nfs_fl.owner->pid;
138         lock->fl.fl_start = fl->fl_start;
139         lock->fl.fl_end = fl->fl_end;
140         lock->fl.fl_type = fl->fl_type;
141 }
142
143 static void nlmclnt_release_lockargs(struct nlm_rqst *req)
144 {
145         BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
146 }
147
148 /**
149  * nlmclnt_proc - Perform a single client-side lock request
150  * @host: address of a valid nlm_host context representing the NLM server
151  * @cmd: fcntl-style file lock operation to perform
152  * @fl: address of arguments for the lock operation
153  *
154  */
155 int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
156 {
157         struct nlm_rqst         *call;
158         sigset_t                oldset;
159         unsigned long           flags;
160         int                     status;
161
162         nlm_get_host(host);
163         call = nlm_alloc_call(host);
164         if (call == NULL)
165                 return -ENOMEM;
166
167         nlmclnt_locks_init_private(fl, host);
168         /* Set up the argument struct */
169         nlmclnt_setlockargs(call, fl);
170
171         /* Keep the old signal mask */
172         spin_lock_irqsave(&current->sighand->siglock, flags);
173         oldset = current->blocked;
174
175         /* If we're cleaning up locks because the process is exiting,
176          * perform the RPC call asynchronously. */
177         if ((IS_SETLK(cmd) || IS_SETLKW(cmd))
178             && fl->fl_type == F_UNLCK
179             && (current->flags & PF_EXITING)) {
180                 sigfillset(&current->blocked);  /* Mask all signals */
181                 recalc_sigpending();
182
183                 call->a_flags = RPC_TASK_ASYNC;
184         }
185         spin_unlock_irqrestore(&current->sighand->siglock, flags);
186
187         if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
188                 if (fl->fl_type != F_UNLCK) {
189                         call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
190                         status = nlmclnt_lock(call, fl);
191                 } else
192                         status = nlmclnt_unlock(call, fl);
193         } else if (IS_GETLK(cmd))
194                 status = nlmclnt_test(call, fl);
195         else
196                 status = -EINVAL;
197
198         fl->fl_ops->fl_release_private(fl);
199         fl->fl_ops = NULL;
200
201         spin_lock_irqsave(&current->sighand->siglock, flags);
202         current->blocked = oldset;
203         recalc_sigpending();
204         spin_unlock_irqrestore(&current->sighand->siglock, flags);
205
206         dprintk("lockd: clnt proc returns %d\n", status);
207         return status;
208 }
209 EXPORT_SYMBOL_GPL(nlmclnt_proc);
210
211 /*
212  * Allocate an NLM RPC call struct
213  *
214  * Note: the caller must hold a reference to host. In case of failure,
215  * this reference will be released.
216  */
217 struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
218 {
219         struct nlm_rqst *call;
220
221         for(;;) {
222                 call = kzalloc(sizeof(*call), GFP_KERNEL);
223                 if (call != NULL) {
224                         locks_init_lock(&call->a_args.lock.fl);
225                         locks_init_lock(&call->a_res.lock.fl);
226                         call->a_host = host;
227                         return call;
228                 }
229                 if (signalled())
230                         break;
231                 printk("nlm_alloc_call: failed, waiting for memory\n");
232                 schedule_timeout_interruptible(5*HZ);
233         }
234         nlm_release_host(host);
235         return NULL;
236 }
237
238 void nlm_release_call(struct nlm_rqst *call)
239 {
240         nlm_release_host(call->a_host);
241         nlmclnt_release_lockargs(call);
242         kfree(call);
243 }
244
245 static void nlmclnt_rpc_release(void *data)
246 {
247         nlm_release_call(data);
248 }
249
250 static int nlm_wait_on_grace(wait_queue_head_t *queue)
251 {
252         DEFINE_WAIT(wait);
253         int status = -EINTR;
254
255         prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
256         if (!signalled ()) {
257                 schedule_timeout(NLMCLNT_GRACE_WAIT);
258                 try_to_freeze();
259                 if (!signalled ())
260                         status = 0;
261         }
262         finish_wait(queue, &wait);
263         return status;
264 }
265
266 /*
267  * Generic NLM call
268  */
269 static int
270 nlmclnt_call(struct nlm_rqst *req, u32 proc)
271 {
272         struct nlm_host *host = req->a_host;
273         struct rpc_clnt *clnt;
274         struct nlm_args *argp = &req->a_args;
275         struct nlm_res  *resp = &req->a_res;
276         struct rpc_message msg = {
277                 .rpc_argp       = argp,
278                 .rpc_resp       = resp,
279         };
280         int             status;
281
282         dprintk("lockd: call procedure %d on %s\n",
283                         (int)proc, host->h_name);
284
285         do {
286                 if (host->h_reclaiming && !argp->reclaim)
287                         goto in_grace_period;
288
289                 /* If we have no RPC client yet, create one. */
290                 if ((clnt = nlm_bind_host(host)) == NULL)
291                         return -ENOLCK;
292                 msg.rpc_proc = &clnt->cl_procinfo[proc];
293
294                 /* Perform the RPC call. If an error occurs, try again */
295                 if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
296                         dprintk("lockd: rpc_call returned error %d\n", -status);
297                         switch (status) {
298                         case -EPROTONOSUPPORT:
299                                 status = -EINVAL;
300                                 break;
301                         case -ECONNREFUSED:
302                         case -ETIMEDOUT:
303                         case -ENOTCONN:
304                                 nlm_rebind_host(host);
305                                 status = -EAGAIN;
306                                 break;
307                         case -ERESTARTSYS:
308                                 return signalled () ? -EINTR : status;
309                         default:
310                                 break;
311                         }
312                         break;
313                 } else
314                 if (resp->status == nlm_lck_denied_grace_period) {
315                         dprintk("lockd: server in grace period\n");
316                         if (argp->reclaim) {
317                                 printk(KERN_WARNING
318                                      "lockd: spurious grace period reject?!\n");
319                                 return -ENOLCK;
320                         }
321                 } else {
322                         if (!argp->reclaim) {
323                                 /* We appear to be out of the grace period */
324                                 wake_up_all(&host->h_gracewait);
325                         }
326                         dprintk("lockd: server returns status %d\n", resp->status);
327                         return 0;       /* Okay, call complete */
328                 }
329
330 in_grace_period:
331                 /*
332                  * The server has rebooted and appears to be in the grace
333                  * period during which locks are only allowed to be
334                  * reclaimed.
335                  * We can only back off and try again later.
336                  */
337                 status = nlm_wait_on_grace(&host->h_gracewait);
338         } while (status == 0);
339
340         return status;
341 }
342
343 /*
344  * Generic NLM call, async version.
345  */
346 static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
347 {
348         struct nlm_host *host = req->a_host;
349         struct rpc_clnt *clnt;
350
351         dprintk("lockd: call procedure %d on %s (async)\n",
352                         (int)proc, host->h_name);
353
354         /* If we have no RPC client yet, create one. */
355         clnt = nlm_bind_host(host);
356         if (clnt == NULL)
357                 goto out_err;
358         msg->rpc_proc = &clnt->cl_procinfo[proc];
359
360         /* bootstrap and kick off the async RPC call */
361         return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
362 out_err:
363         tk_ops->rpc_release(req);
364         return -ENOLCK;
365 }
366
367 int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
368 {
369         struct rpc_message msg = {
370                 .rpc_argp       = &req->a_args,
371                 .rpc_resp       = &req->a_res,
372         };
373         return __nlm_async_call(req, proc, &msg, tk_ops);
374 }
375
376 int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
377 {
378         struct rpc_message msg = {
379                 .rpc_argp       = &req->a_res,
380         };
381         return __nlm_async_call(req, proc, &msg, tk_ops);
382 }
383
384 /*
385  * TEST for the presence of a conflicting lock
386  */
387 static int
388 nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
389 {
390         int     status;
391
392         status = nlmclnt_call(req, NLMPROC_TEST);
393         if (status < 0)
394                 goto out;
395
396         switch (req->a_res.status) {
397                 case nlm_granted:
398                         fl->fl_type = F_UNLCK;
399                         break;
400                 case nlm_lck_denied:
401                         /*
402                          * Report the conflicting lock back to the application.
403                          */
404                         fl->fl_start = req->a_res.lock.fl.fl_start;
405                         fl->fl_end = req->a_res.lock.fl.fl_start;
406                         fl->fl_type = req->a_res.lock.fl.fl_type;
407                         fl->fl_pid = 0;
408                         break;
409                 default:
410                         status = nlm_stat_to_errno(req->a_res.status);
411         }
412 out:
413         nlm_release_call(req);
414         return status;
415 }
416
417 static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
418 {
419         new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
420         new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
421         list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
422 }
423
424 static void nlmclnt_locks_release_private(struct file_lock *fl)
425 {
426         list_del(&fl->fl_u.nfs_fl.list);
427         nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
428 }
429
430 static struct file_lock_operations nlmclnt_lock_ops = {
431         .fl_copy_lock = nlmclnt_locks_copy_lock,
432         .fl_release_private = nlmclnt_locks_release_private,
433 };
434
435 static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
436 {
437         BUG_ON(fl->fl_ops != NULL);
438         fl->fl_u.nfs_fl.state = 0;
439         fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
440         INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
441         fl->fl_ops = &nlmclnt_lock_ops;
442 }
443
444 static int do_vfs_lock(struct file_lock *fl)
445 {
446         int res = 0;
447         switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
448                 case FL_POSIX:
449                         res = posix_lock_file_wait(fl->fl_file, fl);
450                         break;
451                 case FL_FLOCK:
452                         res = flock_lock_file_wait(fl->fl_file, fl);
453                         break;
454                 default:
455                         BUG();
456         }
457         return res;
458 }
459
460 /*
461  * LOCK: Try to create a lock
462  *
463  *                      Programmer Harassment Alert
464  *
465  * When given a blocking lock request in a sync RPC call, the HPUX lockd
466  * will faithfully return LCK_BLOCKED but never cares to notify us when
467  * the lock could be granted. This way, our local process could hang
468  * around forever waiting for the callback.
469  *
470  *  Solution A: Implement busy-waiting
471  *  Solution B: Use the async version of the call (NLM_LOCK_{MSG,RES})
472  *
473  * For now I am implementing solution A, because I hate the idea of
474  * re-implementing lockd for a third time in two months. The async
475  * calls shouldn't be too hard to do, however.
476  *
477  * This is one of the lovely things about standards in the NFS area:
478  * they're so soft and squishy you can't really blame HP for doing this.
479  */
480 static int
481 nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
482 {
483         struct nlm_host *host = req->a_host;
484         struct nlm_res  *resp = &req->a_res;
485         struct nlm_wait *block = NULL;
486         unsigned char fl_flags = fl->fl_flags;
487         int status = -ENOLCK;
488
489         if (nsm_monitor(host) < 0) {
490                 printk(KERN_NOTICE "lockd: failed to monitor %s\n",
491                                         host->h_name);
492                 goto out;
493         }
494         fl->fl_flags |= FL_ACCESS;
495         status = do_vfs_lock(fl);
496         if (status < 0)
497                 goto out;
498
499         block = nlmclnt_prepare_block(host, fl);
500 again:
501         for(;;) {
502                 /* Reboot protection */
503                 fl->fl_u.nfs_fl.state = host->h_state;
504                 status = nlmclnt_call(req, NLMPROC_LOCK);
505                 if (status < 0)
506                         goto out_unblock;
507                 if (!req->a_args.block)
508                         break;
509                 /* Did a reclaimer thread notify us of a server reboot? */
510                 if (resp->status ==  nlm_lck_denied_grace_period)
511                         continue;
512                 if (resp->status != nlm_lck_blocked)
513                         break;
514                 /* Wait on an NLM blocking lock */
515                 status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
516                 /* if we were interrupted. Send a CANCEL request to the server
517                  * and exit
518                  */
519                 if (status < 0)
520                         goto out_unblock;
521                 if (resp->status != nlm_lck_blocked)
522                         break;
523         }
524
525         if (resp->status == nlm_granted) {
526                 down_read(&host->h_rwsem);
527                 /* Check whether or not the server has rebooted */
528                 if (fl->fl_u.nfs_fl.state != host->h_state) {
529                         up_read(&host->h_rwsem);
530                         goto again;
531                 }
532                 /* Ensure the resulting lock will get added to granted list */
533                 fl->fl_flags = fl_flags | FL_SLEEP;
534                 if (do_vfs_lock(fl) < 0)
535                         printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
536                 up_read(&host->h_rwsem);
537         }
538         status = nlm_stat_to_errno(resp->status);
539 out_unblock:
540         nlmclnt_finish_block(block);
541         /* Cancel the blocked request if it is still pending */
542         if (resp->status == nlm_lck_blocked)
543                 nlmclnt_cancel(host, req->a_args.block, fl);
544 out:
545         nlm_release_call(req);
546         fl->fl_flags = fl_flags;
547         return status;
548 }
549
550 /*
551  * RECLAIM: Try to reclaim a lock
552  */
553 int
554 nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
555 {
556         struct nlm_rqst reqst, *req;
557         int             status;
558
559         req = &reqst;
560         memset(req, 0, sizeof(*req));
561         locks_init_lock(&req->a_args.lock.fl);
562         locks_init_lock(&req->a_res.lock.fl);
563         req->a_host  = host;
564         req->a_flags = 0;
565
566         /* Set up the argument struct */
567         nlmclnt_setlockargs(req, fl);
568         req->a_args.reclaim = 1;
569
570         if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0
571          && req->a_res.status == nlm_granted)
572                 return 0;
573
574         printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
575                                 "(errno %d, status %d)\n", fl->fl_pid,
576                                 status, ntohl(req->a_res.status));
577
578         /*
579          * FIXME: This is a serious failure. We can
580          *
581          *  a.  Ignore the problem
582          *  b.  Send the owning process some signal (Linux doesn't have
583          *      SIGLOST, though...)
584          *  c.  Retry the operation
585          *
586          * Until someone comes up with a simple implementation
587          * for b or c, I'll choose option a.
588          */
589
590         return -ENOLCK;
591 }
592
593 /*
594  * UNLOCK: remove an existing lock
595  */
596 static int
597 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
598 {
599         struct nlm_host *host = req->a_host;
600         struct nlm_res  *resp = &req->a_res;
601         int status = 0;
602
603         /*
604          * Note: the server is supposed to either grant us the unlock
605          * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
606          * case, we want to unlock.
607          */
608         fl->fl_flags |= FL_EXISTS;
609         down_read(&host->h_rwsem);
610         if (do_vfs_lock(fl) == -ENOENT) {
611                 up_read(&host->h_rwsem);
612                 goto out;
613         }
614         up_read(&host->h_rwsem);
615
616         if (req->a_flags & RPC_TASK_ASYNC)
617                 return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
618
619         status = nlmclnt_call(req, NLMPROC_UNLOCK);
620         if (status < 0)
621                 goto out;
622
623         if (resp->status == nlm_granted)
624                 goto out;
625
626         if (resp->status != nlm_lck_denied_nolocks)
627                 printk("lockd: unexpected unlock status: %d\n", resp->status);
628         /* What to do now? I'm out of my depth... */
629         status = -ENOLCK;
630 out:
631         nlm_release_call(req);
632         return status;
633 }
634
635 static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
636 {
637         struct nlm_rqst *req = data;
638         u32 status = ntohl(req->a_res.status);
639
640         if (RPC_ASSASSINATED(task))
641                 goto die;
642
643         if (task->tk_status < 0) {
644                 dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
645                 goto retry_rebind;
646         }
647         if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
648                 rpc_delay(task, NLMCLNT_GRACE_WAIT);
649                 goto retry_unlock;
650         }
651         if (status != NLM_LCK_GRANTED)
652                 printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
653 die:
654         return;
655  retry_rebind:
656         nlm_rebind_host(req->a_host);
657  retry_unlock:
658         rpc_restart_call(task);
659 }
660
661 static const struct rpc_call_ops nlmclnt_unlock_ops = {
662         .rpc_call_done = nlmclnt_unlock_callback,
663         .rpc_release = nlmclnt_rpc_release,
664 };
665
666 /*
667  * Cancel a blocked lock request.
668  * We always use an async RPC call for this in order not to hang a
669  * process that has been Ctrl-C'ed.
670  */
671 static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
672 {
673         struct nlm_rqst *req;
674         unsigned long   flags;
675         sigset_t        oldset;
676         int             status;
677
678         /* Block all signals while setting up call */
679         spin_lock_irqsave(&current->sighand->siglock, flags);
680         oldset = current->blocked;
681         sigfillset(&current->blocked);
682         recalc_sigpending();
683         spin_unlock_irqrestore(&current->sighand->siglock, flags);
684
685         req = nlm_alloc_call(nlm_get_host(host));
686         if (!req)
687                 return -ENOMEM;
688         req->a_flags = RPC_TASK_ASYNC;
689
690         nlmclnt_setlockargs(req, fl);
691         req->a_args.block = block;
692
693         status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
694
695         spin_lock_irqsave(&current->sighand->siglock, flags);
696         current->blocked = oldset;
697         recalc_sigpending();
698         spin_unlock_irqrestore(&current->sighand->siglock, flags);
699
700         return status;
701 }
702
703 static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
704 {
705         struct nlm_rqst *req = data;
706         u32 status = ntohl(req->a_res.status);
707
708         if (RPC_ASSASSINATED(task))
709                 goto die;
710
711         if (task->tk_status < 0) {
712                 dprintk("lockd: CANCEL call error %d, retrying.\n",
713                                         task->tk_status);
714                 goto retry_cancel;
715         }
716
717         dprintk("lockd: cancel status %u (task %u)\n",
718                         status, task->tk_pid);
719
720         switch (status) {
721         case NLM_LCK_GRANTED:
722         case NLM_LCK_DENIED_GRACE_PERIOD:
723         case NLM_LCK_DENIED:
724                 /* Everything's good */
725                 break;
726         case NLM_LCK_DENIED_NOLOCKS:
727                 dprintk("lockd: CANCEL failed (server has no locks)\n");
728                 goto retry_cancel;
729         default:
730                 printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n",
731                         status);
732         }
733
734 die:
735         return;
736
737 retry_cancel:
738         /* Don't ever retry more than 3 times */
739         if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
740                 goto die;
741         nlm_rebind_host(req->a_host);
742         rpc_restart_call(task);
743         rpc_delay(task, 30 * HZ);
744 }
745
746 static const struct rpc_call_ops nlmclnt_cancel_ops = {
747         .rpc_call_done = nlmclnt_cancel_callback,
748         .rpc_release = nlmclnt_rpc_release,
749 };
750
751 /*
752  * Convert an NLM status code to a generic kernel errno
753  */
754 static int
755 nlm_stat_to_errno(__be32 status)
756 {
757         switch(ntohl(status)) {
758         case NLM_LCK_GRANTED:
759                 return 0;
760         case NLM_LCK_DENIED:
761                 return -EAGAIN;
762         case NLM_LCK_DENIED_NOLOCKS:
763         case NLM_LCK_DENIED_GRACE_PERIOD:
764                 return -ENOLCK;
765         case NLM_LCK_BLOCKED:
766                 printk(KERN_NOTICE "lockd: unexpected status NLM_BLOCKED\n");
767                 return -ENOLCK;
768 #ifdef CONFIG_LOCKD_V4
769         case NLM_DEADLCK:
770                 return -EDEADLK;
771         case NLM_ROFS:
772                 return -EROFS;
773         case NLM_STALE_FH:
774                 return -ESTALE;
775         case NLM_FBIG:
776                 return -EOVERFLOW;
777         case NLM_FAILED:
778                 return -ENOLCK;
779 #endif
780         }
781         printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
782         return -ENOLCK;
783 }