clntlock.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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