diff options
| -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 | */ |
