0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kmod.h>
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/mount.h>
0013 #include <linux/namei.h>
0014 #include <linux/slab.h>
0015 #include <linux/sunrpc/cache.h>
0016 #include <linux/sunrpc/rpc_pipe_fs.h>
0017 #include <net/net_namespace.h>
0018
0019 #include "cache_lib.h"
0020
0021 #define NFS_CACHE_UPCALL_PATHLEN 256
0022 #define NFS_CACHE_UPCALL_TIMEOUT 15
0023
0024 static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] =
0025 "/sbin/nfs_cache_getent";
0026 static unsigned long nfs_cache_getent_timeout = NFS_CACHE_UPCALL_TIMEOUT;
0027
0028 module_param_string(cache_getent, nfs_cache_getent_prog,
0029 sizeof(nfs_cache_getent_prog), 0600);
0030 MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall program");
0031 module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600);
0032 MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which "
0033 "the cache upcall is assumed to have failed");
0034
0035 int nfs_cache_upcall(struct cache_detail *cd, char *entry_name)
0036 {
0037 static char *envp[] = { "HOME=/",
0038 "TERM=linux",
0039 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
0040 NULL
0041 };
0042 char *argv[] = {
0043 nfs_cache_getent_prog,
0044 cd->name,
0045 entry_name,
0046 NULL
0047 };
0048 int ret = -EACCES;
0049
0050 if (nfs_cache_getent_prog[0] == '\0')
0051 goto out;
0052 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
0053
0054
0055
0056
0057
0058
0059 if (ret == -ENOENT || ret == -EACCES)
0060 nfs_cache_getent_prog[0] = '\0';
0061 out:
0062 return ret > 0 ? 0 : ret;
0063 }
0064
0065
0066
0067
0068 void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq)
0069 {
0070 if (refcount_dec_and_test(&dreq->count))
0071 kfree(dreq);
0072 }
0073
0074 static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int toomany)
0075 {
0076 struct nfs_cache_defer_req *dreq;
0077
0078 dreq = container_of(d, struct nfs_cache_defer_req, deferred_req);
0079
0080 complete(&dreq->completion);
0081 nfs_cache_defer_req_put(dreq);
0082 }
0083
0084 static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_req *req)
0085 {
0086 struct nfs_cache_defer_req *dreq;
0087
0088 dreq = container_of(req, struct nfs_cache_defer_req, req);
0089 dreq->deferred_req.revisit = nfs_dns_cache_revisit;
0090 refcount_inc(&dreq->count);
0091
0092 return &dreq->deferred_req;
0093 }
0094
0095 struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void)
0096 {
0097 struct nfs_cache_defer_req *dreq;
0098
0099 dreq = kzalloc(sizeof(*dreq), GFP_KERNEL);
0100 if (dreq) {
0101 init_completion(&dreq->completion);
0102 refcount_set(&dreq->count, 1);
0103 dreq->req.defer = nfs_dns_cache_defer;
0104 }
0105 return dreq;
0106 }
0107
0108 int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq)
0109 {
0110 if (wait_for_completion_timeout(&dreq->completion,
0111 nfs_cache_getent_timeout * HZ) == 0)
0112 return -ETIMEDOUT;
0113 return 0;
0114 }
0115
0116 int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
0117 {
0118 int ret;
0119 struct dentry *dir;
0120
0121 dir = rpc_d_lookup_sb(sb, "cache");
0122 ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
0123 dput(dir);
0124 return ret;
0125 }
0126
0127 int nfs_cache_register_net(struct net *net, struct cache_detail *cd)
0128 {
0129 struct super_block *pipefs_sb;
0130 int ret = 0;
0131
0132 sunrpc_init_cache_detail(cd);
0133 pipefs_sb = rpc_get_sb_net(net);
0134 if (pipefs_sb) {
0135 ret = nfs_cache_register_sb(pipefs_sb, cd);
0136 rpc_put_sb_net(net);
0137 if (ret)
0138 sunrpc_destroy_cache_detail(cd);
0139 }
0140 return ret;
0141 }
0142
0143 void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd)
0144 {
0145 sunrpc_cache_unregister_pipefs(cd);
0146 }
0147
0148 void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd)
0149 {
0150 struct super_block *pipefs_sb;
0151
0152 pipefs_sb = rpc_get_sb_net(net);
0153 if (pipefs_sb) {
0154 nfs_cache_unregister_sb(pipefs_sb, cd);
0155 rpc_put_sb_net(net);
0156 }
0157 sunrpc_destroy_cache_detail(cd);
0158 }