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/clntlock.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/clntlock.c
    3  *
    4  * Lock handling for the client side NLM implementation
    5  *
    6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
    7  */
    8 
    9 #define __KERNEL_SYSCALLS__
   10 
   11 #include <linux/module.h>
   12 #include <linux/types.h>
   13 #include <linux/sched.h>
   14 #include <linux/nfs_fs.h>
   15 #include <linux/unistd.h>
   16 #include <linux/sunrpc/clnt.h>
   17 #include <linux/sunrpc/svc.h>
   18 #include <linux/lockd/lockd.h>
   19 #include <linux/smp_lock.h>
   20 
   21 #define NLMDBG_FACILITY         NLMDBG_CLIENT
   22 
   23 /*
   24  * Local function prototypes
   25  */
   26 static int                      reclaimer(void *ptr);
   27 
   28 /*
   29  * The following functions handle blocking and granting from the
   30  * client perspective.
   31  */
   32 
   33 /*
   34  * This is the representation of a blocked client lock.
   35  */
   36 struct nlm_wait {
   37         struct nlm_wait *       b_next;         /* linked list */
   38         wait_queue_head_t       b_wait;         /* where to wait on */
   39         struct nlm_host *       b_host;
   40         struct file_lock *      b_lock;         /* local file lock */
   41         unsigned short          b_reclaim;      /* got to reclaim lock */
   42         u32                     b_status;       /* grant callback status */
   43 };
   44 
   45 static struct nlm_wait *        nlm_blocked;
   46 
   47 /*
   48  * Block on a lock
   49  */
   50 int
   51 nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)
   52 {
   53         struct nlm_wait block, **head;
   54         int             err;
   55         u32             pstate;
   56 
   57         block.b_host   = host;
   58         block.b_lock   = fl;
   59         init_waitqueue_head(&block.b_wait);
   60         block.b_status = NLM_LCK_BLOCKED;
   61         block.b_next   = nlm_blocked;
   62         nlm_blocked    = &block;
   63 
   64         /* Remember pseudo nsm state */
   65         pstate = host->h_state;
   66 
   67         /* Go to sleep waiting for GRANT callback. Some servers seem
   68          * to lose callbacks, however, so we're going to poll from
   69          * time to time just to make sure.
   70          *
   71          * For now, the retry frequency is pretty high; normally 
   72          * a 1 minute timeout would do. See the comment before
   73          * nlmclnt_lock for an explanation.
   74          */
   75         sleep_on_timeout(&block.b_wait, 30*HZ);
   76 
   77         for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
   78                 if (*head == &block) {
   79                         *head = block.b_next;
   80                         break;
   81                 }
   82         }
   83 
   84         if (!signalled()) {
   85                 *statp = block.b_status;
   86                 return 0;
   87         }
   88 
   89         /* Okay, we were interrupted. Cancel the pending request
   90          * unless the server has rebooted.
   91          */
   92         if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0)
   93                 printk(KERN_NOTICE
   94                         "lockd: CANCEL call failed (errno %d)\n", -err);
   95 
   96         return -ERESTARTSYS;
   97 }
   98 
   99 /*
  100  * The server lockd has called us back to tell us the lock was granted
  101  */
  102 u32
  103 nlmclnt_grant(struct nlm_lock *lock)
  104 {
  105         struct nlm_wait *block;
  106 
  107         /*
  108          * Look up blocked request based on arguments. 
  109          * Warning: must not use cookie to match it!
  110          */
  111         for (block = nlm_blocked; block; block = block->b_next) {
  112                 if (nlm_compare_locks(block->b_lock, &lock->fl))
  113                         break;
  114         }
  115 
  116         /* Ooops, no blocked request found. */
  117         if (block == NULL)
  118                 return nlm_lck_denied;
  119 
  120         /* Alright, we found the lock. Set the return status and
  121          * wake up the caller.
  122          */
  123         block->b_status = NLM_LCK_GRANTED;
  124         wake_up(&block->b_wait);
  125 
  126         return nlm_granted;
  127 }
  128 
  129 /*
  130  * The following procedures deal with the recovery of locks after a
  131  * server crash.
  132  */
  133 
  134 /*
  135  * Mark the locks for reclaiming.
  136  * FIXME: In 2.5 we don't want to iterate through any global file_lock_list.
  137  *        Maintain NLM lock reclaiming lists in the nlm_host instead.
  138  */
  139 static
  140 void nlmclnt_mark_reclaim(struct nlm_host *host)
  141 {
  142         struct file_lock *fl;
  143         struct inode *inode;
  144         struct list_head *tmp;
  145 
  146         list_for_each(tmp, &file_lock_list) {
  147                 fl = list_entry(tmp, struct file_lock, fl_link);
  148 
  149                 inode = fl->fl_file->f_dentry->d_inode;
  150                 if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
  151                         continue;
  152                 if (fl->fl_u.nfs_fl.host != host)
  153                         continue;
  154                 if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED))
  155                         continue;
  156                 fl->fl_u.nfs_fl.flags |= NFS_LCK_RECLAIM;
  157         }
  158 }
  159 
  160 /*
  161  * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
  162  * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
  163  */
  164 static inline
  165 void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
  166 {
  167         host->h_monitored = 0;
  168         host->h_nsmstate = newstate;
  169         host->h_state++;
  170         host->h_nextrebind = 0;
  171         nlm_rebind_host(host);
  172         nlmclnt_mark_reclaim(host);
  173         dprintk("NLM: reclaiming locks for host %s", host->h_name);
  174 }
  175 
  176 /*
  177  * Reclaim all locks on server host. We do this by spawning a separate
  178  * reclaimer thread.
  179  */
  180 void
  181 nlmclnt_recovery(struct nlm_host *host, u32 newstate)
  182 {
  183         if (host->h_reclaiming++) {
  184                 if (host->h_nsmstate == newstate)
  185                         return;
  186                 nlmclnt_prepare_reclaim(host, newstate);
  187         } else {
  188                 nlmclnt_prepare_reclaim(host, newstate);
  189                 nlm_get_host(host);
  190                 MOD_INC_USE_COUNT;
  191                 kernel_thread(reclaimer, host, CLONE_SIGNAL);
  192         }
  193 }
  194 
  195 static int
  196 reclaimer(void *ptr)
  197 {
  198         struct nlm_host   *host = (struct nlm_host *) ptr;
  199         struct nlm_wait   *block;
  200         struct list_head *tmp;
  201         struct file_lock *fl;
  202         struct inode *inode;
  203 
  204         daemonize();
  205         reparent_to_init();
  206         snprintf(current->comm, sizeof(current->comm),
  207                  "%s-reclaim",
  208                  host->h_name);
  209 
  210         /* This one ensures that our parent doesn't terminate while the
  211          * reclaim is in progress */
  212         lock_kernel();
  213         lockd_up();
  214 
  215         /* First, reclaim all locks that have been marked. */
  216 restart:
  217         list_for_each(tmp, &file_lock_list) {
  218                 fl = list_entry(tmp, struct file_lock, fl_link);
  219 
  220                 inode = fl->fl_file->f_dentry->d_inode;
  221                 if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
  222                         continue;
  223                 if (fl->fl_u.nfs_fl.host != host)
  224                         continue;
  225                 if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM))
  226                         continue;
  227 
  228                 fl->fl_u.nfs_fl.flags &= ~NFS_LCK_RECLAIM;
  229                 nlmclnt_reclaim(host, fl);
  230                 if (signalled())
  231                         break;
  232                 goto restart;
  233         }
  234 
  235         host->h_reclaiming = 0;
  236         wake_up(&host->h_gracewait);
  237 
  238         /* Now, wake up all processes that sleep on a blocked lock */
  239         for (block = nlm_blocked; block; block = block->b_next) {
  240                 if (block->b_host == host) {
  241                         block->b_status = NLM_LCK_DENIED_GRACE_PERIOD;
  242                         wake_up(&block->b_wait);
  243                 }
  244         }
  245 
  246         /* Release host handle after use */
  247         nlm_release_host(host);
  248         lockd_down();
  249         unlock_kernel();
  250         MOD_DEC_USE_COUNT;
  251 
  252         return 0;
  253 }

Cache object: 7cf1b27fc75e8a85902bb884029bdd75


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