SUNRPC: create unix gid cache per network namespace
v2:
1) fixed silly usage of template cache as a real one (this code left from
static global cache for all)
This patch makes unix_gid_cache cache detail allocated and registered per
network namespace context.
Thus with this patch unix_gid_cache contents for network namespace "X" are
controlled from proc file system mount for the same network namespace "X".
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 2f8c426..a6eef38 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -436,7 +436,6 @@
uid_t uid;
struct group_info *gi;
};
-static struct cache_head *gid_table[GID_HASHMAX];
static void unix_gid_put(struct kref *kref)
{
@@ -494,8 +493,7 @@
return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);
}
-static struct unix_gid *unix_gid_lookup(uid_t uid);
-extern struct cache_detail unix_gid_cache;
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid);
static int unix_gid_parse(struct cache_detail *cd,
char *mesg, int mlen)
@@ -539,19 +537,19 @@
GROUP_AT(ug.gi, i) = gid;
}
- ugp = unix_gid_lookup(uid);
+ ugp = unix_gid_lookup(cd, uid);
if (ugp) {
struct cache_head *ch;
ug.h.flags = 0;
ug.h.expiry_time = expiry;
- ch = sunrpc_cache_update(&unix_gid_cache,
+ ch = sunrpc_cache_update(cd,
&ug.h, &ugp->h,
hash_long(uid, GID_HASHBITS));
if (!ch)
err = -ENOMEM;
else {
err = 0;
- cache_put(ch, &unix_gid_cache);
+ cache_put(ch, cd);
}
} else
err = -ENOMEM;
@@ -587,10 +585,9 @@
return 0;
}
-struct cache_detail unix_gid_cache = {
+static struct cache_detail unix_gid_cache_template = {
.owner = THIS_MODULE,
.hash_size = GID_HASHMAX,
- .hash_table = gid_table,
.name = "auth.unix.gid",
.cache_put = unix_gid_put,
.cache_upcall = unix_gid_upcall,
@@ -602,14 +599,42 @@
.alloc = unix_gid_alloc,
};
-static struct unix_gid *unix_gid_lookup(uid_t uid)
+int unix_gid_cache_create(struct net *net)
+{
+ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+ struct cache_detail *cd;
+ int err;
+
+ cd = cache_create_net(&unix_gid_cache_template, net);
+ if (IS_ERR(cd))
+ return PTR_ERR(cd);
+ err = cache_register_net(cd, net);
+ if (err) {
+ cache_destroy_net(cd, net);
+ return err;
+ }
+ sn->unix_gid_cache = cd;
+ return 0;
+}
+
+void unix_gid_cache_destroy(struct net *net)
+{
+ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+ struct cache_detail *cd = sn->unix_gid_cache;
+
+ sn->unix_gid_cache = NULL;
+ cache_purge(cd);
+ cache_unregister_net(cd, net);
+ cache_destroy_net(cd, net);
+}
+
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid)
{
struct unix_gid ug;
struct cache_head *ch;
ug.uid = uid;
- ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h,
- hash_long(uid, GID_HASHBITS));
+ ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS));
if (ch)
return container_of(ch, struct unix_gid, h);
else
@@ -621,11 +646,13 @@
struct unix_gid *ug;
struct group_info *gi;
int ret;
+ struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net,
+ sunrpc_net_id);
- ug = unix_gid_lookup(uid);
+ ug = unix_gid_lookup(sn->unix_gid_cache, uid);
if (!ug)
return ERR_PTR(-EAGAIN);
- ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle);
+ ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle);
switch (ret) {
case -ENOENT:
return ERR_PTR(-ENOENT);
@@ -633,7 +660,7 @@
return ERR_PTR(-ESHUTDOWN);
case 0:
gi = get_group_info(ug->gi);
- cache_put(&ug->h, &unix_gid_cache);
+ cache_put(&ug->h, sn->unix_gid_cache);
return gi;
default:
return ERR_PTR(-EAGAIN);