.. | .. |
---|
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(); |
---|
.. | .. |
---|
318 | 427 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
319 | 428 | |
---|
320 | 429 | nfs4_state_shutdown_net(net); |
---|
| 430 | + nfsd_file_cache_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 | +static void nfsd_complete_shutdown(struct net *net) |
---|
| 604 | +{ |
---|
| 605 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 606 | + |
---|
| 607 | + WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
---|
| 608 | + |
---|
| 609 | + nn->nfsd_serv = NULL; |
---|
| 610 | + complete(&nn->nfsd_shutdown_complete); |
---|
| 611 | +} |
---|
| 612 | + |
---|
| 613 | +void nfsd_shutdown_threads(struct net *net) |
---|
| 614 | +{ |
---|
| 615 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 616 | + struct svc_serv *serv; |
---|
| 617 | + |
---|
| 618 | + mutex_lock(&nfsd_mutex); |
---|
| 619 | + serv = nn->nfsd_serv; |
---|
| 620 | + if (serv == NULL) { |
---|
| 621 | + mutex_unlock(&nfsd_mutex); |
---|
| 622 | + return; |
---|
| 623 | + } |
---|
| 624 | + |
---|
| 625 | + svc_get(serv); |
---|
| 626 | + /* Kill outstanding nfsd threads */ |
---|
| 627 | + serv->sv_ops->svo_setup(serv, NULL, 0); |
---|
| 628 | + nfsd_destroy(net); |
---|
| 629 | + mutex_unlock(&nfsd_mutex); |
---|
| 630 | + /* Wait for shutdown of nfsd_serv to complete */ |
---|
| 631 | + wait_for_completion(&nn->nfsd_shutdown_complete); |
---|
| 632 | +} |
---|
| 633 | + |
---|
| 634 | +bool i_am_nfsd(void) |
---|
| 635 | +{ |
---|
| 636 | + return kthread_func(current) == nfsd; |
---|
| 637 | +} |
---|
| 638 | + |
---|
493 | 639 | int nfsd_create_serv(struct net *net) |
---|
494 | 640 | { |
---|
495 | 641 | int error; |
---|
.. | .. |
---|
502 | 648 | } |
---|
503 | 649 | if (nfsd_max_blksize == 0) |
---|
504 | 650 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
---|
505 | | - nfsd_reset_versions(); |
---|
| 651 | + nfsd_reset_versions(nn); |
---|
506 | 652 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
---|
507 | 653 | &nfsd_thread_sv_ops); |
---|
508 | 654 | if (nn->nfsd_serv == NULL) |
---|
509 | 655 | return -ENOMEM; |
---|
| 656 | + init_completion(&nn->nfsd_shutdown_complete); |
---|
510 | 657 | |
---|
511 | 658 | nn->nfsd_serv->sv_maxconn = nn->max_connections; |
---|
512 | 659 | error = svc_bind(nn->nfsd_serv, net); |
---|
513 | 660 | if (error < 0) { |
---|
514 | 661 | svc_destroy(nn->nfsd_serv); |
---|
| 662 | + nfsd_complete_shutdown(net); |
---|
515 | 663 | return error; |
---|
516 | 664 | } |
---|
517 | 665 | |
---|
.. | .. |
---|
524 | 672 | #endif |
---|
525 | 673 | } |
---|
526 | 674 | atomic_inc(&nn->ntf_refcnt); |
---|
527 | | - ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ |
---|
| 675 | + nfsd_reset_boot_verifier(nn); |
---|
528 | 676 | return 0; |
---|
529 | 677 | } |
---|
530 | 678 | |
---|
.. | .. |
---|
560 | 708 | svc_shutdown_net(nn->nfsd_serv, net); |
---|
561 | 709 | svc_destroy(nn->nfsd_serv); |
---|
562 | 710 | if (destroy) |
---|
563 | | - nn->nfsd_serv = NULL; |
---|
| 711 | + nfsd_complete_shutdown(net); |
---|
564 | 712 | } |
---|
565 | 713 | |
---|
566 | 714 | int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) |
---|
.. | .. |
---|
622 | 770 | * this is the first time nrservs is nonzero. |
---|
623 | 771 | */ |
---|
624 | 772 | int |
---|
625 | | -nfsd_svc(int nrservs, struct net *net) |
---|
| 773 | +nfsd_svc(int nrservs, struct net *net, const struct cred *cred) |
---|
626 | 774 | { |
---|
627 | 775 | int error; |
---|
628 | 776 | bool nfsd_up_before; |
---|
.. | .. |
---|
638 | 786 | if (nrservs == 0 && nn->nfsd_serv == NULL) |
---|
639 | 787 | goto out; |
---|
640 | 788 | |
---|
| 789 | + strlcpy(nn->nfsd_name, utsname()->nodename, |
---|
| 790 | + sizeof(nn->nfsd_name)); |
---|
| 791 | + |
---|
641 | 792 | error = nfsd_create_serv(net); |
---|
642 | 793 | if (error) |
---|
643 | 794 | goto out; |
---|
644 | 795 | |
---|
645 | 796 | nfsd_up_before = nn->nfsd_net_up; |
---|
646 | 797 | |
---|
647 | | - error = nfsd_startup_net(nrservs, net); |
---|
| 798 | + error = nfsd_startup_net(nrservs, net, cred); |
---|
648 | 799 | if (error) |
---|
649 | 800 | goto out_destroy; |
---|
650 | 801 | error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, |
---|
.. | .. |
---|
666 | 817 | return error; |
---|
667 | 818 | } |
---|
668 | 819 | |
---|
| 820 | +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
---|
| 821 | +static bool |
---|
| 822 | +nfsd_support_acl_version(int vers) |
---|
| 823 | +{ |
---|
| 824 | + if (vers >= NFSD_ACL_MINVERS && vers < NFSD_ACL_NRVERS) |
---|
| 825 | + return nfsd_acl_version[vers] != NULL; |
---|
| 826 | + return false; |
---|
| 827 | +} |
---|
| 828 | + |
---|
| 829 | +static int |
---|
| 830 | +nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp, |
---|
| 831 | + u32 version, int family, unsigned short proto, |
---|
| 832 | + unsigned short port) |
---|
| 833 | +{ |
---|
| 834 | + if (!nfsd_support_acl_version(version) || |
---|
| 835 | + !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
---|
| 836 | + return 0; |
---|
| 837 | + return svc_generic_rpcbind_set(net, progp, version, family, |
---|
| 838 | + proto, port); |
---|
| 839 | +} |
---|
| 840 | + |
---|
| 841 | +static __be32 |
---|
| 842 | +nfsd_acl_init_request(struct svc_rqst *rqstp, |
---|
| 843 | + const struct svc_program *progp, |
---|
| 844 | + struct svc_process_info *ret) |
---|
| 845 | +{ |
---|
| 846 | + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
---|
| 847 | + int i; |
---|
| 848 | + |
---|
| 849 | + if (likely(nfsd_support_acl_version(rqstp->rq_vers) && |
---|
| 850 | + nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) |
---|
| 851 | + return svc_generic_init_request(rqstp, progp, ret); |
---|
| 852 | + |
---|
| 853 | + ret->mismatch.lovers = NFSD_ACL_NRVERS; |
---|
| 854 | + for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { |
---|
| 855 | + if (nfsd_support_acl_version(rqstp->rq_vers) && |
---|
| 856 | + nfsd_vers(nn, i, NFSD_TEST)) { |
---|
| 857 | + ret->mismatch.lovers = i; |
---|
| 858 | + break; |
---|
| 859 | + } |
---|
| 860 | + } |
---|
| 861 | + if (ret->mismatch.lovers == NFSD_ACL_NRVERS) |
---|
| 862 | + return rpc_prog_unavail; |
---|
| 863 | + ret->mismatch.hivers = NFSD_ACL_MINVERS; |
---|
| 864 | + for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) { |
---|
| 865 | + if (nfsd_support_acl_version(rqstp->rq_vers) && |
---|
| 866 | + nfsd_vers(nn, i, NFSD_TEST)) { |
---|
| 867 | + ret->mismatch.hivers = i; |
---|
| 868 | + break; |
---|
| 869 | + } |
---|
| 870 | + } |
---|
| 871 | + return rpc_prog_mismatch; |
---|
| 872 | +} |
---|
| 873 | +#endif |
---|
| 874 | + |
---|
| 875 | +static int |
---|
| 876 | +nfsd_rpcbind_set(struct net *net, const struct svc_program *progp, |
---|
| 877 | + u32 version, int family, unsigned short proto, |
---|
| 878 | + unsigned short port) |
---|
| 879 | +{ |
---|
| 880 | + if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) |
---|
| 881 | + return 0; |
---|
| 882 | + return svc_generic_rpcbind_set(net, progp, version, family, |
---|
| 883 | + proto, port); |
---|
| 884 | +} |
---|
| 885 | + |
---|
| 886 | +static __be32 |
---|
| 887 | +nfsd_init_request(struct svc_rqst *rqstp, |
---|
| 888 | + const struct svc_program *progp, |
---|
| 889 | + struct svc_process_info *ret) |
---|
| 890 | +{ |
---|
| 891 | + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
---|
| 892 | + int i; |
---|
| 893 | + |
---|
| 894 | + if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) |
---|
| 895 | + return svc_generic_init_request(rqstp, progp, ret); |
---|
| 896 | + |
---|
| 897 | + ret->mismatch.lovers = NFSD_NRVERS; |
---|
| 898 | + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { |
---|
| 899 | + if (nfsd_vers(nn, i, NFSD_TEST)) { |
---|
| 900 | + ret->mismatch.lovers = i; |
---|
| 901 | + break; |
---|
| 902 | + } |
---|
| 903 | + } |
---|
| 904 | + if (ret->mismatch.lovers == NFSD_NRVERS) |
---|
| 905 | + return rpc_prog_unavail; |
---|
| 906 | + ret->mismatch.hivers = NFSD_MINVERS; |
---|
| 907 | + for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) { |
---|
| 908 | + if (nfsd_vers(nn, i, NFSD_TEST)) { |
---|
| 909 | + ret->mismatch.hivers = i; |
---|
| 910 | + break; |
---|
| 911 | + } |
---|
| 912 | + } |
---|
| 913 | + return rpc_prog_mismatch; |
---|
| 914 | +} |
---|
669 | 915 | |
---|
670 | 916 | /* |
---|
671 | 917 | * This is the NFS server kernel thread |
---|
.. | .. |
---|
746 | 992 | return 0; |
---|
747 | 993 | } |
---|
748 | 994 | |
---|
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 | 995 | /* |
---|
759 | 996 | * A write procedure can have a large argument, and a read procedure can |
---|
760 | 997 | * have a large reply, but no NFSv2 or NFSv3 procedure has argument and |
---|
.. | .. |
---|
786 | 1023 | return rqstp->rq_arg.len > PAGE_SIZE; |
---|
787 | 1024 | } |
---|
788 | 1025 | |
---|
789 | | -int |
---|
790 | | -nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
---|
| 1026 | +/** |
---|
| 1027 | + * nfsd_dispatch - Process an NFS or NFSACL Request |
---|
| 1028 | + * @rqstp: incoming request |
---|
| 1029 | + * @statp: pointer to location of accept_stat field in RPC Reply buffer |
---|
| 1030 | + * |
---|
| 1031 | + * This RPC dispatcher integrates the NFS server's duplicate reply cache. |
---|
| 1032 | + * |
---|
| 1033 | + * Return values: |
---|
| 1034 | + * %0: Processing complete; do not send a Reply |
---|
| 1035 | + * %1: Processing complete; send Reply in rqstp->rq_res |
---|
| 1036 | + */ |
---|
| 1037 | +int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
---|
791 | 1038 | { |
---|
792 | | - const struct svc_procedure *proc; |
---|
793 | | - __be32 nfserr; |
---|
794 | | - __be32 *nfserrp; |
---|
| 1039 | + const struct svc_procedure *proc = rqstp->rq_procinfo; |
---|
| 1040 | + struct kvec *argv = &rqstp->rq_arg.head[0]; |
---|
| 1041 | + struct kvec *resv = &rqstp->rq_res.head[0]; |
---|
| 1042 | + __be32 *p; |
---|
795 | 1043 | |
---|
796 | 1044 | dprintk("nfsd_dispatch: vers %d proc %d\n", |
---|
797 | 1045 | rqstp->rq_vers, rqstp->rq_proc); |
---|
798 | | - proc = rqstp->rq_procinfo; |
---|
799 | 1046 | |
---|
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 | | - } |
---|
| 1047 | + if (nfs_request_too_big(rqstp, proc)) |
---|
| 1048 | + goto out_too_large; |
---|
| 1049 | + |
---|
805 | 1050 | /* |
---|
806 | 1051 | * Give the xdr decoder a chance to change this if it wants |
---|
807 | 1052 | * (necessary in the NFSv4.0 compound case) |
---|
808 | 1053 | */ |
---|
809 | 1054 | 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 | | - } |
---|
| 1055 | + if (!proc->pc_decode(rqstp, argv->iov_base)) |
---|
| 1056 | + goto out_decode_err; |
---|
817 | 1057 | |
---|
818 | | - /* Check whether we have this call in the cache. */ |
---|
819 | 1058 | switch (nfsd_cache_lookup(rqstp)) { |
---|
820 | | - case RC_DROPIT: |
---|
821 | | - return 0; |
---|
| 1059 | + case RC_DOIT: |
---|
| 1060 | + break; |
---|
822 | 1061 | case RC_REPLY: |
---|
823 | | - return 1; |
---|
824 | | - case RC_DOIT:; |
---|
825 | | - /* do it */ |
---|
| 1062 | + goto out_cached_reply; |
---|
| 1063 | + case RC_DROPIT: |
---|
| 1064 | + goto out_dropit; |
---|
826 | 1065 | } |
---|
827 | 1066 | |
---|
828 | | - /* need to grab the location to store the status, as |
---|
829 | | - * nfsv4 does some encoding while processing |
---|
| 1067 | + /* |
---|
| 1068 | + * Need to grab the location to store the status, as |
---|
| 1069 | + * NFSv4 does some encoding while processing |
---|
830 | 1070 | */ |
---|
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); |
---|
| 1071 | + p = resv->iov_base + resv->iov_len; |
---|
| 1072 | + resv->iov_len += sizeof(__be32); |
---|
834 | 1073 | |
---|
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 | | - } |
---|
| 1074 | + *statp = proc->pc_func(rqstp); |
---|
| 1075 | + if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) |
---|
| 1076 | + goto out_update_drop; |
---|
843 | 1077 | |
---|
844 | | - if (rqstp->rq_proc != 0) |
---|
845 | | - *nfserrp++ = nfserr; |
---|
| 1078 | + if (!proc->pc_encode(rqstp, p)) |
---|
| 1079 | + goto out_encode_err; |
---|
846 | 1080 | |
---|
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 | 1081 | nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); |
---|
| 1082 | +out_cached_reply: |
---|
| 1083 | + return 1; |
---|
| 1084 | + |
---|
| 1085 | +out_too_large: |
---|
| 1086 | + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); |
---|
| 1087 | + *statp = rpc_garbage_args; |
---|
| 1088 | + return 1; |
---|
| 1089 | + |
---|
| 1090 | +out_decode_err: |
---|
| 1091 | + dprintk("nfsd: failed to decode arguments!\n"); |
---|
| 1092 | + *statp = rpc_garbage_args; |
---|
| 1093 | + return 1; |
---|
| 1094 | + |
---|
| 1095 | +out_update_drop: |
---|
| 1096 | + dprintk("nfsd: Dropping request; may be revisited later\n"); |
---|
| 1097 | + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
---|
| 1098 | +out_dropit: |
---|
| 1099 | + return 0; |
---|
| 1100 | + |
---|
| 1101 | +out_encode_err: |
---|
| 1102 | + dprintk("nfsd: failed to encode result!\n"); |
---|
| 1103 | + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
---|
| 1104 | + *statp = rpc_system_err; |
---|
862 | 1105 | return 1; |
---|
863 | 1106 | } |
---|
864 | 1107 | |
---|