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/svclock.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/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=%x\n",
  117                                 block->b_file, fl->fl_pid,
  118                                 (long long)fl->fl_start,
  119                                 (long long)fl->fl_end, fl->fl_type,
  120                                 *(unsigned int*)(block->b_call.a_args.cookie.data));
  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)
  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                         break;
  155         }
  156 
  157         return block;
  158 }
  159 
  160 /*
  161  * Create a block and initialize it.
  162  *
  163  * Note: we explicitly set the cookie of the grant reply to that of
  164  * the blocked lock request. The spec explicitly mentions that the client
  165  * should _not_ rely on the callback containing the same cookie as the
  166  * request, but (as I found out later) that's because some implementations
  167  * do just this. Never mind the standards comittees, they support our
  168  * logging industries.
  169  */
  170 static inline struct nlm_block *
  171 nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
  172                                 struct nlm_lock *lock, struct nlm_cookie *cookie)
  173 {
  174         struct nlm_block        *block;
  175         struct nlm_host         *host;
  176         struct nlm_rqst         *call;
  177 
  178         /* Create host handle for callback */
  179         host = nlmclnt_lookup_host(&rqstp->rq_addr,
  180                                 rqstp->rq_prot, rqstp->rq_vers);
  181         if (host == NULL)
  182                 return NULL;
  183 
  184         /* Allocate memory for block, and initialize arguments */
  185         if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))
  186                 goto failed;
  187         memset(block, 0, sizeof(*block));
  188         locks_init_lock(&block->b_call.a_args.lock.fl);
  189         locks_init_lock(&block->b_call.a_res.lock.fl);
  190 
  191         if (!nlmclnt_setgrantargs(&block->b_call, lock))
  192                 goto failed_free;
  193 
  194         /* Set notifier function for VFS, and init args */
  195         block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;
  196         block->b_call.a_args.cookie = *cookie;  /* see above */
  197 
  198         dprintk("lockd: created block %p...\n", block);
  199 
  200         /* Create and initialize the block */
  201         block->b_daemon = rqstp->rq_server;
  202         block->b_host   = host;
  203         block->b_file   = file;
  204 
  205         /* Add to file's list of blocks */
  206         block->b_fnext  = file->f_blocks;
  207         file->f_blocks  = block;
  208 
  209         /* Set up RPC arguments for callback */
  210         call = &block->b_call;
  211         call->a_host    = host;
  212         call->a_flags   = RPC_TASK_ASYNC;
  213 
  214         return block;
  215 
  216 failed_free:
  217         kfree(block);
  218 failed:
  219         nlm_release_host(host);
  220         return NULL;
  221 }
  222 
  223 /*
  224  * Delete a block. If the lock was cancelled or the grant callback
  225  * failed, unlock is set to 1.
  226  * It is the caller's responsibility to check whether the file
  227  * can be closed hereafter.
  228  */
  229 static void
  230 nlmsvc_delete_block(struct nlm_block *block, int unlock)
  231 {
  232         struct file_lock        *fl = &block->b_call.a_args.lock.fl;
  233         struct nlm_file         *file = block->b_file;
  234         struct nlm_block        **bp;
  235 
  236         dprintk("lockd: deleting block %p...\n", block);
  237 
  238         /* Remove block from list */
  239         nlmsvc_remove_block(block);
  240 
  241         /* If granted, unlock it, else remove from inode block list */
  242         if (unlock && block->b_granted) {
  243                 dprintk("lockd: deleting granted lock\n");
  244                 fl->fl_type = F_UNLCK;
  245                 posix_lock_file(&block->b_file->f_file, fl, 0);
  246                 block->b_granted = 0;
  247         } else {
  248                 dprintk("lockd: unblocking blocked lock\n");
  249                 posix_unblock_lock(fl);
  250         }
  251 
  252         /* If the block is in the middle of a GRANT callback,
  253          * don't kill it yet. */
  254         if (block->b_incall) {
  255                 nlmsvc_insert_block(block, NLM_NEVER);
  256                 block->b_done = 1;
  257                 return;
  258         }
  259 
  260         /* Remove block from file's list of blocks */
  261         for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
  262                 if (*bp == block) {
  263                         *bp = block->b_fnext;
  264                         break;
  265                 }
  266         }
  267 
  268         if (block->b_host)
  269                 nlm_release_host(block->b_host);
  270         nlmclnt_freegrantargs(&block->b_call);
  271         kfree(block);
  272 }
  273 
  274 /*
  275  * Loop over all blocks and perform the action specified.
  276  * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
  277  */
  278 int
  279 nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
  280 {
  281         struct nlm_block        *block, *next;
  282 
  283         down(&file->f_sema);
  284         for (block = file->f_blocks; block; block = next) {
  285                 next = block->b_fnext;
  286                 if (action == NLM_ACT_MARK)
  287                         block->b_host->h_inuse = 1;
  288                 else if (action == NLM_ACT_UNLOCK) {
  289                         if (host == NULL || host == block->b_host)
  290                                 nlmsvc_delete_block(block, 1);
  291                 }
  292         }
  293         up(&file->f_sema);
  294         return 0;
  295 }
  296 
  297 /*
  298  * Attempt to establish a lock, and if it can't be granted, block it
  299  * if required.
  300  */
  301 u32
  302 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
  303                         struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
  304 {
  305         struct file_lock        *conflock;
  306         struct nlm_block        *block;
  307         int                     error;
  308 
  309         dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
  310                                 file->f_file.f_dentry->d_inode->i_dev,
  311                                 file->f_file.f_dentry->d_inode->i_ino,
  312                                 lock->fl.fl_type, lock->fl.fl_pid,
  313                                 (long long)lock->fl.fl_start,
  314                                 (long long)lock->fl.fl_end,
  315                                 wait);
  316 
  317         /* Lock file against concurrent access */
  318         down(&file->f_sema);
  319 
  320         /* Get existing block (in case client is busy-waiting) */
  321         block = nlmsvc_lookup_block(file, lock, 0);
  322 
  323         lock->fl.fl_flags |= FL_LOCKD;
  324 
  325 again:
  326         if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
  327                 error = posix_lock_file(&file->f_file, &lock->fl, 0);
  328 
  329                 if (block)
  330                         nlmsvc_delete_block(block, 0);
  331                 up(&file->f_sema);
  332 
  333                 dprintk("lockd: posix_lock_file returned %d\n", -error);
  334                 switch(-error) {
  335                 case 0:
  336                         return nlm_granted;
  337                 case EDEADLK:
  338                         return nlm_deadlock;
  339                 case EAGAIN:
  340                         return nlm_lck_denied;
  341                 default:                        /* includes ENOLCK */
  342                         return nlm_lck_denied_nolocks;
  343                 }
  344         }
  345 
  346         if (!wait) {
  347                 up(&file->f_sema);
  348                 return nlm_lck_denied;
  349         }
  350 
  351         if (posix_locks_deadlock(&lock->fl, conflock)) {
  352                 up(&file->f_sema);
  353                 return nlm_deadlock;
  354         }
  355 
  356         /* If we don't have a block, create and initialize it. Then
  357          * retry because we may have slept in kmalloc. */
  358         if (block == NULL) {
  359                 dprintk("lockd: blocking on this lock (allocating).\n");
  360                 if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
  361                         return nlm_lck_denied_nolocks;
  362                 goto again;
  363         }
  364 
  365         /* Append to list of blocked */
  366         nlmsvc_insert_block(block, NLM_NEVER);
  367 
  368         if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
  369                 /* Now add block to block list of the conflicting lock
  370                    if we haven't done so. */
  371                 dprintk("lockd: blocking on this lock.\n");
  372                 posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
  373         }
  374 
  375         up(&file->f_sema);
  376         return nlm_lck_blocked;
  377 }
  378 
  379 /*
  380  * Test for presence of a conflicting lock.
  381  */
  382 u32
  383 nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
  384                                        struct nlm_lock *conflock)
  385 {
  386         struct file_lock        *fl;
  387 
  388         dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
  389                                 file->f_file.f_dentry->d_inode->i_dev,
  390                                 file->f_file.f_dentry->d_inode->i_ino,
  391                                 lock->fl.fl_type,
  392                                 (long long)lock->fl.fl_start,
  393                                 (long long)lock->fl.fl_end);
  394 
  395         if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
  396                 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
  397                                 fl->fl_type, (long long)fl->fl_start,
  398                                 (long long)fl->fl_end);
  399                 conflock->caller = "somehost";  /* FIXME */
  400                 conflock->oh.len = 0;           /* don't return OH info */
  401                 conflock->fl = *fl;
  402                 return nlm_lck_denied;
  403         }
  404 
  405         return nlm_granted;
  406 }
  407 
  408 /*
  409  * Remove a lock.
  410  * This implies a CANCEL call: We send a GRANT_MSG, the client replies
  411  * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
  412  * afterwards. In this case the block will still be there, and hence
  413  * must be removed.
  414  */
  415 u32
  416 nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
  417 {
  418         int     error;
  419 
  420         dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
  421                                 file->f_file.f_dentry->d_inode->i_dev,
  422                                 file->f_file.f_dentry->d_inode->i_ino,
  423                                 lock->fl.fl_pid,
  424                                 (long long)lock->fl.fl_start,
  425                                 (long long)lock->fl.fl_end);
  426 
  427         /* First, cancel any lock that might be there */
  428         nlmsvc_cancel_blocked(file, lock);
  429 
  430         lock->fl.fl_type = F_UNLCK;
  431         error = posix_lock_file(&file->f_file, &lock->fl, 0);
  432 
  433         return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
  434 }
  435 
  436 /*
  437  * Cancel a previously blocked request.
  438  *
  439  * A cancel request always overrides any grant that may currently
  440  * be in progress.
  441  * The calling procedure must check whether the file can be closed.
  442  */
  443 u32
  444 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
  445 {
  446         struct nlm_block        *block;
  447 
  448         dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
  449                                 file->f_file.f_dentry->d_inode->i_dev,
  450                                 file->f_file.f_dentry->d_inode->i_ino,
  451                                 lock->fl.fl_pid,
  452                                 (long long)lock->fl.fl_start,
  453                                 (long long)lock->fl.fl_end);
  454 
  455         down(&file->f_sema);
  456         if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
  457                 nlmsvc_delete_block(block, 1);
  458         up(&file->f_sema);
  459         return nlm_granted;
  460 }
  461 
  462 /*
  463  * Unblock a blocked lock request. This is a callback invoked from the
  464  * VFS layer when a lock on which we blocked is removed.
  465  *
  466  * This function doesn't grant the blocked lock instantly, but rather moves
  467  * the block to the head of nlm_blocked where it can be picked up by lockd.
  468  */
  469 static void
  470 nlmsvc_notify_blocked(struct file_lock *fl)
  471 {
  472         struct nlm_block        **bp, *block;
  473 
  474         dprintk("lockd: VFS unblock notification for block %p\n", fl);
  475         posix_unblock_lock(fl);
  476         for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
  477                 if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
  478                         nlmsvc_insert_block(block, 0);
  479                         svc_wake_up(block->b_daemon);
  480                         return;
  481                 }
  482         }
  483 
  484         printk(KERN_WARNING "lockd: notification for unknown block!\n");
  485 }
  486 
  487 /*
  488  * Try to claim a lock that was previously blocked.
  489  *
  490  * Note that we use both the RPC_GRANTED_MSG call _and_ an async
  491  * RPC thread when notifying the client. This seems like overkill...
  492  * Here's why:
  493  *  -   we don't want to use a synchronous RPC thread, otherwise
  494  *      we might find ourselves hanging on a dead portmapper.
  495  *  -   Some lockd implementations (e.g. HP) don't react to
  496  *      RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
  497  */
  498 static void
  499 nlmsvc_grant_blocked(struct nlm_block *block)
  500 {
  501         struct nlm_file         *file = block->b_file;
  502         struct nlm_lock         *lock = &block->b_call.a_args.lock;
  503         struct file_lock        *conflock;
  504         int                     error;
  505 
  506         dprintk("lockd: grant blocked lock %p\n", block);
  507 
  508         /* First thing is lock the file */
  509         down(&file->f_sema);
  510 
  511         /* Unlink block request from list */
  512         nlmsvc_remove_block(block);
  513 
  514         /* If b_granted is true this means we've been here before.
  515          * Just retry the grant callback, possibly refreshing the RPC
  516          * binding */
  517         if (block->b_granted) {
  518                 nlm_rebind_host(block->b_host);
  519                 goto callback;
  520         }
  521 
  522         /* Try the lock operation again */
  523         if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
  524                 /* Bummer, we blocked again */
  525                 dprintk("lockd: lock still blocked\n");
  526                 nlmsvc_insert_block(block, NLM_NEVER);
  527                 posix_block_lock(conflock, &lock->fl);
  528                 up(&file->f_sema);
  529                 return;
  530         }
  531 
  532         /* Alright, no conflicting lock. Now lock it for real. If the
  533          * following yields an error, this is most probably due to low
  534          * memory. Retry the lock in a few seconds.
  535          */
  536         if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
  537                 printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
  538                                 -error, __FUNCTION__);
  539                 nlmsvc_insert_block(block, 10 * HZ);
  540                 up(&file->f_sema);
  541                 return;
  542         }
  543 
  544 callback:
  545         /* Lock was granted by VFS. */
  546         dprintk("lockd: GRANTing blocked lock.\n");
  547         block->b_granted = 1;
  548         block->b_incall  = 1;
  549 
  550         /* Schedule next grant callback in 30 seconds */
  551         nlmsvc_insert_block(block, 30 * HZ);
  552 
  553         /* Call the client */
  554         nlm_get_host(block->b_call.a_host);
  555         if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
  556                                                 nlmsvc_grant_callback) < 0)
  557                 nlm_release_host(block->b_call.a_host);
  558         up(&file->f_sema);
  559 }
  560 
  561 /*
  562  * This is the callback from the RPC layer when the NLM_GRANTED_MSG
  563  * RPC call has succeeded or timed out.
  564  * Like all RPC callbacks, it is invoked by the rpciod process, so it
  565  * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
  566  * chain once more in order to have it removed by lockd itself (which can
  567  * then sleep on the file semaphore without disrupting e.g. the nfs client).
  568  */
  569 static void
  570 nlmsvc_grant_callback(struct rpc_task *task)
  571 {
  572         struct nlm_rqst         *call = (struct nlm_rqst *) task->tk_calldata;
  573         struct nlm_block        *block;
  574         unsigned long           timeout;
  575 
  576         dprintk("lockd: GRANT_MSG RPC callback\n");
  577         dprintk("callback: looking for cookie %x \n", 
  578                 *(unsigned int *)(call->a_args.cookie.data));
  579         if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
  580                 dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
  581                 return;
  582         }
  583 
  584         /* Technically, we should down the file semaphore here. Since we
  585          * move the block towards the head of the queue only, no harm
  586          * can be done, though. */
  587         if (task->tk_status < 0) {
  588                 /* RPC error: Re-insert for retransmission */
  589                 timeout = 10 * HZ;
  590         } else if (block->b_done) {
  591                 /* Block already removed, kill it for real */
  592                 timeout = 0;
  593         } else {
  594                 /* Call was successful, now wait for client callback */
  595                 timeout = 60 * HZ;
  596         }
  597         nlmsvc_insert_block(block, timeout);
  598         svc_wake_up(block->b_daemon);
  599         block->b_incall = 0;
  600 
  601         nlm_release_host(call->a_host);
  602 }
  603 
  604 /*
  605  * We received a GRANT_RES callback. Try to find the corresponding
  606  * block.
  607  */
  608 void
  609 nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
  610 {
  611         struct nlm_block        *block;
  612         struct nlm_file         *file;
  613 
  614         if (!(block = nlmsvc_find_block(cookie)))
  615                 return;
  616         file = block->b_file;
  617 
  618         file->f_count++;
  619         down(&file->f_sema);
  620         if ((block = nlmsvc_find_block(cookie)) != NULL) {
  621                 if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
  622                         /* Try again in a couple of seconds */
  623                         nlmsvc_insert_block(block, 10 * HZ);
  624                         block = NULL;
  625                 } else {
  626                         /* Lock is now held by client, or has been rejected.
  627                          * In both cases, the block should be removed. */
  628                         file->f_count++;
  629                         up(&file->f_sema);
  630                         if (status == NLM_LCK_GRANTED)
  631                                 nlmsvc_delete_block(block, 0);
  632                         else
  633                                 nlmsvc_delete_block(block, 1);
  634                 }
  635         }
  636         if (!block)
  637                 up(&file->f_sema);
  638         nlm_release_file(file);
  639 }
  640 
  641 /*
  642  * Retry all blocked locks that have been notified. This is where lockd
  643  * picks up locks that can be granted, or grant notifications that must
  644  * be retransmitted.
  645  */
  646 unsigned long
  647 nlmsvc_retry_blocked(void)
  648 {
  649         struct nlm_block        *block;
  650 
  651         dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
  652                         nlm_blocked,
  653                         nlm_blocked? nlm_blocked->b_when : 0);
  654         while ((block = nlm_blocked)) {
  655                 if (block->b_when == NLM_NEVER)
  656                         break;
  657                 if (time_after(block->b_when,jiffies))
  658                         break;
  659                 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
  660                         block, block->b_when, block->b_done);
  661                 if (block->b_done)
  662                         nlmsvc_delete_block(block, 0);
  663                 else
  664                         nlmsvc_grant_blocked(block);
  665         }
  666 
  667         if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
  668                 return (block->b_when - jiffies);
  669 
  670         return MAX_SCHEDULE_TIMEOUT;
  671 }

Cache object: 793877bcc81e7e18b501f012f2b7ec69


[ 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.