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