cache_lib.c 3.4 KB

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