Commit 1b340d01 authored by Stanislav Kinsbursky's avatar Stanislav Kinsbursky Committed by Trond Myklebust

NFS: DNS resolver cache per network namespace context introduced

This patch implements DNS resolver cache creation and registration for each
alive network namespace context.
This was done by registering NFS per-net operations, responsible for DNS cache
allocation/register and unregister/destructioning instead of initialization and
destruction of static "nfs_dns_resolve" cache detail (this one was removed).
Pointer to network dns resolver cache is stored in new per-net "nfs_net"
structure.
This patch also changes nfs_dns_resolve_name() function prototype (and it's
calls) by adding network pointer parameter, which is used to get proper DNS
resolver cache pointer for do_cache_lookup_wait() call.

Note: empty nfs_dns_resolver_init() and nfs_dns_resolver_destroy() functions
will be used in next patch in the series.
Signed-off-by: default avatarStanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 5c1cacb1
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/dns_resolver.h> #include <linux/dns_resolver.h>
ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
struct sockaddr *sa, size_t salen) struct sockaddr *sa, size_t salen)
{ {
ssize_t ret; ssize_t ret;
...@@ -43,12 +43,11 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ...@@ -43,12 +43,11 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
#include "dns_resolve.h" #include "dns_resolve.h"
#include "cache_lib.h" #include "cache_lib.h"
#include "netns.h"
#define NFS_DNS_HASHBITS 4 #define NFS_DNS_HASHBITS 4
#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE];
struct nfs_dns_ent { struct nfs_dns_ent {
struct cache_head h; struct cache_head h;
...@@ -259,21 +258,6 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) ...@@ -259,21 +258,6 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
return ret; return ret;
} }
static struct cache_detail nfs_dns_resolve = {
.owner = THIS_MODULE,
.hash_size = NFS_DNS_HASHTBL_SIZE,
.hash_table = nfs_dns_table,
.name = "dns_resolve",
.cache_put = nfs_dns_ent_put,
.cache_upcall = nfs_dns_upcall,
.cache_parse = nfs_dns_parse,
.cache_show = nfs_dns_show,
.match = nfs_dns_match,
.init = nfs_dns_ent_init,
.update = nfs_dns_ent_update,
.alloc = nfs_dns_ent_alloc,
};
static int do_cache_lookup(struct cache_detail *cd, static int do_cache_lookup(struct cache_detail *cd,
struct nfs_dns_ent *key, struct nfs_dns_ent *key,
struct nfs_dns_ent **item, struct nfs_dns_ent **item,
...@@ -336,8 +320,8 @@ static int do_cache_lookup_wait(struct cache_detail *cd, ...@@ -336,8 +320,8 @@ static int do_cache_lookup_wait(struct cache_detail *cd,
return ret; return ret;
} }
ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ssize_t nfs_dns_resolve_name(struct net *net, char *name,
struct sockaddr *sa, size_t salen) size_t namelen, struct sockaddr *sa, size_t salen)
{ {
struct nfs_dns_ent key = { struct nfs_dns_ent key = {
.hostname = name, .hostname = name,
...@@ -345,37 +329,83 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ...@@ -345,37 +329,83 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
}; };
struct nfs_dns_ent *item = NULL; struct nfs_dns_ent *item = NULL;
ssize_t ret; ssize_t ret;
struct nfs_net *nn = net_generic(net, nfs_net_id);
ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
if (ret == 0) { if (ret == 0) {
if (salen >= item->addrlen) { if (salen >= item->addrlen) {
memcpy(sa, &item->addr, item->addrlen); memcpy(sa, &item->addr, item->addrlen);
ret = item->addrlen; ret = item->addrlen;
} else } else
ret = -EOVERFLOW; ret = -EOVERFLOW;
cache_put(&item->h, &nfs_dns_resolve); cache_put(&item->h, nn->nfs_dns_resolve);
} else if (ret == -ENOENT) } else if (ret == -ENOENT)
ret = -ESRCH; ret = -ESRCH;
return ret; return ret;
} }
int nfs_dns_resolver_init(void) int nfs_dns_resolver_cache_init(struct net *net)
{ {
int err; int err = -ENOMEM;
struct nfs_net *nn = net_generic(net, nfs_net_id);
struct cache_detail *cd;
struct cache_head **tbl;
cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
if (cd == NULL)
goto err_cd;
tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *),
GFP_KERNEL);
if (tbl == NULL)
goto err_tbl;
cd->owner = THIS_MODULE,
cd->hash_size = NFS_DNS_HASHTBL_SIZE,
cd->hash_table = tbl,
cd->name = "dns_resolve",
cd->cache_put = nfs_dns_ent_put,
cd->cache_upcall = nfs_dns_upcall,
cd->cache_parse = nfs_dns_parse,
cd->cache_show = nfs_dns_show,
cd->match = nfs_dns_match,
cd->init = nfs_dns_ent_init,
cd->update = nfs_dns_ent_update,
cd->alloc = nfs_dns_ent_alloc,
nfs_cache_init(cd);
err = nfs_cache_register_net(net, cd);
if (err)
goto err_reg;
nn->nfs_dns_resolve = cd;
return 0;
nfs_cache_init(&nfs_dns_resolve); err_reg:
err = nfs_cache_register_net(&init_net, &nfs_dns_resolve); nfs_cache_destroy(cd);
if (err) { kfree(cd->hash_table);
nfs_cache_destroy(&nfs_dns_resolve); err_tbl:
return err; kfree(cd);
} err_cd:
return err;
}
void nfs_dns_resolver_cache_destroy(struct net *net)
{
struct nfs_net *nn = net_generic(net, nfs_net_id);
struct cache_detail *cd = nn->nfs_dns_resolve;
nfs_cache_unregister_net(net, cd);
nfs_cache_destroy(cd);
kfree(cd->hash_table);
kfree(cd);
}
int nfs_dns_resolver_init(void)
{
return 0; return 0;
} }
void nfs_dns_resolver_destroy(void) void nfs_dns_resolver_destroy(void)
{ {
nfs_cache_unregister_net(&init_net, &nfs_dns_resolve);
nfs_cache_destroy(&nfs_dns_resolve);
} }
#endif #endif
...@@ -15,12 +15,22 @@ static inline int nfs_dns_resolver_init(void) ...@@ -15,12 +15,22 @@ static inline int nfs_dns_resolver_init(void)
static inline void nfs_dns_resolver_destroy(void) static inline void nfs_dns_resolver_destroy(void)
{} {}
static inline int nfs_dns_resolver_cache_init(struct net *net)
{
return 0;
}
static inline void nfs_dns_resolver_cache_destroy(struct net *net)
{}
#else #else
extern int nfs_dns_resolver_init(void); extern int nfs_dns_resolver_init(void);
extern void nfs_dns_resolver_destroy(void); extern void nfs_dns_resolver_destroy(void);
extern int nfs_dns_resolver_cache_init(struct net *net);
extern void nfs_dns_resolver_cache_destroy(struct net *net);
#endif #endif
extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, extern ssize_t nfs_dns_resolve_name(struct net *net, char *name,
struct sockaddr *sa, size_t salen); size_t namelen, struct sockaddr *sa, size_t salen);
#endif #endif
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include "fscache.h" #include "fscache.h"
#include "dns_resolve.h" #include "dns_resolve.h"
#include "pnfs.h" #include "pnfs.h"
#include "netns.h"
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
...@@ -1552,6 +1553,25 @@ static void nfsiod_stop(void) ...@@ -1552,6 +1553,25 @@ static void nfsiod_stop(void)
destroy_workqueue(wq); destroy_workqueue(wq);
} }
int nfs_net_id;
static int nfs_net_init(struct net *net)
{
return nfs_dns_resolver_cache_init(net);
}
static void nfs_net_exit(struct net *net)
{
nfs_dns_resolver_cache_destroy(net);
}
static struct pernet_operations nfs_net_ops = {
.init = nfs_net_init,
.exit = nfs_net_exit,
.id = &nfs_net_id,
.size = sizeof(struct nfs_net),
};
/* /*
* Initialize NFS * Initialize NFS
*/ */
...@@ -1561,9 +1581,13 @@ static int __init init_nfs_fs(void) ...@@ -1561,9 +1581,13 @@ static int __init init_nfs_fs(void)
err = nfs_idmap_init(); err = nfs_idmap_init();
if (err < 0) if (err < 0)
goto out9; goto out10;
err = nfs_dns_resolver_init(); err = nfs_dns_resolver_init();
if (err < 0)
goto out9;
err = register_pernet_subsys(&nfs_net_ops);
if (err < 0) if (err < 0)
goto out8; goto out8;
...@@ -1625,10 +1649,12 @@ static int __init init_nfs_fs(void) ...@@ -1625,10 +1649,12 @@ static int __init init_nfs_fs(void)
out6: out6:
nfs_fscache_unregister(); nfs_fscache_unregister();
out7: out7:
nfs_dns_resolver_destroy(); unregister_pernet_subsys(&nfs_net_ops);
out8: out8:
nfs_idmap_quit(); nfs_dns_resolver_destroy();
out9: out9:
nfs_idmap_quit();
out10:
return err; return err;
} }
...@@ -1640,6 +1666,7 @@ static void __exit exit_nfs_fs(void) ...@@ -1640,6 +1666,7 @@ static void __exit exit_nfs_fs(void)
nfs_destroy_inodecache(); nfs_destroy_inodecache();
nfs_destroy_nfspagecache(); nfs_destroy_nfspagecache();
nfs_fscache_unregister(); nfs_fscache_unregister();
unregister_pernet_subsys(&nfs_net_ops);
nfs_dns_resolver_destroy(); nfs_dns_resolver_destroy();
nfs_idmap_quit(); nfs_idmap_quit();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
#ifndef __NFS_NETNS_H__
#define __NFS_NETNS_H__
#include <net/net_namespace.h>
#include <net/netns/generic.h>
struct nfs_net {
struct cache_detail *nfs_dns_resolve;
};
extern int nfs_net_id;
#endif
...@@ -94,13 +94,14 @@ static int nfs4_validate_fspath(struct dentry *dentry, ...@@ -94,13 +94,14 @@ static int nfs4_validate_fspath(struct dentry *dentry,
} }
static size_t nfs_parse_server_name(char *string, size_t len, static size_t nfs_parse_server_name(char *string, size_t len,
struct sockaddr *sa, size_t salen) struct sockaddr *sa, size_t salen, struct nfs_server *server)
{ {
ssize_t ret; ssize_t ret;
ret = rpc_pton(string, len, sa, salen); ret = rpc_pton(string, len, sa, salen);
if (ret == 0) { if (ret == 0) {
ret = nfs_dns_resolve_name(string, len, sa, salen); ret = nfs_dns_resolve_name(server->client->cl_xprt->xprt_net,
string, len, sa, salen);
if (ret < 0) if (ret < 0)
ret = 0; ret = 0;
} }
...@@ -137,7 +138,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, ...@@ -137,7 +138,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
continue; continue;
mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
mountdata->addr, addr_bufsize); mountdata->addr, addr_bufsize,
NFS_SB(mountdata->sb));
if (mountdata->addrlen == 0) if (mountdata->addrlen == 0)
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment