The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/lockd/clntproc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: f521481e81170267ddcbf9febea9df09


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.