hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/nfsd/nfssvc.c
....@@ -27,11 +27,36 @@
2727 #include "cache.h"
2828 #include "vfs.h"
2929 #include "netns.h"
30
+#include "filecache.h"
3031
3132 #define NFSDDBG_FACILITY NFSDDBG_SVC
3233
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
+
3340 extern struct svc_program nfsd_program;
3441 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 *);
3560
3661 /*
3762 * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
....@@ -76,16 +101,17 @@
76101
77102 #define NFSD_ACL_MINVERS 2
78103 #define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version)
79
-static const struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
80104
81105 static struct svc_program nfsd_acl_program = {
82106 .pg_prog = NFS_ACL_PROGRAM,
83107 .pg_nvers = NFSD_ACL_NRVERS,
84
- .pg_vers = nfsd_acl_versions,
108
+ .pg_vers = nfsd_acl_version,
85109 .pg_name = "nfsacl",
86110 .pg_class = "nfsd",
87111 .pg_stats = &nfsd_acl_svcstats,
88112 .pg_authenticate = &svc_set_client,
113
+ .pg_init_request = nfsd_acl_init_request,
114
+ .pg_rpcbind_set = nfsd_acl_rpcbind_set,
89115 };
90116
91117 static struct svc_stat nfsd_acl_svcstats = {
....@@ -105,7 +131,6 @@
105131
106132 #define NFSD_MINVERS 2
107133 #define NFSD_NRVERS ARRAY_SIZE(nfsd_version)
108
-static const struct svc_version *nfsd_versions[NFSD_NRVERS];
109134
110135 struct svc_program nfsd_program = {
111136 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
....@@ -113,77 +138,136 @@
113138 #endif
114139 .pg_prog = NFS_PROGRAM, /* program number */
115140 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
116
- .pg_vers = nfsd_versions, /* version table */
141
+ .pg_vers = nfsd_version, /* version table */
117142 .pg_name = "nfsd", /* program name */
118143 .pg_class = "nfsd", /* authentication class */
119144 .pg_stats = &nfsd_svcstats, /* version table */
120145 .pg_authenticate = &svc_set_client, /* export authentication */
121
-
146
+ .pg_init_request = nfsd_init_request,
147
+ .pg_rpcbind_set = nfsd_rpcbind_set,
122148 };
123149
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
+}
129157
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)
131208 {
132209 if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
133210 return 0;
134211 switch(change) {
135212 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);
141215 break;
142216 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;
148220 break;
149221 case NFSD_TEST:
150
- return nfsd_versions[vers] != NULL;
222
+ if (nn->nfsd_versions)
223
+ return nn->nfsd_versions[vers];
224
+ fallthrough;
151225 case NFSD_AVAIL:
152
- return nfsd_version[vers] != NULL;
226
+ return nfsd_support_version(vers);
153227 }
154228 return 0;
155229 }
156230
157231 static void
158
-nfsd_adjust_nfsd_versions4(void)
232
+nfsd_adjust_nfsd_versions4(struct nfsd_net *nn)
159233 {
160234 unsigned i;
161235
162236 for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) {
163
- if (nfsd_supported_minorversions[i])
237
+ if (nn->nfsd4_minorversions[i])
164238 return;
165239 }
166
- nfsd_vers(4, NFSD_CLEAR);
240
+ nfsd_vers(nn, 4, NFSD_CLEAR);
167241 }
168242
169
-int nfsd_minorversion(u32 minorversion, enum vers_op change)
243
+int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change)
170244 {
171245 if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
172246 change != NFSD_AVAIL)
173247 return -1;
248
+
174249 switch(change) {
175250 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
+ }
178256 break;
179257 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
+ }
182263 break;
183264 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);
185268 case NFSD_AVAIL:
186
- return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
269
+ return minorversion <= NFSD_SUPPORTED_MINOR_VERSION &&
270
+ nfsd_vers(nn, 4, NFSD_AVAIL);
187271 }
188272 return 0;
189273 }
....@@ -205,7 +289,7 @@
205289 return rv;
206290 }
207291
208
-static int nfsd_init_socks(struct net *net)
292
+static int nfsd_init_socks(struct net *net, const struct cred *cred)
209293 {
210294 int error;
211295 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
....@@ -214,12 +298,12 @@
214298 return 0;
215299
216300 error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
217
- SVC_SOCK_DEFAULTS);
301
+ SVC_SOCK_DEFAULTS, cred);
218302 if (error < 0)
219303 return error;
220304
221305 error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
222
- SVC_SOCK_DEFAULTS);
306
+ SVC_SOCK_DEFAULTS, cred);
223307 if (error < 0)
224308 return error;
225309
....@@ -235,22 +319,17 @@
235319 if (nfsd_users++)
236320 return 0;
237321
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();
244323 if (ret)
245324 goto dec_users;
246325
247326 ret = nfs4_state_start();
248327 if (ret)
249
- goto out_racache;
328
+ goto out_file_cache;
250329 return 0;
251330
252
-out_racache:
253
- nfsd_racache_shutdown();
331
+out_file_cache:
332
+ nfsd_file_cache_shutdown();
254333 dec_users:
255334 nfsd_users--;
256335 return ret;
....@@ -262,19 +341,44 @@
262341 return;
263342
264343 nfs4_state_shutdown();
265
- nfsd_racache_shutdown();
344
+ nfsd_file_cache_shutdown();
266345 }
267346
268
-static bool nfsd_needs_lockd(void)
347
+static bool nfsd_needs_lockd(struct nfsd_net *nn)
269348 {
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);
275350 }
276351
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)
278382 {
279383 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
280384 int ret;
....@@ -285,28 +389,33 @@
285389 ret = nfsd_startup_generic(nrservs);
286390 if (ret)
287391 return ret;
288
- ret = nfsd_init_socks(net);
392
+ ret = nfsd_init_socks(net, cred);
289393 if (ret)
290394 goto out_socks;
291395
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);
294398 if (ret)
295399 goto out_socks;
296
- nn->lockd_up = 1;
400
+ nn->lockd_up = true;
297401 }
298402
299
- ret = nfs4_state_start_net(net);
403
+ ret = nfsd_file_cache_start_net(net);
300404 if (ret)
301405 goto out_lockd;
406
+ ret = nfs4_state_start_net(net);
407
+ if (ret)
408
+ goto out_filecache;
302409
303410 nn->nfsd_net_up = true;
304411 return 0;
305412
413
+out_filecache:
414
+ nfsd_file_cache_shutdown_net(net);
306415 out_lockd:
307416 if (nn->lockd_up) {
308417 lockd_down(net);
309
- nn->lockd_up = 0;
418
+ nn->lockd_up = false;
310419 }
311420 out_socks:
312421 nfsd_shutdown_generic();
....@@ -318,9 +427,10 @@
318427 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
319428
320429 nfs4_state_shutdown_net(net);
430
+ nfsd_file_cache_shutdown_net(net);
321431 if (nn->lockd_up) {
322432 lockd_down(net);
323
- nn->lockd_up = 0;
433
+ nn->lockd_up = false;
324434 }
325435 nn->nfsd_net_up = false;
326436 nfsd_shutdown_generic();
....@@ -421,20 +531,20 @@
421531 nfsd_export_flush(net);
422532 }
423533
424
-void nfsd_reset_versions(void)
534
+void nfsd_reset_versions(struct nfsd_net *nn)
425535 {
426536 int i;
427537
428538 for (i = 0; i < NFSD_NRVERS; i++)
429
- if (nfsd_vers(i, NFSD_TEST))
539
+ if (nfsd_vers(nn, i, NFSD_TEST))
430540 return;
431541
432542 for (i = 0; i < NFSD_NRVERS; i++)
433543 if (i != 4)
434
- nfsd_vers(i, NFSD_SET);
544
+ nfsd_vers(nn, i, NFSD_SET);
435545 else {
436546 int minor = 0;
437
- while (nfsd_minorversion(minor, NFSD_SET) >= 0)
547
+ while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0)
438548 minor++;
439549 }
440550 }
....@@ -490,6 +600,42 @@
490600 .svo_module = THIS_MODULE,
491601 };
492602
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
+
493639 int nfsd_create_serv(struct net *net)
494640 {
495641 int error;
....@@ -502,16 +648,18 @@
502648 }
503649 if (nfsd_max_blksize == 0)
504650 nfsd_max_blksize = nfsd_get_default_max_blksize();
505
- nfsd_reset_versions();
651
+ nfsd_reset_versions(nn);
506652 nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
507653 &nfsd_thread_sv_ops);
508654 if (nn->nfsd_serv == NULL)
509655 return -ENOMEM;
656
+ init_completion(&nn->nfsd_shutdown_complete);
510657
511658 nn->nfsd_serv->sv_maxconn = nn->max_connections;
512659 error = svc_bind(nn->nfsd_serv, net);
513660 if (error < 0) {
514661 svc_destroy(nn->nfsd_serv);
662
+ nfsd_complete_shutdown(net);
515663 return error;
516664 }
517665
....@@ -524,7 +672,7 @@
524672 #endif
525673 }
526674 atomic_inc(&nn->ntf_refcnt);
527
- ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */
675
+ nfsd_reset_boot_verifier(nn);
528676 return 0;
529677 }
530678
....@@ -560,7 +708,7 @@
560708 svc_shutdown_net(nn->nfsd_serv, net);
561709 svc_destroy(nn->nfsd_serv);
562710 if (destroy)
563
- nn->nfsd_serv = NULL;
711
+ nfsd_complete_shutdown(net);
564712 }
565713
566714 int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
....@@ -622,7 +770,7 @@
622770 * this is the first time nrservs is nonzero.
623771 */
624772 int
625
-nfsd_svc(int nrservs, struct net *net)
773
+nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
626774 {
627775 int error;
628776 bool nfsd_up_before;
....@@ -638,13 +786,16 @@
638786 if (nrservs == 0 && nn->nfsd_serv == NULL)
639787 goto out;
640788
789
+ strlcpy(nn->nfsd_name, utsname()->nodename,
790
+ sizeof(nn->nfsd_name));
791
+
641792 error = nfsd_create_serv(net);
642793 if (error)
643794 goto out;
644795
645796 nfsd_up_before = nn->nfsd_net_up;
646797
647
- error = nfsd_startup_net(nrservs, net);
798
+ error = nfsd_startup_net(nrservs, net, cred);
648799 if (error)
649800 goto out_destroy;
650801 error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
....@@ -666,6 +817,101 @@
666817 return error;
667818 }
668819
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
+}
669915
670916 /*
671917 * This is the NFS server kernel thread
....@@ -746,15 +992,6 @@
746992 return 0;
747993 }
748994
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
-
758995 /*
759996 * A write procedure can have a large argument, and a read procedure can
760997 * have a large reply, but no NFSv2 or NFSv3 procedure has argument and
....@@ -786,79 +1023,85 @@
7861023 return rqstp->rq_arg.len > PAGE_SIZE;
7871024 }
7881025
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)
7911038 {
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;
7951043
7961044 dprintk("nfsd_dispatch: vers %d proc %d\n",
7971045 rqstp->rq_vers, rqstp->rq_proc);
798
- proc = rqstp->rq_procinfo;
7991046
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
+
8051050 /*
8061051 * Give the xdr decoder a chance to change this if it wants
8071052 * (necessary in the NFSv4.0 compound case)
8081053 */
8091054 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;
8171057
818
- /* Check whether we have this call in the cache. */
8191058 switch (nfsd_cache_lookup(rqstp)) {
820
- case RC_DROPIT:
821
- return 0;
1059
+ case RC_DOIT:
1060
+ break;
8221061 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;
8261065 }
8271066
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
8301070 */
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);
8341073
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;
8431077
844
- if (rqstp->rq_proc != 0)
845
- *nfserrp++ = nfserr;
1078
+ if (!proc->pc_encode(rqstp, p))
1079
+ goto out_encode_err;
8461080
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. */
8611081 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;
8621105 return 1;
8631106 }
8641107