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 11c2e8139cSBryan Schumaker #include <linux/sunrpc/clnt.h> 12c2e8139cSBryan Schumaker #include <linux/dns_resolver.h> 13c2e8139cSBryan Schumaker 141b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, 15c2e8139cSBryan Schumaker struct sockaddr *sa, size_t salen) 16c2e8139cSBryan Schumaker { 17c2e8139cSBryan Schumaker ssize_t ret; 18c2e8139cSBryan Schumaker char *ip_addr = NULL; 19c2e8139cSBryan Schumaker int ip_len; 20c2e8139cSBryan Schumaker 21c2e8139cSBryan Schumaker ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); 22c2e8139cSBryan Schumaker if (ip_len > 0) 2390100b17SStanislav Kinsbursky ret = rpc_pton(&init_net, ip_addr, ip_len, sa, salen); 24c2e8139cSBryan Schumaker else 25c2e8139cSBryan Schumaker ret = -ESRCH; 26c2e8139cSBryan Schumaker kfree(ip_addr); 27c2e8139cSBryan Schumaker return ret; 28c2e8139cSBryan Schumaker } 29c2e8139cSBryan Schumaker 30c2e8139cSBryan Schumaker #else 31c2e8139cSBryan Schumaker 32e571cbf1STrond Myklebust #include <linux/hash.h> 33e571cbf1STrond Myklebust #include <linux/string.h> 34e571cbf1STrond Myklebust #include <linux/kmod.h> 355a0e3ad6STejun Heo #include <linux/slab.h> 36e571cbf1STrond Myklebust #include <linux/module.h> 37e571cbf1STrond Myklebust #include <linux/socket.h> 38e571cbf1STrond Myklebust #include <linux/seq_file.h> 39e571cbf1STrond Myklebust #include <linux/inet.h> 40e571cbf1STrond Myklebust #include <linux/sunrpc/clnt.h> 41e571cbf1STrond Myklebust #include <linux/sunrpc/cache.h> 42e571cbf1STrond Myklebust #include <linux/sunrpc/svcauth.h> 439df69c81SStanislav Kinsbursky #include <linux/sunrpc/rpc_pipe_fs.h> 44e571cbf1STrond Myklebust 45e571cbf1STrond Myklebust #include "dns_resolve.h" 46e571cbf1STrond Myklebust #include "cache_lib.h" 471b340d01SStanislav Kinsbursky #include "netns.h" 48e571cbf1STrond Myklebust 49e571cbf1STrond Myklebust #define NFS_DNS_HASHBITS 4 50e571cbf1STrond Myklebust #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) 51e571cbf1STrond Myklebust 52e571cbf1STrond Myklebust struct nfs_dns_ent { 53e571cbf1STrond Myklebust struct cache_head h; 54e571cbf1STrond Myklebust 55e571cbf1STrond Myklebust char *hostname; 56e571cbf1STrond Myklebust size_t namelen; 57e571cbf1STrond Myklebust 58e571cbf1STrond Myklebust struct sockaddr_storage addr; 59e571cbf1STrond Myklebust size_t addrlen; 60e571cbf1STrond Myklebust }; 61e571cbf1STrond Myklebust 62e571cbf1STrond Myklebust 63ebed9203STrond Myklebust static void nfs_dns_ent_update(struct cache_head *cnew, 64ebed9203STrond Myklebust struct cache_head *ckey) 65ebed9203STrond Myklebust { 66ebed9203STrond Myklebust struct nfs_dns_ent *new; 67ebed9203STrond Myklebust struct nfs_dns_ent *key; 68ebed9203STrond Myklebust 69ebed9203STrond Myklebust new = container_of(cnew, struct nfs_dns_ent, h); 70ebed9203STrond Myklebust key = container_of(ckey, struct nfs_dns_ent, h); 71ebed9203STrond Myklebust 72ebed9203STrond Myklebust memcpy(&new->addr, &key->addr, key->addrlen); 73ebed9203STrond Myklebust new->addrlen = key->addrlen; 74ebed9203STrond Myklebust } 75ebed9203STrond Myklebust 76e571cbf1STrond Myklebust static void nfs_dns_ent_init(struct cache_head *cnew, 77e571cbf1STrond Myklebust struct cache_head *ckey) 78e571cbf1STrond Myklebust { 79e571cbf1STrond Myklebust struct nfs_dns_ent *new; 80e571cbf1STrond Myklebust struct nfs_dns_ent *key; 81e571cbf1STrond Myklebust 82e571cbf1STrond Myklebust new = container_of(cnew, struct nfs_dns_ent, h); 83e571cbf1STrond Myklebust key = container_of(ckey, struct nfs_dns_ent, h); 84e571cbf1STrond Myklebust 85e571cbf1STrond Myklebust kfree(new->hostname); 86e571cbf1STrond Myklebust new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); 87e571cbf1STrond Myklebust if (new->hostname) { 88e571cbf1STrond Myklebust new->namelen = key->namelen; 89ebed9203STrond Myklebust nfs_dns_ent_update(cnew, ckey); 90e571cbf1STrond Myklebust } else { 91e571cbf1STrond Myklebust new->namelen = 0; 92e571cbf1STrond Myklebust new->addrlen = 0; 93e571cbf1STrond Myklebust } 94e571cbf1STrond Myklebust } 95e571cbf1STrond Myklebust 96e571cbf1STrond Myklebust static void nfs_dns_ent_put(struct kref *ref) 97e571cbf1STrond Myklebust { 98e571cbf1STrond Myklebust struct nfs_dns_ent *item; 99e571cbf1STrond Myklebust 100e571cbf1STrond Myklebust item = container_of(ref, struct nfs_dns_ent, h.ref); 101e571cbf1STrond Myklebust kfree(item->hostname); 102e571cbf1STrond Myklebust kfree(item); 103e571cbf1STrond Myklebust } 104e571cbf1STrond Myklebust 105e571cbf1STrond Myklebust static struct cache_head *nfs_dns_ent_alloc(void) 106e571cbf1STrond Myklebust { 107e571cbf1STrond Myklebust struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL); 108e571cbf1STrond Myklebust 109e571cbf1STrond Myklebust if (item != NULL) { 110e571cbf1STrond Myklebust item->hostname = NULL; 111e571cbf1STrond Myklebust item->namelen = 0; 112e571cbf1STrond Myklebust item->addrlen = 0; 113e571cbf1STrond Myklebust return &item->h; 114e571cbf1STrond Myklebust } 115e571cbf1STrond Myklebust return NULL; 116e571cbf1STrond Myklebust }; 117e571cbf1STrond Myklebust 118e571cbf1STrond Myklebust static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key) 119e571cbf1STrond Myklebust { 120e571cbf1STrond Myklebust return hash_str(key->hostname, NFS_DNS_HASHBITS); 121e571cbf1STrond Myklebust } 122e571cbf1STrond Myklebust 123e571cbf1STrond Myklebust static void nfs_dns_request(struct cache_detail *cd, 124e571cbf1STrond Myklebust struct cache_head *ch, 125e571cbf1STrond Myklebust char **bpp, int *blen) 126e571cbf1STrond Myklebust { 127e571cbf1STrond Myklebust struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 128e571cbf1STrond Myklebust 129e571cbf1STrond Myklebust qword_add(bpp, blen, key->hostname); 130e571cbf1STrond Myklebust (*bpp)[-1] = '\n'; 131e571cbf1STrond Myklebust } 132e571cbf1STrond Myklebust 133e571cbf1STrond Myklebust static int nfs_dns_upcall(struct cache_detail *cd, 134e571cbf1STrond Myklebust struct cache_head *ch) 135e571cbf1STrond Myklebust { 136e571cbf1STrond Myklebust struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 137e571cbf1STrond Myklebust int ret; 138e571cbf1STrond Myklebust 139e571cbf1STrond Myklebust ret = nfs_cache_upcall(cd, key->hostname); 140e571cbf1STrond Myklebust if (ret) 141e571cbf1STrond Myklebust ret = sunrpc_cache_pipe_upcall(cd, ch, nfs_dns_request); 142e571cbf1STrond Myklebust return ret; 143e571cbf1STrond Myklebust } 144e571cbf1STrond Myklebust 145e571cbf1STrond Myklebust static int nfs_dns_match(struct cache_head *ca, 146e571cbf1STrond Myklebust struct cache_head *cb) 147e571cbf1STrond Myklebust { 148e571cbf1STrond Myklebust struct nfs_dns_ent *a; 149e571cbf1STrond Myklebust struct nfs_dns_ent *b; 150e571cbf1STrond Myklebust 151e571cbf1STrond Myklebust a = container_of(ca, struct nfs_dns_ent, h); 152e571cbf1STrond Myklebust b = container_of(cb, struct nfs_dns_ent, h); 153e571cbf1STrond Myklebust 154e571cbf1STrond Myklebust if (a->namelen == 0 || a->namelen != b->namelen) 155e571cbf1STrond Myklebust return 0; 156e571cbf1STrond Myklebust return memcmp(a->hostname, b->hostname, a->namelen) == 0; 157e571cbf1STrond Myklebust } 158e571cbf1STrond Myklebust 159e571cbf1STrond Myklebust static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, 160e571cbf1STrond Myklebust struct cache_head *h) 161e571cbf1STrond Myklebust { 162e571cbf1STrond Myklebust struct nfs_dns_ent *item; 163e571cbf1STrond Myklebust long ttl; 164e571cbf1STrond Myklebust 165e571cbf1STrond Myklebust if (h == NULL) { 166e571cbf1STrond Myklebust seq_puts(m, "# ip address hostname ttl\n"); 167e571cbf1STrond Myklebust return 0; 168e571cbf1STrond Myklebust } 169e571cbf1STrond Myklebust item = container_of(h, struct nfs_dns_ent, h); 170c5b29f88SNeilBrown ttl = item->h.expiry_time - seconds_since_boot(); 171e571cbf1STrond Myklebust if (ttl < 0) 172e571cbf1STrond Myklebust ttl = 0; 173e571cbf1STrond Myklebust 174e571cbf1STrond Myklebust if (!test_bit(CACHE_NEGATIVE, &h->flags)) { 175e571cbf1STrond Myklebust char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1]; 176e571cbf1STrond Myklebust 177e571cbf1STrond Myklebust rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf)); 178e571cbf1STrond Myklebust seq_printf(m, "%15s ", buf); 179e571cbf1STrond Myklebust } else 180e571cbf1STrond Myklebust seq_puts(m, "<none> "); 181e571cbf1STrond Myklebust seq_printf(m, "%15s %ld\n", item->hostname, ttl); 182e571cbf1STrond Myklebust return 0; 183e571cbf1STrond Myklebust } 184e571cbf1STrond Myklebust 1850a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, 186e571cbf1STrond Myklebust struct nfs_dns_ent *key) 187e571cbf1STrond Myklebust { 188e571cbf1STrond Myklebust struct cache_head *ch; 189e571cbf1STrond Myklebust 190e571cbf1STrond Myklebust ch = sunrpc_cache_lookup(cd, 191e571cbf1STrond Myklebust &key->h, 192e571cbf1STrond Myklebust nfs_dns_hash(key)); 193e571cbf1STrond Myklebust if (!ch) 194e571cbf1STrond Myklebust return NULL; 195e571cbf1STrond Myklebust return container_of(ch, struct nfs_dns_ent, h); 196e571cbf1STrond Myklebust } 197e571cbf1STrond Myklebust 1980a6566ecSTrond Myklebust static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, 199e571cbf1STrond Myklebust struct nfs_dns_ent *new, 200e571cbf1STrond Myklebust struct nfs_dns_ent *key) 201e571cbf1STrond Myklebust { 202e571cbf1STrond Myklebust struct cache_head *ch; 203e571cbf1STrond Myklebust 204e571cbf1STrond Myklebust ch = sunrpc_cache_update(cd, 205e571cbf1STrond Myklebust &new->h, &key->h, 206e571cbf1STrond Myklebust nfs_dns_hash(key)); 207e571cbf1STrond Myklebust if (!ch) 208e571cbf1STrond Myklebust return NULL; 209e571cbf1STrond Myklebust return container_of(ch, struct nfs_dns_ent, h); 210e571cbf1STrond Myklebust } 211e571cbf1STrond Myklebust 212e571cbf1STrond Myklebust static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) 213e571cbf1STrond Myklebust { 214e571cbf1STrond Myklebust char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; 215e571cbf1STrond Myklebust struct nfs_dns_ent key, *item; 216e571cbf1STrond Myklebust unsigned long ttl; 217e571cbf1STrond Myklebust ssize_t len; 218e571cbf1STrond Myklebust int ret = -EINVAL; 219e571cbf1STrond Myklebust 220e571cbf1STrond Myklebust if (buf[buflen-1] != '\n') 221e571cbf1STrond Myklebust goto out; 222e571cbf1STrond Myklebust buf[buflen-1] = '\0'; 223e571cbf1STrond Myklebust 224e571cbf1STrond Myklebust len = qword_get(&buf, buf1, sizeof(buf1)); 225e571cbf1STrond Myklebust if (len <= 0) 226e571cbf1STrond Myklebust goto out; 227599ec129SStanislav Kinsbursky key.addrlen = rpc_pton(cd->net, buf1, len, 228e571cbf1STrond Myklebust (struct sockaddr *)&key.addr, 229e571cbf1STrond Myklebust sizeof(key.addr)); 230e571cbf1STrond Myklebust 231e571cbf1STrond Myklebust len = qword_get(&buf, buf1, sizeof(buf1)); 232e571cbf1STrond Myklebust if (len <= 0) 233e571cbf1STrond Myklebust goto out; 234e571cbf1STrond Myklebust 235e571cbf1STrond Myklebust key.hostname = buf1; 236e571cbf1STrond Myklebust key.namelen = len; 237e571cbf1STrond Myklebust memset(&key.h, 0, sizeof(key.h)); 238e571cbf1STrond Myklebust 239e571cbf1STrond Myklebust ttl = get_expiry(&buf); 240e571cbf1STrond Myklebust if (ttl == 0) 241e571cbf1STrond Myklebust goto out; 242c5b29f88SNeilBrown key.h.expiry_time = ttl + seconds_since_boot(); 243e571cbf1STrond Myklebust 244e571cbf1STrond Myklebust ret = -ENOMEM; 245e571cbf1STrond Myklebust item = nfs_dns_lookup(cd, &key); 246e571cbf1STrond Myklebust if (item == NULL) 247e571cbf1STrond Myklebust goto out; 248e571cbf1STrond Myklebust 249e571cbf1STrond Myklebust if (key.addrlen == 0) 250e571cbf1STrond Myklebust set_bit(CACHE_NEGATIVE, &key.h.flags); 251e571cbf1STrond Myklebust 252e571cbf1STrond Myklebust item = nfs_dns_update(cd, &key, item); 253e571cbf1STrond Myklebust if (item == NULL) 254e571cbf1STrond Myklebust goto out; 255e571cbf1STrond Myklebust 256e571cbf1STrond Myklebust ret = 0; 257e571cbf1STrond Myklebust cache_put(&item->h, cd); 258e571cbf1STrond Myklebust out: 259e571cbf1STrond Myklebust return ret; 260e571cbf1STrond Myklebust } 261e571cbf1STrond Myklebust 262e571cbf1STrond Myklebust static int do_cache_lookup(struct cache_detail *cd, 263e571cbf1STrond Myklebust struct nfs_dns_ent *key, 264e571cbf1STrond Myklebust struct nfs_dns_ent **item, 265e571cbf1STrond Myklebust struct nfs_cache_defer_req *dreq) 266e571cbf1STrond Myklebust { 267e571cbf1STrond Myklebust int ret = -ENOMEM; 268e571cbf1STrond Myklebust 269e571cbf1STrond Myklebust *item = nfs_dns_lookup(cd, key); 270e571cbf1STrond Myklebust if (*item) { 271e571cbf1STrond Myklebust ret = cache_check(cd, &(*item)->h, &dreq->req); 272e571cbf1STrond Myklebust if (ret) 273e571cbf1STrond Myklebust *item = NULL; 274e571cbf1STrond Myklebust } 275e571cbf1STrond Myklebust return ret; 276e571cbf1STrond Myklebust } 277e571cbf1STrond Myklebust 278e571cbf1STrond Myklebust static int do_cache_lookup_nowait(struct cache_detail *cd, 279e571cbf1STrond Myklebust struct nfs_dns_ent *key, 280e571cbf1STrond Myklebust struct nfs_dns_ent **item) 281e571cbf1STrond Myklebust { 282e571cbf1STrond Myklebust int ret = -ENOMEM; 283e571cbf1STrond Myklebust 284e571cbf1STrond Myklebust *item = nfs_dns_lookup(cd, key); 285e571cbf1STrond Myklebust if (!*item) 286e571cbf1STrond Myklebust goto out_err; 287e571cbf1STrond Myklebust ret = -ETIMEDOUT; 288e571cbf1STrond Myklebust if (!test_bit(CACHE_VALID, &(*item)->h.flags) 289c5b29f88SNeilBrown || (*item)->h.expiry_time < seconds_since_boot() 290e571cbf1STrond Myklebust || cd->flush_time > (*item)->h.last_refresh) 291e571cbf1STrond Myklebust goto out_put; 292e571cbf1STrond Myklebust ret = -ENOENT; 293e571cbf1STrond Myklebust if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) 294e571cbf1STrond Myklebust goto out_put; 295e571cbf1STrond Myklebust return 0; 296e571cbf1STrond Myklebust out_put: 297e571cbf1STrond Myklebust cache_put(&(*item)->h, cd); 298e571cbf1STrond Myklebust out_err: 299e571cbf1STrond Myklebust *item = NULL; 300e571cbf1STrond Myklebust return ret; 301e571cbf1STrond Myklebust } 302e571cbf1STrond Myklebust 303e571cbf1STrond Myklebust static int do_cache_lookup_wait(struct cache_detail *cd, 304e571cbf1STrond Myklebust struct nfs_dns_ent *key, 305e571cbf1STrond Myklebust struct nfs_dns_ent **item) 306e571cbf1STrond Myklebust { 307e571cbf1STrond Myklebust struct nfs_cache_defer_req *dreq; 308e571cbf1STrond Myklebust int ret = -ENOMEM; 309e571cbf1STrond Myklebust 310e571cbf1STrond Myklebust dreq = nfs_cache_defer_req_alloc(); 311e571cbf1STrond Myklebust if (!dreq) 312e571cbf1STrond Myklebust goto out; 313e571cbf1STrond Myklebust ret = do_cache_lookup(cd, key, item, dreq); 314e571cbf1STrond Myklebust if (ret == -EAGAIN) { 315e571cbf1STrond Myklebust ret = nfs_cache_wait_for_upcall(dreq); 316e571cbf1STrond Myklebust if (!ret) 317e571cbf1STrond Myklebust ret = do_cache_lookup_nowait(cd, key, item); 318e571cbf1STrond Myklebust } 319e571cbf1STrond Myklebust nfs_cache_defer_req_put(dreq); 320e571cbf1STrond Myklebust out: 321e571cbf1STrond Myklebust return ret; 322e571cbf1STrond Myklebust } 323e571cbf1STrond Myklebust 3241b340d01SStanislav Kinsbursky ssize_t nfs_dns_resolve_name(struct net *net, char *name, 3251b340d01SStanislav Kinsbursky size_t namelen, struct sockaddr *sa, size_t salen) 326e571cbf1STrond Myklebust { 327e571cbf1STrond Myklebust struct nfs_dns_ent key = { 328e571cbf1STrond Myklebust .hostname = name, 329e571cbf1STrond Myklebust .namelen = namelen, 330e571cbf1STrond Myklebust }; 331e571cbf1STrond Myklebust struct nfs_dns_ent *item = NULL; 332e571cbf1STrond Myklebust ssize_t ret; 3331b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 334e571cbf1STrond Myklebust 3351b340d01SStanislav Kinsbursky ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item); 336e571cbf1STrond Myklebust if (ret == 0) { 337e571cbf1STrond Myklebust if (salen >= item->addrlen) { 338e571cbf1STrond Myklebust memcpy(sa, &item->addr, item->addrlen); 339e571cbf1STrond Myklebust ret = item->addrlen; 340e571cbf1STrond Myklebust } else 341e571cbf1STrond Myklebust ret = -EOVERFLOW; 3421b340d01SStanislav Kinsbursky cache_put(&item->h, nn->nfs_dns_resolve); 343e571cbf1STrond Myklebust } else if (ret == -ENOENT) 344e571cbf1STrond Myklebust ret = -ESRCH; 345e571cbf1STrond Myklebust return ret; 346e571cbf1STrond Myklebust } 347e571cbf1STrond Myklebust 3481b340d01SStanislav Kinsbursky int nfs_dns_resolver_cache_init(struct net *net) 349e571cbf1STrond Myklebust { 3501b340d01SStanislav Kinsbursky int err = -ENOMEM; 3511b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 3521b340d01SStanislav Kinsbursky struct cache_detail *cd; 3531b340d01SStanislav Kinsbursky struct cache_head **tbl; 3549222b955SStanislav Kinsbursky 3551b340d01SStanislav Kinsbursky cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); 3561b340d01SStanislav Kinsbursky if (cd == NULL) 3571b340d01SStanislav Kinsbursky goto err_cd; 3581b340d01SStanislav Kinsbursky 3591b340d01SStanislav Kinsbursky tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *), 3601b340d01SStanislav Kinsbursky GFP_KERNEL); 3611b340d01SStanislav Kinsbursky if (tbl == NULL) 3621b340d01SStanislav Kinsbursky goto err_tbl; 3631b340d01SStanislav Kinsbursky 3641b340d01SStanislav Kinsbursky cd->owner = THIS_MODULE, 3651b340d01SStanislav Kinsbursky cd->hash_size = NFS_DNS_HASHTBL_SIZE, 3661b340d01SStanislav Kinsbursky cd->hash_table = tbl, 3671b340d01SStanislav Kinsbursky cd->name = "dns_resolve", 3681b340d01SStanislav Kinsbursky cd->cache_put = nfs_dns_ent_put, 3691b340d01SStanislav Kinsbursky cd->cache_upcall = nfs_dns_upcall, 3701b340d01SStanislav Kinsbursky cd->cache_parse = nfs_dns_parse, 3711b340d01SStanislav Kinsbursky cd->cache_show = nfs_dns_show, 3721b340d01SStanislav Kinsbursky cd->match = nfs_dns_match, 3731b340d01SStanislav Kinsbursky cd->init = nfs_dns_ent_init, 3741b340d01SStanislav Kinsbursky cd->update = nfs_dns_ent_update, 3751b340d01SStanislav Kinsbursky cd->alloc = nfs_dns_ent_alloc, 3761b340d01SStanislav Kinsbursky 3771b340d01SStanislav Kinsbursky nfs_cache_init(cd); 3781b340d01SStanislav Kinsbursky err = nfs_cache_register_net(net, cd); 3791b340d01SStanislav Kinsbursky if (err) 3801b340d01SStanislav Kinsbursky goto err_reg; 3811b340d01SStanislav Kinsbursky nn->nfs_dns_resolve = cd; 3821b340d01SStanislav Kinsbursky return 0; 3831b340d01SStanislav Kinsbursky 3841b340d01SStanislav Kinsbursky err_reg: 3851b340d01SStanislav Kinsbursky nfs_cache_destroy(cd); 3861b340d01SStanislav Kinsbursky kfree(cd->hash_table); 3871b340d01SStanislav Kinsbursky err_tbl: 3881b340d01SStanislav Kinsbursky kfree(cd); 3891b340d01SStanislav Kinsbursky err_cd: 3909222b955SStanislav Kinsbursky return err; 3919222b955SStanislav Kinsbursky } 3921b340d01SStanislav Kinsbursky 3931b340d01SStanislav Kinsbursky void nfs_dns_resolver_cache_destroy(struct net *net) 3941b340d01SStanislav Kinsbursky { 3951b340d01SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 3961b340d01SStanislav Kinsbursky struct cache_detail *cd = nn->nfs_dns_resolve; 3971b340d01SStanislav Kinsbursky 3981b340d01SStanislav Kinsbursky nfs_cache_unregister_net(net, cd); 3991b340d01SStanislav Kinsbursky nfs_cache_destroy(cd); 4001b340d01SStanislav Kinsbursky kfree(cd->hash_table); 4011b340d01SStanislav Kinsbursky kfree(cd); 4021b340d01SStanislav Kinsbursky } 4031b340d01SStanislav Kinsbursky 4049df69c81SStanislav Kinsbursky static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, 4059df69c81SStanislav Kinsbursky void *ptr) 4069df69c81SStanislav Kinsbursky { 4079df69c81SStanislav Kinsbursky struct super_block *sb = ptr; 4089df69c81SStanislav Kinsbursky struct net *net = sb->s_fs_info; 4099df69c81SStanislav Kinsbursky struct nfs_net *nn = net_generic(net, nfs_net_id); 4109df69c81SStanislav Kinsbursky struct cache_detail *cd = nn->nfs_dns_resolve; 4119df69c81SStanislav Kinsbursky int ret = 0; 4129df69c81SStanislav Kinsbursky 4139df69c81SStanislav Kinsbursky if (cd == NULL) 4149df69c81SStanislav Kinsbursky return 0; 4159df69c81SStanislav Kinsbursky 4169df69c81SStanislav Kinsbursky if (!try_module_get(THIS_MODULE)) 4179df69c81SStanislav Kinsbursky return 0; 4189df69c81SStanislav Kinsbursky 4199df69c81SStanislav Kinsbursky switch (event) { 4209df69c81SStanislav Kinsbursky case RPC_PIPEFS_MOUNT: 4219df69c81SStanislav Kinsbursky ret = nfs_cache_register_sb(sb, cd); 4229df69c81SStanislav Kinsbursky break; 4239df69c81SStanislav Kinsbursky case RPC_PIPEFS_UMOUNT: 4249df69c81SStanislav Kinsbursky nfs_cache_unregister_sb(sb, cd); 4259df69c81SStanislav Kinsbursky break; 4269df69c81SStanislav Kinsbursky default: 4279df69c81SStanislav Kinsbursky ret = -ENOTSUPP; 4289df69c81SStanislav Kinsbursky break; 4299df69c81SStanislav Kinsbursky } 4309df69c81SStanislav Kinsbursky module_put(THIS_MODULE); 4319df69c81SStanislav Kinsbursky return ret; 4329df69c81SStanislav Kinsbursky } 4339df69c81SStanislav Kinsbursky 4349df69c81SStanislav Kinsbursky static struct notifier_block nfs_dns_resolver_block = { 4359df69c81SStanislav Kinsbursky .notifier_call = rpc_pipefs_event, 4369df69c81SStanislav Kinsbursky }; 4379df69c81SStanislav Kinsbursky 4381b340d01SStanislav Kinsbursky int nfs_dns_resolver_init(void) 4391b340d01SStanislav Kinsbursky { 4409df69c81SStanislav Kinsbursky return rpc_pipefs_notifier_register(&nfs_dns_resolver_block); 441e571cbf1STrond Myklebust } 442e571cbf1STrond Myklebust 443e571cbf1STrond Myklebust void nfs_dns_resolver_destroy(void) 444e571cbf1STrond Myklebust { 4459df69c81SStanislav Kinsbursky rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block); 446e571cbf1STrond Myklebust } 447c2e8139cSBryan Schumaker #endif 448