1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2e571cbf1STrond Myklebust /* 3e571cbf1STrond Myklebust * linux/fs/nfs/dns_resolve.c 4e571cbf1STrond Myklebust * 5e571cbf1STrond Myklebust * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> 6e571cbf1STrond Myklebust * 7e571cbf1STrond Myklebust * Resolves DNS hostnames into valid ip addresses 8e571cbf1STrond Myklebust */ 9e571cbf1STrond Myklebust 10c2e8139cSBryan Schumaker #ifdef CONFIG_NFS_USE_KERNEL_DNS 11c2e8139cSBryan Schumaker 1289d77c8fSBryan Schumaker #include <linux/module.h> 13c2e8139cSBryan Schumaker #include <linux/sunrpc/clnt.h> 145976687aSJeff Layton #include <linux/sunrpc/addr.h> 15c2e8139cSBryan Schumaker #include <linux/dns_resolver.h> 1617280175STrond Myklebust #include "dns_resolve.h" 17c2e8139cSBryan Schumaker 181b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, 19c2e8139cSBryan Schumaker struct sockaddr *sa, size_t salen) 20c2e8139cSBryan Schumaker { 21c2e8139cSBryan Schumaker ssize_t ret; 22c2e8139cSBryan Schumaker char *ip_addr = NULL; 23c2e8139cSBryan Schumaker int ip_len; 24c2e8139cSBryan Schumaker 25a58946c1SDavid Howells ip_len = dns_query(net, NULL, name, namelen, NULL, &ip_addr, NULL, 26a58946c1SDavid Howells false); 27c2e8139cSBryan Schumaker if (ip_len > 0) 28bc224f53SStanislav Kinsbursky ret = rpc_pton(net, ip_addr, ip_len, sa, salen); 29c2e8139cSBryan Schumaker else 30c2e8139cSBryan Schumaker ret = -ESRCH; 31c2e8139cSBryan Schumaker kfree(ip_addr); 32c2e8139cSBryan Schumaker return ret; 33c2e8139cSBryan Schumaker } 34c2e8139cSBryan Schumaker 35c2e8139cSBryan Schumaker #else 36c2e8139cSBryan Schumaker 3789d77c8fSBryan Schumaker #include <linux/module.h> 38e571cbf1STrond Myklebust #include <linux/hash.h> 39e571cbf1STrond Myklebust #include <linux/string.h> 40e571cbf1STrond Myklebust #include <linux/kmod.h> 415a0e3ad6STejun Heo #include <linux/slab.h> 42e571cbf1STrond Myklebust #include <linux/module.h> 43e571cbf1STrond Myklebust #include <linux/socket.h> 44e571cbf1STrond Myklebust #include <linux/seq_file.h> 45e571cbf1STrond Myklebust #include <linux/inet.h> 46e571cbf1STrond Myklebust #include <linux/sunrpc/clnt.h> 475976687aSJeff Layton #include <linux/sunrpc/addr.h> 48e571cbf1STrond Myklebust #include <linux/sunrpc/cache.h> 49e571cbf1STrond Myklebust #include <linux/sunrpc/svcauth.h> 509df69c81SStanislav Kinsbursky #include <linux/sunrpc/rpc_pipe_fs.h> 51694e096fSAnna Schumaker #include <linux/nfs_fs.h> 52e571cbf1STrond Myklebust 53694e096fSAnna Schumaker #include "nfs4_fs.h" 54e571cbf1STrond Myklebust #include "dns_resolve.h" 55e571cbf1STrond Myklebust #include "cache_lib.h" 561b340d01SStanislav Kinsbursky #include "netns.h" 57e571cbf1STrond Myklebust 58e571cbf1STrond Myklebust #define NFS_DNS_HASHBITS 4 59e571cbf1STrond Myklebust #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) 60e571cbf1STrond Myklebust 61e571cbf1STrond Myklebust struct nfs_dns_ent { 62e571cbf1STrond Myklebust struct cache_head h; 63e571cbf1STrond Myklebust 64e571cbf1STrond Myklebust char *hostname; 65e571cbf1STrond Myklebust size_t namelen; 66e571cbf1STrond Myklebust 67e571cbf1STrond Myklebust struct sockaddr_storage addr; 68e571cbf1STrond Myklebust size_t addrlen; 69437f9145STrond Myklebust struct rcu_head rcu_head; 70e571cbf1STrond Myklebust }; 71e571cbf1STrond Myklebust 72e571cbf1STrond Myklebust 73ebed9203STrond Myklebust static void nfs_dns_ent_update(struct cache_head *cnew, 74ebed9203STrond Myklebust struct cache_head *ckey) 75ebed9203STrond Myklebust { 76ebed9203STrond Myklebust struct nfs_dns_ent *new; 77ebed9203STrond Myklebust struct nfs_dns_ent *key; 78ebed9203STrond Myklebust 79ebed9203STrond Myklebust new = container_of(cnew, struct nfs_dns_ent, h); 80ebed9203STrond Myklebust key = container_of(ckey, struct nfs_dns_ent, h); 81ebed9203STrond Myklebust 82ebed9203STrond Myklebust memcpy(&new->addr, &key->addr, key->addrlen); 83ebed9203STrond Myklebust new->addrlen = key->addrlen; 84ebed9203STrond Myklebust } 85ebed9203STrond Myklebust 86e571cbf1STrond Myklebust static void nfs_dns_ent_init(struct cache_head *cnew, 87e571cbf1STrond Myklebust struct cache_head *ckey) 88e571cbf1STrond Myklebust { 89e571cbf1STrond Myklebust struct nfs_dns_ent *new; 90e571cbf1STrond Myklebust struct nfs_dns_ent *key; 91e571cbf1STrond Myklebust 92e571cbf1STrond Myklebust new = container_of(cnew, struct nfs_dns_ent, h); 93e571cbf1STrond Myklebust key = container_of(ckey, struct nfs_dns_ent, h); 94e571cbf1STrond Myklebust 95e571cbf1STrond Myklebust kfree(new->hostname); 96a8bd9ddfSTrond Myklebust new->hostname = kmemdup_nul(key->hostname, key->namelen, GFP_KERNEL); 97e571cbf1STrond Myklebust if (new->hostname) { 98e571cbf1STrond Myklebust new->namelen = key->namelen; 99ebed9203STrond Myklebust nfs_dns_ent_update(cnew, ckey); 100e571cbf1STrond Myklebust } else { 101e571cbf1STrond Myklebust new->namelen = 0; 102e571cbf1STrond Myklebust new->addrlen = 0; 103e571cbf1STrond Myklebust } 104e571cbf1STrond Myklebust } 105e571cbf1STrond Myklebust 106437f9145STrond Myklebust static void nfs_dns_ent_free_rcu(struct rcu_head *head) 107437f9145STrond Myklebust { 108437f9145STrond Myklebust struct nfs_dns_ent *item; 109437f9145STrond Myklebust 110437f9145STrond Myklebust item = container_of(head, struct nfs_dns_ent, rcu_head); 111437f9145STrond Myklebust kfree(item->hostname); 112437f9145STrond Myklebust kfree(item); 113437f9145STrond Myklebust } 114437f9145STrond Myklebust 115e571cbf1STrond Myklebust static void nfs_dns_ent_put(struct kref *ref) 116e571cbf1STrond Myklebust { 117e571cbf1STrond Myklebust struct nfs_dns_ent *item; 118e571cbf1STrond Myklebust 119e571cbf1STrond Myklebust item = container_of(ref, struct nfs_dns_ent, h.ref); 120a6482733STrond Myklebust call_rcu(&item->rcu_head, nfs_dns_ent_free_rcu); 121e571cbf1STrond Myklebust } 122e571cbf1STrond Myklebust 123e571cbf1STrond Myklebust static struct cache_head *nfs_dns_ent_alloc(void) 124e571cbf1STrond Myklebust { 125e571cbf1STrond Myklebust struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL); 126e571cbf1STrond Myklebust 127e571cbf1STrond Myklebust if (item != NULL) { 128e571cbf1STrond Myklebust item->hostname = NULL; 129e571cbf1STrond Myklebust item->namelen = 0; 130e571cbf1STrond Myklebust item->addrlen = 0; 131e571cbf1STrond Myklebust return &item->h; 132e571cbf1STrond Myklebust } 133e571cbf1STrond Myklebust return NULL; 134e571cbf1STrond Myklebust }; 135e571cbf1STrond Myklebust 136e571cbf1STrond Myklebust static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key) 137e571cbf1STrond Myklebust { 138e571cbf1STrond Myklebust return hash_str(key->hostname, NFS_DNS_HASHBITS); 139e571cbf1STrond Myklebust } 140e571cbf1STrond Myklebust 141e571cbf1STrond Myklebust static void nfs_dns_request(struct cache_detail *cd, 142e571cbf1STrond Myklebust struct cache_head *ch, 143e571cbf1STrond Myklebust char **bpp, int *blen) 144e571cbf1STrond Myklebust { 145e571cbf1STrond Myklebust struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 146e571cbf1STrond Myklebust 147e571cbf1STrond Myklebust qword_add(bpp, blen, key->hostname); 148e571cbf1STrond Myklebust (*bpp)[-1] = '\n'; 149e571cbf1STrond Myklebust } 150e571cbf1STrond Myklebust 151e571cbf1STrond Myklebust static int nfs_dns_upcall(struct cache_detail *cd, 152e571cbf1STrond Myklebust struct cache_head *ch) 153e571cbf1STrond Myklebust { 154e571cbf1STrond Myklebust struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 155e571cbf1STrond Myklebust int ret; 156e571cbf1STrond Myklebust 157e571cbf1STrond Myklebust ret = nfs_cache_upcall(cd, key->hostname); 158e571cbf1STrond Myklebust if (ret) 15921cd1254SStanislav Kinsbursky ret = sunrpc_cache_pipe_upcall(cd, ch); 160e571cbf1STrond Myklebust return ret; 161e571cbf1STrond Myklebust } 162e571cbf1STrond Myklebust 163e571cbf1STrond Myklebust static int nfs_dns_match(struct cache_head *ca, 164e571cbf1STrond Myklebust struct cache_head *cb) 165e571cbf1STrond Myklebust { 166e571cbf1STrond Myklebust struct nfs_dns_ent *a; 167e571cbf1STrond Myklebust struct nfs_dns_ent *b; 168e571cbf1STrond Myklebust 169e571cbf1STrond Myklebust a = container_of(ca, struct nfs_dns_ent, h); 170e571cbf1STrond Myklebust b = container_of(cb, struct nfs_dns_ent, h); 171e571cbf1STrond Myklebust 172e571cbf1STrond Myklebust if (a->namelen == 0 || a->namelen != b->namelen) 173e571cbf1STrond Myklebust return 0; 174e571cbf1STrond Myklebust return memcmp(a->hostname, b->hostname, a->namelen) == 0; 175e571cbf1STrond Myklebust } 176e571cbf1STrond Myklebust 177e571cbf1STrond Myklebust static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, 178e571cbf1STrond Myklebust struct cache_head *h) 179e571cbf1STrond Myklebust { 180e571cbf1STrond Myklebust struct nfs_dns_ent *item; 181e571cbf1STrond Myklebust long ttl; 182e571cbf1STrond Myklebust 183e571cbf1STrond Myklebust if (h == NULL) { 184e571cbf1STrond Myklebust seq_puts(m, "# ip address hostname ttl\n"); 185e571cbf1STrond Myklebust return 0; 186e571cbf1STrond Myklebust } 187e571cbf1STrond Myklebust item = container_of(h, struct nfs_dns_ent, h); 188c5b29f88SNeilBrown ttl = item->h.expiry_time - seconds_since_boot(); 189e571cbf1STrond Myklebust if (ttl < 0) 190e571cbf1STrond Myklebust ttl = 0; 191e571cbf1STrond Myklebust 192e571cbf1STrond Myklebust if (!test_bit(CACHE_NEGATIVE, &h->flags)) { 193e571cbf1STrond Myklebust char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1]; 194e571cbf1STrond Myklebust 195e571cbf1STrond Myklebust rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf)); 196e571cbf1STrond Myklebust seq_printf(m, "%15s ", buf); 197e571cbf1STrond Myklebust } else 198e571cbf1STrond Myklebust seq_puts(m, "<none> "); 199e571cbf1STrond Myklebust seq_printf(m, "%15s %ld\n", item->hostname, ttl); 200e571cbf1STrond Myklebust return 0; 201e571cbf1STrond Myklebust } 202e571cbf1STrond Myklebust 2030a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, 204e571cbf1STrond Myklebust struct nfs_dns_ent *key) 205e571cbf1STrond Myklebust { 206e571cbf1STrond Myklebust struct cache_head *ch; 207e571cbf1STrond Myklebust 208437f9145STrond Myklebust ch = sunrpc_cache_lookup_rcu(cd, 209e571cbf1STrond Myklebust &key->h, 210e571cbf1STrond Myklebust nfs_dns_hash(key)); 211e571cbf1STrond Myklebust if (!ch) 212e571cbf1STrond Myklebust return NULL; 213e571cbf1STrond Myklebust return container_of(ch, struct nfs_dns_ent, h); 214e571cbf1STrond Myklebust } 215e571cbf1STrond Myklebust 2160a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, 217e571cbf1STrond Myklebust struct nfs_dns_ent *new, 218e571cbf1STrond Myklebust struct nfs_dns_ent *key) 219e571cbf1STrond Myklebust { 220e571cbf1STrond Myklebust struct cache_head *ch; 221e571cbf1STrond Myklebust 222e571cbf1STrond Myklebust ch = sunrpc_cache_update(cd, 223e571cbf1STrond Myklebust &new->h, &key->h, 224e571cbf1STrond Myklebust nfs_dns_hash(key)); 225e571cbf1STrond Myklebust if (!ch) 226e571cbf1STrond Myklebust return NULL; 227e571cbf1STrond Myklebust return container_of(ch, struct nfs_dns_ent, h); 228e571cbf1STrond Myklebust } 229e571cbf1STrond Myklebust 230e571cbf1STrond Myklebust static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) 231e571cbf1STrond Myklebust { 232e571cbf1STrond Myklebust char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; 233e571cbf1STrond Myklebust struct nfs_dns_ent key, *item; 2348d96b106SNeilBrown unsigned int ttl; 235e571cbf1STrond Myklebust ssize_t len; 236e571cbf1STrond Myklebust int ret = -EINVAL; 237e571cbf1STrond Myklebust 238e571cbf1STrond Myklebust if (buf[buflen-1] != '\n') 239e571cbf1STrond Myklebust goto out; 240e571cbf1STrond Myklebust buf[buflen-1] = '\0'; 241e571cbf1STrond Myklebust 242e571cbf1STrond Myklebust len = qword_get(&buf, buf1, sizeof(buf1)); 243e571cbf1STrond Myklebust if (len <= 0) 244e571cbf1STrond Myklebust goto out; 245599ec129SStanislav Kinsbursky key.addrlen = rpc_pton(cd->net, buf1, len, 246e571cbf1STrond Myklebust (struct sockaddr *)&key.addr, 247e571cbf1STrond Myklebust sizeof(key.addr)); 248e571cbf1STrond Myklebust 249e571cbf1STrond Myklebust len = qword_get(&buf, buf1, sizeof(buf1)); 250e571cbf1STrond Myklebust if (len <= 0) 251e571cbf1STrond Myklebust goto out; 252e571cbf1STrond Myklebust 253e571cbf1STrond Myklebust key.hostname = buf1; 254e571cbf1STrond Myklebust key.namelen = len; 255e571cbf1STrond Myklebust memset(&key.h, 0, sizeof(key.h)); 256e571cbf1STrond Myklebust 2578d96b106SNeilBrown if (get_uint(&buf, &ttl) < 0) 2588d96b106SNeilBrown goto out; 259e571cbf1STrond Myklebust if (ttl == 0) 260e571cbf1STrond Myklebust goto out; 261c5b29f88SNeilBrown key.h.expiry_time = ttl + seconds_since_boot(); 262e571cbf1STrond Myklebust 263e571cbf1STrond Myklebust ret = -ENOMEM; 264e571cbf1STrond Myklebust item = nfs_dns_lookup(cd, &key); 265e571cbf1STrond Myklebust if (item == NULL) 266e571cbf1STrond Myklebust goto out; 267e571cbf1STrond Myklebust 268e571cbf1STrond Myklebust if (key.addrlen == 0) 269e571cbf1STrond Myklebust set_bit(CACHE_NEGATIVE, &key.h.flags); 270e571cbf1STrond Myklebust 271e571cbf1STrond Myklebust item = nfs_dns_update(cd, &key, item); 272e571cbf1STrond Myklebust if (item == NULL) 273e571cbf1STrond Myklebust goto out; 274e571cbf1STrond Myklebust 275e571cbf1STrond Myklebust ret = 0; 276e571cbf1STrond Myklebust cache_put(&item->h, cd); 277e571cbf1STrond Myklebust out: 278e571cbf1STrond Myklebust return ret; 279e571cbf1STrond Myklebust } 280e571cbf1STrond Myklebust 281e571cbf1STrond Myklebust static int do_cache_lookup(struct cache_detail *cd, 282e571cbf1STrond Myklebust struct nfs_dns_ent *key, 283e571cbf1STrond Myklebust struct nfs_dns_ent **item, 284e571cbf1STrond Myklebust struct nfs_cache_defer_req *dreq) 285e571cbf1STrond Myklebust { 286e571cbf1STrond Myklebust int ret = -ENOMEM; 287e571cbf1STrond Myklebust 288e571cbf1STrond Myklebust *item = nfs_dns_lookup(cd, key); 289e571cbf1STrond Myklebust if (*item) { 290e571cbf1STrond Myklebust ret = cache_check(cd, &(*item)->h, &dreq->req); 291e571cbf1STrond Myklebust if (ret) 292e571cbf1STrond Myklebust *item = NULL; 293e571cbf1STrond Myklebust } 294e571cbf1STrond Myklebust return ret; 295e571cbf1STrond Myklebust } 296e571cbf1STrond Myklebust 297e571cbf1STrond Myklebust static int do_cache_lookup_nowait(struct cache_detail *cd, 298e571cbf1STrond Myklebust struct nfs_dns_ent *key, 299e571cbf1STrond Myklebust struct nfs_dns_ent **item) 300e571cbf1STrond Myklebust { 301e571cbf1STrond Myklebust int ret = -ENOMEM; 302e571cbf1STrond Myklebust 303e571cbf1STrond Myklebust *item = nfs_dns_lookup(cd, key); 304e571cbf1STrond Myklebust if (!*item) 305e571cbf1STrond Myklebust goto out_err; 306e571cbf1STrond Myklebust ret = -ETIMEDOUT; 307e571cbf1STrond Myklebust if (!test_bit(CACHE_VALID, &(*item)->h.flags) 308c5b29f88SNeilBrown || (*item)->h.expiry_time < seconds_since_boot() 309e571cbf1STrond Myklebust || cd->flush_time > (*item)->h.last_refresh) 310e571cbf1STrond Myklebust goto out_put; 311e571cbf1STrond Myklebust ret = -ENOENT; 312e571cbf1STrond Myklebust if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) 313e571cbf1STrond Myklebust goto out_put; 314e571cbf1STrond Myklebust return 0; 315e571cbf1STrond Myklebust out_put: 316e571cbf1STrond Myklebust cache_put(&(*item)->h, cd); 317e571cbf1STrond Myklebust out_err: 318e571cbf1STrond Myklebust *item = NULL; 319e571cbf1STrond Myklebust return ret; 320e571cbf1STrond Myklebust } 321e571cbf1STrond Myklebust 322e571cbf1STrond Myklebust static int do_cache_lookup_wait(struct cache_detail *cd, 323e571cbf1STrond Myklebust struct nfs_dns_ent *key, 324e571cbf1STrond Myklebust struct nfs_dns_ent **item) 325e571cbf1STrond Myklebust { 326e571cbf1STrond Myklebust struct nfs_cache_defer_req *dreq; 327e571cbf1STrond Myklebust int ret = -ENOMEM; 328e571cbf1STrond Myklebust 329e571cbf1STrond Myklebust dreq = nfs_cache_defer_req_alloc(); 330e571cbf1STrond Myklebust if (!dreq) 331e571cbf1STrond Myklebust goto out; 332e571cbf1STrond Myklebust ret = do_cache_lookup(cd, key, item, dreq); 333e571cbf1STrond Myklebust if (ret == -EAGAIN) { 334e571cbf1STrond Myklebust ret = nfs_cache_wait_for_upcall(dreq); 335e571cbf1STrond Myklebust if (!ret) 336e571cbf1STrond Myklebust ret = do_cache_lookup_nowait(cd, key, item); 337e571cbf1STrond Myklebust } 338e571cbf1STrond Myklebust nfs_cache_defer_req_put(dreq); 339e571cbf1STrond Myklebust out: 340e571cbf1STrond Myklebust return ret; 341e571cbf1STrond Myklebust } 342e571cbf1STrond Myklebust 3431b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name, 3441b340d01SStanislav Kinsbursky size_t namelen, struct sockaddr *sa, size_t salen) 345e571cbf1STrond Myklebust { 346e571cbf1STrond Myklebust struct nfs_dns_ent key = { 347e571cbf1STrond Myklebust .hostname = name, 348e571cbf1STrond Myklebust .namelen = namelen, 349e571cbf1STrond Myklebust }; 350e571cbf1STrond Myklebust struct nfs_dns_ent *item = NULL; 351e571cbf1STrond Myklebust ssize_t ret; 3521b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 353e571cbf1STrond Myklebust 3541b340d01SStanislav Kinsbursky ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item); 355e571cbf1STrond Myklebust if (ret == 0) { 356e571cbf1STrond Myklebust if (salen >= item->addrlen) { 357e571cbf1STrond Myklebust memcpy(sa, &item->addr, item->addrlen); 358e571cbf1STrond Myklebust ret = item->addrlen; 359e571cbf1STrond Myklebust } else 360e571cbf1STrond Myklebust ret = -EOVERFLOW; 3611b340d01SStanislav Kinsbursky cache_put(&item->h, nn->nfs_dns_resolve); 362e571cbf1STrond Myklebust } else if (ret == -ENOENT) 363e571cbf1STrond Myklebust ret = -ESRCH; 364e571cbf1STrond Myklebust return ret; 365e571cbf1STrond Myklebust } 366e571cbf1STrond Myklebust 367483479c2SStanislav Kinsbursky static struct cache_detail nfs_dns_resolve_template = { 368483479c2SStanislav Kinsbursky .owner = THIS_MODULE, 369483479c2SStanislav Kinsbursky .hash_size = NFS_DNS_HASHTBL_SIZE, 370483479c2SStanislav Kinsbursky .name = "dns_resolve", 371483479c2SStanislav Kinsbursky .cache_put = nfs_dns_ent_put, 372483479c2SStanislav Kinsbursky .cache_upcall = nfs_dns_upcall, 37373fb847aSStanislav Kinsbursky .cache_request = nfs_dns_request, 374483479c2SStanislav Kinsbursky .cache_parse = nfs_dns_parse, 375483479c2SStanislav Kinsbursky .cache_show = nfs_dns_show, 376483479c2SStanislav Kinsbursky .match = nfs_dns_match, 377483479c2SStanislav Kinsbursky .init = nfs_dns_ent_init, 378483479c2SStanislav Kinsbursky .update = nfs_dns_ent_update, 379483479c2SStanislav Kinsbursky .alloc = nfs_dns_ent_alloc, 380483479c2SStanislav Kinsbursky }; 381483479c2SStanislav Kinsbursky 382483479c2SStanislav Kinsbursky 3831b340d01SStanislav Kinsbursky int nfs_dns_resolver_cache_init(struct net *net) 384e571cbf1STrond Myklebust { 385483479c2SStanislav Kinsbursky int err; 3861b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 3879222b955SStanislav Kinsbursky 388483479c2SStanislav Kinsbursky nn->nfs_dns_resolve = cache_create_net(&nfs_dns_resolve_template, net); 389483479c2SStanislav Kinsbursky if (IS_ERR(nn->nfs_dns_resolve)) 390483479c2SStanislav Kinsbursky return PTR_ERR(nn->nfs_dns_resolve); 3911b340d01SStanislav Kinsbursky 392483479c2SStanislav Kinsbursky err = nfs_cache_register_net(net, nn->nfs_dns_resolve); 3931b340d01SStanislav Kinsbursky if (err) 3941b340d01SStanislav Kinsbursky goto err_reg; 3951b340d01SStanislav Kinsbursky return 0; 3961b340d01SStanislav Kinsbursky 3971b340d01SStanislav Kinsbursky err_reg: 398483479c2SStanislav Kinsbursky cache_destroy_net(nn->nfs_dns_resolve, net); 3999222b955SStanislav Kinsbursky return err; 4009222b955SStanislav Kinsbursky } 4011b340d01SStanislav Kinsbursky 4021b340d01SStanislav Kinsbursky void nfs_dns_resolver_cache_destroy(struct net *net) 4031b340d01SStanislav Kinsbursky { 4041b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 4051b340d01SStanislav Kinsbursky 406462b8f6bSStanislav Kinsbursky nfs_cache_unregister_net(net, nn->nfs_dns_resolve); 407483479c2SStanislav Kinsbursky cache_destroy_net(nn->nfs_dns_resolve, net); 4081b340d01SStanislav Kinsbursky } 4091b340d01SStanislav Kinsbursky 410c8d74d9bSTrond Myklebust static int nfs4_dns_net_init(struct net *net) 411c8d74d9bSTrond Myklebust { 412c8d74d9bSTrond Myklebust return nfs_dns_resolver_cache_init(net); 413c8d74d9bSTrond Myklebust } 414c8d74d9bSTrond Myklebust 415c8d74d9bSTrond Myklebust static void nfs4_dns_net_exit(struct net *net) 416c8d74d9bSTrond Myklebust { 417c8d74d9bSTrond Myklebust nfs_dns_resolver_cache_destroy(net); 418c8d74d9bSTrond Myklebust } 419c8d74d9bSTrond Myklebust 420c8d74d9bSTrond Myklebust static struct pernet_operations nfs4_dns_resolver_ops = { 421c8d74d9bSTrond Myklebust .init = nfs4_dns_net_init, 422c8d74d9bSTrond Myklebust .exit = nfs4_dns_net_exit, 423c8d74d9bSTrond Myklebust }; 424c8d74d9bSTrond Myklebust 4259df69c81SStanislav Kinsbursky static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, 4269df69c81SStanislav Kinsbursky void *ptr) 4279df69c81SStanislav Kinsbursky { 4289df69c81SStanislav Kinsbursky struct super_block *sb = ptr; 4299df69c81SStanislav Kinsbursky struct net *net = sb->s_fs_info; 4309df69c81SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 4319df69c81SStanislav Kinsbursky struct cache_detail *cd = nn->nfs_dns_resolve; 4329df69c81SStanislav Kinsbursky int ret = 0; 4339df69c81SStanislav Kinsbursky 4349df69c81SStanislav Kinsbursky if (cd == NULL) 4359df69c81SStanislav Kinsbursky return 0; 4369df69c81SStanislav Kinsbursky 4379df69c81SStanislav Kinsbursky if (!try_module_get(THIS_MODULE)) 4389df69c81SStanislav Kinsbursky return 0; 4399df69c81SStanislav Kinsbursky 4409df69c81SStanislav Kinsbursky switch (event) { 4419df69c81SStanislav Kinsbursky case RPC_PIPEFS_MOUNT: 4429df69c81SStanislav Kinsbursky ret = nfs_cache_register_sb(sb, cd); 4439df69c81SStanislav Kinsbursky break; 4449df69c81SStanislav Kinsbursky case RPC_PIPEFS_UMOUNT: 4459df69c81SStanislav Kinsbursky nfs_cache_unregister_sb(sb, cd); 4469df69c81SStanislav Kinsbursky break; 4479df69c81SStanislav Kinsbursky default: 4489df69c81SStanislav Kinsbursky ret = -ENOTSUPP; 4499df69c81SStanislav Kinsbursky break; 4509df69c81SStanislav Kinsbursky } 4519df69c81SStanislav Kinsbursky module_put(THIS_MODULE); 4529df69c81SStanislav Kinsbursky return ret; 4539df69c81SStanislav Kinsbursky } 4549df69c81SStanislav Kinsbursky 4559df69c81SStanislav Kinsbursky static struct notifier_block nfs_dns_resolver_block = { 4569df69c81SStanislav Kinsbursky .notifier_call = rpc_pipefs_event, 4579df69c81SStanislav Kinsbursky }; 4589df69c81SStanislav Kinsbursky 4591b340d01SStanislav Kinsbursky int nfs_dns_resolver_init(void) 4601b340d01SStanislav Kinsbursky { 461c8d74d9bSTrond Myklebust int err; 462c8d74d9bSTrond Myklebust 463c8d74d9bSTrond Myklebust err = register_pernet_subsys(&nfs4_dns_resolver_ops); 464c8d74d9bSTrond Myklebust if (err < 0) 465c8d74d9bSTrond Myklebust goto out; 466c8d74d9bSTrond Myklebust err = rpc_pipefs_notifier_register(&nfs_dns_resolver_block); 467c8d74d9bSTrond Myklebust if (err < 0) 468c8d74d9bSTrond Myklebust goto out1; 469c8d74d9bSTrond Myklebust return 0; 470c8d74d9bSTrond Myklebust out1: 471c8d74d9bSTrond Myklebust unregister_pernet_subsys(&nfs4_dns_resolver_ops); 472c8d74d9bSTrond Myklebust out: 473c8d74d9bSTrond Myklebust return err; 474e571cbf1STrond Myklebust } 475e571cbf1STrond Myklebust 476e571cbf1STrond Myklebust void nfs_dns_resolver_destroy(void) 477e571cbf1STrond Myklebust { 4789df69c81SStanislav Kinsbursky rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block); 479c8d74d9bSTrond Myklebust unregister_pernet_subsys(&nfs4_dns_resolver_ops); 480e571cbf1STrond Myklebust } 481c2e8139cSBryan Schumaker #endif 482