cache_lib.c 3.8 KB

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