diff options
author | Trond Myklebust <trondmy@gmail.com> | 2019-04-09 11:46:19 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-04-24 09:46:35 -0400 |
commit | e333f3bbefe3e25e2bcff58063f920a2eaba224b (patch) | |
tree | dcc70057be9950c50a87f76c8b31468b4fa1be6f /fs/nfsd | |
parent | 029be5d03357f0797d1b9a6b5aab5e7e311fd76a (diff) |
nfsd: Allow containers to set supported nfs versions
Support use of the --nfs-version/--no-nfs-version arguments to rpc.nfsd
in containers.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/netns.h | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 25 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 8 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 214 |
5 files changed, 197 insertions, 61 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index b42aaa22fba2..789abc4dd1d2 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
@@ -134,10 +134,18 @@ struct nfsd_net { | |||
134 | u32 s2s_cp_cl_id; | 134 | u32 s2s_cp_cl_id; |
135 | struct idr s2s_cp_stateids; | 135 | struct idr s2s_cp_stateids; |
136 | spinlock_t s2s_cp_lock; | 136 | spinlock_t s2s_cp_lock; |
137 | |||
138 | /* | ||
139 | * Version information | ||
140 | */ | ||
141 | bool *nfsd_versions; | ||
142 | bool *nfsd4_minorversions; | ||
137 | }; | 143 | }; |
138 | 144 | ||
139 | /* Simple check to find out if a given net was properly initialized */ | 145 | /* Simple check to find out if a given net was properly initialized */ |
140 | #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) | 146 | #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) |
141 | 147 | ||
148 | extern void nfsd_netns_free_versions(struct nfsd_net *nn); | ||
149 | |||
142 | extern unsigned int nfsd_net_id; | 150 | extern unsigned int nfsd_net_id; |
143 | #endif /* __NFSD_NETNS_H__ */ | 151 | #endif /* __NFSD_NETNS_H__ */ |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0cfd257ffdaf..b0ad72d701b1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -1926,6 +1926,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) | |||
1926 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1926 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1927 | struct svc_fh *current_fh = &cstate->current_fh; | 1927 | struct svc_fh *current_fh = &cstate->current_fh; |
1928 | struct svc_fh *save_fh = &cstate->save_fh; | 1928 | struct svc_fh *save_fh = &cstate->save_fh; |
1929 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1929 | __be32 status; | 1930 | __be32 status; |
1930 | 1931 | ||
1931 | svcxdr_init_encode(rqstp, resp); | 1932 | svcxdr_init_encode(rqstp, resp); |
@@ -1948,7 +1949,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) | |||
1948 | * According to RFC3010, this takes precedence over all other errors. | 1949 | * According to RFC3010, this takes precedence over all other errors. |
1949 | */ | 1950 | */ |
1950 | status = nfserr_minor_vers_mismatch; | 1951 | status = nfserr_minor_vers_mismatch; |
1951 | if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0) | 1952 | if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0) |
1952 | goto out; | 1953 | goto out; |
1953 | status = nfserr_resource; | 1954 | status = nfserr_resource; |
1954 | if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND) | 1955 | if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND) |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6667d3a4f839..630d629090be 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -537,14 +537,14 @@ out_free: | |||
537 | } | 537 | } |
538 | 538 | ||
539 | static ssize_t | 539 | static ssize_t |
540 | nfsd_print_version_support(char *buf, int remaining, const char *sep, | 540 | nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining, |
541 | unsigned vers, int minor) | 541 | const char *sep, unsigned vers, int minor) |
542 | { | 542 | { |
543 | const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u"; | 543 | const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u"; |
544 | bool supported = !!nfsd_vers(vers, NFSD_TEST); | 544 | bool supported = !!nfsd_vers(nn, vers, NFSD_TEST); |
545 | 545 | ||
546 | if (vers == 4 && minor >= 0 && | 546 | if (vers == 4 && minor >= 0 && |
547 | !nfsd_minorversion(minor, NFSD_TEST)) | 547 | !nfsd_minorversion(nn, minor, NFSD_TEST)) |
548 | supported = false; | 548 | supported = false; |
549 | if (minor == 0 && supported) | 549 | if (minor == 0 && supported) |
550 | /* | 550 | /* |
@@ -599,20 +599,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
599 | switch(num) { | 599 | switch(num) { |
600 | case 2: | 600 | case 2: |
601 | case 3: | 601 | case 3: |
602 | nfsd_vers(num, cmd); | 602 | nfsd_vers(nn, num, cmd); |
603 | break; | 603 | break; |
604 | case 4: | 604 | case 4: |
605 | if (*minorp == '.') { | 605 | if (*minorp == '.') { |
606 | if (nfsd_minorversion(minor, cmd) < 0) | 606 | if (nfsd_minorversion(nn, minor, cmd) < 0) |
607 | return -EINVAL; | 607 | return -EINVAL; |
608 | } else if ((cmd == NFSD_SET) != nfsd_vers(num, NFSD_TEST)) { | 608 | } else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) { |
609 | /* | 609 | /* |
610 | * Either we have +4 and no minors are enabled, | 610 | * Either we have +4 and no minors are enabled, |
611 | * or we have -4 and at least one minor is enabled. | 611 | * or we have -4 and at least one minor is enabled. |
612 | * In either case, propagate 'cmd' to all minors. | 612 | * In either case, propagate 'cmd' to all minors. |
613 | */ | 613 | */ |
614 | minor = 0; | 614 | minor = 0; |
615 | while (nfsd_minorversion(minor, cmd) >= 0) | 615 | while (nfsd_minorversion(nn, minor, cmd) >= 0) |
616 | minor++; | 616 | minor++; |
617 | } | 617 | } |
618 | break; | 618 | break; |
@@ -624,7 +624,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
624 | /* If all get turned off, turn them back on, as | 624 | /* If all get turned off, turn them back on, as |
625 | * having no versions is BAD | 625 | * having no versions is BAD |
626 | */ | 626 | */ |
627 | nfsd_reset_versions(); | 627 | nfsd_reset_versions(nn); |
628 | } | 628 | } |
629 | 629 | ||
630 | /* Now write current state into reply buffer */ | 630 | /* Now write current state into reply buffer */ |
@@ -633,12 +633,12 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
633 | remaining = SIMPLE_TRANSACTION_LIMIT; | 633 | remaining = SIMPLE_TRANSACTION_LIMIT; |
634 | for (num=2 ; num <= 4 ; num++) { | 634 | for (num=2 ; num <= 4 ; num++) { |
635 | int minor; | 635 | int minor; |
636 | if (!nfsd_vers(num, NFSD_AVAIL)) | 636 | if (!nfsd_vers(nn, num, NFSD_AVAIL)) |
637 | continue; | 637 | continue; |
638 | 638 | ||
639 | minor = -1; | 639 | minor = -1; |
640 | do { | 640 | do { |
641 | len = nfsd_print_version_support(buf, remaining, | 641 | len = nfsd_print_version_support(nn, buf, remaining, |
642 | sep, num, minor); | 642 | sep, num, minor); |
643 | if (len >= remaining) | 643 | if (len >= remaining) |
644 | goto out; | 644 | goto out; |
@@ -1239,6 +1239,8 @@ static __net_init int nfsd_init_net(struct net *net) | |||
1239 | retval = nfsd_idmap_init(net); | 1239 | retval = nfsd_idmap_init(net); |
1240 | if (retval) | 1240 | if (retval) |
1241 | goto out_idmap_error; | 1241 | goto out_idmap_error; |
1242 | nn->nfsd_versions = NULL; | ||
1243 | nn->nfsd4_minorversions = NULL; | ||
1242 | nn->nfsd4_lease = 90; /* default lease time */ | 1244 | nn->nfsd4_lease = 90; /* default lease time */ |
1243 | nn->nfsd4_grace = 90; | 1245 | nn->nfsd4_grace = 90; |
1244 | nn->somebody_reclaimed = false; | 1246 | nn->somebody_reclaimed = false; |
@@ -1261,6 +1263,7 @@ static __net_exit void nfsd_exit_net(struct net *net) | |||
1261 | { | 1263 | { |
1262 | nfsd_idmap_shutdown(net); | 1264 | nfsd_idmap_shutdown(net); |
1263 | nfsd_export_shutdown(net); | 1265 | nfsd_export_shutdown(net); |
1266 | nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); | ||
1264 | } | 1267 | } |
1265 | 1268 | ||
1266 | static struct pernet_operations nfsd_net_ops = { | 1269 | static struct pernet_operations nfsd_net_ops = { |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 066899929863..6bae2554b2b2 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -98,10 +98,12 @@ extern const struct svc_version nfsd_acl_version3; | |||
98 | #endif | 98 | #endif |
99 | #endif | 99 | #endif |
100 | 100 | ||
101 | struct nfsd_net; | ||
102 | |||
101 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | 103 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; |
102 | int nfsd_vers(int vers, enum vers_op change); | 104 | int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change); |
103 | int nfsd_minorversion(u32 minorversion, enum vers_op change); | 105 | int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change); |
104 | void nfsd_reset_versions(void); | 106 | void nfsd_reset_versions(struct nfsd_net *nn); |
105 | int nfsd_create_serv(struct net *net); | 107 | int nfsd_create_serv(struct net *net); |
106 | 108 | ||
107 | extern int nfsd_max_blksize; | 109 | extern int nfsd_max_blksize; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 378edcfe9701..520757774614 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -38,12 +38,18 @@ static int nfsd_acl_rpcbind_set(struct net *, | |||
38 | u32, int, | 38 | u32, int, |
39 | unsigned short, | 39 | unsigned short, |
40 | unsigned short); | 40 | unsigned short); |
41 | static __be32 nfsd_acl_init_request(struct svc_rqst *, | ||
42 | const struct svc_program *, | ||
43 | struct svc_process_info *); | ||
41 | #endif | 44 | #endif |
42 | static int nfsd_rpcbind_set(struct net *, | 45 | static int nfsd_rpcbind_set(struct net *, |
43 | const struct svc_program *, | 46 | const struct svc_program *, |
44 | u32, int, | 47 | u32, int, |
45 | unsigned short, | 48 | unsigned short, |
46 | unsigned short); | 49 | unsigned short); |
50 | static __be32 nfsd_init_request(struct svc_rqst *, | ||
51 | const struct svc_program *, | ||
52 | struct svc_process_info *); | ||
47 | 53 | ||
48 | /* | 54 | /* |
49 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members | 55 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members |
@@ -98,7 +104,7 @@ static struct svc_program nfsd_acl_program = { | |||
98 | .pg_class = "nfsd", | 104 | .pg_class = "nfsd", |
99 | .pg_stats = &nfsd_acl_svcstats, | 105 | .pg_stats = &nfsd_acl_svcstats, |
100 | .pg_authenticate = &svc_set_client, | 106 | .pg_authenticate = &svc_set_client, |
101 | .pg_init_request = svc_generic_init_request, | 107 | .pg_init_request = nfsd_acl_init_request, |
102 | .pg_rpcbind_set = nfsd_acl_rpcbind_set, | 108 | .pg_rpcbind_set = nfsd_acl_rpcbind_set, |
103 | }; | 109 | }; |
104 | 110 | ||
@@ -119,7 +125,6 @@ static const struct svc_version *nfsd_version[] = { | |||
119 | 125 | ||
120 | #define NFSD_MINVERS 2 | 126 | #define NFSD_MINVERS 2 |
121 | #define NFSD_NRVERS ARRAY_SIZE(nfsd_version) | 127 | #define NFSD_NRVERS ARRAY_SIZE(nfsd_version) |
122 | static const struct svc_version *nfsd_versions[NFSD_NRVERS]; | ||
123 | 128 | ||
124 | struct svc_program nfsd_program = { | 129 | struct svc_program nfsd_program = { |
125 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 130 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
@@ -127,78 +132,136 @@ struct svc_program nfsd_program = { | |||
127 | #endif | 132 | #endif |
128 | .pg_prog = NFS_PROGRAM, /* program number */ | 133 | .pg_prog = NFS_PROGRAM, /* program number */ |
129 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | 134 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ |
130 | .pg_vers = nfsd_versions, /* version table */ | 135 | .pg_vers = nfsd_version, /* version table */ |
131 | .pg_name = "nfsd", /* program name */ | 136 | .pg_name = "nfsd", /* program name */ |
132 | .pg_class = "nfsd", /* authentication class */ | 137 | .pg_class = "nfsd", /* authentication class */ |
133 | .pg_stats = &nfsd_svcstats, /* version table */ | 138 | .pg_stats = &nfsd_svcstats, /* version table */ |
134 | .pg_authenticate = &svc_set_client, /* export authentication */ | 139 | .pg_authenticate = &svc_set_client, /* export authentication */ |
135 | .pg_init_request = svc_generic_init_request, | 140 | .pg_init_request = nfsd_init_request, |
136 | .pg_rpcbind_set = nfsd_rpcbind_set, | 141 | .pg_rpcbind_set = nfsd_rpcbind_set, |
137 | }; | 142 | }; |
138 | 143 | ||
139 | static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { | 144 | static bool |
140 | [0] = 1, | 145 | nfsd_support_version(int vers) |
141 | [1] = 1, | 146 | { |
142 | [2] = 1, | 147 | if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS) |
143 | }; | 148 | return nfsd_version[vers] != NULL; |
149 | return false; | ||
150 | } | ||
151 | |||
152 | static bool * | ||
153 | nfsd_alloc_versions(void) | ||
154 | { | ||
155 | bool *vers = kmalloc_array(NFSD_NRVERS, sizeof(bool), GFP_KERNEL); | ||
156 | unsigned i; | ||
157 | |||
158 | if (vers) { | ||
159 | /* All compiled versions are enabled by default */ | ||
160 | for (i = 0; i < NFSD_NRVERS; i++) | ||
161 | vers[i] = nfsd_support_version(i); | ||
162 | } | ||
163 | return vers; | ||
164 | } | ||
165 | |||
166 | static bool * | ||
167 | nfsd_alloc_minorversions(void) | ||
168 | { | ||
169 | bool *vers = kmalloc_array(NFSD_SUPPORTED_MINOR_VERSION + 1, | ||
170 | sizeof(bool), GFP_KERNEL); | ||
171 | unsigned i; | ||
144 | 172 | ||
145 | int nfsd_vers(int vers, enum vers_op change) | 173 | if (vers) { |
174 | /* All minor versions are enabled by default */ | ||
175 | for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) | ||
176 | vers[i] = nfsd_support_version(4); | ||
177 | } | ||
178 | return vers; | ||
179 | } | ||
180 | |||
181 | void | ||
182 | nfsd_netns_free_versions(struct nfsd_net *nn) | ||
183 | { | ||
184 | kfree(nn->nfsd_versions); | ||
185 | kfree(nn->nfsd4_minorversions); | ||
186 | nn->nfsd_versions = NULL; | ||
187 | nn->nfsd4_minorversions = NULL; | ||
188 | } | ||
189 | |||
190 | static void | ||
191 | nfsd_netns_init_versions(struct nfsd_net *nn) | ||
192 | { | ||
193 | if (!nn->nfsd_versions) { | ||
194 | nn->nfsd_versions = nfsd_alloc_versions(); | ||
195 | nn->nfsd4_minorversions = nfsd_alloc_minorversions(); | ||
196 | if (!nn->nfsd_versions || !nn->nfsd4_minorversions) | ||
197 | nfsd_netns_free_versions(nn); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change) | ||
146 | { | 202 | { |
147 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) | 203 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) |
148 | return 0; | 204 | return 0; |
149 | switch(change) { | 205 | switch(change) { |
150 | case NFSD_SET: | 206 | case NFSD_SET: |
151 | nfsd_versions[vers] = nfsd_version[vers]; | 207 | if (nn->nfsd_versions) |
152 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 208 | nn->nfsd_versions[vers] = nfsd_support_version(vers); |
153 | if (vers < NFSD_ACL_NRVERS) | ||
154 | nfsd_acl_versions[vers] = nfsd_acl_version[vers]; | ||
155 | #endif | ||
156 | break; | 209 | break; |
157 | case NFSD_CLEAR: | 210 | case NFSD_CLEAR: |
158 | nfsd_versions[vers] = NULL; | 211 | nfsd_netns_init_versions(nn); |
159 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 212 | if (nn->nfsd_versions) |
160 | if (vers < NFSD_ACL_NRVERS) | 213 | nn->nfsd_versions[vers] = false; |
161 | nfsd_acl_versions[vers] = NULL; | ||
162 | #endif | ||
163 | break; | 214 | break; |
164 | case NFSD_TEST: | 215 | case NFSD_TEST: |
165 | return nfsd_versions[vers] != NULL; | 216 | if (nn->nfsd_versions) |
217 | return nn->nfsd_versions[vers]; | ||
218 | /* Fallthrough */ | ||
166 | case NFSD_AVAIL: | 219 | case NFSD_AVAIL: |
167 | return nfsd_version[vers] != NULL; | 220 | return nfsd_support_version(vers); |
168 | } | 221 | } |
169 | return 0; | 222 | return 0; |
170 | } | 223 | } |
171 | 224 | ||
172 | static void | 225 | static void |
173 | nfsd_adjust_nfsd_versions4(void) | 226 | nfsd_adjust_nfsd_versions4(struct nfsd_net *nn) |
174 | { | 227 | { |
175 | unsigned i; | 228 | unsigned i; |
176 | 229 | ||
177 | for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) { | 230 | for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) { |
178 | if (nfsd_supported_minorversions[i]) | 231 | if (nn->nfsd4_minorversions[i]) |
179 | return; | 232 | return; |
180 | } | 233 | } |
181 | nfsd_vers(4, NFSD_CLEAR); | 234 | nfsd_vers(nn, 4, NFSD_CLEAR); |
182 | } | 235 | } |
183 | 236 | ||
184 | int nfsd_minorversion(u32 minorversion, enum vers_op change) | 237 | int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change) |
185 | { | 238 | { |
186 | if (minorversion > NFSD_SUPPORTED_MINOR_VERSION && | 239 | if (minorversion > NFSD_SUPPORTED_MINOR_VERSION && |
187 | change != NFSD_AVAIL) | 240 | change != NFSD_AVAIL) |
188 | return -1; | 241 | return -1; |
242 | |||
189 | switch(change) { | 243 | switch(change) { |
190 | case NFSD_SET: | 244 | case NFSD_SET: |
191 | nfsd_supported_minorversions[minorversion] = true; | 245 | if (nn->nfsd4_minorversions) { |
192 | nfsd_vers(4, NFSD_SET); | 246 | nfsd_vers(nn, 4, NFSD_SET); |
247 | nn->nfsd4_minorversions[minorversion] = | ||
248 | nfsd_vers(nn, 4, NFSD_TEST); | ||
249 | } | ||
193 | break; | 250 | break; |
194 | case NFSD_CLEAR: | 251 | case NFSD_CLEAR: |
195 | nfsd_supported_minorversions[minorversion] = false; | 252 | nfsd_netns_init_versions(nn); |
196 | nfsd_adjust_nfsd_versions4(); | 253 | if (nn->nfsd4_minorversions) { |
254 | nn->nfsd4_minorversions[minorversion] = false; | ||
255 | nfsd_adjust_nfsd_versions4(nn); | ||
256 | } | ||
197 | break; | 257 | break; |
198 | case NFSD_TEST: | 258 | case NFSD_TEST: |
199 | return nfsd_supported_minorversions[minorversion]; | 259 | if (nn->nfsd4_minorversions) |
260 | return nn->nfsd4_minorversions[minorversion]; | ||
261 | return nfsd_vers(nn, 4, NFSD_TEST); | ||
200 | case NFSD_AVAIL: | 262 | case NFSD_AVAIL: |
201 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; | 263 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION && |
264 | nfsd_vers(nn, 4, NFSD_AVAIL); | ||
202 | } | 265 | } |
203 | return 0; | 266 | return 0; |
204 | } | 267 | } |
@@ -280,13 +343,9 @@ static void nfsd_shutdown_generic(void) | |||
280 | nfsd_racache_shutdown(); | 343 | nfsd_racache_shutdown(); |
281 | } | 344 | } |
282 | 345 | ||
283 | static bool nfsd_needs_lockd(void) | 346 | static bool nfsd_needs_lockd(struct nfsd_net *nn) |
284 | { | 347 | { |
285 | #if defined(CONFIG_NFSD_V3) | 348 | return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); |
286 | return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL); | ||
287 | #else | ||
288 | return (nfsd_versions[2] != NULL); | ||
289 | #endif | ||
290 | } | 349 | } |
291 | 350 | ||
292 | static int nfsd_startup_net(int nrservs, struct net *net) | 351 | static int nfsd_startup_net(int nrservs, struct net *net) |
@@ -304,7 +363,7 @@ static int nfsd_startup_net(int nrservs, struct net *net) | |||
304 | if (ret) | 363 | if (ret) |
305 | goto out_socks; | 364 | goto out_socks; |
306 | 365 | ||
307 | if (nfsd_needs_lockd() && !nn->lockd_up) { | 366 | if (nfsd_needs_lockd(nn) && !nn->lockd_up) { |
308 | ret = lockd_up(net); | 367 | ret = lockd_up(net); |
309 | if (ret) | 368 | if (ret) |
310 | goto out_socks; | 369 | goto out_socks; |
@@ -437,20 +496,20 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | |||
437 | nfsd_export_flush(net); | 496 | nfsd_export_flush(net); |
438 | } | 497 | } |
439 | 498 | ||
440 | void nfsd_reset_versions(void) | 499 | void nfsd_reset_versions(struct nfsd_net *nn) |
441 | { | 500 | { |
442 | int i; | 501 | int i; |
443 | 502 | ||
444 | for (i = 0; i < NFSD_NRVERS; i++) | 503 | for (i = 0; i < NFSD_NRVERS; i++) |
445 | if (nfsd_vers(i, NFSD_TEST)) | 504 | if (nfsd_vers(nn, i, NFSD_TEST)) |
446 | return; | 505 | return; |
447 | 506 | ||
448 | for (i = 0; i < NFSD_NRVERS; i++) | 507 | for (i = 0; i < NFSD_NRVERS; i++) |
449 | if (i != 4) | 508 | if (i != 4) |
450 | nfsd_vers(i, NFSD_SET); | 509 | nfsd_vers(nn, i, NFSD_SET); |
451 | else { | 510 | else { |
452 | int minor = 0; | 511 | int minor = 0; |
453 | while (nfsd_minorversion(minor, NFSD_SET) >= 0) | 512 | while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0) |
454 | minor++; | 513 | minor++; |
455 | } | 514 | } |
456 | } | 515 | } |
@@ -518,7 +577,7 @@ int nfsd_create_serv(struct net *net) | |||
518 | } | 577 | } |
519 | if (nfsd_max_blksize == 0) | 578 | if (nfsd_max_blksize == 0) |
520 | nfsd_max_blksize = nfsd_get_default_max_blksize(); | 579 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
521 | nfsd_reset_versions(); | 580 | nfsd_reset_versions(nn); |
522 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, | 581 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
523 | &nfsd_thread_sv_ops); | 582 | &nfsd_thread_sv_ops); |
524 | if (nn->nfsd_serv == NULL) | 583 | if (nn->nfsd_serv == NULL) |
@@ -697,11 +756,44 @@ nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp, | |||
697 | unsigned short port) | 756 | unsigned short port) |
698 | { | 757 | { |
699 | if (!nfsd_support_acl_version(version) || | 758 | if (!nfsd_support_acl_version(version) || |
700 | !nfsd_vers(version, NFSD_TEST)) | 759 | !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
701 | return 0; | 760 | return 0; |
702 | return svc_generic_rpcbind_set(net, progp, version, family, | 761 | return svc_generic_rpcbind_set(net, progp, version, family, |
703 | proto, port); | 762 | proto, port); |
704 | } | 763 | } |
764 | |||
765 | static __be32 | ||
766 | nfsd_acl_init_request(struct svc_rqst *rqstp, | ||
767 | const struct svc_program *progp, | ||
768 | struct svc_process_info *ret) | ||
769 | { | ||
770 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
771 | int i; | ||
772 | |||
773 | if (likely(nfsd_support_acl_version(rqstp->rq_vers) && | ||
774 | nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) | ||
775 | return svc_generic_init_request(rqstp, progp, ret); | ||
776 | |||
777 | ret->mismatch.lovers = NFSD_ACL_NRVERS; | ||
778 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { | ||
779 | if (nfsd_support_acl_version(rqstp->rq_vers) && | ||
780 | nfsd_vers(nn, i, NFSD_TEST)) { | ||
781 | ret->mismatch.lovers = i; | ||
782 | break; | ||
783 | } | ||
784 | } | ||
785 | if (ret->mismatch.lovers == NFSD_ACL_NRVERS) | ||
786 | return rpc_prog_unavail; | ||
787 | ret->mismatch.hivers = NFSD_ACL_MINVERS; | ||
788 | for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) { | ||
789 | if (nfsd_support_acl_version(rqstp->rq_vers) && | ||
790 | nfsd_vers(nn, i, NFSD_TEST)) { | ||
791 | ret->mismatch.hivers = i; | ||
792 | break; | ||
793 | } | ||
794 | } | ||
795 | return rpc_prog_mismatch; | ||
796 | } | ||
705 | #endif | 797 | #endif |
706 | 798 | ||
707 | static int | 799 | static int |
@@ -709,12 +801,42 @@ nfsd_rpcbind_set(struct net *net, const struct svc_program *progp, | |||
709 | u32 version, int family, unsigned short proto, | 801 | u32 version, int family, unsigned short proto, |
710 | unsigned short port) | 802 | unsigned short port) |
711 | { | 803 | { |
712 | if (!nfsd_vers(version, NFSD_TEST)) | 804 | if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
713 | return 0; | 805 | return 0; |
714 | return svc_generic_rpcbind_set(net, progp, version, family, | 806 | return svc_generic_rpcbind_set(net, progp, version, family, |
715 | proto, port); | 807 | proto, port); |
716 | } | 808 | } |
717 | 809 | ||
810 | static __be32 | ||
811 | nfsd_init_request(struct svc_rqst *rqstp, | ||
812 | const struct svc_program *progp, | ||
813 | struct svc_process_info *ret) | ||
814 | { | ||
815 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
816 | int i; | ||
817 | |||
818 | if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) | ||
819 | return svc_generic_init_request(rqstp, progp, ret); | ||
820 | |||
821 | ret->mismatch.lovers = NFSD_NRVERS; | ||
822 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { | ||
823 | if (nfsd_vers(nn, i, NFSD_TEST)) { | ||
824 | ret->mismatch.lovers = i; | ||
825 | break; | ||
826 | } | ||
827 | } | ||
828 | if (ret->mismatch.lovers == NFSD_NRVERS) | ||
829 | return rpc_prog_unavail; | ||
830 | ret->mismatch.hivers = NFSD_MINVERS; | ||
831 | for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) { | ||
832 | if (nfsd_vers(nn, i, NFSD_TEST)) { | ||
833 | ret->mismatch.hivers = i; | ||
834 | break; | ||
835 | } | ||
836 | } | ||
837 | return rpc_prog_mismatch; | ||
838 | } | ||
839 | |||
718 | /* | 840 | /* |
719 | * This is the NFS server kernel thread | 841 | * This is the NFS server kernel thread |
720 | */ | 842 | */ |