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