xref: /openbmc/linux/fs/nfs/dns_resolve.c (revision 21cd1254)
1e571cbf1STrond Myklebust /*
2e571cbf1STrond Myklebust  * linux/fs/nfs/dns_resolve.c
3e571cbf1STrond Myklebust  *
4e571cbf1STrond Myklebust  * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
5e571cbf1STrond Myklebust  *
6e571cbf1STrond Myklebust  * Resolves DNS hostnames into valid ip addresses
7e571cbf1STrond Myklebust  */
8e571cbf1STrond Myklebust 
9c2e8139cSBryan Schumaker #ifdef CONFIG_NFS_USE_KERNEL_DNS
10c2e8139cSBryan Schumaker 
1189d77c8fSBryan Schumaker #include <linux/module.h>
12c2e8139cSBryan Schumaker #include <linux/sunrpc/clnt.h>
135976687aSJeff Layton #include <linux/sunrpc/addr.h>
14c2e8139cSBryan Schumaker #include <linux/dns_resolver.h>
1517280175STrond Myklebust #include "dns_resolve.h"
16c2e8139cSBryan Schumaker 
171b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
18c2e8139cSBryan Schumaker 		struct sockaddr *sa, size_t salen)
19c2e8139cSBryan Schumaker {
20c2e8139cSBryan Schumaker 	ssize_t ret;
21c2e8139cSBryan Schumaker 	char *ip_addr = NULL;
22c2e8139cSBryan Schumaker 	int ip_len;
23c2e8139cSBryan Schumaker 
24c2e8139cSBryan Schumaker 	ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
25c2e8139cSBryan Schumaker 	if (ip_len > 0)
26bc224f53SStanislav Kinsbursky 		ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
27c2e8139cSBryan Schumaker 	else
28c2e8139cSBryan Schumaker 		ret = -ESRCH;
29c2e8139cSBryan Schumaker 	kfree(ip_addr);
30c2e8139cSBryan Schumaker 	return ret;
31c2e8139cSBryan Schumaker }
3289d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_dns_resolve_name);
33c2e8139cSBryan Schumaker 
34c2e8139cSBryan Schumaker #else
35c2e8139cSBryan Schumaker 
3689d77c8fSBryan Schumaker #include <linux/module.h>
37e571cbf1STrond Myklebust #include <linux/hash.h>
38e571cbf1STrond Myklebust #include <linux/string.h>
39e571cbf1STrond Myklebust #include <linux/kmod.h>
405a0e3ad6STejun Heo #include <linux/slab.h>
41e571cbf1STrond Myklebust #include <linux/module.h>
42e571cbf1STrond Myklebust #include <linux/socket.h>
43e571cbf1STrond Myklebust #include <linux/seq_file.h>
44e571cbf1STrond Myklebust #include <linux/inet.h>
45e571cbf1STrond Myklebust #include <linux/sunrpc/clnt.h>
465976687aSJeff Layton #include <linux/sunrpc/addr.h>
47e571cbf1STrond Myklebust #include <linux/sunrpc/cache.h>
48e571cbf1STrond Myklebust #include <linux/sunrpc/svcauth.h>
499df69c81SStanislav Kinsbursky #include <linux/sunrpc/rpc_pipe_fs.h>
50e571cbf1STrond Myklebust 
51e571cbf1STrond Myklebust #include "dns_resolve.h"
52e571cbf1STrond Myklebust #include "cache_lib.h"
531b340d01SStanislav Kinsbursky #include "netns.h"
54e571cbf1STrond Myklebust 
55e571cbf1STrond Myklebust #define NFS_DNS_HASHBITS 4
56e571cbf1STrond Myklebust #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
57e571cbf1STrond Myklebust 
58e571cbf1STrond Myklebust struct nfs_dns_ent {
59e571cbf1STrond Myklebust 	struct cache_head h;
60e571cbf1STrond Myklebust 
61e571cbf1STrond Myklebust 	char *hostname;
62e571cbf1STrond Myklebust 	size_t namelen;
63e571cbf1STrond Myklebust 
64e571cbf1STrond Myklebust 	struct sockaddr_storage addr;
65e571cbf1STrond Myklebust 	size_t addrlen;
66e571cbf1STrond Myklebust };
67e571cbf1STrond Myklebust 
68e571cbf1STrond Myklebust 
69ebed9203STrond Myklebust static void nfs_dns_ent_update(struct cache_head *cnew,
70ebed9203STrond Myklebust 		struct cache_head *ckey)
71ebed9203STrond Myklebust {
72ebed9203STrond Myklebust 	struct nfs_dns_ent *new;
73ebed9203STrond Myklebust 	struct nfs_dns_ent *key;
74ebed9203STrond Myklebust 
75ebed9203STrond Myklebust 	new = container_of(cnew, struct nfs_dns_ent, h);
76ebed9203STrond Myklebust 	key = container_of(ckey, struct nfs_dns_ent, h);
77ebed9203STrond Myklebust 
78ebed9203STrond Myklebust 	memcpy(&new->addr, &key->addr, key->addrlen);
79ebed9203STrond Myklebust 	new->addrlen = key->addrlen;
80ebed9203STrond Myklebust }
81ebed9203STrond Myklebust 
82e571cbf1STrond Myklebust static void nfs_dns_ent_init(struct cache_head *cnew,
83e571cbf1STrond Myklebust 		struct cache_head *ckey)
84e571cbf1STrond Myklebust {
85e571cbf1STrond Myklebust 	struct nfs_dns_ent *new;
86e571cbf1STrond Myklebust 	struct nfs_dns_ent *key;
87e571cbf1STrond Myklebust 
88e571cbf1STrond Myklebust 	new = container_of(cnew, struct nfs_dns_ent, h);
89e571cbf1STrond Myklebust 	key = container_of(ckey, struct nfs_dns_ent, h);
90e571cbf1STrond Myklebust 
91e571cbf1STrond Myklebust 	kfree(new->hostname);
92e571cbf1STrond Myklebust 	new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL);
93e571cbf1STrond Myklebust 	if (new->hostname) {
94e571cbf1STrond Myklebust 		new->namelen = key->namelen;
95ebed9203STrond Myklebust 		nfs_dns_ent_update(cnew, ckey);
96e571cbf1STrond Myklebust 	} else {
97e571cbf1STrond Myklebust 		new->namelen = 0;
98e571cbf1STrond Myklebust 		new->addrlen = 0;
99e571cbf1STrond Myklebust 	}
100e571cbf1STrond Myklebust }
101e571cbf1STrond Myklebust 
102e571cbf1STrond Myklebust static void nfs_dns_ent_put(struct kref *ref)
103e571cbf1STrond Myklebust {
104e571cbf1STrond Myklebust 	struct nfs_dns_ent *item;
105e571cbf1STrond Myklebust 
106e571cbf1STrond Myklebust 	item = container_of(ref, struct nfs_dns_ent, h.ref);
107e571cbf1STrond Myklebust 	kfree(item->hostname);
108e571cbf1STrond Myklebust 	kfree(item);
109e571cbf1STrond Myklebust }
110e571cbf1STrond Myklebust 
111e571cbf1STrond Myklebust static struct cache_head *nfs_dns_ent_alloc(void)
112e571cbf1STrond Myklebust {
113e571cbf1STrond Myklebust 	struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL);
114e571cbf1STrond Myklebust 
115e571cbf1STrond Myklebust 	if (item != NULL) {
116e571cbf1STrond Myklebust 		item->hostname = NULL;
117e571cbf1STrond Myklebust 		item->namelen = 0;
118e571cbf1STrond Myklebust 		item->addrlen = 0;
119e571cbf1STrond Myklebust 		return &item->h;
120e571cbf1STrond Myklebust 	}
121e571cbf1STrond Myklebust 	return NULL;
122e571cbf1STrond Myklebust };
123e571cbf1STrond Myklebust 
124e571cbf1STrond Myklebust static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key)
125e571cbf1STrond Myklebust {
126e571cbf1STrond Myklebust 	return hash_str(key->hostname, NFS_DNS_HASHBITS);
127e571cbf1STrond Myklebust }
128e571cbf1STrond Myklebust 
129e571cbf1STrond Myklebust static void nfs_dns_request(struct cache_detail *cd,
130e571cbf1STrond Myklebust 		struct cache_head *ch,
131e571cbf1STrond Myklebust 		char **bpp, int *blen)
132e571cbf1STrond Myklebust {
133e571cbf1STrond Myklebust 	struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
134e571cbf1STrond Myklebust 
135e571cbf1STrond Myklebust 	qword_add(bpp, blen, key->hostname);
136e571cbf1STrond Myklebust 	(*bpp)[-1] = '\n';
137e571cbf1STrond Myklebust }
138e571cbf1STrond Myklebust 
139e571cbf1STrond Myklebust static int nfs_dns_upcall(struct cache_detail *cd,
140e571cbf1STrond Myklebust 		struct cache_head *ch)
141e571cbf1STrond Myklebust {
142e571cbf1STrond Myklebust 	struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
143e571cbf1STrond Myklebust 	int ret;
144e571cbf1STrond Myklebust 
145e571cbf1STrond Myklebust 	ret = nfs_cache_upcall(cd, key->hostname);
146e571cbf1STrond Myklebust 	if (ret)
14721cd1254SStanislav Kinsbursky 		ret = sunrpc_cache_pipe_upcall(cd, ch);
148e571cbf1STrond Myklebust 	return ret;
149e571cbf1STrond Myklebust }
150e571cbf1STrond Myklebust 
151e571cbf1STrond Myklebust static int nfs_dns_match(struct cache_head *ca,
152e571cbf1STrond Myklebust 		struct cache_head *cb)
153e571cbf1STrond Myklebust {
154e571cbf1STrond Myklebust 	struct nfs_dns_ent *a;
155e571cbf1STrond Myklebust 	struct nfs_dns_ent *b;
156e571cbf1STrond Myklebust 
157e571cbf1STrond Myklebust 	a = container_of(ca, struct nfs_dns_ent, h);
158e571cbf1STrond Myklebust 	b = container_of(cb, struct nfs_dns_ent, h);
159e571cbf1STrond Myklebust 
160e571cbf1STrond Myklebust 	if (a->namelen == 0 || a->namelen != b->namelen)
161e571cbf1STrond Myklebust 		return 0;
162e571cbf1STrond Myklebust 	return memcmp(a->hostname, b->hostname, a->namelen) == 0;
163e571cbf1STrond Myklebust }
164e571cbf1STrond Myklebust 
165e571cbf1STrond Myklebust static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
166e571cbf1STrond Myklebust 		struct cache_head *h)
167e571cbf1STrond Myklebust {
168e571cbf1STrond Myklebust 	struct nfs_dns_ent *item;
169e571cbf1STrond Myklebust 	long ttl;
170e571cbf1STrond Myklebust 
171e571cbf1STrond Myklebust 	if (h == NULL) {
172e571cbf1STrond Myklebust 		seq_puts(m, "# ip address      hostname        ttl\n");
173e571cbf1STrond Myklebust 		return 0;
174e571cbf1STrond Myklebust 	}
175e571cbf1STrond Myklebust 	item = container_of(h, struct nfs_dns_ent, h);
176c5b29f88SNeilBrown 	ttl = item->h.expiry_time - seconds_since_boot();
177e571cbf1STrond Myklebust 	if (ttl < 0)
178e571cbf1STrond Myklebust 		ttl = 0;
179e571cbf1STrond Myklebust 
180e571cbf1STrond Myklebust 	if (!test_bit(CACHE_NEGATIVE, &h->flags)) {
181e571cbf1STrond Myklebust 		char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1];
182e571cbf1STrond Myklebust 
183e571cbf1STrond Myklebust 		rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf));
184e571cbf1STrond Myklebust 		seq_printf(m, "%15s ", buf);
185e571cbf1STrond Myklebust 	} else
186e571cbf1STrond Myklebust 		seq_puts(m, "<none>          ");
187e571cbf1STrond Myklebust 	seq_printf(m, "%15s %ld\n", item->hostname, ttl);
188e571cbf1STrond Myklebust 	return 0;
189e571cbf1STrond Myklebust }
190e571cbf1STrond Myklebust 
1910a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
192e571cbf1STrond Myklebust 		struct nfs_dns_ent *key)
193e571cbf1STrond Myklebust {
194e571cbf1STrond Myklebust 	struct cache_head *ch;
195e571cbf1STrond Myklebust 
196e571cbf1STrond Myklebust 	ch = sunrpc_cache_lookup(cd,
197e571cbf1STrond Myklebust 			&key->h,
198e571cbf1STrond Myklebust 			nfs_dns_hash(key));
199e571cbf1STrond Myklebust 	if (!ch)
200e571cbf1STrond Myklebust 		return NULL;
201e571cbf1STrond Myklebust 	return container_of(ch, struct nfs_dns_ent, h);
202e571cbf1STrond Myklebust }
203e571cbf1STrond Myklebust 
2040a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd,
205e571cbf1STrond Myklebust 		struct nfs_dns_ent *new,
206e571cbf1STrond Myklebust 		struct nfs_dns_ent *key)
207e571cbf1STrond Myklebust {
208e571cbf1STrond Myklebust 	struct cache_head *ch;
209e571cbf1STrond Myklebust 
210e571cbf1STrond Myklebust 	ch = sunrpc_cache_update(cd,
211e571cbf1STrond Myklebust 			&new->h, &key->h,
212e571cbf1STrond Myklebust 			nfs_dns_hash(key));
213e571cbf1STrond Myklebust 	if (!ch)
214e571cbf1STrond Myklebust 		return NULL;
215e571cbf1STrond Myklebust 	return container_of(ch, struct nfs_dns_ent, h);
216e571cbf1STrond Myklebust }
217e571cbf1STrond Myklebust 
218e571cbf1STrond Myklebust static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
219e571cbf1STrond Myklebust {
220e571cbf1STrond Myklebust 	char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
221e571cbf1STrond Myklebust 	struct nfs_dns_ent key, *item;
2228d96b106SNeilBrown 	unsigned int ttl;
223e571cbf1STrond Myklebust 	ssize_t len;
224e571cbf1STrond Myklebust 	int ret = -EINVAL;
225e571cbf1STrond Myklebust 
226e571cbf1STrond Myklebust 	if (buf[buflen-1] != '\n')
227e571cbf1STrond Myklebust 		goto out;
228e571cbf1STrond Myklebust 	buf[buflen-1] = '\0';
229e571cbf1STrond Myklebust 
230e571cbf1STrond Myklebust 	len = qword_get(&buf, buf1, sizeof(buf1));
231e571cbf1STrond Myklebust 	if (len <= 0)
232e571cbf1STrond Myklebust 		goto out;
233599ec129SStanislav Kinsbursky 	key.addrlen = rpc_pton(cd->net, buf1, len,
234e571cbf1STrond Myklebust 			(struct sockaddr *)&key.addr,
235e571cbf1STrond Myklebust 			sizeof(key.addr));
236e571cbf1STrond Myklebust 
237e571cbf1STrond Myklebust 	len = qword_get(&buf, buf1, sizeof(buf1));
238e571cbf1STrond Myklebust 	if (len <= 0)
239e571cbf1STrond Myklebust 		goto out;
240e571cbf1STrond Myklebust 
241e571cbf1STrond Myklebust 	key.hostname = buf1;
242e571cbf1STrond Myklebust 	key.namelen = len;
243e571cbf1STrond Myklebust 	memset(&key.h, 0, sizeof(key.h));
244e571cbf1STrond Myklebust 
2458d96b106SNeilBrown 	if (get_uint(&buf, &ttl) < 0)
2468d96b106SNeilBrown 		goto out;
247e571cbf1STrond Myklebust 	if (ttl == 0)
248e571cbf1STrond Myklebust 		goto out;
249c5b29f88SNeilBrown 	key.h.expiry_time = ttl + seconds_since_boot();
250e571cbf1STrond Myklebust 
251e571cbf1STrond Myklebust 	ret = -ENOMEM;
252e571cbf1STrond Myklebust 	item = nfs_dns_lookup(cd, &key);
253e571cbf1STrond Myklebust 	if (item == NULL)
254e571cbf1STrond Myklebust 		goto out;
255e571cbf1STrond Myklebust 
256e571cbf1STrond Myklebust 	if (key.addrlen == 0)
257e571cbf1STrond Myklebust 		set_bit(CACHE_NEGATIVE, &key.h.flags);
258e571cbf1STrond Myklebust 
259e571cbf1STrond Myklebust 	item = nfs_dns_update(cd, &key, item);
260e571cbf1STrond Myklebust 	if (item == NULL)
261e571cbf1STrond Myklebust 		goto out;
262e571cbf1STrond Myklebust 
263e571cbf1STrond Myklebust 	ret = 0;
264e571cbf1STrond Myklebust 	cache_put(&item->h, cd);
265e571cbf1STrond Myklebust out:
266e571cbf1STrond Myklebust 	return ret;
267e571cbf1STrond Myklebust }
268e571cbf1STrond Myklebust 
269e571cbf1STrond Myklebust static int do_cache_lookup(struct cache_detail *cd,
270e571cbf1STrond Myklebust 		struct nfs_dns_ent *key,
271e571cbf1STrond Myklebust 		struct nfs_dns_ent **item,
272e571cbf1STrond Myklebust 		struct nfs_cache_defer_req *dreq)
273e571cbf1STrond Myklebust {
274e571cbf1STrond Myklebust 	int ret = -ENOMEM;
275e571cbf1STrond Myklebust 
276e571cbf1STrond Myklebust 	*item = nfs_dns_lookup(cd, key);
277e571cbf1STrond Myklebust 	if (*item) {
278e571cbf1STrond Myklebust 		ret = cache_check(cd, &(*item)->h, &dreq->req);
279e571cbf1STrond Myklebust 		if (ret)
280e571cbf1STrond Myklebust 			*item = NULL;
281e571cbf1STrond Myklebust 	}
282e571cbf1STrond Myklebust 	return ret;
283e571cbf1STrond Myklebust }
284e571cbf1STrond Myklebust 
285e571cbf1STrond Myklebust static int do_cache_lookup_nowait(struct cache_detail *cd,
286e571cbf1STrond Myklebust 		struct nfs_dns_ent *key,
287e571cbf1STrond Myklebust 		struct nfs_dns_ent **item)
288e571cbf1STrond Myklebust {
289e571cbf1STrond Myklebust 	int ret = -ENOMEM;
290e571cbf1STrond Myklebust 
291e571cbf1STrond Myklebust 	*item = nfs_dns_lookup(cd, key);
292e571cbf1STrond Myklebust 	if (!*item)
293e571cbf1STrond Myklebust 		goto out_err;
294e571cbf1STrond Myklebust 	ret = -ETIMEDOUT;
295e571cbf1STrond Myklebust 	if (!test_bit(CACHE_VALID, &(*item)->h.flags)
296c5b29f88SNeilBrown 			|| (*item)->h.expiry_time < seconds_since_boot()
297e571cbf1STrond Myklebust 			|| cd->flush_time > (*item)->h.last_refresh)
298e571cbf1STrond Myklebust 		goto out_put;
299e571cbf1STrond Myklebust 	ret = -ENOENT;
300e571cbf1STrond Myklebust 	if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
301e571cbf1STrond Myklebust 		goto out_put;
302e571cbf1STrond Myklebust 	return 0;
303e571cbf1STrond Myklebust out_put:
304e571cbf1STrond Myklebust 	cache_put(&(*item)->h, cd);
305e571cbf1STrond Myklebust out_err:
306e571cbf1STrond Myklebust 	*item = NULL;
307e571cbf1STrond Myklebust 	return ret;
308e571cbf1STrond Myklebust }
309e571cbf1STrond Myklebust 
310e571cbf1STrond Myklebust static int do_cache_lookup_wait(struct cache_detail *cd,
311e571cbf1STrond Myklebust 		struct nfs_dns_ent *key,
312e571cbf1STrond Myklebust 		struct nfs_dns_ent **item)
313e571cbf1STrond Myklebust {
314e571cbf1STrond Myklebust 	struct nfs_cache_defer_req *dreq;
315e571cbf1STrond Myklebust 	int ret = -ENOMEM;
316e571cbf1STrond Myklebust 
317e571cbf1STrond Myklebust 	dreq = nfs_cache_defer_req_alloc();
318e571cbf1STrond Myklebust 	if (!dreq)
319e571cbf1STrond Myklebust 		goto out;
320e571cbf1STrond Myklebust 	ret = do_cache_lookup(cd, key, item, dreq);
321e571cbf1STrond Myklebust 	if (ret == -EAGAIN) {
322e571cbf1STrond Myklebust 		ret = nfs_cache_wait_for_upcall(dreq);
323e571cbf1STrond Myklebust 		if (!ret)
324e571cbf1STrond Myklebust 			ret = do_cache_lookup_nowait(cd, key, item);
325e571cbf1STrond Myklebust 	}
326e571cbf1STrond Myklebust 	nfs_cache_defer_req_put(dreq);
327e571cbf1STrond Myklebust out:
328e571cbf1STrond Myklebust 	return ret;
329e571cbf1STrond Myklebust }
330e571cbf1STrond Myklebust 
3311b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name,
3321b340d01SStanislav Kinsbursky 		size_t namelen, struct sockaddr *sa, size_t salen)
333e571cbf1STrond Myklebust {
334e571cbf1STrond Myklebust 	struct nfs_dns_ent key = {
335e571cbf1STrond Myklebust 		.hostname = name,
336e571cbf1STrond Myklebust 		.namelen = namelen,
337e571cbf1STrond Myklebust 	};
338e571cbf1STrond Myklebust 	struct nfs_dns_ent *item = NULL;
339e571cbf1STrond Myklebust 	ssize_t ret;
3401b340d01SStanislav Kinsbursky 	struct nfs_net *nn = net_generic(net, nfs_net_id);
341e571cbf1STrond Myklebust 
3421b340d01SStanislav Kinsbursky 	ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
343e571cbf1STrond Myklebust 	if (ret == 0) {
344e571cbf1STrond Myklebust 		if (salen >= item->addrlen) {
345e571cbf1STrond Myklebust 			memcpy(sa, &item->addr, item->addrlen);
346e571cbf1STrond Myklebust 			ret = item->addrlen;
347e571cbf1STrond Myklebust 		} else
348e571cbf1STrond Myklebust 			ret = -EOVERFLOW;
3491b340d01SStanislav Kinsbursky 		cache_put(&item->h, nn->nfs_dns_resolve);
350e571cbf1STrond Myklebust 	} else if (ret == -ENOENT)
351e571cbf1STrond Myklebust 		ret = -ESRCH;
352e571cbf1STrond Myklebust 	return ret;
353e571cbf1STrond Myklebust }
35489d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_dns_resolve_name);
355e571cbf1STrond Myklebust 
356483479c2SStanislav Kinsbursky static struct cache_detail nfs_dns_resolve_template = {
357483479c2SStanislav Kinsbursky 	.owner		= THIS_MODULE,
358483479c2SStanislav Kinsbursky 	.hash_size	= NFS_DNS_HASHTBL_SIZE,
359483479c2SStanislav Kinsbursky 	.name		= "dns_resolve",
360483479c2SStanislav Kinsbursky 	.cache_put	= nfs_dns_ent_put,
361483479c2SStanislav Kinsbursky 	.cache_upcall	= nfs_dns_upcall,
36273fb847aSStanislav Kinsbursky 	.cache_request	= nfs_dns_request,
363483479c2SStanislav Kinsbursky 	.cache_parse	= nfs_dns_parse,
364483479c2SStanislav Kinsbursky 	.cache_show	= nfs_dns_show,
365483479c2SStanislav Kinsbursky 	.match		= nfs_dns_match,
366483479c2SStanislav Kinsbursky 	.init		= nfs_dns_ent_init,
367483479c2SStanislav Kinsbursky 	.update		= nfs_dns_ent_update,
368483479c2SStanislav Kinsbursky 	.alloc		= nfs_dns_ent_alloc,
369483479c2SStanislav Kinsbursky };
370483479c2SStanislav Kinsbursky 
371483479c2SStanislav Kinsbursky 
3721b340d01SStanislav Kinsbursky int nfs_dns_resolver_cache_init(struct net *net)
373e571cbf1STrond Myklebust {
374483479c2SStanislav Kinsbursky 	int err;
3751b340d01SStanislav Kinsbursky 	struct nfs_net *nn = net_generic(net, nfs_net_id);
3769222b955SStanislav Kinsbursky 
377483479c2SStanislav Kinsbursky 	nn->nfs_dns_resolve = cache_create_net(&nfs_dns_resolve_template, net);
378483479c2SStanislav Kinsbursky 	if (IS_ERR(nn->nfs_dns_resolve))
379483479c2SStanislav Kinsbursky 		return PTR_ERR(nn->nfs_dns_resolve);
3801b340d01SStanislav Kinsbursky 
381483479c2SStanislav Kinsbursky 	err = nfs_cache_register_net(net, nn->nfs_dns_resolve);
3821b340d01SStanislav Kinsbursky 	if (err)
3831b340d01SStanislav Kinsbursky 		goto err_reg;
3841b340d01SStanislav Kinsbursky 	return 0;
3851b340d01SStanislav Kinsbursky 
3861b340d01SStanislav Kinsbursky err_reg:
387483479c2SStanislav Kinsbursky 	cache_destroy_net(nn->nfs_dns_resolve, net);
3889222b955SStanislav Kinsbursky 	return err;
3899222b955SStanislav Kinsbursky }
3901b340d01SStanislav Kinsbursky 
3911b340d01SStanislav Kinsbursky void nfs_dns_resolver_cache_destroy(struct net *net)
3921b340d01SStanislav Kinsbursky {
3931b340d01SStanislav Kinsbursky 	struct nfs_net *nn = net_generic(net, nfs_net_id);
3941b340d01SStanislav Kinsbursky 
395462b8f6bSStanislav Kinsbursky 	nfs_cache_unregister_net(net, nn->nfs_dns_resolve);
396483479c2SStanislav Kinsbursky 	cache_destroy_net(nn->nfs_dns_resolve, net);
3971b340d01SStanislav Kinsbursky }
3981b340d01SStanislav Kinsbursky 
3999df69c81SStanislav Kinsbursky static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
4009df69c81SStanislav Kinsbursky 			   void *ptr)
4019df69c81SStanislav Kinsbursky {
4029df69c81SStanislav Kinsbursky 	struct super_block *sb = ptr;
4039df69c81SStanislav Kinsbursky 	struct net *net = sb->s_fs_info;
4049df69c81SStanislav Kinsbursky 	struct nfs_net *nn = net_generic(net, nfs_net_id);
4059df69c81SStanislav Kinsbursky 	struct cache_detail *cd = nn->nfs_dns_resolve;
4069df69c81SStanislav Kinsbursky 	int ret = 0;
4079df69c81SStanislav Kinsbursky 
4089df69c81SStanislav Kinsbursky 	if (cd == NULL)
4099df69c81SStanislav Kinsbursky 		return 0;
4109df69c81SStanislav Kinsbursky 
4119df69c81SStanislav Kinsbursky 	if (!try_module_get(THIS_MODULE))
4129df69c81SStanislav Kinsbursky 		return 0;
4139df69c81SStanislav Kinsbursky 
4149df69c81SStanislav Kinsbursky 	switch (event) {
4159df69c81SStanislav Kinsbursky 	case RPC_PIPEFS_MOUNT:
4169df69c81SStanislav Kinsbursky 		ret = nfs_cache_register_sb(sb, cd);
4179df69c81SStanislav Kinsbursky 		break;
4189df69c81SStanislav Kinsbursky 	case RPC_PIPEFS_UMOUNT:
4199df69c81SStanislav Kinsbursky 		nfs_cache_unregister_sb(sb, cd);
4209df69c81SStanislav Kinsbursky 		break;
4219df69c81SStanislav Kinsbursky 	default:
4229df69c81SStanislav Kinsbursky 		ret = -ENOTSUPP;
4239df69c81SStanislav Kinsbursky 		break;
4249df69c81SStanislav Kinsbursky 	}
4259df69c81SStanislav Kinsbursky 	module_put(THIS_MODULE);
4269df69c81SStanislav Kinsbursky 	return ret;
4279df69c81SStanislav Kinsbursky }
4289df69c81SStanislav Kinsbursky 
4299df69c81SStanislav Kinsbursky static struct notifier_block nfs_dns_resolver_block = {
4309df69c81SStanislav Kinsbursky 	.notifier_call	= rpc_pipefs_event,
4319df69c81SStanislav Kinsbursky };
4329df69c81SStanislav Kinsbursky 
4331b340d01SStanislav Kinsbursky int nfs_dns_resolver_init(void)
4341b340d01SStanislav Kinsbursky {
4359df69c81SStanislav Kinsbursky 	return rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
436e571cbf1STrond Myklebust }
437e571cbf1STrond Myklebust 
438e571cbf1STrond Myklebust void nfs_dns_resolver_destroy(void)
439e571cbf1STrond Myklebust {
4409df69c81SStanislav Kinsbursky 	rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
441e571cbf1STrond Myklebust }
442c2e8139cSBryan Schumaker #endif
443