cache_lib.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * linux/fs/nfs/cache_lib.c
  3. *
  4. * Helper routines for the NFS client caches
  5. *
  6. * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
  7. */
  8. #include <linux/kmod.h>
  9. #include <linux/module.h>
  10. #include <linux/moduleparam.h>
  11. #include <linux/mount.h>
  12. #include <linux/namei.h>
  13. #include <linux/sunrpc/cache.h>
  14. #include <linux/sunrpc/rpc_pipe_fs.h>
  15. #include "cache_lib.h"
  16. #define NFS_CACHE_UPCALL_PATHLEN 256
  17. #define NFS_CACHE_UPCALL_TIMEOUT 15
  18. static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] =
  19. "/sbin/nfs_cache_getent";
  20. static unsigned long nfs_cache_getent_timeout = NFS_CACHE_UPCALL_TIMEOUT;
  21. module_param_string(cache_getent, nfs_cache_getent_prog,
  22. sizeof(nfs_cache_getent_prog), 0600);
  23. MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall program");
  24. module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600);
  25. MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which "
  26. "the cache upcall is assumed to have failed");
  27. int nfs_cache_upcall(struct cache_detail *cd, char *entry_name)
  28. {
  29. static char *envp[] = { "HOME=/",
  30. "TERM=linux",
  31. "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
  32. NULL
  33. };
  34. char *argv[] = {
  35. nfs_cache_getent_prog,
  36. cd->name,
  37. entry_name,
  38. NULL
  39. };
  40. int ret = -EACCES;
  41. if (nfs_cache_getent_prog[0] == '\0')
  42. goto out;
  43. ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
  44. /*
  45. * Disable the upcall mechanism if we're getting an ENOENT or
  46. * EACCES error. The admin can re-enable it on the fly by using
  47. * sysfs to set the 'cache_getent' parameter once the problem
  48. * has been fixed.
  49. */
  50. if (ret == -ENOENT || ret == -EACCES)
  51. nfs_cache_getent_prog[0] = '\0';
  52. out:
  53. return ret > 0 ? 0 : ret;
  54. }
  55. /*
  56. * Deferred request handling
  57. */
  58. void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq)
  59. {
  60. if (atomic_dec_and_test(&dreq->count))
  61. kfree(dreq);
  62. }
  63. static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int toomany)
  64. {
  65. struct nfs_cache_defer_req *dreq;
  66. dreq = container_of(d, struct nfs_cache_defer_req, deferred_req);
  67. complete_all(&dreq->completion);
  68. nfs_cache_defer_req_put(dreq);
  69. }
  70. static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_req *req)
  71. {
  72. struct nfs_cache_defer_req *dreq;
  73. dreq = container_of(req, struct nfs_cache_defer_req, req);
  74. dreq->deferred_req.revisit = nfs_dns_cache_revisit;
  75. atomic_inc(&dreq->count);
  76. return &dreq->deferred_req;
  77. }
  78. struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void)
  79. {
  80. struct nfs_cache_defer_req *dreq;
  81. dreq = kzalloc(sizeof(*dreq), GFP_KERNEL);
  82. if (dreq) {
  83. init_completion(&dreq->completion);
  84. atomic_set(&dreq->count, 1);
  85. dreq->req.defer = nfs_dns_cache_defer;
  86. }
  87. return dreq;
  88. }
  89. int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq)
  90. {
  91. if (wait_for_completion_timeout(&dreq->completion,
  92. nfs_cache_getent_timeout * HZ) == 0)
  93. return -ETIMEDOUT;
  94. return 0;
  95. }
  96. int nfs_cache_register(struct cache_detail *cd)
  97. {
  98. struct nameidata nd;
  99. struct vfsmount *mnt;
  100. int ret;
  101. mnt = rpc_get_mount();
  102. if (IS_ERR(mnt))
  103. return PTR_ERR(mnt);
  104. ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd);
  105. if (ret)
  106. goto err;
  107. ret = sunrpc_cache_register_pipefs(nd.path.dentry,
  108. cd->name, 0600, cd);
  109. path_put(&nd.path);
  110. if (!ret)
  111. return ret;
  112. err:
  113. rpc_put_mount();
  114. return ret;
  115. }
  116. void nfs_cache_unregister(struct cache_detail *cd)
  117. {
  118. sunrpc_cache_unregister_pipefs(cd);
  119. rpc_put_mount();
  120. }