diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/export.c | 175 | ||||
-rw-r--r-- | fs/nfsd/idmap.h | 8 | ||||
-rw-r--r-- | fs/nfsd/netns.h | 6 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 109 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 55 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 2 |
9 files changed, 234 insertions, 144 deletions
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) |
41 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; | ||
42 | 43 | ||
43 | static void expkey_put(struct kref *ref) | 44 | static 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 | ||
74 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); | 75 | static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new, |
75 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); | 76 | struct svc_expkey *old); |
76 | static struct cache_detail svc_expkey_cache; | 77 | static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *); |
77 | 78 | ||
78 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | 79 | static 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 | ||
242 | static struct cache_detail svc_expkey_cache = { | 243 | static 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 | ||
270 | static struct svc_expkey * | 270 | static struct svc_expkey * |
271 | svc_expkey_lookup(struct svc_expkey *item) | 271 | svc_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 | ||
284 | static struct svc_expkey * | 283 | static struct svc_expkey * |
285 | svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | 284 | svc_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 | ||
302 | static struct cache_head *export_table[EXPORT_HASHMAX]; | ||
303 | |||
304 | static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) | 301 | static 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 | ||
677 | static void export_update(struct cache_head *cnew, struct cache_head *citem) | 676 | static 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 | ||
710 | struct cache_detail svc_export_cache = { | 709 | struct 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 | ||
766 | static struct svc_expkey * | 761 | static struct svc_expkey * |
767 | exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | 762 | exp_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 | ||
789 | static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, | 785 | static 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 | */ |
813 | static struct svc_export *exp_parent(svc_client *clp, struct path *path) | 810 | static 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 | */ |
836 | int | 834 | int |
837 | exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) | 835 | exp_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 | ||
878 | static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, | 879 | static 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 * | |||
926 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) | 929 | rqst_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 * | |||
955 | rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) | 960 | rqst_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 | ||
1031 | static void *e_start(struct seq_file *m, loff_t *pos) | 1039 | static 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 | ||
1084 | static void e_stop(struct seq_file *m, void *p) | 1096 | static 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 | ||
1090 | static struct flags { | 1104 | static 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 | ||
1212 | const struct seq_operations nfs_exports_op = { | 1227 | const 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 | */ |
1223 | int | 1237 | int |
1224 | nfsd_export_init(void) | 1238 | nfsd_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 | ||
1262 | destroy_expkey_cache: | ||
1263 | cache_destroy_net(nn->svc_expkey_cache, net); | ||
1264 | unregister_export_cache: | ||
1265 | cache_unregister_net(nn->svc_export_cache, net); | ||
1266 | destroy_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 | */ |
1242 | void | 1274 | void |
1243 | nfsd_export_flush(void) | 1275 | nfsd_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 | */ |
1252 | void | 1286 | void |
1253 | nfsd_export_shutdown(void) | 1287 | nfsd_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 |
45 | int nfsd_idmap_init(void); | 45 | int nfsd_idmap_init(struct net *); |
46 | void nfsd_idmap_shutdown(void); | 46 | void nfsd_idmap_shutdown(struct net *); |
47 | #else | 47 | #else |
48 | static inline int nfsd_idmap_init(void) | 48 | static inline int nfsd_idmap_init(struct net *net) |
49 | { | 49 | { |
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | static inline void nfsd_idmap_shutdown(void) | 52 | static 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 | ||
29 | struct nfsd_net { | 29 | struct 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 | ||
33 | extern int nfsd_net_id; | 39 | extern 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 | ||
110 | static struct cache_head *idtoname_table[ENT_HASHMAX]; | ||
111 | |||
112 | static uint32_t | 112 | static uint32_t |
113 | idtoname_hash(struct ent *ent) | 113 | idtoname_hash(struct ent *ent) |
114 | { | 114 | { |
@@ -183,13 +183,13 @@ warn_no_idmapd(struct cache_detail *detail, int has_died) | |||
183 | 183 | ||
184 | 184 | ||
185 | static int idtoname_parse(struct cache_detail *, char *, int); | 185 | static int idtoname_parse(struct cache_detail *, char *, int); |
186 | static struct ent *idtoname_lookup(struct ent *); | 186 | static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); |
187 | static struct ent *idtoname_update(struct ent *, struct ent *); | 187 | static struct ent *idtoname_update(struct cache_detail *, struct ent *, |
188 | struct ent *); | ||
188 | 189 | ||
189 | static struct cache_detail idtoname_cache = { | 190 | static 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; |
270 | out: | 270 | out: |
@@ -275,10 +275,9 @@ out: | |||
275 | 275 | ||
276 | 276 | ||
277 | static struct ent * | 277 | static struct ent * |
278 | idtoname_lookup(struct ent *item) | 278 | idtoname_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 | ||
289 | static struct ent * | 288 | static struct ent * |
290 | idtoname_update(struct ent *new, struct ent *old) | 289 | idtoname_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 | ||
306 | static struct cache_head *nametoid_table[ENT_HASHMAX]; | ||
307 | |||
308 | static inline int | 304 | static inline int |
309 | nametoid_hash(struct ent *ent) | 305 | nametoid_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 | ||
362 | static struct ent *nametoid_lookup(struct ent *); | 358 | static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); |
363 | static struct ent *nametoid_update(struct ent *, struct ent *); | 359 | static struct ent *nametoid_update(struct cache_detail *, struct ent *, |
360 | struct ent *); | ||
364 | static int nametoid_parse(struct cache_detail *, char *, int); | 361 | static int nametoid_parse(struct cache_detail *, char *, int); |
365 | 362 | ||
366 | static struct cache_detail nametoid_cache = { | 363 | static 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; |
438 | out: | 434 | out: |
439 | kfree(buf1); | 435 | kfree(buf1); |
@@ -443,10 +439,9 @@ out: | |||
443 | 439 | ||
444 | 440 | ||
445 | static struct ent * | 441 | static struct ent * |
446 | nametoid_lookup(struct ent *item) | 442 | nametoid_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 | ||
457 | static struct ent * | 452 | static struct ent * |
458 | nametoid_update(struct ent *new, struct ent *old) | 453 | nametoid_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 | ||
473 | int | 467 | int |
474 | nfsd_idmap_init(void) | 468 | nfsd_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 | |||
489 | destroy_nametoid_cache: | ||
490 | cache_destroy_net(nn->nametoid_cache, net); | ||
491 | unregister_idtoname_cache: | ||
492 | cache_unregister_net(nn->idtoname_cache, net); | ||
493 | destroy_idtoname_cache: | ||
494 | cache_destroy_net(nn->idtoname_cache, net); | ||
484 | return rv; | 495 | return rv; |
485 | } | 496 | } |
486 | 497 | ||
487 | void | 498 | void |
488 | nfsd_idmap_shutdown(void) | 499 | nfsd_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 | ||
494 | static int | 509 | static int |
495 | idmap_lookup(struct svc_rqst *rqstp, | 510 | idmap_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: | |||
3155 | static struct lock_manager nfsd4_manager = { | 3155 | static struct lock_manager nfsd4_manager = { |
3156 | }; | 3156 | }; |
3157 | 3157 | ||
3158 | static bool grace_ended; | ||
3159 | |||
3158 | static void | 3160 | static void |
3159 | nfsd4_end_grace(void) | 3161 | nfsd4_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 | ||
128 | static int exports_open(struct inode *inode, struct file *file) | 128 | static 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 | ||
133 | static const struct file_operations exports_operations = { | 143 | static 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 | ||
1129 | int nfsd_net_id; | 1139 | int nfsd_net_id; |
1140 | |||
1141 | static __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 | |||
1153 | out_idmap_error: | ||
1154 | nfsd_export_shutdown(net); | ||
1155 | out_export_error: | ||
1156 | return retval; | ||
1157 | } | ||
1158 | |||
1159 | static __net_exit void nfsd_exit_net(struct net *net) | ||
1160 | { | ||
1161 | nfsd_idmap_shutdown(net); | ||
1162 | nfsd_export_shutdown(net); | ||
1163 | } | ||
1164 | |||
1130 | static struct pernet_operations nfsd_net_ops = { | 1165 | static 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) | |||
1171 | out_free_all: | 1202 | out_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); |
1174 | out_free_idmap: | ||
1175 | nfsd_idmap_shutdown(); | ||
1176 | out_free_lockd: | 1205 | out_free_lockd: |
1177 | nfsd_lockd_shutdown(); | 1206 | nfsd_lockd_shutdown(); |
1178 | nfsd_export_shutdown(); | ||
1179 | out_free_cache: | ||
1180 | nfsd_reply_cache_shutdown(); | 1207 | nfsd_reply_cache_shutdown(); |
1181 | out_free_stat: | 1208 | out_free_stat: |
1182 | nfsd_stat_shutdown(); | 1209 | nfsd_stat_shutdown(); |
@@ -1192,13 +1219,11 @@ out_unregister_notifier: | |||
1192 | 1219 | ||
1193 | static void __exit exit_nfsd(void) | 1220 | static 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; |
231 | out_lockd: | 231 | out_lockd: |
232 | lockd_down(); | 232 | lockd_down(&init_net); |
233 | out_racache: | 233 | out_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 | ||
267 | void nfsd_reset_versions(void) | 267 | void 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; |