diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-06-25 13:06:12 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-06-25 13:10:36 -0400 |
commit | 7b0cfee1a24efdfe0235bac62e53f686fe8a8e24 (patch) | |
tree | eeeb8cc3bf7be5ec0e54b7c4f3808ef88ecca012 /fs/nfsd | |
parent | 9756fe38d10b2bf90c81dc4d2f17d5632e135364 (diff) | |
parent | 6b16351acbd415e66ba16bf7d473ece1574cf0bc (diff) |
Merge tag 'v3.5-rc4' into drm-intel-next-queued
I want to merge the "no more fake agp on gen6+" patches into
drm-intel-next (well, the last pieces). But a patch in 3.5-rc4 also
adds a new use of dev->agp. Hence the backmarge to sort this out, for
otherwise drm-intel-next merged into Linus' tree would conflict in the
relevant code, things would compile but nicely OOPS at driver load :(
Conflicts in this merge are just simple cases of "both branches
changed/added lines at the same place". The only tricky part is to
keep the order correct wrt the unwind code in case of errors in
intel_ringbuffer.c (and the MI_DISPLAY_FLIP #defines in i915_reg.h
together, obviously).
Conflicts:
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ringbuffer.c
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/auth.c | 2 | ||||
-rw-r--r-- | fs/nfsd/export.c | 181 | ||||
-rw-r--r-- | fs/nfsd/fault_inject.c | 1 | ||||
-rw-r--r-- | fs/nfsd/idmap.h | 8 | ||||
-rw-r--r-- | fs/nfsd/netns.h | 6 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 113 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 542 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 62 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 67 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 31 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 6 |
16 files changed, 569 insertions, 464 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 204438cc914e..34a10d78b839 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -11,7 +11,7 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | |||
11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | 11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; |
12 | 12 | ||
13 | for (f = exp->ex_flavors; f < end; f++) { | 13 | for (f = exp->ex_flavors; f < end; f++) { |
14 | if (f->pseudoflavor == rqstp->rq_flavor) | 14 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
15 | return f->flags; | 15 | return f->flags; |
16 | } | 16 | } |
17 | return exp->ex_flags; | 17 | return exp->ex_flags; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8e9689abbc0c..ba233499b9a5 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 | static 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); |
@@ -901,13 +904,13 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | |||
901 | return 0; | 904 | return 0; |
902 | /* ip-address based client; check sec= export option: */ | 905 | /* ip-address based client; check sec= export option: */ |
903 | for (f = exp->ex_flavors; f < end; f++) { | 906 | for (f = exp->ex_flavors; f < end; f++) { |
904 | if (f->pseudoflavor == rqstp->rq_flavor) | 907 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
905 | return 0; | 908 | return 0; |
906 | } | 909 | } |
907 | /* defaults in absence of sec= options: */ | 910 | /* defaults in absence of sec= options: */ |
908 | if (exp->ex_nflavors == 0) { | 911 | if (exp->ex_nflavors == 0) { |
909 | if (rqstp->rq_flavor == RPC_AUTH_NULL || | 912 | if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL || |
910 | rqstp->rq_flavor == RPC_AUTH_UNIX) | 913 | rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX) |
911 | return 0; | 914 | return 0; |
912 | } | 915 | } |
913 | return nfserr_wrongsec; | 916 | return nfserr_wrongsec; |
@@ -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/fault_inject.c b/fs/nfsd/fault_inject.c index 9559ce468732..e6c38159622f 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -58,6 +58,7 @@ static int nfsd_inject_set(void *op_ptr, u64 val) | |||
58 | 58 | ||
59 | static int nfsd_inject_get(void *data, u64 *val) | 59 | static int nfsd_inject_get(void *data, u64 *val) |
60 | { | 60 | { |
61 | *val = 0; | ||
61 | return 0; | 62 | return 0; |
62 | } | 63 | } |
63 | 64 | ||
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/nfs4callback.c b/fs/nfsd/nfs4callback.c index c8e9f637153a..a5fd6b982f27 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -650,9 +650,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
650 | struct rpc_clnt *client; | 650 | struct rpc_clnt *client; |
651 | 651 | ||
652 | if (clp->cl_minorversion == 0) { | 652 | if (clp->cl_minorversion == 0) { |
653 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 653 | if (!clp->cl_cred.cr_principal && |
654 | (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | ||
654 | return -EINVAL; | 655 | return -EINVAL; |
655 | args.client_name = clp->cl_principal; | 656 | args.client_name = clp->cl_cred.cr_principal; |
656 | args.prognumber = conn->cb_prog, | 657 | args.prognumber = conn->cb_prog, |
657 | args.protocol = XPRT_TRANSPORT_TCP; | 658 | args.protocol = XPRT_TRANSPORT_TCP; |
658 | args.authflavor = clp->cl_flavor; | 659 | args.authflavor = clp->cl_flavor; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 322d11ce06a4..dae36f1dee95 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 | ||
@@ -588,7 +605,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel | |||
588 | static __be32 | 605 | static __be32 |
589 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) | 606 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) |
590 | { | 607 | { |
591 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 608 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
592 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) | 609 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) |
593 | return 0; | 610 | return 0; |
594 | /* | 611 | /* |
@@ -601,7 +618,7 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u | |||
601 | static int | 618 | static int |
602 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | 619 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) |
603 | { | 620 | { |
604 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 621 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
605 | return sprintf(name, "%u", id); | 622 | return sprintf(name, "%u", id); |
606 | return idmap_id_to_name(rqstp, type, id, name); | 623 | return idmap_id_to_name(rqstp, type, id, name); |
607 | } | 624 | } |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ed3f9206a0ee..5ff0b7b9fc08 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -570,7 +570,7 @@ static ssize_t | |||
570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
571 | { | 571 | { |
572 | struct cld_upcall *tmp, *cup; | 572 | struct cld_upcall *tmp, *cup; |
573 | struct cld_msg *cmsg = (struct cld_msg *)src; | 573 | struct cld_msg __user *cmsg = (struct cld_msg __user *)src; |
574 | uint32_t xid; | 574 | uint32_t xid; |
575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, | 575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, |
576 | nfsd_net_id); | 576 | nfsd_net_id); |
@@ -1029,7 +1029,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) | |||
1029 | return ret; | 1029 | return ret; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | struct notifier_block nfsd4_cld_block = { | 1032 | static struct notifier_block nfsd4_cld_block = { |
1033 | .notifier_call = rpc_pipefs_event, | 1033 | .notifier_call = rpc_pipefs_event, |
1034 | }; | 1034 | }; |
1035 | 1035 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7f71c69cdcdf..94effd5bc4a1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
43 | #include "xdr4.h" | 43 | #include "xdr4.h" |
44 | #include "vfs.h" | 44 | #include "vfs.h" |
45 | #include "current_stateid.h" | ||
45 | 46 | ||
46 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 47 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
47 | 48 | ||
@@ -447,37 +448,69 @@ static struct list_head close_lru; | |||
447 | * | 448 | * |
448 | * which we should reject. | 449 | * which we should reject. |
449 | */ | 450 | */ |
450 | static void | 451 | static unsigned int |
451 | set_access(unsigned int *access, unsigned long bmap) { | 452 | bmap_to_share_mode(unsigned long bmap) { |
452 | int i; | 453 | int i; |
454 | unsigned int access = 0; | ||
453 | 455 | ||
454 | *access = 0; | ||
455 | for (i = 1; i < 4; i++) { | 456 | for (i = 1; i < 4; i++) { |
456 | if (test_bit(i, &bmap)) | 457 | if (test_bit(i, &bmap)) |
457 | *access |= i; | 458 | access |= i; |
458 | } | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
463 | int i; | ||
464 | |||
465 | *deny = 0; | ||
466 | for (i = 0; i < 4; i++) { | ||
467 | if (test_bit(i, &bmap)) | ||
468 | *deny |= i ; | ||
469 | } | 459 | } |
460 | return access; | ||
470 | } | 461 | } |
471 | 462 | ||
472 | static int | 463 | static bool |
473 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { | 464 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { |
474 | unsigned int access, deny; | 465 | unsigned int access, deny; |
475 | 466 | ||
476 | set_access(&access, stp->st_access_bmap); | 467 | access = bmap_to_share_mode(stp->st_access_bmap); |
477 | set_deny(&deny, stp->st_deny_bmap); | 468 | deny = bmap_to_share_mode(stp->st_deny_bmap); |
478 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | 469 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) |
479 | return 0; | 470 | return false; |
480 | return 1; | 471 | return true; |
472 | } | ||
473 | |||
474 | /* set share access for a given stateid */ | ||
475 | static inline void | ||
476 | set_access(u32 access, struct nfs4_ol_stateid *stp) | ||
477 | { | ||
478 | __set_bit(access, &stp->st_access_bmap); | ||
479 | } | ||
480 | |||
481 | /* clear share access for a given stateid */ | ||
482 | static inline void | ||
483 | clear_access(u32 access, struct nfs4_ol_stateid *stp) | ||
484 | { | ||
485 | __clear_bit(access, &stp->st_access_bmap); | ||
486 | } | ||
487 | |||
488 | /* test whether a given stateid has access */ | ||
489 | static inline bool | ||
490 | test_access(u32 access, struct nfs4_ol_stateid *stp) | ||
491 | { | ||
492 | return test_bit(access, &stp->st_access_bmap); | ||
493 | } | ||
494 | |||
495 | /* set share deny for a given stateid */ | ||
496 | static inline void | ||
497 | set_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
498 | { | ||
499 | __set_bit(access, &stp->st_deny_bmap); | ||
500 | } | ||
501 | |||
502 | /* clear share deny for a given stateid */ | ||
503 | static inline void | ||
504 | clear_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
505 | { | ||
506 | __clear_bit(access, &stp->st_deny_bmap); | ||
507 | } | ||
508 | |||
509 | /* test whether a given stateid is denying specific access */ | ||
510 | static inline bool | ||
511 | test_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
512 | { | ||
513 | return test_bit(access, &stp->st_deny_bmap); | ||
481 | } | 514 | } |
482 | 515 | ||
483 | static int nfs4_access_to_omode(u32 access) | 516 | static int nfs4_access_to_omode(u32 access) |
@@ -493,6 +526,20 @@ static int nfs4_access_to_omode(u32 access) | |||
493 | BUG(); | 526 | BUG(); |
494 | } | 527 | } |
495 | 528 | ||
529 | /* release all access and file references for a given stateid */ | ||
530 | static void | ||
531 | release_all_access(struct nfs4_ol_stateid *stp) | ||
532 | { | ||
533 | int i; | ||
534 | |||
535 | for (i = 1; i < 4; i++) { | ||
536 | if (test_access(i, stp)) | ||
537 | nfs4_file_put_access(stp->st_file, | ||
538 | nfs4_access_to_omode(i)); | ||
539 | clear_access(i, stp); | ||
540 | } | ||
541 | } | ||
542 | |||
496 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 543 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) |
497 | { | 544 | { |
498 | list_del(&stp->st_perfile); | 545 | list_del(&stp->st_perfile); |
@@ -501,16 +548,7 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | |||
501 | 548 | ||
502 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) | 549 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) |
503 | { | 550 | { |
504 | int i; | 551 | release_all_access(stp); |
505 | |||
506 | if (stp->st_access_bmap) { | ||
507 | for (i = 1; i < 4; i++) { | ||
508 | if (test_bit(i, &stp->st_access_bmap)) | ||
509 | nfs4_file_put_access(stp->st_file, | ||
510 | nfs4_access_to_omode(i)); | ||
511 | __clear_bit(i, &stp->st_access_bmap); | ||
512 | } | ||
513 | } | ||
514 | put_nfs4_file(stp->st_file); | 552 | put_nfs4_file(stp->st_file); |
515 | stp->st_file = NULL; | 553 | stp->st_file = NULL; |
516 | } | 554 | } |
@@ -862,7 +900,7 @@ static void free_session(struct kref *kref) | |||
862 | struct nfsd4_session *ses; | 900 | struct nfsd4_session *ses; |
863 | int mem; | 901 | int mem; |
864 | 902 | ||
865 | BUG_ON(!spin_is_locked(&client_lock)); | 903 | lockdep_assert_held(&client_lock); |
866 | ses = container_of(kref, struct nfsd4_session, se_ref); | 904 | ses = container_of(kref, struct nfsd4_session, se_ref); |
867 | nfsd4_del_conns(ses); | 905 | nfsd4_del_conns(ses); |
868 | spin_lock(&nfsd_drc_lock); | 906 | spin_lock(&nfsd_drc_lock); |
@@ -885,7 +923,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
885 | struct nfsd4_session *new; | 923 | struct nfsd4_session *new; |
886 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | 924 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; |
887 | int numslots, slotsize; | 925 | int numslots, slotsize; |
888 | int status; | 926 | __be32 status; |
889 | int idx; | 927 | int idx; |
890 | 928 | ||
891 | /* | 929 | /* |
@@ -984,7 +1022,8 @@ static inline void | |||
984 | renew_client_locked(struct nfs4_client *clp) | 1022 | renew_client_locked(struct nfs4_client *clp) |
985 | { | 1023 | { |
986 | if (is_client_expired(clp)) { | 1024 | if (is_client_expired(clp)) { |
987 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | 1025 | WARN_ON(1); |
1026 | printk("%s: client (clientid %08x/%08x) already expired\n", | ||
988 | __func__, | 1027 | __func__, |
989 | clp->cl_clientid.cl_boot, | 1028 | clp->cl_clientid.cl_boot, |
990 | clp->cl_clientid.cl_id); | 1029 | clp->cl_clientid.cl_id); |
@@ -1041,7 +1080,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
1041 | static inline void | 1080 | static inline void |
1042 | free_client(struct nfs4_client *clp) | 1081 | free_client(struct nfs4_client *clp) |
1043 | { | 1082 | { |
1044 | BUG_ON(!spin_is_locked(&client_lock)); | 1083 | lockdep_assert_held(&client_lock); |
1045 | while (!list_empty(&clp->cl_sessions)) { | 1084 | while (!list_empty(&clp->cl_sessions)) { |
1046 | struct nfsd4_session *ses; | 1085 | struct nfsd4_session *ses; |
1047 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 1086 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, |
@@ -1049,9 +1088,7 @@ free_client(struct nfs4_client *clp) | |||
1049 | list_del(&ses->se_perclnt); | 1088 | list_del(&ses->se_perclnt); |
1050 | nfsd4_put_session_locked(ses); | 1089 | nfsd4_put_session_locked(ses); |
1051 | } | 1090 | } |
1052 | if (clp->cl_cred.cr_group_info) | 1091 | free_svc_cred(&clp->cl_cred); |
1053 | put_group_info(clp->cl_cred.cr_group_info); | ||
1054 | kfree(clp->cl_principal); | ||
1055 | kfree(clp->cl_name.data); | 1092 | kfree(clp->cl_name.data); |
1056 | kfree(clp); | 1093 | kfree(clp); |
1057 | } | 1094 | } |
@@ -1132,12 +1169,21 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
1132 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 1169 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
1133 | } | 1170 | } |
1134 | 1171 | ||
1135 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) | 1172 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) |
1136 | { | 1173 | { |
1174 | if (source->cr_principal) { | ||
1175 | target->cr_principal = | ||
1176 | kstrdup(source->cr_principal, GFP_KERNEL); | ||
1177 | if (target->cr_principal == NULL) | ||
1178 | return -ENOMEM; | ||
1179 | } else | ||
1180 | target->cr_principal = NULL; | ||
1181 | target->cr_flavor = source->cr_flavor; | ||
1137 | target->cr_uid = source->cr_uid; | 1182 | target->cr_uid = source->cr_uid; |
1138 | target->cr_gid = source->cr_gid; | 1183 | target->cr_gid = source->cr_gid; |
1139 | target->cr_group_info = source->cr_group_info; | 1184 | target->cr_group_info = source->cr_group_info; |
1140 | get_group_info(target->cr_group_info); | 1185 | get_group_info(target->cr_group_info); |
1186 | return 0; | ||
1141 | } | 1187 | } |
1142 | 1188 | ||
1143 | static int same_name(const char *n1, const char *n2) | 1189 | static int same_name(const char *n1, const char *n2) |
@@ -1157,11 +1203,31 @@ same_clid(clientid_t *cl1, clientid_t *cl2) | |||
1157 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); | 1203 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); |
1158 | } | 1204 | } |
1159 | 1205 | ||
1160 | /* XXX what about NGROUP */ | 1206 | static bool groups_equal(struct group_info *g1, struct group_info *g2) |
1207 | { | ||
1208 | int i; | ||
1209 | |||
1210 | if (g1->ngroups != g2->ngroups) | ||
1211 | return false; | ||
1212 | for (i=0; i<g1->ngroups; i++) | ||
1213 | if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) | ||
1214 | return false; | ||
1215 | return true; | ||
1216 | } | ||
1217 | |||
1161 | static int | 1218 | static int |
1162 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | 1219 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) |
1163 | { | 1220 | { |
1164 | return cr1->cr_uid == cr2->cr_uid; | 1221 | if ((cr1->cr_flavor != cr2->cr_flavor) |
1222 | || (cr1->cr_uid != cr2->cr_uid) | ||
1223 | || (cr1->cr_gid != cr2->cr_gid) | ||
1224 | || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) | ||
1225 | return false; | ||
1226 | if (cr1->cr_principal == cr2->cr_principal) | ||
1227 | return true; | ||
1228 | if (!cr1->cr_principal || !cr2->cr_principal) | ||
1229 | return false; | ||
1230 | return 0 == strcmp(cr1->cr_principal, cr1->cr_principal); | ||
1165 | } | 1231 | } |
1166 | 1232 | ||
1167 | static void gen_clid(struct nfs4_client *clp) | 1233 | static void gen_clid(struct nfs4_client *clp) |
@@ -1204,25 +1270,20 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1204 | { | 1270 | { |
1205 | struct nfs4_client *clp; | 1271 | struct nfs4_client *clp; |
1206 | struct sockaddr *sa = svc_addr(rqstp); | 1272 | struct sockaddr *sa = svc_addr(rqstp); |
1207 | char *princ; | 1273 | int ret; |
1208 | 1274 | ||
1209 | clp = alloc_client(name); | 1275 | clp = alloc_client(name); |
1210 | if (clp == NULL) | 1276 | if (clp == NULL) |
1211 | return NULL; | 1277 | return NULL; |
1212 | 1278 | ||
1213 | INIT_LIST_HEAD(&clp->cl_sessions); | 1279 | INIT_LIST_HEAD(&clp->cl_sessions); |
1214 | 1280 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | |
1215 | princ = svc_gss_principal(rqstp); | 1281 | if (ret) { |
1216 | if (princ) { | 1282 | spin_lock(&client_lock); |
1217 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1283 | free_client(clp); |
1218 | if (clp->cl_principal == NULL) { | 1284 | spin_unlock(&client_lock); |
1219 | spin_lock(&client_lock); | 1285 | return NULL; |
1220 | free_client(clp); | ||
1221 | spin_unlock(&client_lock); | ||
1222 | return NULL; | ||
1223 | } | ||
1224 | } | 1286 | } |
1225 | |||
1226 | idr_init(&clp->cl_stateids); | 1287 | idr_init(&clp->cl_stateids); |
1227 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1288 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1228 | atomic_set(&clp->cl_refcount, 0); | 1289 | atomic_set(&clp->cl_refcount, 0); |
@@ -1240,8 +1301,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1240 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1301 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
1241 | copy_verf(clp, verf); | 1302 | copy_verf(clp, verf); |
1242 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1303 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
1243 | clp->cl_flavor = rqstp->rq_flavor; | ||
1244 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
1245 | gen_confirm(clp); | 1304 | gen_confirm(clp); |
1246 | clp->cl_cb_session = NULL; | 1305 | clp->cl_cb_session = NULL; |
1247 | return clp; | 1306 | return clp; |
@@ -1470,18 +1529,32 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
1470 | clid->flags = new->cl_exchange_flags; | 1529 | clid->flags = new->cl_exchange_flags; |
1471 | } | 1530 | } |
1472 | 1531 | ||
1532 | static bool client_has_state(struct nfs4_client *clp) | ||
1533 | { | ||
1534 | /* | ||
1535 | * Note clp->cl_openowners check isn't quite right: there's no | ||
1536 | * need to count owners without stateid's. | ||
1537 | * | ||
1538 | * Also note we should probably be using this in 4.0 case too. | ||
1539 | */ | ||
1540 | return !list_empty(&clp->cl_openowners) | ||
1541 | || !list_empty(&clp->cl_delegations) | ||
1542 | || !list_empty(&clp->cl_sessions); | ||
1543 | } | ||
1544 | |||
1473 | __be32 | 1545 | __be32 |
1474 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 1546 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
1475 | struct nfsd4_compound_state *cstate, | 1547 | struct nfsd4_compound_state *cstate, |
1476 | struct nfsd4_exchange_id *exid) | 1548 | struct nfsd4_exchange_id *exid) |
1477 | { | 1549 | { |
1478 | struct nfs4_client *unconf, *conf, *new; | 1550 | struct nfs4_client *unconf, *conf, *new; |
1479 | int status; | 1551 | __be32 status; |
1480 | unsigned int strhashval; | 1552 | unsigned int strhashval; |
1481 | char dname[HEXDIR_LEN]; | 1553 | char dname[HEXDIR_LEN]; |
1482 | char addr_str[INET6_ADDRSTRLEN]; | 1554 | char addr_str[INET6_ADDRSTRLEN]; |
1483 | nfs4_verifier verf = exid->verifier; | 1555 | nfs4_verifier verf = exid->verifier; |
1484 | struct sockaddr *sa = svc_addr(rqstp); | 1556 | struct sockaddr *sa = svc_addr(rqstp); |
1557 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | ||
1485 | 1558 | ||
1486 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1559 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
1487 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1560 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
@@ -1507,71 +1580,63 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1507 | status = nfs4_make_rec_clidname(dname, &exid->clname); | 1580 | status = nfs4_make_rec_clidname(dname, &exid->clname); |
1508 | 1581 | ||
1509 | if (status) | 1582 | if (status) |
1510 | goto error; | 1583 | return status; |
1511 | 1584 | ||
1512 | strhashval = clientstr_hashval(dname); | 1585 | strhashval = clientstr_hashval(dname); |
1513 | 1586 | ||
1587 | /* Cases below refer to rfc 5661 section 18.35.4: */ | ||
1514 | nfs4_lock_state(); | 1588 | nfs4_lock_state(); |
1515 | status = nfs_ok; | ||
1516 | |||
1517 | conf = find_confirmed_client_by_str(dname, strhashval); | 1589 | conf = find_confirmed_client_by_str(dname, strhashval); |
1518 | if (conf) { | 1590 | if (conf) { |
1519 | if (!clp_used_exchangeid(conf)) { | 1591 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
1520 | status = nfserr_clid_inuse; /* XXX: ? */ | 1592 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
1521 | goto out; | 1593 | |
1522 | } | 1594 | if (update) { |
1523 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1595 | if (!clp_used_exchangeid(conf)) { /* buggy client */ |
1524 | /* 18.35.4 case 8 */ | 1596 | status = nfserr_inval; |
1525 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1597 | goto out; |
1598 | } | ||
1599 | if (!creds_match) { /* case 9 */ | ||
1600 | status = nfserr_perm; | ||
1601 | goto out; | ||
1602 | } | ||
1603 | if (!verfs_match) { /* case 8 */ | ||
1526 | status = nfserr_not_same; | 1604 | status = nfserr_not_same; |
1527 | goto out; | 1605 | goto out; |
1528 | } | 1606 | } |
1529 | /* Client reboot: destroy old state */ | 1607 | /* case 6 */ |
1530 | expire_client(conf); | 1608 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1531 | goto out_new; | 1609 | new = conf; |
1610 | goto out_copy; | ||
1532 | } | 1611 | } |
1533 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1612 | if (!creds_match) { /* case 3 */ |
1534 | /* 18.35.4 case 9 */ | 1613 | if (client_has_state(conf)) { |
1535 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1614 | status = nfserr_clid_inuse; |
1536 | status = nfserr_perm; | ||
1537 | goto out; | 1615 | goto out; |
1538 | } | 1616 | } |
1539 | expire_client(conf); | 1617 | expire_client(conf); |
1540 | goto out_new; | 1618 | goto out_new; |
1541 | } | 1619 | } |
1542 | /* | 1620 | if (verfs_match) { /* case 2 */ |
1543 | * Set bit when the owner id and verifier map to an already | 1621 | conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1544 | * confirmed client id (18.35.3). | 1622 | new = conf; |
1545 | */ | 1623 | goto out_copy; |
1546 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1624 | } |
1547 | 1625 | /* case 5, client reboot */ | |
1548 | /* | 1626 | goto out_new; |
1549 | * Falling into 18.35.4 case 2, possible router replay. | ||
1550 | * Leave confirmed record intact and return same result. | ||
1551 | */ | ||
1552 | copy_verf(conf, &verf); | ||
1553 | new = conf; | ||
1554 | goto out_copy; | ||
1555 | } | 1627 | } |
1556 | 1628 | ||
1557 | /* 18.35.4 case 7 */ | 1629 | if (update) { /* case 7 */ |
1558 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1559 | status = nfserr_noent; | 1630 | status = nfserr_noent; |
1560 | goto out; | 1631 | goto out; |
1561 | } | 1632 | } |
1562 | 1633 | ||
1563 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1634 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1564 | if (unconf) { | 1635 | if (unconf) /* case 4, possible retry or client restart */ |
1565 | /* | ||
1566 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
1567 | * a new unconfirmed record should be generated regardless | ||
1568 | * of whether any properties have changed. | ||
1569 | */ | ||
1570 | expire_client(unconf); | 1636 | expire_client(unconf); |
1571 | } | ||
1572 | 1637 | ||
1638 | /* case 1 (normal case) */ | ||
1573 | out_new: | 1639 | out_new: |
1574 | /* Normal case */ | ||
1575 | new = create_client(exid->clname, dname, rqstp, &verf); | 1640 | new = create_client(exid->clname, dname, rqstp, &verf); |
1576 | if (new == NULL) { | 1641 | if (new == NULL) { |
1577 | status = nfserr_jukebox; | 1642 | status = nfserr_jukebox; |
@@ -1584,7 +1649,7 @@ out_copy: | |||
1584 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1649 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1585 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1650 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1586 | 1651 | ||
1587 | exid->seqid = 1; | 1652 | exid->seqid = new->cl_cs_slot.sl_seqid + 1; |
1588 | nfsd4_set_ex_flags(new, exid); | 1653 | nfsd4_set_ex_flags(new, exid); |
1589 | 1654 | ||
1590 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1655 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
@@ -1593,12 +1658,10 @@ out_copy: | |||
1593 | 1658 | ||
1594 | out: | 1659 | out: |
1595 | nfs4_unlock_state(); | 1660 | nfs4_unlock_state(); |
1596 | error: | ||
1597 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
1598 | return status; | 1661 | return status; |
1599 | } | 1662 | } |
1600 | 1663 | ||
1601 | static int | 1664 | static __be32 |
1602 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | 1665 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1603 | { | 1666 | { |
1604 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, | 1667 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
@@ -1626,7 +1689,7 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1626 | */ | 1689 | */ |
1627 | static void | 1690 | static void |
1628 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | 1691 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, |
1629 | struct nfsd4_clid_slot *slot, int nfserr) | 1692 | struct nfsd4_clid_slot *slot, __be32 nfserr) |
1630 | { | 1693 | { |
1631 | slot->sl_status = nfserr; | 1694 | slot->sl_status = nfserr; |
1632 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | 1695 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); |
@@ -1657,7 +1720,7 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
1657 | /* seqid, slotID, slotID, slotID, status */ \ | 1720 | /* seqid, slotID, slotID, slotID, status */ \ |
1658 | 5 ) * sizeof(__be32)) | 1721 | 5 ) * sizeof(__be32)) |
1659 | 1722 | ||
1660 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | 1723 | static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) |
1661 | { | 1724 | { |
1662 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | 1725 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ |
1663 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | 1726 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; |
@@ -1673,7 +1736,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1673 | struct nfsd4_session *new; | 1736 | struct nfsd4_session *new; |
1674 | struct nfsd4_clid_slot *cs_slot = NULL; | 1737 | struct nfsd4_clid_slot *cs_slot = NULL; |
1675 | bool confirm_me = false; | 1738 | bool confirm_me = false; |
1676 | int status = 0; | 1739 | __be32 status = 0; |
1677 | 1740 | ||
1678 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1741 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1679 | return nfserr_inval; | 1742 | return nfserr_inval; |
@@ -1686,16 +1749,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1686 | cs_slot = &conf->cl_cs_slot; | 1749 | cs_slot = &conf->cl_cs_slot; |
1687 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1750 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1688 | if (status == nfserr_replay_cache) { | 1751 | if (status == nfserr_replay_cache) { |
1689 | dprintk("Got a create_session replay! seqid= %d\n", | ||
1690 | cs_slot->sl_seqid); | ||
1691 | /* Return the cached reply status */ | ||
1692 | status = nfsd4_replay_create_session(cr_ses, cs_slot); | 1752 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1693 | goto out; | 1753 | goto out; |
1694 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { | 1754 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1695 | status = nfserr_seq_misordered; | 1755 | status = nfserr_seq_misordered; |
1696 | dprintk("Sequence misordered!\n"); | ||
1697 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
1698 | cs_slot->sl_seqid, cr_ses->seqid); | ||
1699 | goto out; | 1756 | goto out; |
1700 | } | 1757 | } |
1701 | } else if (unconf) { | 1758 | } else if (unconf) { |
@@ -1704,7 +1761,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1704 | status = nfserr_clid_inuse; | 1761 | status = nfserr_clid_inuse; |
1705 | goto out; | 1762 | goto out; |
1706 | } | 1763 | } |
1707 | |||
1708 | cs_slot = &unconf->cl_cs_slot; | 1764 | cs_slot = &unconf->cl_cs_slot; |
1709 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1765 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1710 | if (status) { | 1766 | if (status) { |
@@ -1712,7 +1768,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1712 | status = nfserr_seq_misordered; | 1768 | status = nfserr_seq_misordered; |
1713 | goto out; | 1769 | goto out; |
1714 | } | 1770 | } |
1715 | |||
1716 | confirm_me = true; | 1771 | confirm_me = true; |
1717 | conf = unconf; | 1772 | conf = unconf; |
1718 | } else { | 1773 | } else { |
@@ -1749,8 +1804,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1749 | 1804 | ||
1750 | /* cache solo and embedded create sessions under the state lock */ | 1805 | /* cache solo and embedded create sessions under the state lock */ |
1751 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1806 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1752 | if (confirm_me) | 1807 | if (confirm_me) { |
1808 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
1809 | struct nfs4_client *old = | ||
1810 | find_confirmed_client_by_str(conf->cl_recdir, hash); | ||
1811 | if (old) | ||
1812 | expire_client(old); | ||
1753 | move_to_confirmed(conf); | 1813 | move_to_confirmed(conf); |
1814 | } | ||
1754 | out: | 1815 | out: |
1755 | nfs4_unlock_state(); | 1816 | nfs4_unlock_state(); |
1756 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1817 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1818,7 +1879,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1818 | struct nfsd4_destroy_session *sessionid) | 1879 | struct nfsd4_destroy_session *sessionid) |
1819 | { | 1880 | { |
1820 | struct nfsd4_session *ses; | 1881 | struct nfsd4_session *ses; |
1821 | u32 status = nfserr_badsession; | 1882 | __be32 status = nfserr_badsession; |
1822 | 1883 | ||
1823 | /* Notes: | 1884 | /* Notes: |
1824 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1885 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
@@ -1914,7 +1975,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1914 | struct nfsd4_session *session; | 1975 | struct nfsd4_session *session; |
1915 | struct nfsd4_slot *slot; | 1976 | struct nfsd4_slot *slot; |
1916 | struct nfsd4_conn *conn; | 1977 | struct nfsd4_conn *conn; |
1917 | int status; | 1978 | __be32 status; |
1918 | 1979 | ||
1919 | if (resp->opcnt != 1) | 1980 | if (resp->opcnt != 1) |
1920 | return nfserr_sequence_pos; | 1981 | return nfserr_sequence_pos; |
@@ -2008,18 +2069,11 @@ out: | |||
2008 | return status; | 2069 | return status; |
2009 | } | 2070 | } |
2010 | 2071 | ||
2011 | static inline bool has_resources(struct nfs4_client *clp) | ||
2012 | { | ||
2013 | return !list_empty(&clp->cl_openowners) | ||
2014 | || !list_empty(&clp->cl_delegations) | ||
2015 | || !list_empty(&clp->cl_sessions); | ||
2016 | } | ||
2017 | |||
2018 | __be32 | 2072 | __be32 |
2019 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | 2073 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) |
2020 | { | 2074 | { |
2021 | struct nfs4_client *conf, *unconf, *clp; | 2075 | struct nfs4_client *conf, *unconf, *clp; |
2022 | int status = 0; | 2076 | __be32 status = 0; |
2023 | 2077 | ||
2024 | nfs4_lock_state(); | 2078 | nfs4_lock_state(); |
2025 | unconf = find_unconfirmed_client(&dc->clientid); | 2079 | unconf = find_unconfirmed_client(&dc->clientid); |
@@ -2028,7 +2082,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2028 | if (conf) { | 2082 | if (conf) { |
2029 | clp = conf; | 2083 | clp = conf; |
2030 | 2084 | ||
2031 | if (!is_client_expired(conf) && has_resources(conf)) { | 2085 | if (!is_client_expired(conf) && client_has_state(conf)) { |
2032 | status = nfserr_clientid_busy; | 2086 | status = nfserr_clientid_busy; |
2033 | goto out; | 2087 | goto out; |
2034 | } | 2088 | } |
@@ -2055,7 +2109,7 @@ out: | |||
2055 | __be32 | 2109 | __be32 |
2056 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 2110 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
2057 | { | 2111 | { |
2058 | int status = 0; | 2112 | __be32 status = 0; |
2059 | 2113 | ||
2060 | if (rc->rca_one_fs) { | 2114 | if (rc->rca_one_fs) { |
2061 | if (!cstate->current_fh.fh_dentry) | 2115 | if (!cstate->current_fh.fh_dentry) |
@@ -2106,17 +2160,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2106 | if (status) | 2160 | if (status) |
2107 | return status; | 2161 | return status; |
2108 | 2162 | ||
2109 | /* | ||
2110 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2111 | * We get here on a DRC miss. | ||
2112 | */ | ||
2113 | |||
2114 | strhashval = clientstr_hashval(dname); | 2163 | strhashval = clientstr_hashval(dname); |
2115 | 2164 | ||
2165 | /* Cases below refer to rfc 3530 section 14.2.33: */ | ||
2116 | nfs4_lock_state(); | 2166 | nfs4_lock_state(); |
2117 | conf = find_confirmed_client_by_str(dname, strhashval); | 2167 | conf = find_confirmed_client_by_str(dname, strhashval); |
2118 | if (conf) { | 2168 | if (conf) { |
2119 | /* RFC 3530 14.2.33 CASE 0: */ | 2169 | /* case 0: */ |
2120 | status = nfserr_clid_inuse; | 2170 | status = nfserr_clid_inuse; |
2121 | if (clp_used_exchangeid(conf)) | 2171 | if (clp_used_exchangeid(conf)) |
2122 | goto out; | 2172 | goto out; |
@@ -2129,63 +2179,18 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2129 | goto out; | 2179 | goto out; |
2130 | } | 2180 | } |
2131 | } | 2181 | } |
2132 | /* | ||
2133 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") | ||
2134 | * has a description of SETCLIENTID request processing consisting | ||
2135 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
2136 | */ | ||
2137 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2182 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
2183 | if (unconf) | ||
2184 | expire_client(unconf); | ||
2138 | status = nfserr_jukebox; | 2185 | status = nfserr_jukebox; |
2139 | if (!conf) { | 2186 | new = create_client(clname, dname, rqstp, &clverifier); |
2140 | /* | 2187 | if (new == NULL) |
2141 | * RFC 3530 14.2.33 CASE 4: | 2188 | goto out; |
2142 | * placed first, because it is the normal case | 2189 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
2143 | */ | 2190 | /* case 1: probable callback update */ |
2144 | if (unconf) | ||
2145 | expire_client(unconf); | ||
2146 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2147 | if (new == NULL) | ||
2148 | goto out; | ||
2149 | gen_clid(new); | ||
2150 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | ||
2151 | /* | ||
2152 | * RFC 3530 14.2.33 CASE 1: | ||
2153 | * probable callback update | ||
2154 | */ | ||
2155 | if (unconf) { | ||
2156 | /* Note this is removing unconfirmed {*x***}, | ||
2157 | * which is stronger than RFC recommended {vxc**}. | ||
2158 | * This has the advantage that there is at most | ||
2159 | * one {*x***} in either list at any time. | ||
2160 | */ | ||
2161 | expire_client(unconf); | ||
2162 | } | ||
2163 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2164 | if (new == NULL) | ||
2165 | goto out; | ||
2166 | copy_clid(new, conf); | 2191 | copy_clid(new, conf); |
2167 | } else if (!unconf) { | 2192 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
2168 | /* | ||
2169 | * RFC 3530 14.2.33 CASE 2: | ||
2170 | * probable client reboot; state will be removed if | ||
2171 | * confirmed. | ||
2172 | */ | ||
2173 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2174 | if (new == NULL) | ||
2175 | goto out; | ||
2176 | gen_clid(new); | ||
2177 | } else { | ||
2178 | /* | ||
2179 | * RFC 3530 14.2.33 CASE 3: | ||
2180 | * probable client reboot; state will be removed if | ||
2181 | * confirmed. | ||
2182 | */ | ||
2183 | expire_client(unconf); | ||
2184 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2185 | if (new == NULL) | ||
2186 | goto out; | ||
2187 | gen_clid(new); | 2193 | gen_clid(new); |
2188 | } | ||
2189 | /* | 2194 | /* |
2190 | * XXX: we should probably set this at creation time, and check | 2195 | * XXX: we should probably set this at creation time, and check |
2191 | * for consistent minorversion use throughout: | 2196 | * for consistent minorversion use throughout: |
@@ -2203,17 +2208,11 @@ out: | |||
2203 | } | 2208 | } |
2204 | 2209 | ||
2205 | 2210 | ||
2206 | /* | ||
2207 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has | ||
2208 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 | ||
2209 | * bullets, labeled as CASE1 - CASE4 below. | ||
2210 | */ | ||
2211 | __be32 | 2211 | __be32 |
2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
2213 | struct nfsd4_compound_state *cstate, | 2213 | struct nfsd4_compound_state *cstate, |
2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
2215 | { | 2215 | { |
2216 | struct sockaddr *sa = svc_addr(rqstp); | ||
2217 | struct nfs4_client *conf, *unconf; | 2216 | struct nfs4_client *conf, *unconf; |
2218 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2217 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
2219 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2218 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
@@ -2221,84 +2220,44 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2221 | 2220 | ||
2222 | if (STALE_CLIENTID(clid)) | 2221 | if (STALE_CLIENTID(clid)) |
2223 | return nfserr_stale_clientid; | 2222 | return nfserr_stale_clientid; |
2224 | /* | ||
2225 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2226 | * We get here on a DRC miss. | ||
2227 | */ | ||
2228 | |||
2229 | nfs4_lock_state(); | 2223 | nfs4_lock_state(); |
2230 | 2224 | ||
2231 | conf = find_confirmed_client(clid); | 2225 | conf = find_confirmed_client(clid); |
2232 | unconf = find_unconfirmed_client(clid); | 2226 | unconf = find_unconfirmed_client(clid); |
2233 | |||
2234 | status = nfserr_clid_inuse; | ||
2235 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) | ||
2236 | goto out; | ||
2237 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) | ||
2238 | goto out; | ||
2239 | |||
2240 | /* | 2227 | /* |
2241 | * section 14.2.34 of RFC 3530 has a description of | 2228 | * We try hard to give out unique clientid's, so if we get an |
2242 | * SETCLIENTID_CONFIRM request processing consisting | 2229 | * attempt to confirm the same clientid with a different cred, |
2243 | * of 4 bullet points, labeled as CASE1 - CASE4 below. | 2230 | * there's a bug somewhere. Let's charitably assume it's our |
2231 | * bug. | ||
2244 | */ | 2232 | */ |
2245 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { | 2233 | status = nfserr_serverfault; |
2246 | /* | 2234 | if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) |
2247 | * RFC 3530 14.2.34 CASE 1: | 2235 | goto out; |
2248 | * callback update | 2236 | if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
2249 | */ | 2237 | goto out; |
2250 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2238 | /* cases below refer to rfc 3530 section 14.2.34: */ |
2251 | status = nfserr_clid_inuse; | 2239 | if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { |
2252 | else { | 2240 | if (conf && !unconf) /* case 2: probable retransmit */ |
2253 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2254 | nfsd4_probe_callback(conf); | ||
2255 | expire_client(unconf); | ||
2256 | status = nfs_ok; | 2241 | status = nfs_ok; |
2242 | else /* case 4: client hasn't noticed we rebooted yet? */ | ||
2243 | status = nfserr_stale_clientid; | ||
2244 | goto out; | ||
2245 | } | ||
2246 | status = nfs_ok; | ||
2247 | if (conf) { /* case 1: callback update */ | ||
2248 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2249 | nfsd4_probe_callback(conf); | ||
2250 | expire_client(unconf); | ||
2251 | } else { /* case 3: normal case; new or rebooted client */ | ||
2252 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
2257 | 2253 | ||
2254 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
2255 | if (conf) { | ||
2256 | nfsd4_client_record_remove(conf); | ||
2257 | expire_client(conf); | ||
2258 | } | 2258 | } |
2259 | } else if (conf && !unconf) { | 2259 | move_to_confirmed(unconf); |
2260 | /* | 2260 | nfsd4_probe_callback(unconf); |
2261 | * RFC 3530 14.2.34 CASE 2: | ||
2262 | * probable retransmitted request; play it safe and | ||
2263 | * do nothing. | ||
2264 | */ | ||
2265 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) | ||
2266 | status = nfserr_clid_inuse; | ||
2267 | else | ||
2268 | status = nfs_ok; | ||
2269 | } else if (!conf && unconf | ||
2270 | && same_verf(&unconf->cl_confirm, &confirm)) { | ||
2271 | /* | ||
2272 | * RFC 3530 14.2.34 CASE 3: | ||
2273 | * Normal case; new or rebooted client: | ||
2274 | */ | ||
2275 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | ||
2276 | status = nfserr_clid_inuse; | ||
2277 | } else { | ||
2278 | unsigned int hash = | ||
2279 | clientstr_hashval(unconf->cl_recdir); | ||
2280 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
2281 | hash); | ||
2282 | if (conf) { | ||
2283 | nfsd4_client_record_remove(conf); | ||
2284 | expire_client(conf); | ||
2285 | } | ||
2286 | move_to_confirmed(unconf); | ||
2287 | conf = unconf; | ||
2288 | nfsd4_probe_callback(conf); | ||
2289 | status = nfs_ok; | ||
2290 | } | ||
2291 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | ||
2292 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | ||
2293 | &confirm)))) { | ||
2294 | /* | ||
2295 | * RFC 3530 14.2.34 CASE 4: | ||
2296 | * Client probably hasn't noticed that we rebooted yet. | ||
2297 | */ | ||
2298 | status = nfserr_stale_clientid; | ||
2299 | } else { | ||
2300 | /* check that we have hit one of the cases...*/ | ||
2301 | status = nfserr_clid_inuse; | ||
2302 | } | 2261 | } |
2303 | out: | 2262 | out: |
2304 | nfs4_unlock_state(); | 2263 | nfs4_unlock_state(); |
@@ -2454,8 +2413,8 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
2454 | stp->st_file = fp; | 2413 | stp->st_file = fp; |
2455 | stp->st_access_bmap = 0; | 2414 | stp->st_access_bmap = 0; |
2456 | stp->st_deny_bmap = 0; | 2415 | stp->st_deny_bmap = 0; |
2457 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2416 | set_access(open->op_share_access, stp); |
2458 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2417 | set_deny(open->op_share_deny, stp); |
2459 | stp->st_openstp = NULL; | 2418 | stp->st_openstp = NULL; |
2460 | } | 2419 | } |
2461 | 2420 | ||
@@ -2534,8 +2493,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2534 | ret = nfserr_locked; | 2493 | ret = nfserr_locked; |
2535 | /* Search for conflicting share reservations */ | 2494 | /* Search for conflicting share reservations */ |
2536 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { | 2495 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
2537 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 2496 | if (test_deny(deny_type, stp) || |
2538 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 2497 | test_deny(NFS4_SHARE_DENY_BOTH, stp)) |
2539 | goto out; | 2498 | goto out; |
2540 | } | 2499 | } |
2541 | ret = nfs_ok; | 2500 | ret = nfs_ok; |
@@ -2791,7 +2750,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2791 | bool new_access; | 2750 | bool new_access; |
2792 | __be32 status; | 2751 | __be32 status; |
2793 | 2752 | ||
2794 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); | 2753 | new_access = !test_access(op_share_access, stp); |
2795 | if (new_access) { | 2754 | if (new_access) { |
2796 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | 2755 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2797 | if (status) | 2756 | if (status) |
@@ -2806,8 +2765,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2806 | return status; | 2765 | return status; |
2807 | } | 2766 | } |
2808 | /* remember the open */ | 2767 | /* remember the open */ |
2809 | __set_bit(op_share_access, &stp->st_access_bmap); | 2768 | set_access(op_share_access, stp); |
2810 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2769 | set_deny(open->op_share_deny, stp); |
2811 | 2770 | ||
2812 | return nfs_ok; | 2771 | return nfs_ok; |
2813 | } | 2772 | } |
@@ -3155,10 +3114,17 @@ out: | |||
3155 | static struct lock_manager nfsd4_manager = { | 3114 | static struct lock_manager nfsd4_manager = { |
3156 | }; | 3115 | }; |
3157 | 3116 | ||
3117 | static bool grace_ended; | ||
3118 | |||
3158 | static void | 3119 | static void |
3159 | nfsd4_end_grace(void) | 3120 | nfsd4_end_grace(void) |
3160 | { | 3121 | { |
3122 | /* do nothing if grace period already ended */ | ||
3123 | if (grace_ended) | ||
3124 | return; | ||
3125 | |||
3161 | dprintk("NFSD: end of grace period\n"); | 3126 | dprintk("NFSD: end of grace period\n"); |
3127 | grace_ended = true; | ||
3162 | nfsd4_record_grace_done(&init_net, boot_time); | 3128 | nfsd4_record_grace_done(&init_net, boot_time); |
3163 | locks_end_grace(&nfsd4_manager); | 3129 | locks_end_grace(&nfsd4_manager); |
3164 | /* | 3130 | /* |
@@ -3183,8 +3149,7 @@ nfs4_laundromat(void) | |||
3183 | nfs4_lock_state(); | 3149 | nfs4_lock_state(); |
3184 | 3150 | ||
3185 | dprintk("NFSD: laundromat service - starting\n"); | 3151 | dprintk("NFSD: laundromat service - starting\n"); |
3186 | if (locks_in_grace()) | 3152 | nfsd4_end_grace(); |
3187 | nfsd4_end_grace(); | ||
3188 | INIT_LIST_HEAD(&reaplist); | 3153 | INIT_LIST_HEAD(&reaplist); |
3189 | spin_lock(&client_lock); | 3154 | spin_lock(&client_lock); |
3190 | list_for_each_safe(pos, next, &client_lru) { | 3155 | list_for_each_safe(pos, next, &client_lru) { |
@@ -3276,18 +3241,18 @@ STALE_STATEID(stateid_t *stateid) | |||
3276 | } | 3241 | } |
3277 | 3242 | ||
3278 | static inline int | 3243 | static inline int |
3279 | access_permit_read(unsigned long access_bmap) | 3244 | access_permit_read(struct nfs4_ol_stateid *stp) |
3280 | { | 3245 | { |
3281 | return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || | 3246 | return test_access(NFS4_SHARE_ACCESS_READ, stp) || |
3282 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || | 3247 | test_access(NFS4_SHARE_ACCESS_BOTH, stp) || |
3283 | test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); | 3248 | test_access(NFS4_SHARE_ACCESS_WRITE, stp); |
3284 | } | 3249 | } |
3285 | 3250 | ||
3286 | static inline int | 3251 | static inline int |
3287 | access_permit_write(unsigned long access_bmap) | 3252 | access_permit_write(struct nfs4_ol_stateid *stp) |
3288 | { | 3253 | { |
3289 | return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || | 3254 | return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || |
3290 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); | 3255 | test_access(NFS4_SHARE_ACCESS_BOTH, stp); |
3291 | } | 3256 | } |
3292 | 3257 | ||
3293 | static | 3258 | static |
@@ -3298,9 +3263,9 @@ __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) | |||
3298 | /* For lock stateid's, we test the parent open, not the lock: */ | 3263 | /* For lock stateid's, we test the parent open, not the lock: */ |
3299 | if (stp->st_openstp) | 3264 | if (stp->st_openstp) |
3300 | stp = stp->st_openstp; | 3265 | stp = stp->st_openstp; |
3301 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 3266 | if ((flags & WR_STATE) && !access_permit_write(stp)) |
3302 | goto out; | 3267 | goto out; |
3303 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 3268 | if ((flags & RD_STATE) && !access_permit_read(stp)) |
3304 | goto out; | 3269 | goto out; |
3305 | status = nfs_ok; | 3270 | status = nfs_ok; |
3306 | out: | 3271 | out: |
@@ -3340,7 +3305,7 @@ static bool stateid_generation_after(stateid_t *a, stateid_t *b) | |||
3340 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3305 | return (s32)a->si_generation - (s32)b->si_generation > 0; |
3341 | } | 3306 | } |
3342 | 3307 | ||
3343 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3308 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
3344 | { | 3309 | { |
3345 | /* | 3310 | /* |
3346 | * When sessions are used the stateid generation number is ignored | 3311 | * When sessions are used the stateid generation number is ignored |
@@ -3649,10 +3614,10 @@ out: | |||
3649 | 3614 | ||
3650 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) | 3615 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) |
3651 | { | 3616 | { |
3652 | if (!test_bit(access, &stp->st_access_bmap)) | 3617 | if (!test_access(access, stp)) |
3653 | return; | 3618 | return; |
3654 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | 3619 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); |
3655 | __clear_bit(access, &stp->st_access_bmap); | 3620 | clear_access(access, stp); |
3656 | } | 3621 | } |
3657 | 3622 | ||
3658 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) | 3623 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) |
@@ -3674,12 +3639,12 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
3674 | } | 3639 | } |
3675 | 3640 | ||
3676 | static void | 3641 | static void |
3677 | reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) | 3642 | reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) |
3678 | { | 3643 | { |
3679 | int i; | 3644 | int i; |
3680 | for (i = 0; i < 4; i++) { | 3645 | for (i = 0; i < 4; i++) { |
3681 | if ((i & deny) != i) | 3646 | if ((i & deny) != i) |
3682 | __clear_bit(i, bmap); | 3647 | clear_deny(i, stp); |
3683 | } | 3648 | } |
3684 | } | 3649 | } |
3685 | 3650 | ||
@@ -3706,19 +3671,19 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3706 | if (status) | 3671 | if (status) |
3707 | goto out; | 3672 | goto out; |
3708 | status = nfserr_inval; | 3673 | status = nfserr_inval; |
3709 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { | 3674 | if (!test_access(od->od_share_access, stp)) { |
3710 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3675 | dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", |
3711 | stp->st_access_bmap, od->od_share_access); | 3676 | stp->st_access_bmap, od->od_share_access); |
3712 | goto out; | 3677 | goto out; |
3713 | } | 3678 | } |
3714 | if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { | 3679 | if (!test_deny(od->od_share_deny, stp)) { |
3715 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", | 3680 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", |
3716 | stp->st_deny_bmap, od->od_share_deny); | 3681 | stp->st_deny_bmap, od->od_share_deny); |
3717 | goto out; | 3682 | goto out; |
3718 | } | 3683 | } |
3719 | nfs4_stateid_downgrade(stp, od->od_share_access); | 3684 | nfs4_stateid_downgrade(stp, od->od_share_access); |
3720 | 3685 | ||
3721 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3686 | reset_union_bmap_deny(od->od_share_deny, stp); |
3722 | 3687 | ||
3723 | update_stateid(&stp->st_stid.sc_stateid); | 3688 | update_stateid(&stp->st_stid.sc_stateid); |
3724 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3689 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
@@ -4008,13 +3973,13 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
4008 | struct nfs4_file *fp = lock_stp->st_file; | 3973 | struct nfs4_file *fp = lock_stp->st_file; |
4009 | int oflag = nfs4_access_to_omode(access); | 3974 | int oflag = nfs4_access_to_omode(access); |
4010 | 3975 | ||
4011 | if (test_bit(access, &lock_stp->st_access_bmap)) | 3976 | if (test_access(access, lock_stp)) |
4012 | return; | 3977 | return; |
4013 | nfs4_file_get_access(fp, oflag); | 3978 | nfs4_file_get_access(fp, oflag); |
4014 | __set_bit(access, &lock_stp->st_access_bmap); | 3979 | set_access(access, lock_stp); |
4015 | } | 3980 | } |
4016 | 3981 | ||
4017 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | 3982 | static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) |
4018 | { | 3983 | { |
4019 | struct nfs4_file *fi = ost->st_file; | 3984 | struct nfs4_file *fi = ost->st_file; |
4020 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | 3985 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); |
@@ -4055,7 +4020,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4055 | struct nfs4_openowner *open_sop = NULL; | 4020 | struct nfs4_openowner *open_sop = NULL; |
4056 | struct nfs4_lockowner *lock_sop = NULL; | 4021 | struct nfs4_lockowner *lock_sop = NULL; |
4057 | struct nfs4_ol_stateid *lock_stp; | 4022 | struct nfs4_ol_stateid *lock_stp; |
4058 | struct nfs4_file *fp; | ||
4059 | struct file *filp = NULL; | 4023 | struct file *filp = NULL; |
4060 | struct file_lock file_lock; | 4024 | struct file_lock file_lock; |
4061 | struct file_lock conflock; | 4025 | struct file_lock conflock; |
@@ -4123,7 +4087,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4123 | goto out; | 4087 | goto out; |
4124 | } | 4088 | } |
4125 | lock_sop = lockowner(lock_stp->st_stateowner); | 4089 | lock_sop = lockowner(lock_stp->st_stateowner); |
4126 | fp = lock_stp->st_file; | ||
4127 | 4090 | ||
4128 | lkflg = setlkflg(lock->lk_type); | 4091 | lkflg = setlkflg(lock->lk_type); |
4129 | status = nfs4_check_openmode(lock_stp, lkflg); | 4092 | status = nfs4_check_openmode(lock_stp, lkflg); |
@@ -4715,6 +4678,7 @@ nfs4_state_start(void) | |||
4715 | nfsd4_client_tracking_init(&init_net); | 4678 | nfsd4_client_tracking_init(&init_net); |
4716 | boot_time = get_seconds(); | 4679 | boot_time = get_seconds(); |
4717 | locks_start_grace(&nfsd4_manager); | 4680 | locks_start_grace(&nfsd4_manager); |
4681 | grace_ended = false; | ||
4718 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4682 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4719 | nfsd4_grace); | 4683 | nfsd4_grace); |
4720 | ret = set_callback_cred(); | 4684 | ret = set_callback_cred(); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 74c00bc92b9a..4949667c84ea 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1674,12 +1674,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1674 | 1674 | ||
1675 | static void write32(__be32 **p, u32 n) | 1675 | static void write32(__be32 **p, u32 n) |
1676 | { | 1676 | { |
1677 | *(*p)++ = n; | 1677 | *(*p)++ = htonl(n); |
1678 | } | 1678 | } |
1679 | 1679 | ||
1680 | static void write64(__be32 **p, u64 n) | 1680 | static void write64(__be32 **p, u64 n) |
1681 | { | 1681 | { |
1682 | write32(p, (u32)(n >> 32)); | 1682 | write32(p, (n >> 32)); |
1683 | write32(p, (u32)n); | 1683 | write32(p, (u32)n); |
1684 | } | 1684 | } |
1685 | 1685 | ||
@@ -1744,15 +1744,16 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _ | |||
1744 | } | 1744 | } |
1745 | 1745 | ||
1746 | /* Encode as an array of strings the string given with components | 1746 | /* Encode as an array of strings the string given with components |
1747 | * separated @sep. | 1747 | * separated @sep, escaped with esc_enter and esc_exit. |
1748 | */ | 1748 | */ |
1749 | static __be32 nfsd4_encode_components(char sep, char *components, | 1749 | static __be32 nfsd4_encode_components_esc(char sep, char *components, |
1750 | __be32 **pp, int *buflen) | 1750 | __be32 **pp, int *buflen, |
1751 | char esc_enter, char esc_exit) | ||
1751 | { | 1752 | { |
1752 | __be32 *p = *pp; | 1753 | __be32 *p = *pp; |
1753 | __be32 *countp = p; | 1754 | __be32 *countp = p; |
1754 | int strlen, count=0; | 1755 | int strlen, count=0; |
1755 | char *str, *end; | 1756 | char *str, *end, *next; |
1756 | 1757 | ||
1757 | dprintk("nfsd4_encode_components(%s)\n", components); | 1758 | dprintk("nfsd4_encode_components(%s)\n", components); |
1758 | if ((*buflen -= 4) < 0) | 1759 | if ((*buflen -= 4) < 0) |
@@ -1760,8 +1761,23 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1760 | WRITE32(0); /* We will fill this in with @count later */ | 1761 | WRITE32(0); /* We will fill this in with @count later */ |
1761 | end = str = components; | 1762 | end = str = components; |
1762 | while (*end) { | 1763 | while (*end) { |
1763 | for (; *end && (*end != sep); end++) | 1764 | bool found_esc = false; |
1764 | ; /* Point to end of component */ | 1765 | |
1766 | /* try to parse as esc_start, ..., esc_end, sep */ | ||
1767 | if (*str == esc_enter) { | ||
1768 | for (; *end && (*end != esc_exit); end++) | ||
1769 | /* find esc_exit or end of string */; | ||
1770 | next = end + 1; | ||
1771 | if (*end && (!*next || *next == sep)) { | ||
1772 | str++; | ||
1773 | found_esc = true; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | if (!found_esc) | ||
1778 | for (; *end && (*end != sep); end++) | ||
1779 | /* find sep or end of string */; | ||
1780 | |||
1765 | strlen = end - str; | 1781 | strlen = end - str; |
1766 | if (strlen) { | 1782 | if (strlen) { |
1767 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) | 1783 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) |
@@ -1780,6 +1796,15 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1780 | return 0; | 1796 | return 0; |
1781 | } | 1797 | } |
1782 | 1798 | ||
1799 | /* Encode as an array of strings the string given with components | ||
1800 | * separated @sep. | ||
1801 | */ | ||
1802 | static __be32 nfsd4_encode_components(char sep, char *components, | ||
1803 | __be32 **pp, int *buflen) | ||
1804 | { | ||
1805 | return nfsd4_encode_components_esc(sep, components, pp, buflen, 0, 0); | ||
1806 | } | ||
1807 | |||
1783 | /* | 1808 | /* |
1784 | * encode a location element of a fs_locations structure | 1809 | * encode a location element of a fs_locations structure |
1785 | */ | 1810 | */ |
@@ -1789,7 +1814,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | |||
1789 | __be32 status; | 1814 | __be32 status; |
1790 | __be32 *p = *pp; | 1815 | __be32 *p = *pp; |
1791 | 1816 | ||
1792 | status = nfsd4_encode_components(':', location->hosts, &p, buflen); | 1817 | status = nfsd4_encode_components_esc(':', location->hosts, &p, buflen, |
1818 | '[', ']'); | ||
1793 | if (status) | 1819 | if (status) |
1794 | return status; | 1820 | return status; |
1795 | status = nfsd4_encode_components('/', location->path, &p, buflen); | 1821 | status = nfsd4_encode_components('/', location->path, &p, buflen); |
@@ -3251,7 +3277,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3251 | } | 3277 | } |
3252 | 3278 | ||
3253 | static __be32 | 3279 | static __be32 |
3254 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 3280 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3255 | struct nfsd4_exchange_id *exid) | 3281 | struct nfsd4_exchange_id *exid) |
3256 | { | 3282 | { |
3257 | __be32 *p; | 3283 | __be32 *p; |
@@ -3306,7 +3332,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | |||
3306 | } | 3332 | } |
3307 | 3333 | ||
3308 | static __be32 | 3334 | static __be32 |
3309 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 3335 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3310 | struct nfsd4_create_session *sess) | 3336 | struct nfsd4_create_session *sess) |
3311 | { | 3337 | { |
3312 | __be32 *p; | 3338 | __be32 *p; |
@@ -3355,14 +3381,14 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | |||
3355 | } | 3381 | } |
3356 | 3382 | ||
3357 | static __be32 | 3383 | static __be32 |
3358 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, | 3384 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3359 | struct nfsd4_destroy_session *destroy_session) | 3385 | struct nfsd4_destroy_session *destroy_session) |
3360 | { | 3386 | { |
3361 | return nfserr; | 3387 | return nfserr; |
3362 | } | 3388 | } |
3363 | 3389 | ||
3364 | static __be32 | 3390 | static __be32 |
3365 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3391 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3366 | struct nfsd4_free_stateid *free_stateid) | 3392 | struct nfsd4_free_stateid *free_stateid) |
3367 | { | 3393 | { |
3368 | __be32 *p; | 3394 | __be32 *p; |
@@ -3371,13 +3397,13 @@ nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | |||
3371 | return nfserr; | 3397 | return nfserr; |
3372 | 3398 | ||
3373 | RESERVE_SPACE(4); | 3399 | RESERVE_SPACE(4); |
3374 | WRITE32(nfserr); | 3400 | *p++ = nfserr; |
3375 | ADJUST_ARGS(); | 3401 | ADJUST_ARGS(); |
3376 | return nfserr; | 3402 | return nfserr; |
3377 | } | 3403 | } |
3378 | 3404 | ||
3379 | static __be32 | 3405 | static __be32 |
3380 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3406 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, |
3381 | struct nfsd4_sequence *seq) | 3407 | struct nfsd4_sequence *seq) |
3382 | { | 3408 | { |
3383 | __be32 *p; | 3409 | __be32 *p; |
@@ -3399,8 +3425,8 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3399 | return 0; | 3425 | return 0; |
3400 | } | 3426 | } |
3401 | 3427 | ||
3402 | __be32 | 3428 | static __be32 |
3403 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3429 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3404 | struct nfsd4_test_stateid *test_stateid) | 3430 | struct nfsd4_test_stateid *test_stateid) |
3405 | { | 3431 | { |
3406 | struct nfsd4_test_stateid_id *stateid, *next; | 3432 | struct nfsd4_test_stateid_id *stateid, *next; |
@@ -3503,7 +3529,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3503 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3529 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3504 | * will be at least a page and will therefore hold the xdr_buf head. | 3530 | * will be at least a page and will therefore hold the xdr_buf head. |
3505 | */ | 3531 | */ |
3506 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) | 3532 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3507 | { | 3533 | { |
3508 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3534 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3509 | struct nfsd4_session *session = NULL; | 3535 | struct nfsd4_session *session = NULL; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2c53be6d3579..c55298ed5772 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; |
@@ -651,6 +661,7 @@ static ssize_t __write_ports_addfd(char *buf) | |||
651 | { | 661 | { |
652 | char *mesg = buf; | 662 | char *mesg = buf; |
653 | int fd, err; | 663 | int fd, err; |
664 | struct net *net = &init_net; | ||
654 | 665 | ||
655 | err = get_int(&mesg, &fd); | 666 | err = get_int(&mesg, &fd); |
656 | if (err != 0 || fd < 0) | 667 | if (err != 0 || fd < 0) |
@@ -662,6 +673,8 @@ static ssize_t __write_ports_addfd(char *buf) | |||
662 | 673 | ||
663 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 674 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
664 | if (err < 0) { | 675 | if (err < 0) { |
676 | if (nfsd_serv->sv_nrthreads == 1) | ||
677 | svc_shutdown_net(nfsd_serv, net); | ||
665 | svc_destroy(nfsd_serv); | 678 | svc_destroy(nfsd_serv); |
666 | return err; | 679 | return err; |
667 | } | 680 | } |
@@ -699,6 +712,7 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
699 | char transport[16]; | 712 | char transport[16]; |
700 | struct svc_xprt *xprt; | 713 | struct svc_xprt *xprt; |
701 | int port, err; | 714 | int port, err; |
715 | struct net *net = &init_net; | ||
702 | 716 | ||
703 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) | 717 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
704 | return -EINVAL; | 718 | return -EINVAL; |
@@ -710,12 +724,12 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
710 | if (err != 0) | 724 | if (err != 0) |
711 | return err; | 725 | return err; |
712 | 726 | ||
713 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 727 | err = svc_create_xprt(nfsd_serv, transport, net, |
714 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 728 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
715 | if (err < 0) | 729 | if (err < 0) |
716 | goto out_err; | 730 | goto out_err; |
717 | 731 | ||
718 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 732 | err = svc_create_xprt(nfsd_serv, transport, net, |
719 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 733 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
720 | if (err < 0 && err != -EAFNOSUPPORT) | 734 | if (err < 0 && err != -EAFNOSUPPORT) |
721 | goto out_close; | 735 | goto out_close; |
@@ -724,12 +738,14 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
724 | nfsd_serv->sv_nrthreads--; | 738 | nfsd_serv->sv_nrthreads--; |
725 | return 0; | 739 | return 0; |
726 | out_close: | 740 | out_close: |
727 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); | 741 | xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); |
728 | if (xprt != NULL) { | 742 | if (xprt != NULL) { |
729 | svc_close_xprt(xprt); | 743 | svc_close_xprt(xprt); |
730 | svc_xprt_put(xprt); | 744 | svc_xprt_put(xprt); |
731 | } | 745 | } |
732 | out_err: | 746 | out_err: |
747 | if (nfsd_serv->sv_nrthreads == 1) | ||
748 | svc_shutdown_net(nfsd_serv, net); | ||
733 | svc_destroy(nfsd_serv); | 749 | svc_destroy(nfsd_serv); |
734 | return err; | 750 | return err; |
735 | } | 751 | } |
@@ -1127,7 +1143,34 @@ static int create_proc_exports_entry(void) | |||
1127 | #endif | 1143 | #endif |
1128 | 1144 | ||
1129 | int nfsd_net_id; | 1145 | int nfsd_net_id; |
1146 | |||
1147 | static __net_init int nfsd_init_net(struct net *net) | ||
1148 | { | ||
1149 | int retval; | ||
1150 | |||
1151 | retval = nfsd_export_init(net); | ||
1152 | if (retval) | ||
1153 | goto out_export_error; | ||
1154 | retval = nfsd_idmap_init(net); | ||
1155 | if (retval) | ||
1156 | goto out_idmap_error; | ||
1157 | return 0; | ||
1158 | |||
1159 | out_idmap_error: | ||
1160 | nfsd_export_shutdown(net); | ||
1161 | out_export_error: | ||
1162 | return retval; | ||
1163 | } | ||
1164 | |||
1165 | static __net_exit void nfsd_exit_net(struct net *net) | ||
1166 | { | ||
1167 | nfsd_idmap_shutdown(net); | ||
1168 | nfsd_export_shutdown(net); | ||
1169 | } | ||
1170 | |||
1130 | static struct pernet_operations nfsd_net_ops = { | 1171 | static struct pernet_operations nfsd_net_ops = { |
1172 | .init = nfsd_init_net, | ||
1173 | .exit = nfsd_exit_net, | ||
1131 | .id = &nfsd_net_id, | 1174 | .id = &nfsd_net_id, |
1132 | .size = sizeof(struct nfsd_net), | 1175 | .size = sizeof(struct nfsd_net), |
1133 | }; | 1176 | }; |
@@ -1154,16 +1197,10 @@ static int __init init_nfsd(void) | |||
1154 | retval = nfsd_reply_cache_init(); | 1197 | retval = nfsd_reply_cache_init(); |
1155 | if (retval) | 1198 | if (retval) |
1156 | goto out_free_stat; | 1199 | goto out_free_stat; |
1157 | retval = nfsd_export_init(); | ||
1158 | if (retval) | ||
1159 | goto out_free_cache; | ||
1160 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 1200 | 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(); | 1201 | retval = create_proc_exports_entry(); |
1165 | if (retval) | 1202 | if (retval) |
1166 | goto out_free_idmap; | 1203 | goto out_free_lockd; |
1167 | retval = register_filesystem(&nfsd_fs_type); | 1204 | retval = register_filesystem(&nfsd_fs_type); |
1168 | if (retval) | 1205 | if (retval) |
1169 | goto out_free_all; | 1206 | goto out_free_all; |
@@ -1171,12 +1208,8 @@ static int __init init_nfsd(void) | |||
1171 | out_free_all: | 1208 | out_free_all: |
1172 | remove_proc_entry("fs/nfs/exports", NULL); | 1209 | remove_proc_entry("fs/nfs/exports", NULL); |
1173 | remove_proc_entry("fs/nfs", NULL); | 1210 | remove_proc_entry("fs/nfs", NULL); |
1174 | out_free_idmap: | ||
1175 | nfsd_idmap_shutdown(); | ||
1176 | out_free_lockd: | 1211 | out_free_lockd: |
1177 | nfsd_lockd_shutdown(); | 1212 | nfsd_lockd_shutdown(); |
1178 | nfsd_export_shutdown(); | ||
1179 | out_free_cache: | ||
1180 | nfsd_reply_cache_shutdown(); | 1213 | nfsd_reply_cache_shutdown(); |
1181 | out_free_stat: | 1214 | out_free_stat: |
1182 | nfsd_stat_shutdown(); | 1215 | nfsd_stat_shutdown(); |
@@ -1192,13 +1225,11 @@ out_unregister_notifier: | |||
1192 | 1225 | ||
1193 | static void __exit exit_nfsd(void) | 1226 | static void __exit exit_nfsd(void) |
1194 | { | 1227 | { |
1195 | nfsd_export_shutdown(); | ||
1196 | nfsd_reply_cache_shutdown(); | 1228 | nfsd_reply_cache_shutdown(); |
1197 | remove_proc_entry("fs/nfs/exports", NULL); | 1229 | remove_proc_entry("fs/nfs/exports", NULL); |
1198 | remove_proc_entry("fs/nfs", NULL); | 1230 | remove_proc_entry("fs/nfs", NULL); |
1199 | nfsd_stat_shutdown(); | 1231 | nfsd_stat_shutdown(); |
1200 | nfsd_lockd_shutdown(); | 1232 | nfsd_lockd_shutdown(); |
1201 | nfsd_idmap_shutdown(); | ||
1202 | nfsd4_free_slabs(); | 1233 | nfsd4_free_slabs(); |
1203 | nfsd_fault_inject_cleanup(); | 1234 | nfsd_fault_inject_cleanup(); |
1204 | unregister_filesystem(&nfsd_fs_type); | 1235 | 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..ee709fc8f58b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
13 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
14 | #include <linux/nsproxy.h> | ||
14 | 15 | ||
15 | #include <linux/sunrpc/stats.h> | 16 | #include <linux/sunrpc/stats.h> |
16 | #include <linux/sunrpc/svcsock.h> | 17 | #include <linux/sunrpc/svcsock.h> |
@@ -220,7 +221,7 @@ static int nfsd_startup(unsigned short port, int nrservs) | |||
220 | ret = nfsd_init_socks(port); | 221 | ret = nfsd_init_socks(port); |
221 | if (ret) | 222 | if (ret) |
222 | goto out_racache; | 223 | goto out_racache; |
223 | ret = lockd_up(); | 224 | ret = lockd_up(&init_net); |
224 | if (ret) | 225 | if (ret) |
225 | goto out_racache; | 226 | goto out_racache; |
226 | ret = nfs4_state_start(); | 227 | ret = nfs4_state_start(); |
@@ -229,7 +230,7 @@ static int nfsd_startup(unsigned short port, int nrservs) | |||
229 | nfsd_up = true; | 230 | nfsd_up = true; |
230 | return 0; | 231 | return 0; |
231 | out_lockd: | 232 | out_lockd: |
232 | lockd_down(); | 233 | lockd_down(&init_net); |
233 | out_racache: | 234 | out_racache: |
234 | nfsd_racache_shutdown(); | 235 | nfsd_racache_shutdown(); |
235 | return ret; | 236 | return ret; |
@@ -246,7 +247,7 @@ static void nfsd_shutdown(void) | |||
246 | if (!nfsd_up) | 247 | if (!nfsd_up) |
247 | return; | 248 | return; |
248 | nfs4_state_shutdown(); | 249 | nfs4_state_shutdown(); |
249 | lockd_down(); | 250 | lockd_down(&init_net); |
250 | nfsd_racache_shutdown(); | 251 | nfsd_racache_shutdown(); |
251 | nfsd_up = false; | 252 | nfsd_up = false; |
252 | } | 253 | } |
@@ -261,7 +262,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | |||
261 | 262 | ||
262 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 263 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
263 | "cache\n"); | 264 | "cache\n"); |
264 | nfsd_export_flush(); | 265 | nfsd_export_flush(net); |
265 | } | 266 | } |
266 | 267 | ||
267 | void nfsd_reset_versions(void) | 268 | void nfsd_reset_versions(void) |
@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void) | |||
330 | 331 | ||
331 | int nfsd_create_serv(void) | 332 | int nfsd_create_serv(void) |
332 | { | 333 | { |
334 | int error; | ||
335 | |||
333 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 336 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
334 | if (nfsd_serv) { | 337 | if (nfsd_serv) { |
335 | svc_get(nfsd_serv); | 338 | svc_get(nfsd_serv); |
@@ -343,6 +346,12 @@ int nfsd_create_serv(void) | |||
343 | if (nfsd_serv == NULL) | 346 | if (nfsd_serv == NULL) |
344 | return -ENOMEM; | 347 | return -ENOMEM; |
345 | 348 | ||
349 | error = svc_bind(nfsd_serv, current->nsproxy->net_ns); | ||
350 | if (error < 0) { | ||
351 | svc_destroy(nfsd_serv); | ||
352 | return error; | ||
353 | } | ||
354 | |||
346 | set_max_drc(); | 355 | set_max_drc(); |
347 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 356 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
348 | return 0; | 357 | return 0; |
@@ -373,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
373 | int i = 0; | 382 | int i = 0; |
374 | int tot = 0; | 383 | int tot = 0; |
375 | int err = 0; | 384 | int err = 0; |
385 | struct net *net = &init_net; | ||
376 | 386 | ||
377 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 387 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
378 | 388 | ||
@@ -417,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
417 | if (err) | 427 | if (err) |
418 | break; | 428 | break; |
419 | } | 429 | } |
430 | |||
431 | if (nfsd_serv->sv_nrthreads == 1) | ||
432 | svc_shutdown_net(nfsd_serv, net); | ||
420 | svc_destroy(nfsd_serv); | 433 | svc_destroy(nfsd_serv); |
421 | 434 | ||
422 | return err; | 435 | return err; |
@@ -432,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
432 | { | 445 | { |
433 | int error; | 446 | int error; |
434 | bool nfsd_up_before; | 447 | bool nfsd_up_before; |
448 | struct net *net = &init_net; | ||
435 | 449 | ||
436 | mutex_lock(&nfsd_mutex); | 450 | mutex_lock(&nfsd_mutex); |
437 | dprintk("nfsd: creating service\n"); | 451 | dprintk("nfsd: creating service\n"); |
@@ -464,6 +478,8 @@ out_shutdown: | |||
464 | if (error < 0 && !nfsd_up_before) | 478 | if (error < 0 && !nfsd_up_before) |
465 | nfsd_shutdown(); | 479 | nfsd_shutdown(); |
466 | out_destroy: | 480 | out_destroy: |
481 | if (nfsd_serv->sv_nrthreads == 1) | ||
482 | svc_shutdown_net(nfsd_serv, net); | ||
467 | svc_destroy(nfsd_serv); /* Release server */ | 483 | svc_destroy(nfsd_serv); /* Release server */ |
468 | out: | 484 | out: |
469 | mutex_unlock(&nfsd_mutex); | 485 | mutex_unlock(&nfsd_mutex); |
@@ -547,6 +563,9 @@ nfsd(void *vrqstp) | |||
547 | nfsdstats.th_cnt --; | 563 | nfsdstats.th_cnt --; |
548 | 564 | ||
549 | out: | 565 | out: |
566 | if (rqstp->rq_server->sv_nrthreads == 1) | ||
567 | svc_shutdown_net(rqstp->rq_server, &init_net); | ||
568 | |||
550 | /* Release the thread */ | 569 | /* Release the thread */ |
551 | svc_exit_thread(rqstp); | 570 | svc_exit_thread(rqstp); |
552 | 571 | ||
@@ -659,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) | |||
659 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) | 678 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) |
660 | { | 679 | { |
661 | int ret = seq_release(inode, file); | 680 | int ret = seq_release(inode, file); |
681 | struct net *net = &init_net; | ||
682 | |||
662 | mutex_lock(&nfsd_mutex); | 683 | mutex_lock(&nfsd_mutex); |
663 | /* this function really, really should have been called svc_put() */ | 684 | /* this function really, really should have been called svc_put() */ |
685 | if (nfsd_serv->sv_nrthreads == 1) | ||
686 | svc_shutdown_net(nfsd_serv, net); | ||
664 | svc_destroy(nfsd_serv); | 687 | svc_destroy(nfsd_serv); |
665 | mutex_unlock(&nfsd_mutex); | 688 | mutex_unlock(&nfsd_mutex); |
666 | return ret; | 689 | return ret; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 89ab137d379a..849091e16ea6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -232,7 +232,6 @@ struct nfs4_client { | |||
232 | time_t cl_time; /* time of last lease renewal */ | 232 | time_t cl_time; /* time of last lease renewal */ |
233 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 233 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
234 | u32 cl_flavor; /* setclientid pseudoflavor */ | 234 | u32 cl_flavor; /* setclientid pseudoflavor */ |
235 | char *cl_principal; /* setclientid principal name */ | ||
236 | struct svc_cred cl_cred; /* setclientid principal */ | 235 | struct svc_cred cl_cred; /* setclientid principal */ |
237 | clientid_t cl_clientid; /* generated by server */ | 236 | clientid_t cl_clientid; /* generated by server */ |
238 | nfs4_verifier cl_confirm; /* generated by server */ | 237 | nfs4_verifier cl_confirm; /* generated by server */ |
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/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1b3501598ab5..acd127d4ee82 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -60,7 +60,7 @@ struct nfsd4_compound_state { | |||
60 | __be32 *datap; | 60 | __be32 *datap; |
61 | size_t iovlen; | 61 | size_t iovlen; |
62 | u32 minorversion; | 62 | u32 minorversion; |
63 | u32 status; | 63 | __be32 status; |
64 | stateid_t current_stateid; | 64 | stateid_t current_stateid; |
65 | stateid_t save_stateid; | 65 | stateid_t save_stateid; |
66 | /* to indicate current and saved state id presents */ | 66 | /* to indicate current and saved state id presents */ |
@@ -364,7 +364,7 @@ struct nfsd4_test_stateid_id { | |||
364 | }; | 364 | }; |
365 | 365 | ||
366 | struct nfsd4_test_stateid { | 366 | struct nfsd4_test_stateid { |
367 | __be32 ts_num_ids; | 367 | u32 ts_num_ids; |
368 | struct list_head ts_stateid_list; | 368 | struct list_head ts_stateid_list; |
369 | }; | 369 | }; |
370 | 370 | ||
@@ -549,7 +549,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, | |||
549 | struct nfsd4_compoundargs *); | 549 | struct nfsd4_compoundargs *); |
550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, | 550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, |
551 | struct nfsd4_compoundres *); | 551 | struct nfsd4_compoundres *); |
552 | int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); | 552 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); |
553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); | 553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); |
554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); | 554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); |
555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |