~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/lockd/clntproc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/types.h>
 10 #include <linux/errno.h>
 11 #include <linux/fs.h>
 12 #include <linux/nfs_fs.h>
 13 #include <linux/utsname.h>
 14 #include <linux/smp_lock.h>
 15 #include <linux/sunrpc/clnt.h>
 16 #include <linux/sunrpc/svc.h>
 17 #include <linux/lockd/lockd.h>
 18 #include <linux/lockd/sm_inter.h>
 19 
 20 #define NLMDBG_FACILITY         NLMDBG_CLIENT
 21 
 22 static int      nlmclnt_test(struct nlm_rqst *, struct file_lock *);
 23 static int      nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
 24 static int      nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
 25 static void     nlmclnt_unlock_callback(struct rpc_task *);
 26 static void     nlmclnt_cancel_callback(struct rpc_task *);
 27 static int      nlm_stat_to_errno(u32 stat);
 28 
 29 /*
 30  * Cookie counter for NLM requests
 31  */
 32 static u32      nlm_cookie = 0x1234;
 33 
 34 static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
 35 {
 36         memcpy(c->data, &nlm_cookie, 4);
 37         memset(c->data+4, 0, 4);
 38         c->len=4;
 39         nlm_cookie++;
 40 }
 41 
 42 /*
 43  * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
 44  */
 45 static inline void
 46 nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
 47 {
 48         struct nlm_args *argp = &req->a_args;
 49         struct nlm_lock *lock = &argp->lock;
 50 
 51         nlmclnt_next_cookie(&argp->cookie);
 52         argp->state   = nsm_local_state;
 53         memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
 54         lock->caller  = system_utsname.nodename;
 55         lock->oh.data = req->a_owner;
 56         lock->oh.len  = sprintf(req->a_owner, "%d@%s",
 57                                 current->pid, system_utsname.nodename);
 58         locks_copy_lock(&lock->fl, fl);
 59 }
 60 
 61 /*
 62  * Initialize arguments for GRANTED call. The nlm_rqst structure
 63  * has been cleared already.
 64  */
 65 int
 66 nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
 67 {
 68         locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
 69         memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
 70         call->a_args.lock.caller = system_utsname.nodename;
 71         call->a_args.lock.oh.len = lock->oh.len;
 72 
 73         /* set default data area */
 74         call->a_args.lock.oh.data = call->a_owner;
 75 
 76         if (lock->oh.len > NLMCLNT_OHSIZE) {
 77                 void *data = kmalloc(lock->oh.len, GFP_KERNEL);
 78                 if (!data)
 79                         return 0;
 80                 call->a_args.lock.oh.data = (u8 *) data;
 81         }
 82 
 83         memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
 84         return 1;
 85 }
 86 
 87 void
 88 nlmclnt_freegrantargs(struct nlm_rqst *call)
 89 {
 90         /*
 91          * Check whether we allocated memory for the owner.
 92          */
 93         if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
 94                 kfree(call->a_args.lock.oh.data);
 95         }
 96 }
 97 
 98 /*
 99  * This is the main entry point for the NLM client.
100  */
101 int
102 nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
103 {
104         struct nfs_server       *nfssrv = NFS_SERVER(inode);
105         struct nlm_host         *host;
106         struct nlm_rqst         reqst, *call = &reqst;
107         sigset_t                oldset;
108         unsigned long           flags;
109         int                     status, proto, vers;
110 
111         vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
112         if (NFS_PROTO(inode)->version > 3) {
113                 printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
114                 return -ENOLCK;
115         }
116 
117         /* Retrieve transport protocol from NFS client */
118         proto = NFS_CLIENT(inode)->cl_xprt->prot;
119 
120         if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
121                 return -ENOLCK;
122 
123         /* Create RPC client handle if not there, and copy soft
124          * and intr flags from NFS client. */
125         if (host->h_rpcclnt == NULL) {
126                 struct rpc_clnt *clnt;
127 
128                 /* Bind an rpc client to this host handle (does not
129                  * perform a portmapper lookup) */
130                 if (!(clnt = nlm_bind_host(host))) {
131                         status = -ENOLCK;
132                         goto done;
133                 }
134                 clnt->cl_softrtry = nfssrv->client->cl_softrtry;
135                 clnt->cl_intr     = nfssrv->client->cl_intr;
136                 clnt->cl_chatty   = nfssrv->client->cl_chatty;
137         }
138 
139         /* Keep the old signal mask */
140         spin_lock_irqsave(&current->sigmask_lock, flags);
141         oldset = current->blocked;
142 
143         /* If we're cleaning up locks because the process is exiting,
144          * perform the RPC call asynchronously. */
145         if ((cmd == F_SETLK || cmd == F_SETLKW)
146             && fl->fl_type == F_UNLCK
147             && (current->flags & PF_EXITING)) {
148                 sigfillset(&current->blocked);  /* Mask all signals */
149                 recalc_sigpending(current);
150                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
151 
152                 call = nlmclnt_alloc_call();
153                 if (!call) {
154                         status = -ENOMEM;
155                         goto out_restore;
156                 }
157                 call->a_flags = RPC_TASK_ASYNC;
158         } else {
159                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
160                 memset(call, 0, sizeof(*call));
161                 locks_init_lock(&call->a_args.lock.fl);
162                 locks_init_lock(&call->a_res.lock.fl);
163         }
164         call->a_host = host;
165 
166         /* Set up the argument struct */
167         nlmclnt_setlockargs(call, fl);
168 
169         if (cmd == F_GETLK) {
170                 status = nlmclnt_test(call, fl);
171         } else if ((cmd == F_SETLK || cmd == F_SETLKW)
172                    && fl->fl_type == F_UNLCK) {
173                 status = nlmclnt_unlock(call, fl);
174         } else if (cmd == F_SETLK || cmd == F_SETLKW) {
175                 call->a_args.block = (cmd == F_SETLKW)? 1 : 0;
176                 status = nlmclnt_lock(call, fl);
177         } else {
178                 status = -EINVAL;
179         }
180 
181         if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
182                 kfree(call);
183 
184  out_restore:
185         spin_lock_irqsave(&current->sigmask_lock, flags);
186         current->blocked = oldset;
187         recalc_sigpending(current);
188         spin_unlock_irqrestore(&current->sigmask_lock, flags);
189 
190 done:
191         dprintk("lockd: clnt proc returns %d\n", status);
192         nlm_release_host(host);
193         return status;
194 }
195 
196 /*
197  * Wait while server is in grace period
198  */
199 static inline int
200 nlmclnt_grace_wait(struct nlm_host *host)
201 {
202         if (!host->h_reclaiming)
203                 interruptible_sleep_on_timeout(&host->h_gracewait, 10*HZ);
204         else
205                 interruptible_sleep_on(&host->h_gracewait);
206         return signalled()? -ERESTARTSYS : 0;
207 }
208 
209 /*
210  * Allocate an NLM RPC call struct
211  */
212 struct nlm_rqst *
213 nlmclnt_alloc_call(void)
214 {
215         struct nlm_rqst *call;
216 
217         while (!signalled()) {
218                 call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
219                 if (call) {
220                         memset(call, 0, sizeof(*call));
221                         locks_init_lock(&call->a_args.lock.fl);
222                         locks_init_lock(&call->a_res.lock.fl);
223                         return call;
224                 }
225                 printk("nlmclnt_alloc_call: failed, waiting for memory\n");
226                 current->state = TASK_INTERRUPTIBLE;
227                 schedule_timeout(5*HZ);
228         }
229         return NULL;
230 }
231 
232 /*
233  * Generic NLM call
234  */
235 int
236 nlmclnt_call(struct nlm_rqst *req, u32 proc)
237 {
238         struct nlm_host *host = req->a_host;
239         struct rpc_clnt *clnt;
240         struct nlm_args *argp = &req->a_args;
241         struct nlm_res  *resp = &req->a_res;
242         struct file     *filp = argp->lock.fl.fl_file;
243         struct rpc_message msg;
244         int             status;
245 
246         dprintk("lockd: call procedure %s on %s\n",
247                         nlm_procname(proc), host->h_name);
248 
249         msg.rpc_proc = proc;
250         msg.rpc_argp = argp;
251         msg.rpc_resp = resp;
252         if (filp)
253                 msg.rpc_cred = nfs_file_cred(filp);
254         else
255                 msg.rpc_cred = NULL;
256 
257         do {
258                 if (host->h_reclaiming && !argp->reclaim) {
259                         interruptible_sleep_on(&host->h_gracewait);
260                         continue;
261                 }
262 
263                 /* If we have no RPC client yet, create one. */
264                 if ((clnt = nlm_bind_host(host)) == NULL)
265                         return -ENOLCK;
266 
267                 /* Perform the RPC call. If an error occurs, try again */
268                 if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
269                         dprintk("lockd: rpc_call returned error %d\n", -status);
270                         switch (status) {
271                         case -EPROTONOSUPPORT:
272                                 status = -EINVAL;
273                                 break;
274                         case -ECONNREFUSED:
275                         case -ETIMEDOUT:
276                         case -ENOTCONN:
277                                 nlm_rebind_host(host);
278                                 status = -EAGAIN;
279                                 break;
280                         case -ERESTARTSYS:
281                                 return signalled () ? -EINTR : status;
282                         default:
283                                 break;
284                         }
285                         break;
286                 } else
287                 if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
288                         dprintk("lockd: server in grace period\n");
289                         if (argp->reclaim) {
290                                 printk(KERN_WARNING
291                                      "lockd: spurious grace period reject?!\n");
292                                 return -ENOLCK;
293                         }
294                 } else {
295                         dprintk("lockd: server returns status %d\n", resp->status);
296                         return 0;       /* Okay, call complete */
297                 }
298 
299                 /* Back off a little and try again */
300                 interruptible_sleep_on_timeout(&host->h_gracewait, 15*HZ);
301 
302                 /* When the lock requested by F_SETLKW isn't available,
303                    we will wait until the request can be satisfied. If
304                    a signal is received during wait, we should return
305                    -EINTR. */
306                 if (signalled ()) {
307                         status = -EINTR;
308                         break;
309                 }
310         } while (1);
311 
312         return status;
313 }
314 
315 /*
316  * Generic NLM call, async version.
317  */
318 int
319 nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
320 {
321         struct nlm_host *host = req->a_host;
322         struct rpc_clnt *clnt;
323         struct nlm_args *argp = &req->a_args;
324         struct nlm_res  *resp = &req->a_res;
325         struct rpc_message msg;
326         int             status;
327 
328         dprintk("lockd: call procedure %s on %s (async)\n",
329                         nlm_procname(proc), host->h_name);
330 
331         /* If we have no RPC client yet, create one. */
332         if ((clnt = nlm_bind_host(host)) == NULL)
333                 return -ENOLCK;
334 
335         /* bootstrap and kick off the async RPC call */
336         msg.rpc_proc = proc;
337         msg.rpc_argp = argp;
338         msg.rpc_resp =resp;
339         msg.rpc_cred = NULL;    
340         status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
341 
342         return status;
343 }
344 
345 int
346 nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
347 {
348         struct nlm_host *host = req->a_host;
349         struct rpc_clnt *clnt;
350         struct nlm_args *argp = &req->a_args;
351         struct nlm_res  *resp = &req->a_res;
352         struct file     *file = argp->lock.fl.fl_file;
353         struct rpc_message msg;
354         int             status;
355 
356         dprintk("lockd: call procedure %s on %s (async)\n",
357                         nlm_procname(proc), host->h_name);
358 
359         /* If we have no RPC client yet, create one. */
360         if ((clnt = nlm_bind_host(host)) == NULL)
361                 return -ENOLCK;
362 
363         /* bootstrap and kick off the async RPC call */
364         msg.rpc_proc = proc;
365         msg.rpc_argp = argp;
366         msg.rpc_resp =resp;
367         if (file)
368                 msg.rpc_cred = nfs_file_cred(file);
369         else
370                 msg.rpc_cred = NULL;
371         /* Increment host refcount */
372         nlm_get_host(host);
373         status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
374         if (status < 0)
375                 nlm_release_host(host);
376         return status;
377 }
378 
379 /*
380  * TEST for the presence of a conflicting lock
381  */
382 static int
383 nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
384 {
385         int     status;
386 
387         if ((status = nlmclnt_call(req, NLMPROC_TEST)) < 0)
388                 return status;
389 
390         status = req->a_res.status;
391         if (status == NLM_LCK_GRANTED) {
392                 fl->fl_type = F_UNLCK;
393         } if (status == NLM_LCK_DENIED) {
394                 /*
395                  * Report the conflicting lock back to the application.
396                  * FIXME: Is it OK to report the pid back as well?
397                  */
398                 locks_copy_lock(fl, &req->a_res.lock.fl);
399                 /* fl->fl_pid = 0; */
400         } else {
401                 return nlm_stat_to_errno(req->a_res.status);
402         }
403 
404         return 0;
405 }
406 
407 static
408 void nlmclnt_insert_lock_callback(struct file_lock *fl)
409 {
410         nlm_get_host(fl->fl_u.nfs_fl.host);
411 }
412 static
413 void nlmclnt_remove_lock_callback(struct file_lock *fl)
414 {
415         if (fl->fl_u.nfs_fl.host) {
416                 nlm_release_host(fl->fl_u.nfs_fl.host);
417                 fl->fl_u.nfs_fl.host = NULL;
418         }
419 }
420 
421 /*
422  * LOCK: Try to create a lock
423  *
424  *                      Programmer Harassment Alert
425  *
426  * When given a blocking lock request in a sync RPC call, the HPUX lockd
427  * will faithfully return LCK_BLOCKED but never cares to notify us when
428  * the lock could be granted. This way, our local process could hang
429  * around forever waiting for the callback.
430  *
431  *  Solution A: Implement busy-waiting
432  *  Solution B: Use the async version of the call (NLM_LOCK_{MSG,RES})
433  *
434  * For now I am implementing solution A, because I hate the idea of
435  * re-implementing lockd for a third time in two months. The async
436  * calls shouldn't be too hard to do, however.
437  *
438  * This is one of the lovely things about standards in the NFS area:
439  * they're so soft and squishy you can't really blame HP for doing this.
440  */
441 static int
442 nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
443 {
444         struct nlm_host *host = req->a_host;
445         struct nlm_res  *resp = &req->a_res;
446         int             status;
447 
448         if (!host->h_monitored && nsm_monitor(host) < 0) {
449                 printk(KERN_NOTICE "lockd: failed to monitor %s\n",
450                                         host->h_name);
451                 return -ENOLCK;
452         }
453 
454         do {
455                 if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
456                         if (resp->status != NLM_LCK_BLOCKED)
457                                 break;
458                         status = nlmclnt_block(host, fl, &resp->status);
459                 }
460                 if (status < 0)
461                         return status;
462         } while (resp->status == NLM_LCK_BLOCKED);
463 
464         if (resp->status == NLM_LCK_GRANTED) {
465                 fl->fl_u.nfs_fl.state = host->h_state;
466                 fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
467                 fl->fl_u.nfs_fl.host = host;
468                 fl->fl_insert = nlmclnt_insert_lock_callback;
469                 fl->fl_remove = nlmclnt_remove_lock_callback;
470         }
471 
472         return nlm_stat_to_errno(resp->status);
473 }
474 
475 /*
476  * RECLAIM: Try to reclaim a lock
477  */
478 int
479 nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
480 {
481         struct nlm_rqst reqst, *req;
482         int             status;
483 
484         req = &reqst;
485         memset(req, 0, sizeof(*req));
486         locks_init_lock(&req->a_args.lock.fl);
487         locks_init_lock(&req->a_res.lock.fl);
488         req->a_host  = host;
489         req->a_flags = 0;
490 
491         /* Set up the argument struct */
492         nlmclnt_setlockargs(req, fl);
493         req->a_args.reclaim = 1;
494 
495         if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0
496          && req->a_res.status == NLM_LCK_GRANTED)
497                 return 0;
498 
499         printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
500                                 "(errno %d, status %d)\n", fl->fl_pid,
501                                 status, req->a_res.status);
502 
503         /*
504          * FIXME: This is a serious failure. We can
505          *
506          *  a.  Ignore the problem
507          *  b.  Send the owning process some signal (Linux doesn't have
508          *      SIGLOST, though...)
509          *  c.  Retry the operation
510          *
511          * Until someone comes up with a simple implementation
512          * for b or c, I'll choose option a.
513          */
514 
515         return -ENOLCK;
516 }
517 
518 /*
519  * UNLOCK: remove an existing lock
520  */
521 static int
522 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
523 {
524         struct nlm_res  *resp = &req->a_res;
525         int             status;
526 
527         /* Clean the GRANTED flag now so the lock doesn't get
528          * reclaimed while we're stuck in the unlock call. */
529         fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
530 
531         if (req->a_flags & RPC_TASK_ASYNC) {
532                 return nlmclnt_async_call(req, NLMPROC_UNLOCK,
533                                         nlmclnt_unlock_callback);
534         }
535 
536         if ((status = nlmclnt_call(req, NLMPROC_UNLOCK)) < 0)
537                 return status;
538 
539         if (resp->status == NLM_LCK_GRANTED)
540                 return 0;
541 
542         if (resp->status != NLM_LCK_DENIED_NOLOCKS)
543                 printk("lockd: unexpected unlock status: %d\n", resp->status);
544 
545         /* What to do now? I'm out of my depth... */
546 
547         return -ENOLCK;
548 }
549 
550 static void
551 nlmclnt_unlock_callback(struct rpc_task *task)
552 {
553         struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata;
554         int             status = req->a_res.status;
555 
556         if (RPC_ASSASSINATED(task))
557                 goto die;
558 
559         if (task->tk_status < 0) {
560                 dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
561                 goto retry_unlock;
562         }
563         if (status != NLM_LCK_GRANTED
564          && status != NLM_LCK_DENIED_GRACE_PERIOD) {
565                 printk("lockd: unexpected unlock status: %d\n", status);
566         }
567 
568 die:
569         nlm_release_host(req->a_host);
570         kfree(req);
571         return;
572  retry_unlock:
573         nlm_rebind_host(req->a_host);
574         rpc_restart_call(task);
575 }
576 
577 /*
578  * Cancel a blocked lock request.
579  * We always use an async RPC call for this in order not to hang a
580  * process that has been Ctrl-C'ed.
581  */
582 int
583 nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
584 {
585         struct nlm_rqst *req;
586         unsigned long   flags;
587         sigset_t        oldset;
588         int             status;
589 
590         /* Block all signals while setting up call */
591         spin_lock_irqsave(&current->sigmask_lock, flags);
592         oldset = current->blocked;
593         sigfillset(&current->blocked);
594         recalc_sigpending(current);
595         spin_unlock_irqrestore(&current->sigmask_lock, flags);
596 
597         req = nlmclnt_alloc_call();
598         if (!req)
599                 return -ENOMEM;
600         req->a_host  = host;
601         req->a_flags = RPC_TASK_ASYNC;
602 
603         nlmclnt_setlockargs(req, fl);
604 
605         status = nlmclnt_async_call(req, NLMPROC_CANCEL,
606                                         nlmclnt_cancel_callback);
607         if (status < 0)
608                 kfree(req);
609 
610         spin_lock_irqsave(&current->sigmask_lock, flags);
611         current->blocked = oldset;
612         recalc_sigpending(current);
613         spin_unlock_irqrestore(&current->sigmask_lock, flags);
614 
615         return status;
616 }
617 
618 static void
619 nlmclnt_cancel_callback(struct rpc_task *task)
620 {
621         struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata;
622 
623         if (RPC_ASSASSINATED(task))
624                 goto die;
625 
626         if (task->tk_status < 0) {
627                 dprintk("lockd: CANCEL call error %d, retrying.\n",
628                                         task->tk_status);
629                 goto retry_cancel;
630         }
631 
632         dprintk("lockd: cancel status %d (task %d)\n",
633                         req->a_res.status, task->tk_pid);
634 
635         switch (req->a_res.status) {
636         case NLM_LCK_GRANTED:
637         case NLM_LCK_DENIED_GRACE_PERIOD:
638                 /* Everything's good */
639                 break;
640         case NLM_LCK_DENIED_NOLOCKS:
641                 dprintk("lockd: CANCEL failed (server has no locks)\n");
642                 goto retry_cancel;
643         default:
644                 printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n",
645                         req->a_res.status);
646         }
647 
648 die:
649         nlm_release_host(req->a_host);
650         kfree(req);
651         return;
652 
653 retry_cancel:
654         nlm_rebind_host(req->a_host);
655         rpc_restart_call(task);
656         rpc_delay(task, 30 * HZ);
657 }
658 
659 /*
660  * Convert an NLM status code to a generic kernel errno
661  */
662 static int
663 nlm_stat_to_errno(u32 status)
664 {
665         switch(status) {
666         case NLM_LCK_GRANTED:
667                 return 0;
668         case NLM_LCK_DENIED:
669                 return -EAGAIN;
670         case NLM_LCK_DENIED_NOLOCKS:
671         case NLM_LCK_DENIED_GRACE_PERIOD:
672                 return -ENOLCK;
673         case NLM_LCK_BLOCKED:
674                 printk(KERN_NOTICE "lockd: unexpected status NLM_BLOCKED\n");
675                 return -ENOLCK;
676         }
677         printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
678         return -ENOLCK;
679 }
680 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.