aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:18:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:18:11 -0400
commita00b6151a2ae4c52576c35d3998e144a993d50b8 (patch)
treefc312be05c4deb4dead7a6afa09e88017d3a0146
parent08615d7d85e5aa02c05bf6c4dde87d940e7f85f6 (diff)
parentb108fe6b08f3f61c2c465649b20b7d4b4c185728 (diff)
Merge branch 'for-3.5-take-2' of git://linux-nfs.org/~bfields/linux
Pull nfsd update from Bruce Fields. * 'for-3.5-take-2' of git://linux-nfs.org/~bfields/linux: (23 commits) nfsd: trivial: use SEEK_SET instead of 0 in vfs_llseek SUNRPC: split upcall function to extract reusable parts nfsd: allocate id-to-name and name-to-id caches in per-net operations. nfsd: make name-to-id cache allocated per network namespace context nfsd: make id-to-name cache allocated per network namespace context nfsd: pass network context to idmap init/exit functions nfsd: allocate export and expkey caches in per-net operations. nfsd: make expkey cache allocated per network namespace context nfsd: make export cache allocated per network namespace context nfsd: pass pointer to export cache down to stack wherever possible. nfsd: pass network context to export caches init/shutdown routines Lockd: pass network namespace to creation and destruction routines NFSd: remove hard-coded dereferences to name-to-id and id-to-name caches nfsd: pass pointer to expkey cache down to stack wherever possible. nfsd: use hash table from cache detail in nfsd export seq ops nfsd: pass svc_export_cache pointer as private data to "exports" seq file ops nfsd: use exp_put() for svc_export_cache put nfsd: use cache detail pointer from svc_export structure on cache put nfsd: add link to owner cache detail to svc_export structure nfsd: use passed cache_detail pointer expkey_parse() ...
-rw-r--r--fs/lockd/clntlock.c13
-rw-r--r--fs/lockd/svc.c7
-rw-r--r--fs/nfsd/export.c175
-rw-r--r--fs/nfsd/idmap.h8
-rw-r--r--fs/nfsd/netns.h6
-rw-r--r--fs/nfsd/nfs4idmap.c109
-rw-r--r--fs/nfsd/nfs4state.c13
-rw-r--r--fs/nfsd/nfsctl.c55
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/nfsd/nfssvc.c8
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--include/linux/lockd/bind.h4
-rw-r--r--include/linux/nfsd/export.h13
-rw-r--r--include/linux/sunrpc/svcauth.h3
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c100
-rw-r--r--net/sunrpc/svcauth_unix.c13
16 files changed, 322 insertions, 209 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index ba1dc2eebd1e..ca0a08001449 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
56 u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; 56 u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
57 int status; 57 int status;
58 58
59 status = lockd_up(); 59 status = lockd_up(nlm_init->net);
60 if (status < 0) 60 if (status < 0)
61 return ERR_PTR(status); 61 return ERR_PTR(status);
62 62
@@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
65 nlm_init->hostname, nlm_init->noresvport, 65 nlm_init->hostname, nlm_init->noresvport,
66 nlm_init->net); 66 nlm_init->net);
67 if (host == NULL) { 67 if (host == NULL) {
68 lockd_down(); 68 lockd_down(nlm_init->net);
69 return ERR_PTR(-ENOLCK); 69 return ERR_PTR(-ENOLCK);
70 } 70 }
71 71
@@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init);
80 */ 80 */
81void nlmclnt_done(struct nlm_host *host) 81void nlmclnt_done(struct nlm_host *host)
82{ 82{
83 struct net *net = host->net;
84
83 nlmclnt_release_host(host); 85 nlmclnt_release_host(host);
84 lockd_down(); 86 lockd_down(net);
85} 87}
86EXPORT_SYMBOL_GPL(nlmclnt_done); 88EXPORT_SYMBOL_GPL(nlmclnt_done);
87 89
@@ -220,11 +222,12 @@ reclaimer(void *ptr)
220 struct nlm_wait *block; 222 struct nlm_wait *block;
221 struct file_lock *fl, *next; 223 struct file_lock *fl, *next;
222 u32 nsmstate; 224 u32 nsmstate;
225 struct net *net = host->net;
223 226
224 allow_signal(SIGKILL); 227 allow_signal(SIGKILL);
225 228
226 down_write(&host->h_rwsem); 229 down_write(&host->h_rwsem);
227 lockd_up(); /* note: this cannot fail as lockd is already running */ 230 lockd_up(net); /* note: this cannot fail as lockd is already running */
228 231
229 dprintk("lockd: reclaiming locks for host %s\n", host->h_name); 232 dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
230 233
@@ -275,6 +278,6 @@ restart:
275 278
276 /* Release host handle after use */ 279 /* Release host handle after use */
277 nlmclnt_release_host(host); 280 nlmclnt_release_host(host);
278 lockd_down(); 281 lockd_down(net);
279 return 0; 282 return 0;
280} 283}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index f49b9afc4436..1ead0750cdbb 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -295,11 +295,10 @@ static void lockd_down_net(struct net *net)
295/* 295/*
296 * Bring up the lockd process if it's not already up. 296 * Bring up the lockd process if it's not already up.
297 */ 297 */
298int lockd_up(void) 298int lockd_up(struct net *net)
299{ 299{
300 struct svc_serv *serv; 300 struct svc_serv *serv;
301 int error = 0; 301 int error = 0;
302 struct net *net = current->nsproxy->net_ns;
303 302
304 mutex_lock(&nlmsvc_mutex); 303 mutex_lock(&nlmsvc_mutex);
305 /* 304 /*
@@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up);
378 * Decrement the user count and bring down lockd if we're the last. 377 * Decrement the user count and bring down lockd if we're the last.
379 */ 378 */
380void 379void
381lockd_down(void) 380lockd_down(struct net *net)
382{ 381{
383 mutex_lock(&nlmsvc_mutex); 382 mutex_lock(&nlmsvc_mutex);
384 if (nlmsvc_users) { 383 if (nlmsvc_users) {
385 if (--nlmsvc_users) { 384 if (--nlmsvc_users) {
386 lockd_down_net(current->nsproxy->net_ns); 385 lockd_down_net(net);
387 goto out; 386 goto out;
388 } 387 }
389 } else { 388 } else {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 8e9689abbc0c..dcb52b884519 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -15,11 +15,13 @@
15#include <linux/namei.h> 15#include <linux/namei.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/exportfs.h> 17#include <linux/exportfs.h>
18#include <linux/sunrpc/svc_xprt.h>
18 19
19#include <net/ipv6.h> 20#include <net/ipv6.h>
20 21
21#include "nfsd.h" 22#include "nfsd.h"
22#include "nfsfh.h" 23#include "nfsfh.h"
24#include "netns.h"
23 25
24#define NFSDDBG_FACILITY NFSDDBG_EXPORT 26#define NFSDDBG_FACILITY NFSDDBG_EXPORT
25 27
@@ -38,7 +40,6 @@ typedef struct svc_export svc_export;
38#define EXPKEY_HASHBITS 8 40#define EXPKEY_HASHBITS 8
39#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) 41#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
40#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) 42#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
41static struct cache_head *expkey_table[EXPKEY_HASHMAX];
42 43
43static void expkey_put(struct kref *ref) 44static void expkey_put(struct kref *ref)
44{ 45{
@@ -71,9 +72,9 @@ static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
71 return sunrpc_cache_pipe_upcall(cd, h, expkey_request); 72 return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
72} 73}
73 74
74static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); 75static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
75static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); 76 struct svc_expkey *old);
76static struct cache_detail svc_expkey_cache; 77static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
77 78
78static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) 79static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
79{ 80{
@@ -131,7 +132,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
131 key.ek_fsidtype = fsidtype; 132 key.ek_fsidtype = fsidtype;
132 memcpy(key.ek_fsid, buf, len); 133 memcpy(key.ek_fsid, buf, len);
133 134
134 ek = svc_expkey_lookup(&key); 135 ek = svc_expkey_lookup(cd, &key);
135 err = -ENOMEM; 136 err = -ENOMEM;
136 if (!ek) 137 if (!ek)
137 goto out; 138 goto out;
@@ -145,7 +146,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
145 err = 0; 146 err = 0;
146 if (len == 0) { 147 if (len == 0) {
147 set_bit(CACHE_NEGATIVE, &key.h.flags); 148 set_bit(CACHE_NEGATIVE, &key.h.flags);
148 ek = svc_expkey_update(&key, ek); 149 ek = svc_expkey_update(cd, &key, ek);
149 if (!ek) 150 if (!ek)
150 err = -ENOMEM; 151 err = -ENOMEM;
151 } else { 152 } else {
@@ -155,7 +156,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
155 156
156 dprintk("Found the path %s\n", buf); 157 dprintk("Found the path %s\n", buf);
157 158
158 ek = svc_expkey_update(&key, ek); 159 ek = svc_expkey_update(cd, &key, ek);
159 if (!ek) 160 if (!ek)
160 err = -ENOMEM; 161 err = -ENOMEM;
161 path_put(&key.ek_path); 162 path_put(&key.ek_path);
@@ -163,7 +164,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
163 cache_flush(); 164 cache_flush();
164 out: 165 out:
165 if (ek) 166 if (ek)
166 cache_put(&ek->h, &svc_expkey_cache); 167 cache_put(&ek->h, cd);
167 if (dom) 168 if (dom)
168 auth_domain_put(dom); 169 auth_domain_put(dom);
169 kfree(buf); 170 kfree(buf);
@@ -239,10 +240,9 @@ static struct cache_head *expkey_alloc(void)
239 return NULL; 240 return NULL;
240} 241}
241 242
242static struct cache_detail svc_expkey_cache = { 243static struct cache_detail svc_expkey_cache_template = {
243 .owner = THIS_MODULE, 244 .owner = THIS_MODULE,
244 .hash_size = EXPKEY_HASHMAX, 245 .hash_size = EXPKEY_HASHMAX,
245 .hash_table = expkey_table,
246 .name = "nfsd.fh", 246 .name = "nfsd.fh",
247 .cache_put = expkey_put, 247 .cache_put = expkey_put,
248 .cache_upcall = expkey_upcall, 248 .cache_upcall = expkey_upcall,
@@ -268,13 +268,12 @@ svc_expkey_hash(struct svc_expkey *item)
268} 268}
269 269
270static struct svc_expkey * 270static struct svc_expkey *
271svc_expkey_lookup(struct svc_expkey *item) 271svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
272{ 272{
273 struct cache_head *ch; 273 struct cache_head *ch;
274 int hash = svc_expkey_hash(item); 274 int hash = svc_expkey_hash(item);
275 275
276 ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, 276 ch = sunrpc_cache_lookup(cd, &item->h, hash);
277 hash);
278 if (ch) 277 if (ch)
279 return container_of(ch, struct svc_expkey, h); 278 return container_of(ch, struct svc_expkey, h);
280 else 279 else
@@ -282,13 +281,13 @@ svc_expkey_lookup(struct svc_expkey *item)
282} 281}
283 282
284static struct svc_expkey * 283static struct svc_expkey *
285svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) 284svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
285 struct svc_expkey *old)
286{ 286{
287 struct cache_head *ch; 287 struct cache_head *ch;
288 int hash = svc_expkey_hash(new); 288 int hash = svc_expkey_hash(new);
289 289
290 ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, 290 ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
291 &old->h, hash);
292 if (ch) 291 if (ch)
293 return container_of(ch, struct svc_expkey, h); 292 return container_of(ch, struct svc_expkey, h);
294 else 293 else
@@ -299,8 +298,6 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
299#define EXPORT_HASHBITS 8 298#define EXPORT_HASHBITS 8
300#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) 299#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
301 300
302static struct cache_head *export_table[EXPORT_HASHMAX];
303
304static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) 301static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
305{ 302{
306 int i; 303 int i;
@@ -525,6 +522,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
525 goto out1; 522 goto out1;
526 523
527 exp.ex_client = dom; 524 exp.ex_client = dom;
525 exp.cd = cd;
528 526
529 /* expiry */ 527 /* expiry */
530 err = -EINVAL; 528 err = -EINVAL;
@@ -672,6 +670,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
672 new->ex_fslocs.locations = NULL; 670 new->ex_fslocs.locations = NULL;
673 new->ex_fslocs.locations_count = 0; 671 new->ex_fslocs.locations_count = 0;
674 new->ex_fslocs.migrated = 0; 672 new->ex_fslocs.migrated = 0;
673 new->cd = item->cd;
675} 674}
676 675
677static void export_update(struct cache_head *cnew, struct cache_head *citem) 676static void export_update(struct cache_head *cnew, struct cache_head *citem)
@@ -707,10 +706,9 @@ static struct cache_head *svc_export_alloc(void)
707 return NULL; 706 return NULL;
708} 707}
709 708
710struct cache_detail svc_export_cache = { 709struct cache_detail svc_export_cache_template = {
711 .owner = THIS_MODULE, 710 .owner = THIS_MODULE,
712 .hash_size = EXPORT_HASHMAX, 711 .hash_size = EXPORT_HASHMAX,
713 .hash_table = export_table,
714 .name = "nfsd.export", 712 .name = "nfsd.export",
715 .cache_put = svc_export_put, 713 .cache_put = svc_export_put,
716 .cache_upcall = svc_export_upcall, 714 .cache_upcall = svc_export_upcall,
@@ -739,8 +737,7 @@ svc_export_lookup(struct svc_export *exp)
739 struct cache_head *ch; 737 struct cache_head *ch;
740 int hash = svc_export_hash(exp); 738 int hash = svc_export_hash(exp);
741 739
742 ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, 740 ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash);
743 hash);
744 if (ch) 741 if (ch)
745 return container_of(ch, struct svc_export, h); 742 return container_of(ch, struct svc_export, h);
746 else 743 else
@@ -753,9 +750,7 @@ svc_export_update(struct svc_export *new, struct svc_export *old)
753 struct cache_head *ch; 750 struct cache_head *ch;
754 int hash = svc_export_hash(old); 751 int hash = svc_export_hash(old);
755 752
756 ch = sunrpc_cache_update(&svc_export_cache, &new->h, 753 ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
757 &old->h,
758 hash);
759 if (ch) 754 if (ch)
760 return container_of(ch, struct svc_export, h); 755 return container_of(ch, struct svc_export, h);
761 else 756 else
@@ -764,7 +759,8 @@ svc_export_update(struct svc_export *new, struct svc_export *old)
764 759
765 760
766static struct svc_expkey * 761static struct svc_expkey *
767exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) 762exp_find_key(struct cache_detail *cd, svc_client *clp, int fsid_type,
763 u32 *fsidv, struct cache_req *reqp)
768{ 764{
769 struct svc_expkey key, *ek; 765 struct svc_expkey key, *ek;
770 int err; 766 int err;
@@ -776,18 +772,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
776 key.ek_fsidtype = fsid_type; 772 key.ek_fsidtype = fsid_type;
777 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 773 memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
778 774
779 ek = svc_expkey_lookup(&key); 775 ek = svc_expkey_lookup(cd, &key);
780 if (ek == NULL) 776 if (ek == NULL)
781 return ERR_PTR(-ENOMEM); 777 return ERR_PTR(-ENOMEM);
782 err = cache_check(&svc_expkey_cache, &ek->h, reqp); 778 err = cache_check(cd, &ek->h, reqp);
783 if (err) 779 if (err)
784 return ERR_PTR(err); 780 return ERR_PTR(err);
785 return ek; 781 return ek;
786} 782}
787 783
788 784
789static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, 785static svc_export *exp_get_by_name(struct cache_detail *cd, svc_client *clp,
790 struct cache_req *reqp) 786 const struct path *path, struct cache_req *reqp)
791{ 787{
792 struct svc_export *exp, key; 788 struct svc_export *exp, key;
793 int err; 789 int err;
@@ -797,11 +793,12 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
797 793
798 key.ex_client = clp; 794 key.ex_client = clp;
799 key.ex_path = *path; 795 key.ex_path = *path;
796 key.cd = cd;
800 797
801 exp = svc_export_lookup(&key); 798 exp = svc_export_lookup(&key);
802 if (exp == NULL) 799 if (exp == NULL)
803 return ERR_PTR(-ENOMEM); 800 return ERR_PTR(-ENOMEM);
804 err = cache_check(&svc_export_cache, &exp->h, reqp); 801 err = cache_check(cd, &exp->h, reqp);
805 if (err) 802 if (err)
806 return ERR_PTR(err); 803 return ERR_PTR(err);
807 return exp; 804 return exp;
@@ -810,16 +807,17 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
810/* 807/*
811 * Find the export entry for a given dentry. 808 * Find the export entry for a given dentry.
812 */ 809 */
813static struct svc_export *exp_parent(svc_client *clp, struct path *path) 810static struct svc_export *exp_parent(struct cache_detail *cd, svc_client *clp,
811 struct path *path)
814{ 812{
815 struct dentry *saved = dget(path->dentry); 813 struct dentry *saved = dget(path->dentry);
816 svc_export *exp = exp_get_by_name(clp, path, NULL); 814 svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
817 815
818 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { 816 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
819 struct dentry *parent = dget_parent(path->dentry); 817 struct dentry *parent = dget_parent(path->dentry);
820 dput(path->dentry); 818 dput(path->dentry);
821 path->dentry = parent; 819 path->dentry = parent;
822 exp = exp_get_by_name(clp, path, NULL); 820 exp = exp_get_by_name(cd, clp, path, NULL);
823 } 821 }
824 dput(path->dentry); 822 dput(path->dentry);
825 path->dentry = saved; 823 path->dentry = saved;
@@ -834,13 +832,16 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path)
834 * since its harder to fool a kernel module than a user space program. 832 * since its harder to fool a kernel module than a user space program.
835 */ 833 */
836int 834int
837exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) 835exp_rootfh(struct net *net, svc_client *clp, char *name,
836 struct knfsd_fh *f, int maxsize)
838{ 837{
839 struct svc_export *exp; 838 struct svc_export *exp;
840 struct path path; 839 struct path path;
841 struct inode *inode; 840 struct inode *inode;
842 struct svc_fh fh; 841 struct svc_fh fh;
843 int err; 842 int err;
843 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
844 struct cache_detail *cd = nn->svc_export_cache;
844 845
845 err = -EPERM; 846 err = -EPERM;
846 /* NB: we probably ought to check that it's NUL-terminated */ 847 /* NB: we probably ought to check that it's NUL-terminated */
@@ -853,7 +854,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
853 dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", 854 dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
854 name, path.dentry, clp->name, 855 name, path.dentry, clp->name,
855 inode->i_sb->s_id, inode->i_ino); 856 inode->i_sb->s_id, inode->i_ino);
856 exp = exp_parent(clp, &path); 857 exp = exp_parent(cd, clp, &path);
857 if (IS_ERR(exp)) { 858 if (IS_ERR(exp)) {
858 err = PTR_ERR(exp); 859 err = PTR_ERR(exp);
859 goto out; 860 goto out;
@@ -875,16 +876,18 @@ out:
875 return err; 876 return err;
876} 877}
877 878
878static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, 879static struct svc_export *exp_find(struct cache_detail *cd,
880 struct auth_domain *clp, int fsid_type,
879 u32 *fsidv, struct cache_req *reqp) 881 u32 *fsidv, struct cache_req *reqp)
880{ 882{
881 struct svc_export *exp; 883 struct svc_export *exp;
882 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); 884 struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
885 struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
883 if (IS_ERR(ek)) 886 if (IS_ERR(ek))
884 return ERR_CAST(ek); 887 return ERR_CAST(ek);
885 888
886 exp = exp_get_by_name(clp, &ek->ek_path, reqp); 889 exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
887 cache_put(&ek->h, &svc_expkey_cache); 890 cache_put(&ek->h, nn->svc_expkey_cache);
888 891
889 if (IS_ERR(exp)) 892 if (IS_ERR(exp))
890 return ERR_CAST(exp); 893 return ERR_CAST(exp);
@@ -926,12 +929,14 @@ struct svc_export *
926rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) 929rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
927{ 930{
928 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); 931 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
932 struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
933 struct cache_detail *cd = nn->svc_export_cache;
929 934
930 if (rqstp->rq_client == NULL) 935 if (rqstp->rq_client == NULL)
931 goto gss; 936 goto gss;
932 937
933 /* First try the auth_unix client: */ 938 /* First try the auth_unix client: */
934 exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle); 939 exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
935 if (PTR_ERR(exp) == -ENOENT) 940 if (PTR_ERR(exp) == -ENOENT)
936 goto gss; 941 goto gss;
937 if (IS_ERR(exp)) 942 if (IS_ERR(exp))
@@ -943,7 +948,7 @@ gss:
943 /* Otherwise, try falling back on gss client */ 948 /* Otherwise, try falling back on gss client */
944 if (rqstp->rq_gssclient == NULL) 949 if (rqstp->rq_gssclient == NULL)
945 return exp; 950 return exp;
946 gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle); 951 gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
947 if (PTR_ERR(gssexp) == -ENOENT) 952 if (PTR_ERR(gssexp) == -ENOENT)
948 return exp; 953 return exp;
949 if (!IS_ERR(exp)) 954 if (!IS_ERR(exp))
@@ -955,12 +960,15 @@ struct svc_export *
955rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) 960rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
956{ 961{
957 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); 962 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
963 struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
964 struct cache_detail *cd = nn->svc_export_cache;
958 965
959 if (rqstp->rq_client == NULL) 966 if (rqstp->rq_client == NULL)
960 goto gss; 967 goto gss;
961 968
962 /* First try the auth_unix client: */ 969 /* First try the auth_unix client: */
963 exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle); 970 exp = exp_find(cd, rqstp->rq_client, fsid_type,
971 fsidv, &rqstp->rq_chandle);
964 if (PTR_ERR(exp) == -ENOENT) 972 if (PTR_ERR(exp) == -ENOENT)
965 goto gss; 973 goto gss;
966 if (IS_ERR(exp)) 974 if (IS_ERR(exp))
@@ -972,7 +980,7 @@ gss:
972 /* Otherwise, try falling back on gss client */ 980 /* Otherwise, try falling back on gss client */
973 if (rqstp->rq_gssclient == NULL) 981 if (rqstp->rq_gssclient == NULL)
974 return exp; 982 return exp;
975 gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv, 983 gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
976 &rqstp->rq_chandle); 984 &rqstp->rq_chandle);
977 if (PTR_ERR(gssexp) == -ENOENT) 985 if (PTR_ERR(gssexp) == -ENOENT)
978 return exp; 986 return exp;
@@ -1029,13 +1037,15 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1029/* Iterator */ 1037/* Iterator */
1030 1038
1031static void *e_start(struct seq_file *m, loff_t *pos) 1039static void *e_start(struct seq_file *m, loff_t *pos)
1032 __acquires(svc_export_cache.hash_lock) 1040 __acquires(((struct cache_detail *)m->private)->hash_lock)
1033{ 1041{
1034 loff_t n = *pos; 1042 loff_t n = *pos;
1035 unsigned hash, export; 1043 unsigned hash, export;
1036 struct cache_head *ch; 1044 struct cache_head *ch;
1037 1045 struct cache_detail *cd = m->private;
1038 read_lock(&svc_export_cache.hash_lock); 1046 struct cache_head **export_table = cd->hash_table;
1047
1048 read_lock(&cd->hash_lock);
1039 if (!n--) 1049 if (!n--)
1040 return SEQ_START_TOKEN; 1050 return SEQ_START_TOKEN;
1041 hash = n >> 32; 1051 hash = n >> 32;
@@ -1060,6 +1070,8 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1060{ 1070{
1061 struct cache_head *ch = p; 1071 struct cache_head *ch = p;
1062 int hash = (*pos >> 32); 1072 int hash = (*pos >> 32);
1073 struct cache_detail *cd = m->private;
1074 struct cache_head **export_table = cd->hash_table;
1063 1075
1064 if (p == SEQ_START_TOKEN) 1076 if (p == SEQ_START_TOKEN)
1065 hash = 0; 1077 hash = 0;
@@ -1082,9 +1094,11 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1082} 1094}
1083 1095
1084static void e_stop(struct seq_file *m, void *p) 1096static void e_stop(struct seq_file *m, void *p)
1085 __releases(svc_export_cache.hash_lock) 1097 __releases(((struct cache_detail *)m->private)->hash_lock)
1086{ 1098{
1087 read_unlock(&svc_export_cache.hash_lock); 1099 struct cache_detail *cd = m->private;
1100
1101 read_unlock(&cd->hash_lock);
1088} 1102}
1089 1103
1090static struct flags { 1104static struct flags {
@@ -1195,6 +1209,7 @@ static int e_show(struct seq_file *m, void *p)
1195{ 1209{
1196 struct cache_head *cp = p; 1210 struct cache_head *cp = p;
1197 struct svc_export *exp = container_of(cp, struct svc_export, h); 1211 struct svc_export *exp = container_of(cp, struct svc_export, h);
1212 struct cache_detail *cd = m->private;
1198 1213
1199 if (p == SEQ_START_TOKEN) { 1214 if (p == SEQ_START_TOKEN) {
1200 seq_puts(m, "# Version 1.1\n"); 1215 seq_puts(m, "# Version 1.1\n");
@@ -1203,10 +1218,10 @@ static int e_show(struct seq_file *m, void *p)
1203 } 1218 }
1204 1219
1205 cache_get(&exp->h); 1220 cache_get(&exp->h);
1206 if (cache_check(&svc_export_cache, &exp->h, NULL)) 1221 if (cache_check(cd, &exp->h, NULL))
1207 return 0; 1222 return 0;
1208 cache_put(&exp->h, &svc_export_cache); 1223 exp_put(exp);
1209 return svc_export_show(m, &svc_export_cache, cp); 1224 return svc_export_show(m, cd, cp);
1210} 1225}
1211 1226
1212const struct seq_operations nfs_exports_op = { 1227const struct seq_operations nfs_exports_op = {
@@ -1216,48 +1231,70 @@ const struct seq_operations nfs_exports_op = {
1216 .show = e_show, 1231 .show = e_show,
1217}; 1232};
1218 1233
1219
1220/* 1234/*
1221 * Initialize the exports module. 1235 * Initialize the exports module.
1222 */ 1236 */
1223int 1237int
1224nfsd_export_init(void) 1238nfsd_export_init(struct net *net)
1225{ 1239{
1226 int rv; 1240 int rv;
1227 dprintk("nfsd: initializing export module.\n"); 1241 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1242
1243 dprintk("nfsd: initializing export module (net: %p).\n", net);
1228 1244
1229 rv = cache_register_net(&svc_export_cache, &init_net); 1245 nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
1246 if (IS_ERR(nn->svc_export_cache))
1247 return PTR_ERR(nn->svc_export_cache);
1248 rv = cache_register_net(nn->svc_export_cache, net);
1230 if (rv) 1249 if (rv)
1231 return rv; 1250 goto destroy_export_cache;
1232 rv = cache_register_net(&svc_expkey_cache, &init_net); 1251
1252 nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
1253 if (IS_ERR(nn->svc_expkey_cache)) {
1254 rv = PTR_ERR(nn->svc_expkey_cache);
1255 goto unregister_export_cache;
1256 }
1257 rv = cache_register_net(nn->svc_expkey_cache, net);
1233 if (rv) 1258 if (rv)
1234 cache_unregister_net(&svc_export_cache, &init_net); 1259 goto destroy_expkey_cache;
1235 return rv; 1260 return 0;
1236 1261
1262destroy_expkey_cache:
1263 cache_destroy_net(nn->svc_expkey_cache, net);
1264unregister_export_cache:
1265 cache_unregister_net(nn->svc_export_cache, net);
1266destroy_export_cache:
1267 cache_destroy_net(nn->svc_export_cache, net);
1268 return rv;
1237} 1269}
1238 1270
1239/* 1271/*
1240 * Flush exports table - called when last nfsd thread is killed 1272 * Flush exports table - called when last nfsd thread is killed
1241 */ 1273 */
1242void 1274void
1243nfsd_export_flush(void) 1275nfsd_export_flush(struct net *net)
1244{ 1276{
1245 cache_purge(&svc_expkey_cache); 1277 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1246 cache_purge(&svc_export_cache); 1278
1279 cache_purge(nn->svc_expkey_cache);
1280 cache_purge(nn->svc_export_cache);
1247} 1281}
1248 1282
1249/* 1283/*
1250 * Shutdown the exports module. 1284 * Shutdown the exports module.
1251 */ 1285 */
1252void 1286void
1253nfsd_export_shutdown(void) 1287nfsd_export_shutdown(struct net *net)
1254{ 1288{
1289 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1255 1290
1256 dprintk("nfsd: shutting down export module.\n"); 1291 dprintk("nfsd: shutting down export module (net: %p).\n", net);
1257 1292
1258 cache_unregister_net(&svc_expkey_cache, &init_net); 1293 cache_unregister_net(nn->svc_expkey_cache, net);
1259 cache_unregister_net(&svc_export_cache, &init_net); 1294 cache_unregister_net(nn->svc_export_cache, net);
1260 svcauth_unix_purge(); 1295 cache_destroy_net(nn->svc_expkey_cache, net);
1296 cache_destroy_net(nn->svc_export_cache, net);
1297 svcauth_unix_purge(net);
1261 1298
1262 dprintk("nfsd: export shutdown complete.\n"); 1299 dprintk("nfsd: export shutdown complete (net: %p).\n", net);
1263} 1300}
diff --git a/fs/nfsd/idmap.h b/fs/nfsd/idmap.h
index 2f3be1321534..9d513efc01ba 100644
--- a/fs/nfsd/idmap.h
+++ b/fs/nfsd/idmap.h
@@ -42,14 +42,14 @@
42#define IDMAP_NAMESZ 128 42#define IDMAP_NAMESZ 128
43 43
44#ifdef CONFIG_NFSD_V4 44#ifdef CONFIG_NFSD_V4
45int nfsd_idmap_init(void); 45int nfsd_idmap_init(struct net *);
46void nfsd_idmap_shutdown(void); 46void nfsd_idmap_shutdown(struct net *);
47#else 47#else
48static inline int nfsd_idmap_init(void) 48static inline int nfsd_idmap_init(struct net *net)
49{ 49{
50 return 0; 50 return 0;
51} 51}
52static inline void nfsd_idmap_shutdown(void) 52static inline void nfsd_idmap_shutdown(struct net *net)
53{ 53{
54} 54}
55#endif 55#endif
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 12e0cff435b4..39365636b244 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -28,6 +28,12 @@ struct cld_net;
28 28
29struct nfsd_net { 29struct nfsd_net {
30 struct cld_net *cld_net; 30 struct cld_net *cld_net;
31
32 struct cache_detail *svc_expkey_cache;
33 struct cache_detail *svc_export_cache;
34
35 struct cache_detail *idtoname_cache;
36 struct cache_detail *nametoid_cache;
31}; 37};
32 38
33extern int nfsd_net_id; 39extern int nfsd_net_id;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 322d11ce06a4..286a7f8f2024 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -36,9 +36,11 @@
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <linux/sched.h> 37#include <linux/sched.h>
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <linux/sunrpc/svc_xprt.h>
39#include <net/net_namespace.h> 40#include <net/net_namespace.h>
40#include "idmap.h" 41#include "idmap.h"
41#include "nfsd.h" 42#include "nfsd.h"
43#include "netns.h"
42 44
43/* 45/*
44 * Turn off idmapping when using AUTH_SYS. 46 * Turn off idmapping when using AUTH_SYS.
@@ -107,8 +109,6 @@ ent_alloc(void)
107 * ID -> Name cache 109 * ID -> Name cache
108 */ 110 */
109 111
110static struct cache_head *idtoname_table[ENT_HASHMAX];
111
112static uint32_t 112static uint32_t
113idtoname_hash(struct ent *ent) 113idtoname_hash(struct ent *ent)
114{ 114{
@@ -183,13 +183,13 @@ warn_no_idmapd(struct cache_detail *detail, int has_died)
183 183
184 184
185static int idtoname_parse(struct cache_detail *, char *, int); 185static int idtoname_parse(struct cache_detail *, char *, int);
186static struct ent *idtoname_lookup(struct ent *); 186static struct ent *idtoname_lookup(struct cache_detail *, struct ent *);
187static struct ent *idtoname_update(struct ent *, struct ent *); 187static struct ent *idtoname_update(struct cache_detail *, struct ent *,
188 struct ent *);
188 189
189static struct cache_detail idtoname_cache = { 190static struct cache_detail idtoname_cache_template = {
190 .owner = THIS_MODULE, 191 .owner = THIS_MODULE,
191 .hash_size = ENT_HASHMAX, 192 .hash_size = ENT_HASHMAX,
192 .hash_table = idtoname_table,
193 .name = "nfs4.idtoname", 193 .name = "nfs4.idtoname",
194 .cache_put = ent_put, 194 .cache_put = ent_put,
195 .cache_upcall = idtoname_upcall, 195 .cache_upcall = idtoname_upcall,
@@ -244,7 +244,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
244 goto out; 244 goto out;
245 245
246 error = -ENOMEM; 246 error = -ENOMEM;
247 res = idtoname_lookup(&ent); 247 res = idtoname_lookup(cd, &ent);
248 if (!res) 248 if (!res)
249 goto out; 249 goto out;
250 250
@@ -260,11 +260,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
260 else 260 else
261 memcpy(ent.name, buf1, sizeof(ent.name)); 261 memcpy(ent.name, buf1, sizeof(ent.name));
262 error = -ENOMEM; 262 error = -ENOMEM;
263 res = idtoname_update(&ent, res); 263 res = idtoname_update(cd, &ent, res);
264 if (res == NULL) 264 if (res == NULL)
265 goto out; 265 goto out;
266 266
267 cache_put(&res->h, &idtoname_cache); 267 cache_put(&res->h, cd);
268 268
269 error = 0; 269 error = 0;
270out: 270out:
@@ -275,10 +275,9 @@ out:
275 275
276 276
277static struct ent * 277static struct ent *
278idtoname_lookup(struct ent *item) 278idtoname_lookup(struct cache_detail *cd, struct ent *item)
279{ 279{
280 struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, 280 struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
281 &item->h,
282 idtoname_hash(item)); 281 idtoname_hash(item));
283 if (ch) 282 if (ch)
284 return container_of(ch, struct ent, h); 283 return container_of(ch, struct ent, h);
@@ -287,10 +286,9 @@ idtoname_lookup(struct ent *item)
287} 286}
288 287
289static struct ent * 288static struct ent *
290idtoname_update(struct ent *new, struct ent *old) 289idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old)
291{ 290{
292 struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, 291 struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h,
293 &new->h, &old->h,
294 idtoname_hash(new)); 292 idtoname_hash(new));
295 if (ch) 293 if (ch)
296 return container_of(ch, struct ent, h); 294 return container_of(ch, struct ent, h);
@@ -303,8 +301,6 @@ idtoname_update(struct ent *new, struct ent *old)
303 * Name -> ID cache 301 * Name -> ID cache
304 */ 302 */
305 303
306static struct cache_head *nametoid_table[ENT_HASHMAX];
307
308static inline int 304static inline int
309nametoid_hash(struct ent *ent) 305nametoid_hash(struct ent *ent)
310{ 306{
@@ -359,14 +355,14 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
359 return 0; 355 return 0;
360} 356}
361 357
362static struct ent *nametoid_lookup(struct ent *); 358static struct ent *nametoid_lookup(struct cache_detail *, struct ent *);
363static struct ent *nametoid_update(struct ent *, struct ent *); 359static struct ent *nametoid_update(struct cache_detail *, struct ent *,
360 struct ent *);
364static int nametoid_parse(struct cache_detail *, char *, int); 361static int nametoid_parse(struct cache_detail *, char *, int);
365 362
366static struct cache_detail nametoid_cache = { 363static struct cache_detail nametoid_cache_template = {
367 .owner = THIS_MODULE, 364 .owner = THIS_MODULE,
368 .hash_size = ENT_HASHMAX, 365 .hash_size = ENT_HASHMAX,
369 .hash_table = nametoid_table,
370 .name = "nfs4.nametoid", 366 .name = "nfs4.nametoid",
371 .cache_put = ent_put, 367 .cache_put = ent_put,
372 .cache_upcall = nametoid_upcall, 368 .cache_upcall = nametoid_upcall,
@@ -426,14 +422,14 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
426 set_bit(CACHE_NEGATIVE, &ent.h.flags); 422 set_bit(CACHE_NEGATIVE, &ent.h.flags);
427 423
428 error = -ENOMEM; 424 error = -ENOMEM;
429 res = nametoid_lookup(&ent); 425 res = nametoid_lookup(cd, &ent);
430 if (res == NULL) 426 if (res == NULL)
431 goto out; 427 goto out;
432 res = nametoid_update(&ent, res); 428 res = nametoid_update(cd, &ent, res);
433 if (res == NULL) 429 if (res == NULL)
434 goto out; 430 goto out;
435 431
436 cache_put(&res->h, &nametoid_cache); 432 cache_put(&res->h, cd);
437 error = 0; 433 error = 0;
438out: 434out:
439 kfree(buf1); 435 kfree(buf1);
@@ -443,10 +439,9 @@ out:
443 439
444 440
445static struct ent * 441static struct ent *
446nametoid_lookup(struct ent *item) 442nametoid_lookup(struct cache_detail *cd, struct ent *item)
447{ 443{
448 struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache, 444 struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
449 &item->h,
450 nametoid_hash(item)); 445 nametoid_hash(item));
451 if (ch) 446 if (ch)
452 return container_of(ch, struct ent, h); 447 return container_of(ch, struct ent, h);
@@ -455,10 +450,9 @@ nametoid_lookup(struct ent *item)
455} 450}
456 451
457static struct ent * 452static struct ent *
458nametoid_update(struct ent *new, struct ent *old) 453nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old)
459{ 454{
460 struct cache_head *ch = sunrpc_cache_update(&nametoid_cache, 455 struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h,
461 &new->h, &old->h,
462 nametoid_hash(new)); 456 nametoid_hash(new));
463 if (ch) 457 if (ch)
464 return container_of(ch, struct ent, h); 458 return container_of(ch, struct ent, h);
@@ -471,34 +465,55 @@ nametoid_update(struct ent *new, struct ent *old)
471 */ 465 */
472 466
473int 467int
474nfsd_idmap_init(void) 468nfsd_idmap_init(struct net *net)
475{ 469{
476 int rv; 470 int rv;
471 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
477 472
478 rv = cache_register_net(&idtoname_cache, &init_net); 473 nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net);
474 if (IS_ERR(nn->idtoname_cache))
475 return PTR_ERR(nn->idtoname_cache);
476 rv = cache_register_net(nn->idtoname_cache, net);
479 if (rv) 477 if (rv)
480 return rv; 478 goto destroy_idtoname_cache;
481 rv = cache_register_net(&nametoid_cache, &init_net); 479 nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net);
480 if (IS_ERR(nn->nametoid_cache)) {
481 rv = PTR_ERR(nn->idtoname_cache);
482 goto unregister_idtoname_cache;
483 }
484 rv = cache_register_net(nn->nametoid_cache, net);
482 if (rv) 485 if (rv)
483 cache_unregister_net(&idtoname_cache, &init_net); 486 goto destroy_nametoid_cache;
487 return 0;
488
489destroy_nametoid_cache:
490 cache_destroy_net(nn->nametoid_cache, net);
491unregister_idtoname_cache:
492 cache_unregister_net(nn->idtoname_cache, net);
493destroy_idtoname_cache:
494 cache_destroy_net(nn->idtoname_cache, net);
484 return rv; 495 return rv;
485} 496}
486 497
487void 498void
488nfsd_idmap_shutdown(void) 499nfsd_idmap_shutdown(struct net *net)
489{ 500{
490 cache_unregister_net(&idtoname_cache, &init_net); 501 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
491 cache_unregister_net(&nametoid_cache, &init_net); 502
503 cache_unregister_net(nn->idtoname_cache, net);
504 cache_unregister_net(nn->nametoid_cache, net);
505 cache_destroy_net(nn->idtoname_cache, net);
506 cache_destroy_net(nn->nametoid_cache, net);
492} 507}
493 508
494static int 509static int
495idmap_lookup(struct svc_rqst *rqstp, 510idmap_lookup(struct svc_rqst *rqstp,
496 struct ent *(*lookup_fn)(struct ent *), struct ent *key, 511 struct ent *(*lookup_fn)(struct cache_detail *, struct ent *),
497 struct cache_detail *detail, struct ent **item) 512 struct ent *key, struct cache_detail *detail, struct ent **item)
498{ 513{
499 int ret; 514 int ret;
500 515
501 *item = lookup_fn(key); 516 *item = lookup_fn(detail, key);
502 if (!*item) 517 if (!*item)
503 return -ENOMEM; 518 return -ENOMEM;
504 retry: 519 retry:
@@ -506,7 +521,7 @@ idmap_lookup(struct svc_rqst *rqstp,
506 521
507 if (ret == -ETIMEDOUT) { 522 if (ret == -ETIMEDOUT) {
508 struct ent *prev_item = *item; 523 struct ent *prev_item = *item;
509 *item = lookup_fn(key); 524 *item = lookup_fn(detail, key);
510 if (*item != prev_item) 525 if (*item != prev_item)
511 goto retry; 526 goto retry;
512 cache_put(&(*item)->h, detail); 527 cache_put(&(*item)->h, detail);
@@ -531,19 +546,20 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
531 .type = type, 546 .type = type,
532 }; 547 };
533 int ret; 548 int ret;
549 struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
534 550
535 if (namelen + 1 > sizeof(key.name)) 551 if (namelen + 1 > sizeof(key.name))
536 return nfserr_badowner; 552 return nfserr_badowner;
537 memcpy(key.name, name, namelen); 553 memcpy(key.name, name, namelen);
538 key.name[namelen] = '\0'; 554 key.name[namelen] = '\0';
539 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 555 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
540 ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); 556 ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item);
541 if (ret == -ENOENT) 557 if (ret == -ENOENT)
542 return nfserr_badowner; 558 return nfserr_badowner;
543 if (ret) 559 if (ret)
544 return nfserrno(ret); 560 return nfserrno(ret);
545 *id = item->id; 561 *id = item->id;
546 cache_put(&item->h, &nametoid_cache); 562 cache_put(&item->h, nn->nametoid_cache);
547 return 0; 563 return 0;
548} 564}
549 565
@@ -555,9 +571,10 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
555 .type = type, 571 .type = type,
556 }; 572 };
557 int ret; 573 int ret;
574 struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
558 575
559 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 576 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
560 ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); 577 ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
561 if (ret == -ENOENT) 578 if (ret == -ENOENT)
562 return sprintf(name, "%u", id); 579 return sprintf(name, "%u", id);
563 if (ret) 580 if (ret)
@@ -565,7 +582,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
565 ret = strlen(item->name); 582 ret = strlen(item->name);
566 BUG_ON(ret > IDMAP_NAMESZ); 583 BUG_ON(ret > IDMAP_NAMESZ);
567 memcpy(name, item->name, ret); 584 memcpy(name, item->name, ret);
568 cache_put(&item->h, &idtoname_cache); 585 cache_put(&item->h, nn->idtoname_cache);
569 return ret; 586 return ret;
570} 587}
571 588
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7f71c69cdcdf..03f82c0bc35d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3155,10 +3155,17 @@ out:
3155static struct lock_manager nfsd4_manager = { 3155static struct lock_manager nfsd4_manager = {
3156}; 3156};
3157 3157
3158static bool grace_ended;
3159
3158static void 3160static void
3159nfsd4_end_grace(void) 3161nfsd4_end_grace(void)
3160{ 3162{
3163 /* do nothing if grace period already ended */
3164 if (grace_ended)
3165 return;
3166
3161 dprintk("NFSD: end of grace period\n"); 3167 dprintk("NFSD: end of grace period\n");
3168 grace_ended = true;
3162 nfsd4_record_grace_done(&init_net, boot_time); 3169 nfsd4_record_grace_done(&init_net, boot_time);
3163 locks_end_grace(&nfsd4_manager); 3170 locks_end_grace(&nfsd4_manager);
3164 /* 3171 /*
@@ -3183,8 +3190,7 @@ nfs4_laundromat(void)
3183 nfs4_lock_state(); 3190 nfs4_lock_state();
3184 3191
3185 dprintk("NFSD: laundromat service - starting\n"); 3192 dprintk("NFSD: laundromat service - starting\n");
3186 if (locks_in_grace()) 3193 nfsd4_end_grace();
3187 nfsd4_end_grace();
3188 INIT_LIST_HEAD(&reaplist); 3194 INIT_LIST_HEAD(&reaplist);
3189 spin_lock(&client_lock); 3195 spin_lock(&client_lock);
3190 list_for_each_safe(pos, next, &client_lru) { 3196 list_for_each_safe(pos, next, &client_lru) {
@@ -4055,7 +4061,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4055 struct nfs4_openowner *open_sop = NULL; 4061 struct nfs4_openowner *open_sop = NULL;
4056 struct nfs4_lockowner *lock_sop = NULL; 4062 struct nfs4_lockowner *lock_sop = NULL;
4057 struct nfs4_ol_stateid *lock_stp; 4063 struct nfs4_ol_stateid *lock_stp;
4058 struct nfs4_file *fp;
4059 struct file *filp = NULL; 4064 struct file *filp = NULL;
4060 struct file_lock file_lock; 4065 struct file_lock file_lock;
4061 struct file_lock conflock; 4066 struct file_lock conflock;
@@ -4123,7 +4128,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4123 goto out; 4128 goto out;
4124 } 4129 }
4125 lock_sop = lockowner(lock_stp->st_stateowner); 4130 lock_sop = lockowner(lock_stp->st_stateowner);
4126 fp = lock_stp->st_file;
4127 4131
4128 lkflg = setlkflg(lock->lk_type); 4132 lkflg = setlkflg(lock->lk_type);
4129 status = nfs4_check_openmode(lock_stp, lkflg); 4133 status = nfs4_check_openmode(lock_stp, lkflg);
@@ -4715,6 +4719,7 @@ nfs4_state_start(void)
4715 nfsd4_client_tracking_init(&init_net); 4719 nfsd4_client_tracking_init(&init_net);
4716 boot_time = get_seconds(); 4720 boot_time = get_seconds();
4717 locks_start_grace(&nfsd4_manager); 4721 locks_start_grace(&nfsd4_manager);
4722 grace_ended = false;
4718 printk(KERN_INFO "NFSD: starting %ld-second grace period\n", 4723 printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
4719 nfsd4_grace); 4724 nfsd4_grace);
4720 ret = set_callback_cred(); 4725 ret = set_callback_cred();
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2c53be6d3579..72699885ac48 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -127,7 +127,17 @@ static const struct file_operations transaction_ops = {
127 127
128static int exports_open(struct inode *inode, struct file *file) 128static int exports_open(struct inode *inode, struct file *file)
129{ 129{
130 return seq_open(file, &nfs_exports_op); 130 int err;
131 struct seq_file *seq;
132 struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
133
134 err = seq_open(file, &nfs_exports_op);
135 if (err)
136 return err;
137
138 seq = file->private_data;
139 seq->private = nn->svc_export_cache;
140 return 0;
131} 141}
132 142
133static const struct file_operations exports_operations = { 143static const struct file_operations exports_operations = {
@@ -345,7 +355,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
345 if (!dom) 355 if (!dom)
346 return -ENOMEM; 356 return -ENOMEM;
347 357
348 len = exp_rootfh(dom, path, &fh, maxsize); 358 len = exp_rootfh(&init_net, dom, path, &fh, maxsize);
349 auth_domain_put(dom); 359 auth_domain_put(dom);
350 if (len) 360 if (len)
351 return len; 361 return len;
@@ -1127,7 +1137,34 @@ static int create_proc_exports_entry(void)
1127#endif 1137#endif
1128 1138
1129int nfsd_net_id; 1139int nfsd_net_id;
1140
1141static __net_init int nfsd_init_net(struct net *net)
1142{
1143 int retval;
1144
1145 retval = nfsd_export_init(net);
1146 if (retval)
1147 goto out_export_error;
1148 retval = nfsd_idmap_init(net);
1149 if (retval)
1150 goto out_idmap_error;
1151 return 0;
1152
1153out_idmap_error:
1154 nfsd_export_shutdown(net);
1155out_export_error:
1156 return retval;
1157}
1158
1159static __net_exit void nfsd_exit_net(struct net *net)
1160{
1161 nfsd_idmap_shutdown(net);
1162 nfsd_export_shutdown(net);
1163}
1164
1130static struct pernet_operations nfsd_net_ops = { 1165static struct pernet_operations nfsd_net_ops = {
1166 .init = nfsd_init_net,
1167 .exit = nfsd_exit_net,
1131 .id = &nfsd_net_id, 1168 .id = &nfsd_net_id,
1132 .size = sizeof(struct nfsd_net), 1169 .size = sizeof(struct nfsd_net),
1133}; 1170};
@@ -1154,16 +1191,10 @@ static int __init init_nfsd(void)
1154 retval = nfsd_reply_cache_init(); 1191 retval = nfsd_reply_cache_init();
1155 if (retval) 1192 if (retval)
1156 goto out_free_stat; 1193 goto out_free_stat;
1157 retval = nfsd_export_init();
1158 if (retval)
1159 goto out_free_cache;
1160 nfsd_lockd_init(); /* lockd->nfsd callbacks */ 1194 nfsd_lockd_init(); /* lockd->nfsd callbacks */
1161 retval = nfsd_idmap_init();
1162 if (retval)
1163 goto out_free_lockd;
1164 retval = create_proc_exports_entry(); 1195 retval = create_proc_exports_entry();
1165 if (retval) 1196 if (retval)
1166 goto out_free_idmap; 1197 goto out_free_lockd;
1167 retval = register_filesystem(&nfsd_fs_type); 1198 retval = register_filesystem(&nfsd_fs_type);
1168 if (retval) 1199 if (retval)
1169 goto out_free_all; 1200 goto out_free_all;
@@ -1171,12 +1202,8 @@ static int __init init_nfsd(void)
1171out_free_all: 1202out_free_all:
1172 remove_proc_entry("fs/nfs/exports", NULL); 1203 remove_proc_entry("fs/nfs/exports", NULL);
1173 remove_proc_entry("fs/nfs", NULL); 1204 remove_proc_entry("fs/nfs", NULL);
1174out_free_idmap:
1175 nfsd_idmap_shutdown();
1176out_free_lockd: 1205out_free_lockd:
1177 nfsd_lockd_shutdown(); 1206 nfsd_lockd_shutdown();
1178 nfsd_export_shutdown();
1179out_free_cache:
1180 nfsd_reply_cache_shutdown(); 1207 nfsd_reply_cache_shutdown();
1181out_free_stat: 1208out_free_stat:
1182 nfsd_stat_shutdown(); 1209 nfsd_stat_shutdown();
@@ -1192,13 +1219,11 @@ out_unregister_notifier:
1192 1219
1193static void __exit exit_nfsd(void) 1220static void __exit exit_nfsd(void)
1194{ 1221{
1195 nfsd_export_shutdown();
1196 nfsd_reply_cache_shutdown(); 1222 nfsd_reply_cache_shutdown();
1197 remove_proc_entry("fs/nfs/exports", NULL); 1223 remove_proc_entry("fs/nfs/exports", NULL);
1198 remove_proc_entry("fs/nfs", NULL); 1224 remove_proc_entry("fs/nfs", NULL);
1199 nfsd_stat_shutdown(); 1225 nfsd_stat_shutdown();
1200 nfsd_lockd_shutdown(); 1226 nfsd_lockd_shutdown();
1201 nfsd_idmap_shutdown();
1202 nfsd4_free_slabs(); 1227 nfsd4_free_slabs();
1203 nfsd_fault_inject_cleanup(); 1228 nfsd_fault_inject_cleanup();
1204 unregister_filesystem(&nfsd_fs_type); 1229 unregister_filesystem(&nfsd_fs_type);
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 68454e75fce9..cc793005a87c 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -636,7 +636,7 @@ fh_put(struct svc_fh *fhp)
636#endif 636#endif
637 } 637 }
638 if (exp) { 638 if (exp) {
639 cache_put(&exp->h, &svc_export_cache); 639 exp_put(exp);
640 fhp->fh_export = NULL; 640 fhp->fh_export = NULL;
641 } 641 }
642 return; 642 return;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 28dfad39f0c5..cb4d51d8cbdb 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
220 ret = nfsd_init_socks(port); 220 ret = nfsd_init_socks(port);
221 if (ret) 221 if (ret)
222 goto out_racache; 222 goto out_racache;
223 ret = lockd_up(); 223 ret = lockd_up(&init_net);
224 if (ret) 224 if (ret)
225 goto out_racache; 225 goto out_racache;
226 ret = nfs4_state_start(); 226 ret = nfs4_state_start();
@@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
229 nfsd_up = true; 229 nfsd_up = true;
230 return 0; 230 return 0;
231out_lockd: 231out_lockd:
232 lockd_down(); 232 lockd_down(&init_net);
233out_racache: 233out_racache:
234 nfsd_racache_shutdown(); 234 nfsd_racache_shutdown();
235 return ret; 235 return ret;
@@ -246,7 +246,7 @@ static void nfsd_shutdown(void)
246 if (!nfsd_up) 246 if (!nfsd_up)
247 return; 247 return;
248 nfs4_state_shutdown(); 248 nfs4_state_shutdown();
249 lockd_down(); 249 lockd_down(&init_net);
250 nfsd_racache_shutdown(); 250 nfsd_racache_shutdown();
251 nfsd_up = false; 251 nfsd_up = false;
252} 252}
@@ -261,7 +261,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
261 261
262 printk(KERN_WARNING "nfsd: last server has exited, flushing export " 262 printk(KERN_WARNING "nfsd: last server has exited, flushing export "
263 "cache\n"); 263 "cache\n");
264 nfsd_export_flush(); 264 nfsd_export_flush(net);
265} 265}
266 266
267void nfsd_reset_versions(void) 267void nfsd_reset_versions(void)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 568666156ea4..c8bd9c3be7f7 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2039,7 +2039,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
2039 if (err) 2039 if (err)
2040 goto out; 2040 goto out;
2041 2041
2042 offset = vfs_llseek(file, offset, 0); 2042 offset = vfs_llseek(file, offset, SEEK_SET);
2043 if (offset < 0) { 2043 if (offset < 0) {
2044 err = nfserrno((int)offset); 2044 err = nfserrno((int)offset);
2045 goto out_close; 2045 goto out_close;
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 11a966e5f829..4d24d64578c4 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -54,7 +54,7 @@ extern void nlmclnt_done(struct nlm_host *host);
54 54
55extern int nlmclnt_proc(struct nlm_host *host, int cmd, 55extern int nlmclnt_proc(struct nlm_host *host, int cmd,
56 struct file_lock *fl); 56 struct file_lock *fl);
57extern int lockd_up(void); 57extern int lockd_up(struct net *net);
58extern void lockd_down(void); 58extern void lockd_down(struct net *net);
59 59
60#endif /* LINUX_LOCKD_BIND_H */ 60#endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index f85308e688fd..e33f747b173c 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -103,6 +103,7 @@ struct svc_export {
103 struct nfsd4_fs_locations ex_fslocs; 103 struct nfsd4_fs_locations ex_fslocs;
104 int ex_nflavors; 104 int ex_nflavors;
105 struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST]; 105 struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
106 struct cache_detail *cd;
106}; 107};
107 108
108/* an "export key" (expkey) maps a filehandlefragement to an 109/* an "export key" (expkey) maps a filehandlefragement to an
@@ -129,24 +130,22 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
129/* 130/*
130 * Function declarations 131 * Function declarations
131 */ 132 */
132int nfsd_export_init(void); 133int nfsd_export_init(struct net *);
133void nfsd_export_shutdown(void); 134void nfsd_export_shutdown(struct net *);
134void nfsd_export_flush(void); 135void nfsd_export_flush(struct net *);
135struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, 136struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
136 struct path *); 137 struct path *);
137struct svc_export * rqst_exp_parent(struct svc_rqst *, 138struct svc_export * rqst_exp_parent(struct svc_rqst *,
138 struct path *); 139 struct path *);
139struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); 140struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *);
140int exp_rootfh(struct auth_domain *, 141int exp_rootfh(struct net *, struct auth_domain *,
141 char *path, struct knfsd_fh *, int maxsize); 142 char *path, struct knfsd_fh *, int maxsize);
142__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); 143__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
143__be32 nfserrno(int errno); 144__be32 nfserrno(int errno);
144 145
145extern struct cache_detail svc_export_cache;
146
147static inline void exp_put(struct svc_export *exp) 146static inline void exp_put(struct svc_export *exp)
148{ 147{
149 cache_put(&exp->h, &svc_export_cache); 148 cache_put(&exp->h, exp->cd);
150} 149}
151 150
152static inline void exp_get(struct svc_export *exp) 151static inline void exp_get(struct svc_export *exp)
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 548790e9113b..2c54683b91de 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -16,7 +16,6 @@
16#include <linux/sunrpc/cache.h> 16#include <linux/sunrpc/cache.h>
17#include <linux/hash.h> 17#include <linux/hash.h>
18 18
19#define SVC_CRED_NGROUPS 32
20struct svc_cred { 19struct svc_cred {
21 uid_t cr_uid; 20 uid_t cr_uid;
22 gid_t cr_gid; 21 gid_t cr_gid;
@@ -131,7 +130,7 @@ extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *ne
131extern struct auth_domain *auth_domain_find(char *name); 130extern struct auth_domain *auth_domain_find(char *name);
132extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr); 131extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr);
133extern int auth_unix_forget_old(struct auth_domain *dom); 132extern int auth_unix_forget_old(struct auth_domain *dom);
134extern void svcauth_unix_purge(void); 133extern void svcauth_unix_purge(struct net *net);
135extern void svcauth_unix_info_release(struct svc_xprt *xpt); 134extern void svcauth_unix_info_release(struct svc_xprt *xpt);
136extern int svcauth_unix_set_client(struct svc_rqst *rqstp); 135extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
137 136
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 28b62dbb6d1e..3089de37c433 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -969,16 +969,17 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
969} 969}
970 970
971static inline int 971static inline int
972gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip) 972gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
973 struct xdr_netobj *out_handle, int *major_status)
973{ 974{
974 struct rsc *rsci; 975 struct rsc *rsci;
975 int rc; 976 int rc;
976 977
977 if (rsip->major_status != GSS_S_COMPLETE) 978 if (*major_status != GSS_S_COMPLETE)
978 return gss_write_null_verf(rqstp); 979 return gss_write_null_verf(rqstp);
979 rsci = gss_svc_searchbyctx(cd, &rsip->out_handle); 980 rsci = gss_svc_searchbyctx(cd, out_handle);
980 if (rsci == NULL) { 981 if (rsci == NULL) {
981 rsip->major_status = GSS_S_NO_CONTEXT; 982 *major_status = GSS_S_NO_CONTEXT;
982 return gss_write_null_verf(rqstp); 983 return gss_write_null_verf(rqstp);
983 } 984 }
984 rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); 985 rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
@@ -986,22 +987,13 @@ gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi
986 return rc; 987 return rc;
987} 988}
988 989
989/* 990static inline int
990 * Having read the cred already and found we're in the context 991gss_read_verf(struct rpc_gss_wire_cred *gc,
991 * initiation case, read the verifier and initiate (or check the results 992 struct kvec *argv, __be32 *authp,
992 * of) upcalls to userspace for help with context initiation. If 993 struct xdr_netobj *in_handle,
993 * the upcall results are available, write the verifier and result. 994 struct xdr_netobj *in_token)
994 * Otherwise, drop the request pending an answer to the upcall.
995 */
996static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
997 struct rpc_gss_wire_cred *gc, __be32 *authp)
998{ 995{
999 struct kvec *argv = &rqstp->rq_arg.head[0];
1000 struct kvec *resv = &rqstp->rq_res.head[0];
1001 struct xdr_netobj tmpobj; 996 struct xdr_netobj tmpobj;
1002 struct rsi *rsip, rsikey;
1003 int ret;
1004 struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
1005 997
1006 /* Read the verifier; should be NULL: */ 998 /* Read the verifier; should be NULL: */
1007 *authp = rpc_autherr_badverf; 999 *authp = rpc_autherr_badverf;
@@ -1011,24 +1003,67 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
1011 return SVC_DENIED; 1003 return SVC_DENIED;
1012 if (svc_getnl(argv) != 0) 1004 if (svc_getnl(argv) != 0)
1013 return SVC_DENIED; 1005 return SVC_DENIED;
1014
1015 /* Martial context handle and token for upcall: */ 1006 /* Martial context handle and token for upcall: */
1016 *authp = rpc_autherr_badcred; 1007 *authp = rpc_autherr_badcred;
1017 if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0) 1008 if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
1018 return SVC_DENIED; 1009 return SVC_DENIED;
1019 memset(&rsikey, 0, sizeof(rsikey)); 1010 if (dup_netobj(in_handle, &gc->gc_ctx))
1020 if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
1021 return SVC_CLOSE; 1011 return SVC_CLOSE;
1022 *authp = rpc_autherr_badverf; 1012 *authp = rpc_autherr_badverf;
1023 if (svc_safe_getnetobj(argv, &tmpobj)) { 1013 if (svc_safe_getnetobj(argv, &tmpobj)) {
1024 kfree(rsikey.in_handle.data); 1014 kfree(in_handle->data);
1025 return SVC_DENIED; 1015 return SVC_DENIED;
1026 } 1016 }
1027 if (dup_netobj(&rsikey.in_token, &tmpobj)) { 1017 if (dup_netobj(in_token, &tmpobj)) {
1028 kfree(rsikey.in_handle.data); 1018 kfree(in_handle->data);
1029 return SVC_CLOSE; 1019 return SVC_CLOSE;
1030 } 1020 }
1031 1021
1022 return 0;
1023}
1024
1025static inline int
1026gss_write_resv(struct kvec *resv, size_t size_limit,
1027 struct xdr_netobj *out_handle, struct xdr_netobj *out_token,
1028 int major_status, int minor_status)
1029{
1030 if (resv->iov_len + 4 > size_limit)
1031 return -1;
1032 svc_putnl(resv, RPC_SUCCESS);
1033 if (svc_safe_putnetobj(resv, out_handle))
1034 return -1;
1035 if (resv->iov_len + 3 * 4 > size_limit)
1036 return -1;
1037 svc_putnl(resv, major_status);
1038 svc_putnl(resv, minor_status);
1039 svc_putnl(resv, GSS_SEQ_WIN);
1040 if (svc_safe_putnetobj(resv, out_token))
1041 return -1;
1042 return 0;
1043}
1044
1045/*
1046 * Having read the cred already and found we're in the context
1047 * initiation case, read the verifier and initiate (or check the results
1048 * of) upcalls to userspace for help with context initiation. If
1049 * the upcall results are available, write the verifier and result.
1050 * Otherwise, drop the request pending an answer to the upcall.
1051 */
1052static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
1053 struct rpc_gss_wire_cred *gc, __be32 *authp)
1054{
1055 struct kvec *argv = &rqstp->rq_arg.head[0];
1056 struct kvec *resv = &rqstp->rq_res.head[0];
1057 struct rsi *rsip, rsikey;
1058 int ret;
1059 struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
1060
1061 memset(&rsikey, 0, sizeof(rsikey));
1062 ret = gss_read_verf(gc, argv, authp,
1063 &rsikey.in_handle, &rsikey.in_token);
1064 if (ret)
1065 return ret;
1066
1032 /* Perform upcall, or find upcall result: */ 1067 /* Perform upcall, or find upcall result: */
1033 rsip = rsi_lookup(sn->rsi_cache, &rsikey); 1068 rsip = rsi_lookup(sn->rsi_cache, &rsikey);
1034 rsi_free(&rsikey); 1069 rsi_free(&rsikey);
@@ -1040,19 +1075,12 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
1040 1075
1041 ret = SVC_CLOSE; 1076 ret = SVC_CLOSE;
1042 /* Got an answer to the upcall; use it: */ 1077 /* Got an answer to the upcall; use it: */
1043 if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip)) 1078 if (gss_write_init_verf(sn->rsc_cache, rqstp,
1079 &rsip->out_handle, &rsip->major_status))
1044 goto out; 1080 goto out;
1045 if (resv->iov_len + 4 > PAGE_SIZE) 1081 if (gss_write_resv(resv, PAGE_SIZE,
1046 goto out; 1082 &rsip->out_handle, &rsip->out_token,
1047 svc_putnl(resv, RPC_SUCCESS); 1083 rsip->major_status, rsip->minor_status))
1048 if (svc_safe_putnetobj(resv, &rsip->out_handle))
1049 goto out;
1050 if (resv->iov_len + 3 * 4 > PAGE_SIZE)
1051 goto out;
1052 svc_putnl(resv, rsip->major_status);
1053 svc_putnl(resv, rsip->minor_status);
1054 svc_putnl(resv, GSS_SEQ_WIN);
1055 if (svc_safe_putnetobj(resv, &rsip->out_token))
1056 goto out; 1084 goto out;
1057 1085
1058 ret = SVC_COMPLETE; 1086 ret = SVC_COMPLETE;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 71ec8530ec8c..6138c925923d 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -347,17 +347,12 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm,
347 return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); 347 return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
348} 348}
349 349
350 350void svcauth_unix_purge(struct net *net)
351void svcauth_unix_purge(void)
352{ 351{
353 struct net *net; 352 struct sunrpc_net *sn;
354
355 for_each_net(net) {
356 struct sunrpc_net *sn;
357 353
358 sn = net_generic(net, sunrpc_net_id); 354 sn = net_generic(net, sunrpc_net_id);
359 cache_purge(sn->ip_map_cache); 355 cache_purge(sn->ip_map_cache);
360 }
361} 356}
362EXPORT_SYMBOL_GPL(svcauth_unix_purge); 357EXPORT_SYMBOL_GPL(svcauth_unix_purge);
363 358