LCOV - code coverage report
Current view: top level - fs/nfs - dns_resolve.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 7 0.0 %
Date: 2014-02-18 Functions: 0 1 0.0 %
Branches: 0 2 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * linux/fs/nfs/dns_resolve.c
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
       5                 :            :  *
       6                 :            :  * Resolves DNS hostnames into valid ip addresses
       7                 :            :  */
       8                 :            : 
       9                 :            : #ifdef CONFIG_NFS_USE_KERNEL_DNS
      10                 :            : 
      11                 :            : #include <linux/module.h>
      12                 :            : #include <linux/sunrpc/clnt.h>
      13                 :            : #include <linux/sunrpc/addr.h>
      14                 :            : #include <linux/dns_resolver.h>
      15                 :            : #include "dns_resolve.h"
      16                 :            : 
      17                 :          0 : ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
      18                 :            :                 struct sockaddr *sa, size_t salen)
      19                 :            : {
      20                 :            :         ssize_t ret;
      21                 :          0 :         char *ip_addr = NULL;
      22                 :            :         int ip_len;
      23                 :            : 
      24                 :          0 :         ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
      25         [ #  # ]:          0 :         if (ip_len > 0)
      26                 :          0 :                 ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
      27                 :            :         else
      28                 :            :                 ret = -ESRCH;
      29                 :          0 :         kfree(ip_addr);
      30                 :          0 :         return ret;
      31                 :            : }
      32                 :            : 
      33                 :            : #else
      34                 :            : 
      35                 :            : #include <linux/module.h>
      36                 :            : #include <linux/hash.h>
      37                 :            : #include <linux/string.h>
      38                 :            : #include <linux/kmod.h>
      39                 :            : #include <linux/slab.h>
      40                 :            : #include <linux/module.h>
      41                 :            : #include <linux/socket.h>
      42                 :            : #include <linux/seq_file.h>
      43                 :            : #include <linux/inet.h>
      44                 :            : #include <linux/sunrpc/clnt.h>
      45                 :            : #include <linux/sunrpc/addr.h>
      46                 :            : #include <linux/sunrpc/cache.h>
      47                 :            : #include <linux/sunrpc/svcauth.h>
      48                 :            : #include <linux/sunrpc/rpc_pipe_fs.h>
      49                 :            : #include <linux/nfs_fs.h>
      50                 :            : 
      51                 :            : #include "nfs4_fs.h"
      52                 :            : #include "dns_resolve.h"
      53                 :            : #include "cache_lib.h"
      54                 :            : #include "netns.h"
      55                 :            : 
      56                 :            : #define NFS_DNS_HASHBITS 4
      57                 :            : #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
      58                 :            : 
      59                 :            : struct nfs_dns_ent {
      60                 :            :         struct cache_head h;
      61                 :            : 
      62                 :            :         char *hostname;
      63                 :            :         size_t namelen;
      64                 :            : 
      65                 :            :         struct sockaddr_storage addr;
      66                 :            :         size_t addrlen;
      67                 :            : };
      68                 :            : 
      69                 :            : 
      70                 :            : static void nfs_dns_ent_update(struct cache_head *cnew,
      71                 :            :                 struct cache_head *ckey)
      72                 :            : {
      73                 :            :         struct nfs_dns_ent *new;
      74                 :            :         struct nfs_dns_ent *key;
      75                 :            : 
      76                 :            :         new = container_of(cnew, struct nfs_dns_ent, h);
      77                 :            :         key = container_of(ckey, struct nfs_dns_ent, h);
      78                 :            : 
      79                 :            :         memcpy(&new->addr, &key->addr, key->addrlen);
      80                 :            :         new->addrlen = key->addrlen;
      81                 :            : }
      82                 :            : 
      83                 :            : static void nfs_dns_ent_init(struct cache_head *cnew,
      84                 :            :                 struct cache_head *ckey)
      85                 :            : {
      86                 :            :         struct nfs_dns_ent *new;
      87                 :            :         struct nfs_dns_ent *key;
      88                 :            : 
      89                 :            :         new = container_of(cnew, struct nfs_dns_ent, h);
      90                 :            :         key = container_of(ckey, struct nfs_dns_ent, h);
      91                 :            : 
      92                 :            :         kfree(new->hostname);
      93                 :            :         new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL);
      94                 :            :         if (new->hostname) {
      95                 :            :                 new->namelen = key->namelen;
      96                 :            :                 nfs_dns_ent_update(cnew, ckey);
      97                 :            :         } else {
      98                 :            :                 new->namelen = 0;
      99                 :            :                 new->addrlen = 0;
     100                 :            :         }
     101                 :            : }
     102                 :            : 
     103                 :            : static void nfs_dns_ent_put(struct kref *ref)
     104                 :            : {
     105                 :            :         struct nfs_dns_ent *item;
     106                 :            : 
     107                 :            :         item = container_of(ref, struct nfs_dns_ent, h.ref);
     108                 :            :         kfree(item->hostname);
     109                 :            :         kfree(item);
     110                 :            : }
     111                 :            : 
     112                 :            : static struct cache_head *nfs_dns_ent_alloc(void)
     113                 :            : {
     114                 :            :         struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL);
     115                 :            : 
     116                 :            :         if (item != NULL) {
     117                 :            :                 item->hostname = NULL;
     118                 :            :                 item->namelen = 0;
     119                 :            :                 item->addrlen = 0;
     120                 :            :                 return &item->h;
     121                 :            :         }
     122                 :            :         return NULL;
     123                 :            : };
     124                 :            : 
     125                 :            : static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key)
     126                 :            : {
     127                 :            :         return hash_str(key->hostname, NFS_DNS_HASHBITS);
     128                 :            : }
     129                 :            : 
     130                 :            : static void nfs_dns_request(struct cache_detail *cd,
     131                 :            :                 struct cache_head *ch,
     132                 :            :                 char **bpp, int *blen)
     133                 :            : {
     134                 :            :         struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
     135                 :            : 
     136                 :            :         qword_add(bpp, blen, key->hostname);
     137                 :            :         (*bpp)[-1] = '\n';
     138                 :            : }
     139                 :            : 
     140                 :            : static int nfs_dns_upcall(struct cache_detail *cd,
     141                 :            :                 struct cache_head *ch)
     142                 :            : {
     143                 :            :         struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
     144                 :            :         int ret;
     145                 :            : 
     146                 :            :         ret = nfs_cache_upcall(cd, key->hostname);
     147                 :            :         if (ret)
     148                 :            :                 ret = sunrpc_cache_pipe_upcall(cd, ch);
     149                 :            :         return ret;
     150                 :            : }
     151                 :            : 
     152                 :            : static int nfs_dns_match(struct cache_head *ca,
     153                 :            :                 struct cache_head *cb)
     154                 :            : {
     155                 :            :         struct nfs_dns_ent *a;
     156                 :            :         struct nfs_dns_ent *b;
     157                 :            : 
     158                 :            :         a = container_of(ca, struct nfs_dns_ent, h);
     159                 :            :         b = container_of(cb, struct nfs_dns_ent, h);
     160                 :            : 
     161                 :            :         if (a->namelen == 0 || a->namelen != b->namelen)
     162                 :            :                 return 0;
     163                 :            :         return memcmp(a->hostname, b->hostname, a->namelen) == 0;
     164                 :            : }
     165                 :            : 
     166                 :            : static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
     167                 :            :                 struct cache_head *h)
     168                 :            : {
     169                 :            :         struct nfs_dns_ent *item;
     170                 :            :         long ttl;
     171                 :            : 
     172                 :            :         if (h == NULL) {
     173                 :            :                 seq_puts(m, "# ip address      hostname        ttl\n");
     174                 :            :                 return 0;
     175                 :            :         }
     176                 :            :         item = container_of(h, struct nfs_dns_ent, h);
     177                 :            :         ttl = item->h.expiry_time - seconds_since_boot();
     178                 :            :         if (ttl < 0)
     179                 :            :                 ttl = 0;
     180                 :            : 
     181                 :            :         if (!test_bit(CACHE_NEGATIVE, &h->flags)) {
     182                 :            :                 char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1];
     183                 :            : 
     184                 :            :                 rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf));
     185                 :            :                 seq_printf(m, "%15s ", buf);
     186                 :            :         } else
     187                 :            :                 seq_puts(m, "<none>          ");
     188                 :            :         seq_printf(m, "%15s %ld\n", item->hostname, ttl);
     189                 :            :         return 0;
     190                 :            : }
     191                 :            : 
     192                 :            : static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
     193                 :            :                 struct nfs_dns_ent *key)
     194                 :            : {
     195                 :            :         struct cache_head *ch;
     196                 :            : 
     197                 :            :         ch = sunrpc_cache_lookup(cd,
     198                 :            :                         &key->h,
     199                 :            :                         nfs_dns_hash(key));
     200                 :            :         if (!ch)
     201                 :            :                 return NULL;
     202                 :            :         return container_of(ch, struct nfs_dns_ent, h);
     203                 :            : }
     204                 :            : 
     205                 :            : static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd,
     206                 :            :                 struct nfs_dns_ent *new,
     207                 :            :                 struct nfs_dns_ent *key)
     208                 :            : {
     209                 :            :         struct cache_head *ch;
     210                 :            : 
     211                 :            :         ch = sunrpc_cache_update(cd,
     212                 :            :                         &new->h, &key->h,
     213                 :            :                         nfs_dns_hash(key));
     214                 :            :         if (!ch)
     215                 :            :                 return NULL;
     216                 :            :         return container_of(ch, struct nfs_dns_ent, h);
     217                 :            : }
     218                 :            : 
     219                 :            : static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
     220                 :            : {
     221                 :            :         char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
     222                 :            :         struct nfs_dns_ent key, *item;
     223                 :            :         unsigned int ttl;
     224                 :            :         ssize_t len;
     225                 :            :         int ret = -EINVAL;
     226                 :            : 
     227                 :            :         if (buf[buflen-1] != '\n')
     228                 :            :                 goto out;
     229                 :            :         buf[buflen-1] = '\0';
     230                 :            : 
     231                 :            :         len = qword_get(&buf, buf1, sizeof(buf1));
     232                 :            :         if (len <= 0)
     233                 :            :                 goto out;
     234                 :            :         key.addrlen = rpc_pton(cd->net, buf1, len,
     235                 :            :                         (struct sockaddr *)&key.addr,
     236                 :            :                         sizeof(key.addr));
     237                 :            : 
     238                 :            :         len = qword_get(&buf, buf1, sizeof(buf1));
     239                 :            :         if (len <= 0)
     240                 :            :                 goto out;
     241                 :            : 
     242                 :            :         key.hostname = buf1;
     243                 :            :         key.namelen = len;
     244                 :            :         memset(&key.h, 0, sizeof(key.h));
     245                 :            : 
     246                 :            :         if (get_uint(&buf, &ttl) < 0)
     247                 :            :                 goto out;
     248                 :            :         if (ttl == 0)
     249                 :            :                 goto out;
     250                 :            :         key.h.expiry_time = ttl + seconds_since_boot();
     251                 :            : 
     252                 :            :         ret = -ENOMEM;
     253                 :            :         item = nfs_dns_lookup(cd, &key);
     254                 :            :         if (item == NULL)
     255                 :            :                 goto out;
     256                 :            : 
     257                 :            :         if (key.addrlen == 0)
     258                 :            :                 set_bit(CACHE_NEGATIVE, &key.h.flags);
     259                 :            : 
     260                 :            :         item = nfs_dns_update(cd, &key, item);
     261                 :            :         if (item == NULL)
     262                 :            :                 goto out;
     263                 :            : 
     264                 :            :         ret = 0;
     265                 :            :         cache_put(&item->h, cd);
     266                 :            : out:
     267                 :            :         return ret;
     268                 :            : }
     269                 :            : 
     270                 :            : static int do_cache_lookup(struct cache_detail *cd,
     271                 :            :                 struct nfs_dns_ent *key,
     272                 :            :                 struct nfs_dns_ent **item,
     273                 :            :                 struct nfs_cache_defer_req *dreq)
     274                 :            : {
     275                 :            :         int ret = -ENOMEM;
     276                 :            : 
     277                 :            :         *item = nfs_dns_lookup(cd, key);
     278                 :            :         if (*item) {
     279                 :            :                 ret = cache_check(cd, &(*item)->h, &dreq->req);
     280                 :            :                 if (ret)
     281                 :            :                         *item = NULL;
     282                 :            :         }
     283                 :            :         return ret;
     284                 :            : }
     285                 :            : 
     286                 :            : static int do_cache_lookup_nowait(struct cache_detail *cd,
     287                 :            :                 struct nfs_dns_ent *key,
     288                 :            :                 struct nfs_dns_ent **item)
     289                 :            : {
     290                 :            :         int ret = -ENOMEM;
     291                 :            : 
     292                 :            :         *item = nfs_dns_lookup(cd, key);
     293                 :            :         if (!*item)
     294                 :            :                 goto out_err;
     295                 :            :         ret = -ETIMEDOUT;
     296                 :            :         if (!test_bit(CACHE_VALID, &(*item)->h.flags)
     297                 :            :                         || (*item)->h.expiry_time < seconds_since_boot()
     298                 :            :                         || cd->flush_time > (*item)->h.last_refresh)
     299                 :            :                 goto out_put;
     300                 :            :         ret = -ENOENT;
     301                 :            :         if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
     302                 :            :                 goto out_put;
     303                 :            :         return 0;
     304                 :            : out_put:
     305                 :            :         cache_put(&(*item)->h, cd);
     306                 :            : out_err:
     307                 :            :         *item = NULL;
     308                 :            :         return ret;
     309                 :            : }
     310                 :            : 
     311                 :            : static int do_cache_lookup_wait(struct cache_detail *cd,
     312                 :            :                 struct nfs_dns_ent *key,
     313                 :            :                 struct nfs_dns_ent **item)
     314                 :            : {
     315                 :            :         struct nfs_cache_defer_req *dreq;
     316                 :            :         int ret = -ENOMEM;
     317                 :            : 
     318                 :            :         dreq = nfs_cache_defer_req_alloc();
     319                 :            :         if (!dreq)
     320                 :            :                 goto out;
     321                 :            :         ret = do_cache_lookup(cd, key, item, dreq);
     322                 :            :         if (ret == -EAGAIN) {
     323                 :            :                 ret = nfs_cache_wait_for_upcall(dreq);
     324                 :            :                 if (!ret)
     325                 :            :                         ret = do_cache_lookup_nowait(cd, key, item);
     326                 :            :         }
     327                 :            :         nfs_cache_defer_req_put(dreq);
     328                 :            : out:
     329                 :            :         return ret;
     330                 :            : }
     331                 :            : 
     332                 :            : ssize_t nfs_dns_resolve_name(struct net *net, char *name,
     333                 :            :                 size_t namelen, struct sockaddr *sa, size_t salen)
     334                 :            : {
     335                 :            :         struct nfs_dns_ent key = {
     336                 :            :                 .hostname = name,
     337                 :            :                 .namelen = namelen,
     338                 :            :         };
     339                 :            :         struct nfs_dns_ent *item = NULL;
     340                 :            :         ssize_t ret;
     341                 :            :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     342                 :            : 
     343                 :            :         ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
     344                 :            :         if (ret == 0) {
     345                 :            :                 if (salen >= item->addrlen) {
     346                 :            :                         memcpy(sa, &item->addr, item->addrlen);
     347                 :            :                         ret = item->addrlen;
     348                 :            :                 } else
     349                 :            :                         ret = -EOVERFLOW;
     350                 :            :                 cache_put(&item->h, nn->nfs_dns_resolve);
     351                 :            :         } else if (ret == -ENOENT)
     352                 :            :                 ret = -ESRCH;
     353                 :            :         return ret;
     354                 :            : }
     355                 :            : 
     356                 :            : static struct cache_detail nfs_dns_resolve_template = {
     357                 :            :         .owner          = THIS_MODULE,
     358                 :            :         .hash_size      = NFS_DNS_HASHTBL_SIZE,
     359                 :            :         .name           = "dns_resolve",
     360                 :            :         .cache_put      = nfs_dns_ent_put,
     361                 :            :         .cache_upcall   = nfs_dns_upcall,
     362                 :            :         .cache_request  = nfs_dns_request,
     363                 :            :         .cache_parse    = nfs_dns_parse,
     364                 :            :         .cache_show     = nfs_dns_show,
     365                 :            :         .match          = nfs_dns_match,
     366                 :            :         .init           = nfs_dns_ent_init,
     367                 :            :         .update         = nfs_dns_ent_update,
     368                 :            :         .alloc          = nfs_dns_ent_alloc,
     369                 :            : };
     370                 :            : 
     371                 :            : 
     372                 :            : int nfs_dns_resolver_cache_init(struct net *net)
     373                 :            : {
     374                 :            :         int err;
     375                 :            :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     376                 :            : 
     377                 :            :         nn->nfs_dns_resolve = cache_create_net(&nfs_dns_resolve_template, net);
     378                 :            :         if (IS_ERR(nn->nfs_dns_resolve))
     379                 :            :                 return PTR_ERR(nn->nfs_dns_resolve);
     380                 :            : 
     381                 :            :         err = nfs_cache_register_net(net, nn->nfs_dns_resolve);
     382                 :            :         if (err)
     383                 :            :                 goto err_reg;
     384                 :            :         return 0;
     385                 :            : 
     386                 :            : err_reg:
     387                 :            :         cache_destroy_net(nn->nfs_dns_resolve, net);
     388                 :            :         return err;
     389                 :            : }
     390                 :            : 
     391                 :            : void nfs_dns_resolver_cache_destroy(struct net *net)
     392                 :            : {
     393                 :            :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     394                 :            : 
     395                 :            :         nfs_cache_unregister_net(net, nn->nfs_dns_resolve);
     396                 :            :         cache_destroy_net(nn->nfs_dns_resolve, net);
     397                 :            : }
     398                 :            : 
     399                 :            : static int nfs4_dns_net_init(struct net *net)
     400                 :            : {
     401                 :            :         return nfs_dns_resolver_cache_init(net);
     402                 :            : }
     403                 :            : 
     404                 :            : static void nfs4_dns_net_exit(struct net *net)
     405                 :            : {
     406                 :            :         nfs_dns_resolver_cache_destroy(net);
     407                 :            : }
     408                 :            : 
     409                 :            : static struct pernet_operations nfs4_dns_resolver_ops = {
     410                 :            :         .init = nfs4_dns_net_init,
     411                 :            :         .exit = nfs4_dns_net_exit,
     412                 :            : };
     413                 :            : 
     414                 :            : static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
     415                 :            :                            void *ptr)
     416                 :            : {
     417                 :            :         struct super_block *sb = ptr;
     418                 :            :         struct net *net = sb->s_fs_info;
     419                 :            :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     420                 :            :         struct cache_detail *cd = nn->nfs_dns_resolve;
     421                 :            :         int ret = 0;
     422                 :            : 
     423                 :            :         if (cd == NULL)
     424                 :            :                 return 0;
     425                 :            : 
     426                 :            :         if (!try_module_get(THIS_MODULE))
     427                 :            :                 return 0;
     428                 :            : 
     429                 :            :         switch (event) {
     430                 :            :         case RPC_PIPEFS_MOUNT:
     431                 :            :                 ret = nfs_cache_register_sb(sb, cd);
     432                 :            :                 break;
     433                 :            :         case RPC_PIPEFS_UMOUNT:
     434                 :            :                 nfs_cache_unregister_sb(sb, cd);
     435                 :            :                 break;
     436                 :            :         default:
     437                 :            :                 ret = -ENOTSUPP;
     438                 :            :                 break;
     439                 :            :         }
     440                 :            :         module_put(THIS_MODULE);
     441                 :            :         return ret;
     442                 :            : }
     443                 :            : 
     444                 :            : static struct notifier_block nfs_dns_resolver_block = {
     445                 :            :         .notifier_call  = rpc_pipefs_event,
     446                 :            : };
     447                 :            : 
     448                 :            : int nfs_dns_resolver_init(void)
     449                 :            : {
     450                 :            :         int err;
     451                 :            : 
     452                 :            :         err = register_pernet_subsys(&nfs4_dns_resolver_ops);
     453                 :            :         if (err < 0)
     454                 :            :                 goto out;
     455                 :            :         err = rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
     456                 :            :         if (err < 0)
     457                 :            :                 goto out1;
     458                 :            :         return 0;
     459                 :            : out1:
     460                 :            :         unregister_pernet_subsys(&nfs4_dns_resolver_ops);
     461                 :            : out:
     462                 :            :         return err;
     463                 :            : }
     464                 :            : 
     465                 :            : void nfs_dns_resolver_destroy(void)
     466                 :            : {
     467                 :            :         rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
     468                 :            :         unregister_pernet_subsys(&nfs4_dns_resolver_ops);
     469                 :            : }
     470                 :            : #endif

Generated by: LCOV version 1.9