| .. | .. |
|---|
| 27 | 27 | #include "cache.h" |
|---|
| 28 | 28 | #include "vfs.h" |
|---|
| 29 | 29 | #include "netns.h" |
|---|
| 30 | +#include "filecache.h" |
|---|
| 30 | 31 | |
|---|
| 31 | 32 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
|---|
| 32 | 33 | |
|---|
| 34 | +bool inter_copy_offload_enable; |
|---|
| 35 | +EXPORT_SYMBOL_GPL(inter_copy_offload_enable); |
|---|
| 36 | +module_param(inter_copy_offload_enable, bool, 0644); |
|---|
| 37 | +MODULE_PARM_DESC(inter_copy_offload_enable, |
|---|
| 38 | + "Enable inter server to server copy offload. Default: false"); |
|---|
| 39 | + |
|---|
| 33 | 40 | extern struct svc_program nfsd_program; |
|---|
| 34 | 41 | static int nfsd(void *vrqstp); |
|---|
| 42 | +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
|---|
| 43 | +static int nfsd_acl_rpcbind_set(struct net *, |
|---|
| 44 | + const struct svc_program *, |
|---|
| 45 | + u32, int, |
|---|
| 46 | + unsigned short, |
|---|
| 47 | + unsigned short); |
|---|
| 48 | +static __be32 nfsd_acl_init_request(struct svc_rqst *, |
|---|
| 49 | + const struct svc_program *, |
|---|
| 50 | + struct svc_process_info *); |
|---|
| 51 | +#endif |
|---|
| 52 | +static int nfsd_rpcbind_set(struct net *, |
|---|
| 53 | + const struct svc_program *, |
|---|
| 54 | + u32, int, |
|---|
| 55 | + unsigned short, |
|---|
| 56 | + unsigned short); |
|---|
| 57 | +static __be32 nfsd_init_request(struct svc_rqst *, |
|---|
| 58 | + const struct svc_program *, |
|---|
| 59 | + struct svc_process_info *); |
|---|
| 35 | 60 | |
|---|
| 36 | 61 | /* |
|---|
| 37 | 62 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members |
|---|
| .. | .. |
|---|
| 76 | 101 | |
|---|
| 77 | 102 | #define NFSD_ACL_MINVERS 2 |
|---|
| 78 | 103 | #define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version) |
|---|
| 79 | | -static const struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS]; |
|---|
| 80 | 104 | |
|---|
| 81 | 105 | static struct svc_program nfsd_acl_program = { |
|---|
| 82 | 106 | .pg_prog = NFS_ACL_PROGRAM, |
|---|
| 83 | 107 | .pg_nvers = NFSD_ACL_NRVERS, |
|---|
| 84 | | - .pg_vers = nfsd_acl_versions, |
|---|
| 108 | + .pg_vers = nfsd_acl_version, |
|---|
| 85 | 109 | .pg_name = "nfsacl", |
|---|
| 86 | 110 | .pg_class = "nfsd", |
|---|
| 87 | 111 | .pg_stats = &nfsd_acl_svcstats, |
|---|
| 88 | 112 | .pg_authenticate = &svc_set_client, |
|---|
| 113 | + .pg_init_request = nfsd_acl_init_request, |
|---|
| 114 | + .pg_rpcbind_set = nfsd_acl_rpcbind_set, |
|---|
| 89 | 115 | }; |
|---|
| 90 | 116 | |
|---|
| 91 | 117 | static struct svc_stat nfsd_acl_svcstats = { |
|---|
| .. | .. |
|---|
| 105 | 131 | |
|---|
| 106 | 132 | #define NFSD_MINVERS 2 |
|---|
| 107 | 133 | #define NFSD_NRVERS ARRAY_SIZE(nfsd_version) |
|---|
| 108 | | -static const struct svc_version *nfsd_versions[NFSD_NRVERS]; |
|---|
| 109 | 134 | |
|---|
| 110 | 135 | struct svc_program nfsd_program = { |
|---|
| 111 | 136 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
|---|
| .. | .. |
|---|
| 113 | 138 | #endif |
|---|
| 114 | 139 | .pg_prog = NFS_PROGRAM, /* program number */ |
|---|
| 115 | 140 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ |
|---|
| 116 | | - .pg_vers = nfsd_versions, /* version table */ |
|---|
| 141 | + .pg_vers = nfsd_version, /* version table */ |
|---|
| 117 | 142 | .pg_name = "nfsd", /* program name */ |
|---|
| 118 | 143 | .pg_class = "nfsd", /* authentication class */ |
|---|
| 119 | 144 | .pg_stats = &nfsd_svcstats, /* version table */ |
|---|
| 120 | 145 | .pg_authenticate = &svc_set_client, /* export authentication */ |
|---|
| 121 | | - |
|---|
| 146 | + .pg_init_request = nfsd_init_request, |
|---|
| 147 | + .pg_rpcbind_set = nfsd_rpcbind_set, |
|---|
| 122 | 148 | }; |
|---|
| 123 | 149 | |
|---|
| 124 | | -static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { |
|---|
| 125 | | - [0] = 1, |
|---|
| 126 | | - [1] = 1, |
|---|
| 127 | | - [2] = 1, |
|---|
| 128 | | -}; |
|---|
| 150 | +static bool |
|---|
| 151 | +nfsd_support_version(int vers) |
|---|
| 152 | +{ |
|---|
| 153 | + if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS) |
|---|
| 154 | + return nfsd_version[vers] != NULL; |
|---|
| 155 | + return false; |
|---|
| 156 | +} |
|---|
| 129 | 157 | |
|---|
| 130 | | -int nfsd_vers(int vers, enum vers_op change) |
|---|
| 158 | +static bool * |
|---|
| 159 | +nfsd_alloc_versions(void) |
|---|
| 160 | +{ |
|---|
| 161 | + bool *vers = kmalloc_array(NFSD_NRVERS, sizeof(bool), GFP_KERNEL); |
|---|
| 162 | + unsigned i; |
|---|
| 163 | + |
|---|
| 164 | + if (vers) { |
|---|
| 165 | + /* All compiled versions are enabled by default */ |
|---|
| 166 | + for (i = 0; i < NFSD_NRVERS; i++) |
|---|
| 167 | + vers[i] = nfsd_support_version(i); |
|---|
| 168 | + } |
|---|
| 169 | + return vers; |
|---|
| 170 | +} |
|---|
| 171 | + |
|---|
| 172 | +static bool * |
|---|
| 173 | +nfsd_alloc_minorversions(void) |
|---|
| 174 | +{ |
|---|
| 175 | + bool *vers = kmalloc_array(NFSD_SUPPORTED_MINOR_VERSION + 1, |
|---|
| 176 | + sizeof(bool), GFP_KERNEL); |
|---|
| 177 | + unsigned i; |
|---|
| 178 | + |
|---|
| 179 | + if (vers) { |
|---|
| 180 | + /* All minor versions are enabled by default */ |
|---|
| 181 | + for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) |
|---|
| 182 | + vers[i] = nfsd_support_version(4); |
|---|
| 183 | + } |
|---|
| 184 | + return vers; |
|---|
| 185 | +} |
|---|
| 186 | + |
|---|
| 187 | +void |
|---|
| 188 | +nfsd_netns_free_versions(struct nfsd_net *nn) |
|---|
| 189 | +{ |
|---|
| 190 | + kfree(nn->nfsd_versions); |
|---|
| 191 | + kfree(nn->nfsd4_minorversions); |
|---|
| 192 | + nn->nfsd_versions = NULL; |
|---|
| 193 | + nn->nfsd4_minorversions = NULL; |
|---|
| 194 | +} |
|---|
| 195 | + |
|---|
| 196 | +static void |
|---|
| 197 | +nfsd_netns_init_versions(struct nfsd_net *nn) |
|---|
| 198 | +{ |
|---|
| 199 | + if (!nn->nfsd_versions) { |
|---|
| 200 | + nn->nfsd_versions = nfsd_alloc_versions(); |
|---|
| 201 | + nn->nfsd4_minorversions = nfsd_alloc_minorversions(); |
|---|
| 202 | + if (!nn->nfsd_versions || !nn->nfsd4_minorversions) |
|---|
| 203 | + nfsd_netns_free_versions(nn); |
|---|
| 204 | + } |
|---|
| 205 | +} |
|---|
| 206 | + |
|---|
| 207 | +int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change) |
|---|
| 131 | 208 | { |
|---|
| 132 | 209 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) |
|---|
| 133 | 210 | return 0; |
|---|
| 134 | 211 | switch(change) { |
|---|
| 135 | 212 | case NFSD_SET: |
|---|
| 136 | | - nfsd_versions[vers] = nfsd_version[vers]; |
|---|
| 137 | | -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
|---|
| 138 | | - if (vers < NFSD_ACL_NRVERS) |
|---|
| 139 | | - nfsd_acl_versions[vers] = nfsd_acl_version[vers]; |
|---|
| 140 | | -#endif |
|---|
| 213 | + if (nn->nfsd_versions) |
|---|
| 214 | + nn->nfsd_versions[vers] = nfsd_support_version(vers); |
|---|
| 141 | 215 | break; |
|---|
| 142 | 216 | case NFSD_CLEAR: |
|---|
| 143 | | - nfsd_versions[vers] = NULL; |
|---|
| 144 | | -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
|---|
| 145 | | - if (vers < NFSD_ACL_NRVERS) |
|---|
| 146 | | - nfsd_acl_versions[vers] = NULL; |
|---|
| 147 | | -#endif |
|---|
| 217 | + nfsd_netns_init_versions(nn); |
|---|
| 218 | + if (nn->nfsd_versions) |
|---|
| 219 | + nn->nfsd_versions[vers] = false; |
|---|
| 148 | 220 | break; |
|---|
| 149 | 221 | case NFSD_TEST: |
|---|
| 150 | | - return nfsd_versions[vers] != NULL; |
|---|
| 222 | + if (nn->nfsd_versions) |
|---|
| 223 | + return nn->nfsd_versions[vers]; |
|---|
| 224 | + fallthrough; |
|---|
| 151 | 225 | case NFSD_AVAIL: |
|---|
| 152 | | - return nfsd_version[vers] != NULL; |
|---|
| 226 | + return nfsd_support_version(vers); |
|---|
| 153 | 227 | } |
|---|
| 154 | 228 | return 0; |
|---|
| 155 | 229 | } |
|---|
| 156 | 230 | |
|---|
| 157 | 231 | static void |
|---|
| 158 | | -nfsd_adjust_nfsd_versions4(void) |
|---|
| 232 | +nfsd_adjust_nfsd_versions4(struct nfsd_net *nn) |
|---|
| 159 | 233 | { |
|---|
| 160 | 234 | unsigned i; |
|---|
| 161 | 235 | |
|---|
| 162 | 236 | for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) { |
|---|
| 163 | | - if (nfsd_supported_minorversions[i]) |
|---|
| 237 | + if (nn->nfsd4_minorversions[i]) |
|---|
| 164 | 238 | return; |
|---|
| 165 | 239 | } |
|---|
| 166 | | - nfsd_vers(4, NFSD_CLEAR); |
|---|
| 240 | + nfsd_vers(nn, 4, NFSD_CLEAR); |
|---|
| 167 | 241 | } |
|---|
| 168 | 242 | |
|---|
| 169 | | -int nfsd_minorversion(u32 minorversion, enum vers_op change) |
|---|
| 243 | +int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change) |
|---|
| 170 | 244 | { |
|---|
| 171 | 245 | if (minorversion > NFSD_SUPPORTED_MINOR_VERSION && |
|---|
| 172 | 246 | change != NFSD_AVAIL) |
|---|
| 173 | 247 | return -1; |
|---|
| 248 | + |
|---|
| 174 | 249 | switch(change) { |
|---|
| 175 | 250 | case NFSD_SET: |
|---|
| 176 | | - nfsd_supported_minorversions[minorversion] = true; |
|---|
| 177 | | - nfsd_vers(4, NFSD_SET); |
|---|
| 251 | + if (nn->nfsd4_minorversions) { |
|---|
| 252 | + nfsd_vers(nn, 4, NFSD_SET); |
|---|
| 253 | + nn->nfsd4_minorversions[minorversion] = |
|---|
| 254 | + nfsd_vers(nn, 4, NFSD_TEST); |
|---|
| 255 | + } |
|---|
| 178 | 256 | break; |
|---|
| 179 | 257 | case NFSD_CLEAR: |
|---|
| 180 | | - nfsd_supported_minorversions[minorversion] = false; |
|---|
| 181 | | - nfsd_adjust_nfsd_versions4(); |
|---|
| 258 | + nfsd_netns_init_versions(nn); |
|---|
| 259 | + if (nn->nfsd4_minorversions) { |
|---|
| 260 | + nn->nfsd4_minorversions[minorversion] = false; |
|---|
| 261 | + nfsd_adjust_nfsd_versions4(nn); |
|---|
| 262 | + } |
|---|
| 182 | 263 | break; |
|---|
| 183 | 264 | case NFSD_TEST: |
|---|
| 184 | | - return nfsd_supported_minorversions[minorversion]; |
|---|
| 265 | + if (nn->nfsd4_minorversions) |
|---|
| 266 | + return nn->nfsd4_minorversions[minorversion]; |
|---|
| 267 | + return nfsd_vers(nn, 4, NFSD_TEST); |
|---|
| 185 | 268 | case NFSD_AVAIL: |
|---|
| 186 | | - return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; |
|---|
| 269 | + return minorversion <= NFSD_SUPPORTED_MINOR_VERSION && |
|---|
| 270 | + nfsd_vers(nn, 4, NFSD_AVAIL); |
|---|
| 187 | 271 | } |
|---|
| 188 | 272 | return 0; |
|---|
| 189 | 273 | } |
|---|
| .. | .. |
|---|
| 205 | 289 | return rv; |
|---|
| 206 | 290 | } |
|---|
| 207 | 291 | |
|---|
| 208 | | -static int nfsd_init_socks(struct net *net) |
|---|
| 292 | +static int nfsd_init_socks(struct net *net, const struct cred *cred) |
|---|
| 209 | 293 | { |
|---|
| 210 | 294 | int error; |
|---|
| 211 | 295 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
|---|
| .. | .. |
|---|
| 214 | 298 | return 0; |
|---|
| 215 | 299 | |
|---|
| 216 | 300 | error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, |
|---|
| 217 | | - SVC_SOCK_DEFAULTS); |
|---|
| 301 | + SVC_SOCK_DEFAULTS, cred); |
|---|
| 218 | 302 | if (error < 0) |
|---|
| 219 | 303 | return error; |
|---|
| 220 | 304 | |
|---|
| 221 | 305 | error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, |
|---|
| 222 | | - SVC_SOCK_DEFAULTS); |
|---|
| 306 | + SVC_SOCK_DEFAULTS, cred); |
|---|
| 223 | 307 | if (error < 0) |
|---|
| 224 | 308 | return error; |
|---|
| 225 | 309 | |
|---|
| .. | .. |
|---|
| 235 | 319 | if (nfsd_users++) |
|---|
| 236 | 320 | return 0; |
|---|
| 237 | 321 | |
|---|
| 238 | | - /* |
|---|
| 239 | | - * Readahead param cache - will no-op if it already exists. |
|---|
| 240 | | - * (Note therefore results will be suboptimal if number of |
|---|
| 241 | | - * threads is modified after nfsd start.) |
|---|
| 242 | | - */ |
|---|
| 243 | | - ret = nfsd_racache_init(2*nrservs); |
|---|
| 322 | + ret = nfsd_file_cache_init(); |
|---|
| 244 | 323 | if (ret) |
|---|
| 245 | 324 | goto dec_users; |
|---|
| 246 | 325 | |
|---|
| 247 | 326 | ret = nfs4_state_start(); |
|---|
| 248 | 327 | if (ret) |
|---|
| 249 | | - goto out_racache; |
|---|
| 328 | + goto out_file_cache; |
|---|
| 250 | 329 | return 0; |
|---|
| 251 | 330 | |
|---|
| 252 | | -out_racache: |
|---|
| 253 | | - nfsd_racache_shutdown(); |
|---|
| 331 | +out_file_cache: |
|---|
| 332 | + nfsd_file_cache_shutdown(); |
|---|
| 254 | 333 | dec_users: |
|---|
| 255 | 334 | nfsd_users--; |
|---|
| 256 | 335 | return ret; |
|---|
| .. | .. |
|---|
| 262 | 341 | return; |
|---|
| 263 | 342 | |
|---|
| 264 | 343 | nfs4_state_shutdown(); |
|---|
| 265 | | - nfsd_racache_shutdown(); |
|---|
| 344 | + nfsd_file_cache_shutdown(); |
|---|
| 266 | 345 | } |
|---|
| 267 | 346 | |
|---|
| 268 | | -static bool nfsd_needs_lockd(void) |
|---|
| 347 | +static bool nfsd_needs_lockd(struct nfsd_net *nn) |
|---|
| 269 | 348 | { |
|---|
| 270 | | -#if defined(CONFIG_NFSD_V3) |
|---|
| 271 | | - return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL); |
|---|
| 272 | | -#else |
|---|
| 273 | | - return (nfsd_versions[2] != NULL); |
|---|
| 274 | | -#endif |
|---|
| 349 | + return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); |
|---|
| 275 | 350 | } |
|---|
| 276 | 351 | |
|---|
| 277 | | -static int nfsd_startup_net(int nrservs, struct net *net) |
|---|
| 352 | +void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) |
|---|
| 353 | +{ |
|---|
| 354 | + int seq = 0; |
|---|
| 355 | + |
|---|
| 356 | + do { |
|---|
| 357 | + read_seqbegin_or_lock(&nn->boot_lock, &seq); |
|---|
| 358 | + /* |
|---|
| 359 | + * This is opaque to client, so no need to byte-swap. Use |
|---|
| 360 | + * __force to keep sparse happy. y2038 time_t overflow is |
|---|
| 361 | + * irrelevant in this usage |
|---|
| 362 | + */ |
|---|
| 363 | + verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; |
|---|
| 364 | + verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; |
|---|
| 365 | + } while (need_seqretry(&nn->boot_lock, seq)); |
|---|
| 366 | + done_seqretry(&nn->boot_lock, seq); |
|---|
| 367 | +} |
|---|
| 368 | + |
|---|
| 369 | +static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) |
|---|
| 370 | +{ |
|---|
| 371 | + ktime_get_real_ts64(&nn->nfssvc_boot); |
|---|
| 372 | +} |
|---|
| 373 | + |
|---|
| 374 | +void nfsd_reset_boot_verifier(struct nfsd_net *nn) |
|---|
| 375 | +{ |
|---|
| 376 | + write_seqlock(&nn->boot_lock); |
|---|
| 377 | + nfsd_reset_boot_verifier_locked(nn); |
|---|
| 378 | + write_sequnlock(&nn->boot_lock); |
|---|
| 379 | +} |
|---|
| 380 | + |
|---|
| 381 | +static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) |
|---|
| 278 | 382 | { |
|---|
| 279 | 383 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
|---|
| 280 | 384 | int ret; |
|---|
| .. | .. |
|---|
| 285 | 389 | ret = nfsd_startup_generic(nrservs); |
|---|
| 286 | 390 | if (ret) |
|---|
| 287 | 391 | return ret; |
|---|
| 288 | | - ret = nfsd_init_socks(net); |
|---|
| 392 | + ret = nfsd_init_socks(net, cred); |
|---|
| 289 | 393 | if (ret) |
|---|
| 290 | 394 | goto out_socks; |
|---|
| 291 | 395 | |
|---|
| 292 | | - if (nfsd_needs_lockd() && !nn->lockd_up) { |
|---|
| 293 | | - ret = lockd_up(net); |
|---|
| 396 | + if (nfsd_needs_lockd(nn) && !nn->lockd_up) { |
|---|
| 397 | + ret = lockd_up(net, cred); |
|---|
| 294 | 398 | if (ret) |
|---|
| 295 | 399 | goto out_socks; |
|---|
| 296 | | - nn->lockd_up = 1; |
|---|
| 400 | + nn->lockd_up = true; |
|---|
| 297 | 401 | } |
|---|
| 298 | 402 | |
|---|
| 299 | | - ret = nfs4_state_start_net(net); |
|---|
| 403 | + ret = nfsd_file_cache_start_net(net); |
|---|
| 300 | 404 | if (ret) |
|---|
| 301 | 405 | goto out_lockd; |
|---|
| 406 | + ret = nfs4_state_start_net(net); |
|---|
| 407 | + if (ret) |
|---|
| 408 | + goto out_filecache; |
|---|
| 302 | 409 | |
|---|
| 303 | 410 | nn->nfsd_net_up = true; |
|---|
| 304 | 411 | return 0; |
|---|
| 305 | 412 | |
|---|
| 413 | +out_filecache: |
|---|
| 414 | + nfsd_file_cache_shutdown_net(net); |
|---|
| 306 | 415 | out_lockd: |
|---|
| 307 | 416 | if (nn->lockd_up) { |
|---|
| 308 | 417 | lockd_down(net); |
|---|
| 309 | | - nn->lockd_up = 0; |
|---|
| 418 | + nn->lockd_up = false; |
|---|
| 310 | 419 | } |
|---|
| 311 | 420 | out_socks: |
|---|
| 312 | 421 | nfsd_shutdown_generic(); |
|---|
| .. | .. |
|---|
| 317 | 426 | { |
|---|
| 318 | 427 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
|---|
| 319 | 428 | |
|---|
| 429 | + nfsd_file_cache_shutdown_net(net); |
|---|
| 320 | 430 | nfs4_state_shutdown_net(net); |
|---|
| 321 | 431 | if (nn->lockd_up) { |
|---|
| 322 | 432 | lockd_down(net); |
|---|
| 323 | | - nn->lockd_up = 0; |
|---|
| 433 | + nn->lockd_up = false; |
|---|
| 324 | 434 | } |
|---|
| 325 | 435 | nn->nfsd_net_up = false; |
|---|
| 326 | 436 | nfsd_shutdown_generic(); |
|---|
| .. | .. |
|---|
| 421 | 531 | nfsd_export_flush(net); |
|---|
| 422 | 532 | } |
|---|
| 423 | 533 | |
|---|
| 424 | | -void nfsd_reset_versions(void) |
|---|
| 534 | +void nfsd_reset_versions(struct nfsd_net *nn) |
|---|
| 425 | 535 | { |
|---|
| 426 | 536 | int i; |
|---|
| 427 | 537 | |
|---|
| 428 | 538 | for (i = 0; i < NFSD_NRVERS; i++) |
|---|
| 429 | | - if (nfsd_vers(i, NFSD_TEST)) |
|---|
| 539 | + if (nfsd_vers(nn, i, NFSD_TEST)) |
|---|
| 430 | 540 | return; |
|---|
| 431 | 541 | |
|---|
| 432 | 542 | for (i = 0; i < NFSD_NRVERS; i++) |
|---|
| 433 | 543 | if (i != 4) |
|---|
| 434 | | - nfsd_vers(i, NFSD_SET); |
|---|
| 544 | + nfsd_vers(nn, i, NFSD_SET); |
|---|
| 435 | 545 | else { |
|---|
| 436 | 546 | int minor = 0; |
|---|
| 437 | | - while (nfsd_minorversion(minor, NFSD_SET) >= 0) |
|---|
| 547 | + while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0) |
|---|
| 438 | 548 | minor++; |
|---|
| 439 | 549 | } |
|---|
| 440 | 550 | } |
|---|
| .. | .. |
|---|
| 490 | 600 | .svo_module = THIS_MODULE, |
|---|
| 491 | 601 | }; |
|---|
| 492 | 602 | |
|---|
| 603 | +bool i_am_nfsd(void) |
|---|
| 604 | +{ |
|---|
| 605 | + return kthread_func(current) == nfsd; |
|---|
| 606 | +} |
|---|
| 607 | + |
|---|
| 493 | 608 | int nfsd_create_serv(struct net *net) |
|---|
| 494 | 609 | { |
|---|
| 495 | 610 | int error; |
|---|
| .. | .. |
|---|
| 502 | 617 | } |
|---|
| 503 | 618 | if (nfsd_max_blksize == 0) |
|---|
| 504 | 619 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
|---|
| 505 | | - nfsd_reset_versions(); |
|---|
| 620 | + nfsd_reset_versions(nn); |
|---|
| 506 | 621 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
|---|
| 507 | 622 | &nfsd_thread_sv_ops); |
|---|
| 508 | 623 | if (nn->nfsd_serv == NULL) |
|---|
| .. | .. |
|---|
| 524 | 639 | #endif |
|---|
| 525 | 640 | } |
|---|
| 526 | 641 | atomic_inc(&nn->ntf_refcnt); |
|---|
| 527 | | - ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ |
|---|
| 642 | + nfsd_reset_boot_verifier(nn); |
|---|
| 528 | 643 | return 0; |
|---|
| 529 | 644 | } |
|---|
| 530 | 645 | |
|---|
| .. | .. |
|---|
| 622 | 737 | * this is the first time nrservs is nonzero. |
|---|
| 623 | 738 | */ |
|---|
| 624 | 739 | int |
|---|
| 625 | | -nfsd_svc(int nrservs, struct net *net) |
|---|
| 740 | +nfsd_svc(int nrservs, struct net *net, const struct cred *cred) |
|---|
| 626 | 741 | { |
|---|
| 627 | 742 | int error; |
|---|
| 628 | 743 | bool nfsd_up_before; |
|---|
| .. | .. |
|---|
| 638 | 753 | if (nrservs == 0 && nn->nfsd_serv == NULL) |
|---|
| 639 | 754 | goto out; |
|---|
| 640 | 755 | |
|---|
| 756 | + strlcpy(nn->nfsd_name, utsname()->nodename, |
|---|
| 757 | + sizeof(nn->nfsd_name)); |
|---|
| 758 | + |
|---|
| 641 | 759 | error = nfsd_create_serv(net); |
|---|
| 642 | 760 | if (error) |
|---|
| 643 | 761 | goto out; |
|---|
| 644 | 762 | |
|---|
| 645 | 763 | nfsd_up_before = nn->nfsd_net_up; |
|---|
| 646 | 764 | |
|---|
| 647 | | - error = nfsd_startup_net(nrservs, net); |
|---|
| 765 | + error = nfsd_startup_net(nrservs, net, cred); |
|---|
| 648 | 766 | if (error) |
|---|
| 649 | 767 | goto out_destroy; |
|---|
| 650 | 768 | error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, |
|---|
| .. | .. |
|---|
| 666 | 784 | return error; |
|---|
| 667 | 785 | } |
|---|
| 668 | 786 | |
|---|
| 787 | +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
|---|
| 788 | +static bool |
|---|
| 789 | +nfsd_support_acl_version(int vers) |
|---|
| 790 | +{ |
|---|
| 791 | + if (vers >= NFSD_ACL_MINVERS && vers < NFSD_ACL_NRVERS) |
|---|
| 792 | + return nfsd_acl_version[vers] != NULL; |
|---|
| 793 | + return false; |
|---|
| 794 | +} |
|---|
| 795 | + |
|---|
| 796 | +static int |
|---|
| 797 | +nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp, |
|---|
| 798 | + u32 version, int family, unsigned short proto, |
|---|
| 799 | + unsigned short port) |
|---|
| 800 | +{ |
|---|
| 801 | + if (!nfsd_support_acl_version(version) || |
|---|
| 802 | + !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
|---|
| 803 | + return 0; |
|---|
| 804 | + return svc_generic_rpcbind_set(net, progp, version, family, |
|---|
| 805 | + proto, port); |
|---|
| 806 | +} |
|---|
| 807 | + |
|---|
| 808 | +static __be32 |
|---|
| 809 | +nfsd_acl_init_request(struct svc_rqst *rqstp, |
|---|
| 810 | + const struct svc_program *progp, |
|---|
| 811 | + struct svc_process_info *ret) |
|---|
| 812 | +{ |
|---|
| 813 | + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
|---|
| 814 | + int i; |
|---|
| 815 | + |
|---|
| 816 | + if (likely(nfsd_support_acl_version(rqstp->rq_vers) && |
|---|
| 817 | + nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) |
|---|
| 818 | + return svc_generic_init_request(rqstp, progp, ret); |
|---|
| 819 | + |
|---|
| 820 | + ret->mismatch.lovers = NFSD_ACL_NRVERS; |
|---|
| 821 | + for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { |
|---|
| 822 | + if (nfsd_support_acl_version(rqstp->rq_vers) && |
|---|
| 823 | + nfsd_vers(nn, i, NFSD_TEST)) { |
|---|
| 824 | + ret->mismatch.lovers = i; |
|---|
| 825 | + break; |
|---|
| 826 | + } |
|---|
| 827 | + } |
|---|
| 828 | + if (ret->mismatch.lovers == NFSD_ACL_NRVERS) |
|---|
| 829 | + return rpc_prog_unavail; |
|---|
| 830 | + ret->mismatch.hivers = NFSD_ACL_MINVERS; |
|---|
| 831 | + for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) { |
|---|
| 832 | + if (nfsd_support_acl_version(rqstp->rq_vers) && |
|---|
| 833 | + nfsd_vers(nn, i, NFSD_TEST)) { |
|---|
| 834 | + ret->mismatch.hivers = i; |
|---|
| 835 | + break; |
|---|
| 836 | + } |
|---|
| 837 | + } |
|---|
| 838 | + return rpc_prog_mismatch; |
|---|
| 839 | +} |
|---|
| 840 | +#endif |
|---|
| 841 | + |
|---|
| 842 | +static int |
|---|
| 843 | +nfsd_rpcbind_set(struct net *net, const struct svc_program *progp, |
|---|
| 844 | + u32 version, int family, unsigned short proto, |
|---|
| 845 | + unsigned short port) |
|---|
| 846 | +{ |
|---|
| 847 | + if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
|---|
| 848 | + return 0; |
|---|
| 849 | + return svc_generic_rpcbind_set(net, progp, version, family, |
|---|
| 850 | + proto, port); |
|---|
| 851 | +} |
|---|
| 852 | + |
|---|
| 853 | +static __be32 |
|---|
| 854 | +nfsd_init_request(struct svc_rqst *rqstp, |
|---|
| 855 | + const struct svc_program *progp, |
|---|
| 856 | + struct svc_process_info *ret) |
|---|
| 857 | +{ |
|---|
| 858 | + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
|---|
| 859 | + int i; |
|---|
| 860 | + |
|---|
| 861 | + if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) |
|---|
| 862 | + return svc_generic_init_request(rqstp, progp, ret); |
|---|
| 863 | + |
|---|
| 864 | + ret->mismatch.lovers = NFSD_NRVERS; |
|---|
| 865 | + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { |
|---|
| 866 | + if (nfsd_vers(nn, i, NFSD_TEST)) { |
|---|
| 867 | + ret->mismatch.lovers = i; |
|---|
| 868 | + break; |
|---|
| 869 | + } |
|---|
| 870 | + } |
|---|
| 871 | + if (ret->mismatch.lovers == NFSD_NRVERS) |
|---|
| 872 | + return rpc_prog_unavail; |
|---|
| 873 | + ret->mismatch.hivers = NFSD_MINVERS; |
|---|
| 874 | + for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) { |
|---|
| 875 | + if (nfsd_vers(nn, i, NFSD_TEST)) { |
|---|
| 876 | + ret->mismatch.hivers = i; |
|---|
| 877 | + break; |
|---|
| 878 | + } |
|---|
| 879 | + } |
|---|
| 880 | + return rpc_prog_mismatch; |
|---|
| 881 | +} |
|---|
| 669 | 882 | |
|---|
| 670 | 883 | /* |
|---|
| 671 | 884 | * This is the NFS server kernel thread |
|---|
| .. | .. |
|---|
| 746 | 959 | return 0; |
|---|
| 747 | 960 | } |
|---|
| 748 | 961 | |
|---|
| 749 | | -static __be32 map_new_errors(u32 vers, __be32 nfserr) |
|---|
| 750 | | -{ |
|---|
| 751 | | - if (nfserr == nfserr_jukebox && vers == 2) |
|---|
| 752 | | - return nfserr_dropit; |
|---|
| 753 | | - if (nfserr == nfserr_wrongsec && vers < 4) |
|---|
| 754 | | - return nfserr_acces; |
|---|
| 755 | | - return nfserr; |
|---|
| 756 | | -} |
|---|
| 757 | | - |
|---|
| 758 | 962 | /* |
|---|
| 759 | 963 | * A write procedure can have a large argument, and a read procedure can |
|---|
| 760 | 964 | * have a large reply, but no NFSv2 or NFSv3 procedure has argument and |
|---|
| .. | .. |
|---|
| 786 | 990 | return rqstp->rq_arg.len > PAGE_SIZE; |
|---|
| 787 | 991 | } |
|---|
| 788 | 992 | |
|---|
| 789 | | -int |
|---|
| 790 | | -nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
|---|
| 993 | +/** |
|---|
| 994 | + * nfsd_dispatch - Process an NFS or NFSACL Request |
|---|
| 995 | + * @rqstp: incoming request |
|---|
| 996 | + * @statp: pointer to location of accept_stat field in RPC Reply buffer |
|---|
| 997 | + * |
|---|
| 998 | + * This RPC dispatcher integrates the NFS server's duplicate reply cache. |
|---|
| 999 | + * |
|---|
| 1000 | + * Return values: |
|---|
| 1001 | + * %0: Processing complete; do not send a Reply |
|---|
| 1002 | + * %1: Processing complete; send Reply in rqstp->rq_res |
|---|
| 1003 | + */ |
|---|
| 1004 | +int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
|---|
| 791 | 1005 | { |
|---|
| 792 | | - const struct svc_procedure *proc; |
|---|
| 793 | | - __be32 nfserr; |
|---|
| 794 | | - __be32 *nfserrp; |
|---|
| 1006 | + const struct svc_procedure *proc = rqstp->rq_procinfo; |
|---|
| 1007 | + struct kvec *argv = &rqstp->rq_arg.head[0]; |
|---|
| 1008 | + struct kvec *resv = &rqstp->rq_res.head[0]; |
|---|
| 1009 | + __be32 *p; |
|---|
| 795 | 1010 | |
|---|
| 796 | 1011 | dprintk("nfsd_dispatch: vers %d proc %d\n", |
|---|
| 797 | 1012 | rqstp->rq_vers, rqstp->rq_proc); |
|---|
| 798 | | - proc = rqstp->rq_procinfo; |
|---|
| 799 | 1013 | |
|---|
| 800 | | - if (nfs_request_too_big(rqstp, proc)) { |
|---|
| 801 | | - dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); |
|---|
| 802 | | - *statp = rpc_garbage_args; |
|---|
| 803 | | - return 1; |
|---|
| 804 | | - } |
|---|
| 1014 | + if (nfs_request_too_big(rqstp, proc)) |
|---|
| 1015 | + goto out_too_large; |
|---|
| 1016 | + |
|---|
| 805 | 1017 | /* |
|---|
| 806 | 1018 | * Give the xdr decoder a chance to change this if it wants |
|---|
| 807 | 1019 | * (necessary in the NFSv4.0 compound case) |
|---|
| 808 | 1020 | */ |
|---|
| 809 | 1021 | rqstp->rq_cachetype = proc->pc_cachetype; |
|---|
| 810 | | - /* Decode arguments */ |
|---|
| 811 | | - if (proc->pc_decode && |
|---|
| 812 | | - !proc->pc_decode(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base)) { |
|---|
| 813 | | - dprintk("nfsd: failed to decode arguments!\n"); |
|---|
| 814 | | - *statp = rpc_garbage_args; |
|---|
| 815 | | - return 1; |
|---|
| 816 | | - } |
|---|
| 1022 | + if (!proc->pc_decode(rqstp, argv->iov_base)) |
|---|
| 1023 | + goto out_decode_err; |
|---|
| 817 | 1024 | |
|---|
| 818 | | - /* Check whether we have this call in the cache. */ |
|---|
| 819 | 1025 | switch (nfsd_cache_lookup(rqstp)) { |
|---|
| 820 | | - case RC_DROPIT: |
|---|
| 821 | | - return 0; |
|---|
| 1026 | + case RC_DOIT: |
|---|
| 1027 | + break; |
|---|
| 822 | 1028 | case RC_REPLY: |
|---|
| 823 | | - return 1; |
|---|
| 824 | | - case RC_DOIT:; |
|---|
| 825 | | - /* do it */ |
|---|
| 1029 | + goto out_cached_reply; |
|---|
| 1030 | + case RC_DROPIT: |
|---|
| 1031 | + goto out_dropit; |
|---|
| 826 | 1032 | } |
|---|
| 827 | 1033 | |
|---|
| 828 | | - /* need to grab the location to store the status, as |
|---|
| 829 | | - * nfsv4 does some encoding while processing |
|---|
| 1034 | + /* |
|---|
| 1035 | + * Need to grab the location to store the status, as |
|---|
| 1036 | + * NFSv4 does some encoding while processing |
|---|
| 830 | 1037 | */ |
|---|
| 831 | | - nfserrp = rqstp->rq_res.head[0].iov_base |
|---|
| 832 | | - + rqstp->rq_res.head[0].iov_len; |
|---|
| 833 | | - rqstp->rq_res.head[0].iov_len += sizeof(__be32); |
|---|
| 1038 | + p = resv->iov_base + resv->iov_len; |
|---|
| 1039 | + resv->iov_len += sizeof(__be32); |
|---|
| 834 | 1040 | |
|---|
| 835 | | - /* Now call the procedure handler, and encode NFS status. */ |
|---|
| 836 | | - nfserr = proc->pc_func(rqstp); |
|---|
| 837 | | - nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
|---|
| 838 | | - if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) { |
|---|
| 839 | | - dprintk("nfsd: Dropping request; may be revisited later\n"); |
|---|
| 840 | | - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
|---|
| 841 | | - return 0; |
|---|
| 842 | | - } |
|---|
| 1041 | + *statp = proc->pc_func(rqstp); |
|---|
| 1042 | + if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) |
|---|
| 1043 | + goto out_update_drop; |
|---|
| 843 | 1044 | |
|---|
| 844 | | - if (rqstp->rq_proc != 0) |
|---|
| 845 | | - *nfserrp++ = nfserr; |
|---|
| 1045 | + if (!proc->pc_encode(rqstp, p)) |
|---|
| 1046 | + goto out_encode_err; |
|---|
| 846 | 1047 | |
|---|
| 847 | | - /* Encode result. |
|---|
| 848 | | - * For NFSv2, additional info is never returned in case of an error. |
|---|
| 849 | | - */ |
|---|
| 850 | | - if (!(nfserr && rqstp->rq_vers == 2)) { |
|---|
| 851 | | - if (proc->pc_encode && !proc->pc_encode(rqstp, nfserrp)) { |
|---|
| 852 | | - /* Failed to encode result. Release cache entry */ |
|---|
| 853 | | - dprintk("nfsd: failed to encode result!\n"); |
|---|
| 854 | | - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
|---|
| 855 | | - *statp = rpc_system_err; |
|---|
| 856 | | - return 1; |
|---|
| 857 | | - } |
|---|
| 858 | | - } |
|---|
| 859 | | - |
|---|
| 860 | | - /* Store reply in cache. */ |
|---|
| 861 | 1048 | nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); |
|---|
| 1049 | +out_cached_reply: |
|---|
| 1050 | + return 1; |
|---|
| 1051 | + |
|---|
| 1052 | +out_too_large: |
|---|
| 1053 | + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); |
|---|
| 1054 | + *statp = rpc_garbage_args; |
|---|
| 1055 | + return 1; |
|---|
| 1056 | + |
|---|
| 1057 | +out_decode_err: |
|---|
| 1058 | + dprintk("nfsd: failed to decode arguments!\n"); |
|---|
| 1059 | + *statp = rpc_garbage_args; |
|---|
| 1060 | + return 1; |
|---|
| 1061 | + |
|---|
| 1062 | +out_update_drop: |
|---|
| 1063 | + dprintk("nfsd: Dropping request; may be revisited later\n"); |
|---|
| 1064 | + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
|---|
| 1065 | +out_dropit: |
|---|
| 1066 | + return 0; |
|---|
| 1067 | + |
|---|
| 1068 | +out_encode_err: |
|---|
| 1069 | + dprintk("nfsd: failed to encode result!\n"); |
|---|
| 1070 | + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
|---|
| 1071 | + *statp = rpc_system_err; |
|---|
| 862 | 1072 | return 1; |
|---|
| 863 | 1073 | } |
|---|
| 864 | 1074 | |
|---|