1
2
3
4
5
6
7#include <linux/slab.h>
8#include <linux/namei.h>
9#include <linux/ctype.h>
10
11#include <linux/sunrpc/svcsock.h>
12#include <linux/lockd/lockd.h>
13#include <linux/sunrpc/addr.h>
14#include <linux/sunrpc/gss_api.h>
15#include <linux/sunrpc/gss_krb5_enctypes.h>
16#include <linux/sunrpc/rpc_pipe_fs.h>
17#include <linux/module.h>
18
19#include "idmap.h"
20#include "nfsd.h"
21#include "cache.h"
22#include "state.h"
23#include "netns.h"
24#include "pnfs.h"
25
26
27
28
29enum {
30 NFSD_Root = 1,
31 NFSD_List,
32 NFSD_Export_features,
33 NFSD_Fh,
34 NFSD_FO_UnlockIP,
35 NFSD_FO_UnlockFS,
36 NFSD_Threads,
37 NFSD_Pool_Threads,
38 NFSD_Pool_Stats,
39 NFSD_Reply_Cache_Stats,
40 NFSD_Versions,
41 NFSD_Ports,
42 NFSD_MaxBlkSize,
43 NFSD_MaxConnections,
44 NFSD_SupportedEnctypes,
45
46
47
48
49#ifdef CONFIG_NFSD_V4
50 NFSD_Leasetime,
51 NFSD_Gracetime,
52 NFSD_RecoveryDir,
53 NFSD_V4EndGrace,
54#endif
55};
56
57
58
59
60static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
61static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
62static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
63static ssize_t write_threads(struct file *file, char *buf, size_t size);
64static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
65static ssize_t write_versions(struct file *file, char *buf, size_t size);
66static ssize_t write_ports(struct file *file, char *buf, size_t size);
67static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
68static ssize_t write_maxconn(struct file *file, char *buf, size_t size);
69#ifdef CONFIG_NFSD_V4
70static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
71static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
72static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
73static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
74#endif
75
76static ssize_t (*write_op[])(struct file *, char *, size_t) = {
77 [NFSD_Fh] = write_filehandle,
78 [NFSD_FO_UnlockIP] = write_unlock_ip,
79 [NFSD_FO_UnlockFS] = write_unlock_fs,
80 [NFSD_Threads] = write_threads,
81 [NFSD_Pool_Threads] = write_pool_threads,
82 [NFSD_Versions] = write_versions,
83 [NFSD_Ports] = write_ports,
84 [NFSD_MaxBlkSize] = write_maxblksize,
85 [NFSD_MaxConnections] = write_maxconn,
86#ifdef CONFIG_NFSD_V4
87 [NFSD_Leasetime] = write_leasetime,
88 [NFSD_Gracetime] = write_gracetime,
89 [NFSD_RecoveryDir] = write_recoverydir,
90 [NFSD_V4EndGrace] = write_v4_end_grace,
91#endif
92};
93
94static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
95{
96 ino_t ino = file_inode(file)->i_ino;
97 char *data;
98 ssize_t rv;
99
100 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
101 return -EINVAL;
102
103 data = simple_transaction_get(file, buf, size);
104 if (IS_ERR(data))
105 return PTR_ERR(data);
106
107 rv = write_op[ino](file, data, size);
108 if (rv >= 0) {
109 simple_transaction_set(file, rv);
110 rv = size;
111 }
112 return rv;
113}
114
115static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
116{
117 if (! file->private_data) {
118
119
120
121
122 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
123 if (rv < 0)
124 return rv;
125 }
126 return simple_transaction_read(file, buf, size, pos);
127}
128
129static const struct file_operations transaction_ops = {
130 .write = nfsctl_transaction_write,
131 .read = nfsctl_transaction_read,
132 .release = simple_transaction_release,
133 .llseek = default_llseek,
134};
135
136static int exports_net_open(struct net *net, struct file *file)
137{
138 int err;
139 struct seq_file *seq;
140 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
141
142 err = seq_open(file, &nfs_exports_op);
143 if (err)
144 return err;
145
146 seq = file->private_data;
147 seq->private = nn->svc_export_cache;
148 return 0;
149}
150
151static int exports_proc_open(struct inode *inode, struct file *file)
152{
153 return exports_net_open(current->nsproxy->net_ns, file);
154}
155
156static const struct file_operations exports_proc_operations = {
157 .open = exports_proc_open,
158 .read = seq_read,
159 .llseek = seq_lseek,
160 .release = seq_release,
161 .owner = THIS_MODULE,
162};
163
164static int exports_nfsd_open(struct inode *inode, struct file *file)
165{
166 return exports_net_open(inode->i_sb->s_fs_info, file);
167}
168
169static const struct file_operations exports_nfsd_operations = {
170 .open = exports_nfsd_open,
171 .read = seq_read,
172 .llseek = seq_lseek,
173 .release = seq_release,
174 .owner = THIS_MODULE,
175};
176
177static int export_features_show(struct seq_file *m, void *v)
178{
179 seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
180 return 0;
181}
182
183static int export_features_open(struct inode *inode, struct file *file)
184{
185 return single_open(file, export_features_show, NULL);
186}
187
188static const struct file_operations export_features_operations = {
189 .open = export_features_open,
190 .read = seq_read,
191 .llseek = seq_lseek,
192 .release = single_release,
193};
194
195#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
196static int supported_enctypes_show(struct seq_file *m, void *v)
197{
198 seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
199 return 0;
200}
201
202static int supported_enctypes_open(struct inode *inode, struct file *file)
203{
204 return single_open(file, supported_enctypes_show, NULL);
205}
206
207static const struct file_operations supported_enctypes_ops = {
208 .open = supported_enctypes_open,
209 .read = seq_read,
210 .llseek = seq_lseek,
211 .release = single_release,
212};
213#endif
214
215static const struct file_operations pool_stats_operations = {
216 .open = nfsd_pool_stats_open,
217 .read = seq_read,
218 .llseek = seq_lseek,
219 .release = nfsd_pool_stats_release,
220 .owner = THIS_MODULE,
221};
222
223static struct file_operations reply_cache_stats_operations = {
224 .open = nfsd_reply_cache_stats_open,
225 .read = seq_read,
226 .llseek = seq_lseek,
227 .release = single_release,
228};
229
230
231
232
233
234
235static inline struct net *netns(struct file *file)
236{
237 return file_inode(file)->i_sb->s_fs_info;
238}
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
255{
256 struct sockaddr_storage address;
257 struct sockaddr *sap = (struct sockaddr *)&address;
258 size_t salen = sizeof(address);
259 char *fo_path;
260 struct net *net = netns(file);
261
262
263 if (size == 0)
264 return -EINVAL;
265
266 if (buf[size-1] != '\n')
267 return -EINVAL;
268
269 fo_path = buf;
270 if (qword_get(&buf, fo_path, size) < 0)
271 return -EINVAL;
272
273 if (rpc_pton(net, fo_path, size, sap, salen) == 0)
274 return -EINVAL;
275
276 return nlmsvc_unlock_all_by_ip(sap);
277}
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
294{
295 struct path path;
296 char *fo_path;
297 int error;
298
299
300 if (size == 0)
301 return -EINVAL;
302
303 if (buf[size-1] != '\n')
304 return -EINVAL;
305
306 fo_path = buf;
307 if (qword_get(&buf, fo_path, size) < 0)
308 return -EINVAL;
309
310 error = kern_path(fo_path, 0, &path);
311 if (error)
312 return error;
313
314
315
316
317
318
319
320
321
322
323 error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
324
325 path_put(&path);
326 return error;
327}
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
351{
352 char *dname, *path;
353 int uninitialized_var(maxsize);
354 char *mesg = buf;
355 int len;
356 struct auth_domain *dom;
357 struct knfsd_fh fh;
358
359 if (size == 0)
360 return -EINVAL;
361
362 if (buf[size-1] != '\n')
363 return -EINVAL;
364 buf[size-1] = 0;
365
366 dname = mesg;
367 len = qword_get(&mesg, dname, size);
368 if (len <= 0)
369 return -EINVAL;
370
371 path = dname+len+1;
372 len = qword_get(&mesg, path, size);
373 if (len <= 0)
374 return -EINVAL;
375
376 len = get_int(&mesg, &maxsize);
377 if (len)
378 return len;
379
380 if (maxsize < NFS_FHSIZE)
381 return -EINVAL;
382 maxsize = min(maxsize, NFS3_FHSIZE);
383
384 if (qword_get(&mesg, mesg, size)>0)
385 return -EINVAL;
386
387
388 dom = unix_domain_find(dname);
389 if (!dom)
390 return -ENOMEM;
391
392 len = exp_rootfh(netns(file), dom, path, &fh, maxsize);
393 auth_domain_put(dom);
394 if (len)
395 return len;
396
397 mesg = buf;
398 len = SIMPLE_TRANSACTION_LIMIT;
399 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
400 mesg[-1] = '\n';
401 return mesg - buf;
402}
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432static ssize_t write_threads(struct file *file, char *buf, size_t size)
433{
434 char *mesg = buf;
435 int rv;
436 struct net *net = netns(file);
437
438 if (size > 0) {
439 int newthreads;
440 rv = get_int(&mesg, &newthreads);
441 if (rv)
442 return rv;
443 if (newthreads < 0)
444 return -EINVAL;
445 rv = nfsd_svc(newthreads, net);
446 if (rv < 0)
447 return rv;
448 } else
449 rv = nfsd_nrthreads(net);
450
451 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
452}
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
477{
478
479
480
481 char *mesg = buf;
482 int i;
483 int rv;
484 int len;
485 int npools;
486 int *nthreads;
487 struct net *net = netns(file);
488
489 mutex_lock(&nfsd_mutex);
490 npools = nfsd_nrpools(net);
491 if (npools == 0) {
492
493
494
495
496
497 mutex_unlock(&nfsd_mutex);
498 strcpy(buf, "0\n");
499 return strlen(buf);
500 }
501
502 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
503 rv = -ENOMEM;
504 if (nthreads == NULL)
505 goto out_free;
506
507 if (size > 0) {
508 for (i = 0; i < npools; i++) {
509 rv = get_int(&mesg, &nthreads[i]);
510 if (rv == -ENOENT)
511 break;
512 if (rv)
513 goto out_free;
514 rv = -EINVAL;
515 if (nthreads[i] < 0)
516 goto out_free;
517 }
518 rv = nfsd_set_nrthreads(i, nthreads, net);
519 if (rv)
520 goto out_free;
521 }
522
523 rv = nfsd_get_nrthreads(npools, nthreads, net);
524 if (rv)
525 goto out_free;
526
527 mesg = buf;
528 size = SIMPLE_TRANSACTION_LIMIT;
529 for (i = 0; i < npools && size > 0; i++) {
530 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
531 len = strlen(mesg);
532 size -= len;
533 mesg += len;
534 }
535 rv = mesg - buf;
536out_free:
537 kfree(nthreads);
538 mutex_unlock(&nfsd_mutex);
539 return rv;
540}
541
542static ssize_t __write_versions(struct file *file, char *buf, size_t size)
543{
544 char *mesg = buf;
545 char *vers, *minorp, sign;
546 int len, num, remaining;
547 unsigned minor;
548 ssize_t tlen = 0;
549 char *sep;
550 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
551
552 if (size>0) {
553 if (nn->nfsd_serv)
554
555
556
557
558 return -EBUSY;
559 if (buf[size-1] != '\n')
560 return -EINVAL;
561 buf[size-1] = 0;
562
563 vers = mesg;
564 len = qword_get(&mesg, vers, size);
565 if (len <= 0) return -EINVAL;
566 do {
567 sign = *vers;
568 if (sign == '+' || sign == '-')
569 num = simple_strtol((vers+1), &minorp, 0);
570 else
571 num = simple_strtol(vers, &minorp, 0);
572 if (*minorp == '.') {
573 if (num != 4)
574 return -EINVAL;
575 minor = simple_strtoul(minorp+1, NULL, 0);
576 if (minor == 0)
577 return -EINVAL;
578 if (nfsd_minorversion(minor, sign == '-' ?
579 NFSD_CLEAR : NFSD_SET) < 0)
580 return -EINVAL;
581 goto next;
582 }
583 switch(num) {
584 case 2:
585 case 3:
586 case 4:
587 nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
588 break;
589 default:
590 return -EINVAL;
591 }
592 next:
593 vers += len + 1;
594 } while ((len = qword_get(&mesg, vers, size)) > 0);
595
596
597
598 nfsd_reset_versions();
599 }
600
601
602 len = 0;
603 sep = "";
604 remaining = SIMPLE_TRANSACTION_LIMIT;
605 for (num=2 ; num <= 4 ; num++)
606 if (nfsd_vers(num, NFSD_AVAIL)) {
607 len = snprintf(buf, remaining, "%s%c%d", sep,
608 nfsd_vers(num, NFSD_TEST)?'+':'-',
609 num);
610 sep = " ";
611
612 if (len >= remaining)
613 break;
614 remaining -= len;
615 buf += len;
616 tlen += len;
617 }
618 if (nfsd_vers(4, NFSD_AVAIL))
619 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
620 minor++) {
621 len = snprintf(buf, remaining, " %c4.%u",
622 (nfsd_vers(4, NFSD_TEST) &&
623 nfsd_minorversion(minor, NFSD_TEST)) ?
624 '+' : '-',
625 minor);
626
627 if (len >= remaining)
628 break;
629 remaining -= len;
630 buf += len;
631 tlen += len;
632 }
633
634 len = snprintf(buf, remaining, "\n");
635 if (len >= remaining)
636 return -EINVAL;
637 return tlen + len;
638}
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672static ssize_t write_versions(struct file *file, char *buf, size_t size)
673{
674 ssize_t rv;
675
676 mutex_lock(&nfsd_mutex);
677 rv = __write_versions(file, buf, size);
678 mutex_unlock(&nfsd_mutex);
679 return rv;
680}
681
682
683
684
685
686static ssize_t __write_ports_names(char *buf, struct net *net)
687{
688 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
689
690 if (nn->nfsd_serv == NULL)
691 return 0;
692 return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
693}
694
695
696
697
698
699
700static ssize_t __write_ports_addfd(char *buf, struct net *net)
701{
702 char *mesg = buf;
703 int fd, err;
704 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
705
706 err = get_int(&mesg, &fd);
707 if (err != 0 || fd < 0)
708 return -EINVAL;
709
710 if (svc_alien_sock(net, fd)) {
711 printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
712 return -EINVAL;
713 }
714
715 err = nfsd_create_serv(net);
716 if (err != 0)
717 return err;
718
719 err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
720 if (err < 0) {
721 nfsd_destroy(net);
722 return err;
723 }
724
725
726 nn->nfsd_serv->sv_nrthreads--;
727 return err;
728}
729
730
731
732
733
734static ssize_t __write_ports_addxprt(char *buf, struct net *net)
735{
736 char transport[16];
737 struct svc_xprt *xprt;
738 int port, err;
739 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
740
741 if (sscanf(buf, "%15s %5u", transport, &port) != 2)
742 return -EINVAL;
743
744 if (port < 1 || port > USHRT_MAX)
745 return -EINVAL;
746
747 err = nfsd_create_serv(net);
748 if (err != 0)
749 return err;
750
751 err = svc_create_xprt(nn->nfsd_serv, transport, net,
752 PF_INET, port, SVC_SOCK_ANONYMOUS);
753 if (err < 0)
754 goto out_err;
755
756 err = svc_create_xprt(nn->nfsd_serv, transport, net,
757 PF_INET6, port, SVC_SOCK_ANONYMOUS);
758 if (err < 0 && err != -EAFNOSUPPORT)
759 goto out_close;
760
761
762 nn->nfsd_serv->sv_nrthreads--;
763 return 0;
764out_close:
765 xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port);
766 if (xprt != NULL) {
767 svc_close_xprt(xprt);
768 svc_xprt_put(xprt);
769 }
770out_err:
771 nfsd_destroy(net);
772 return err;
773}
774
775static ssize_t __write_ports(struct file *file, char *buf, size_t size,
776 struct net *net)
777{
778 if (size == 0)
779 return __write_ports_names(buf, net);
780
781 if (isdigit(buf[0]))
782 return __write_ports_addfd(buf, net);
783
784 if (isalpha(buf[0]))
785 return __write_ports_addxprt(buf, net);
786
787 return -EINVAL;
788}
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833static ssize_t write_ports(struct file *file, char *buf, size_t size)
834{
835 ssize_t rv;
836
837 mutex_lock(&nfsd_mutex);
838 rv = __write_ports(file, buf, size, netns(file));
839 mutex_unlock(&nfsd_mutex);
840 return rv;
841}
842
843
844int nfsd_max_blksize;
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
868{
869 char *mesg = buf;
870 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
871
872 if (size > 0) {
873 int bsize;
874 int rv = get_int(&mesg, &bsize);
875 if (rv)
876 return rv;
877
878
879
880 bsize = max_t(int, bsize, 1024);
881 bsize = min_t(int, bsize, NFSSVC_MAXBLKSIZE);
882 bsize &= ~(1024-1);
883 mutex_lock(&nfsd_mutex);
884 if (nn->nfsd_serv) {
885 mutex_unlock(&nfsd_mutex);
886 return -EBUSY;
887 }
888 nfsd_max_blksize = bsize;
889 mutex_unlock(&nfsd_mutex);
890 }
891
892 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
893 nfsd_max_blksize);
894}
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
917{
918 char *mesg = buf;
919 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
920 unsigned int maxconn = nn->max_connections;
921
922 if (size > 0) {
923 int rv = get_uint(&mesg, &maxconn);
924
925 if (rv)
926 return rv;
927 nn->max_connections = maxconn;
928 }
929
930 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%u\n", maxconn);
931}
932
933#ifdef CONFIG_NFSD_V4
934static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
935 time_t *time, struct nfsd_net *nn)
936{
937 char *mesg = buf;
938 int rv, i;
939
940 if (size > 0) {
941 if (nn->nfsd_serv)
942 return -EBUSY;
943 rv = get_int(&mesg, &i);
944 if (rv)
945 return rv;
946
947
948
949
950
951
952
953
954
955
956
957
958 if (i < 10 || i > 3600)
959 return -EINVAL;
960 *time = i;
961 }
962
963 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
964}
965
966static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
967 time_t *time, struct nfsd_net *nn)
968{
969 ssize_t rv;
970
971 mutex_lock(&nfsd_mutex);
972 rv = __nfsd4_write_time(file, buf, size, time, nn);
973 mutex_unlock(&nfsd_mutex);
974 return rv;
975}
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
999{
1000 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
1001 return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
1002}
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
1015{
1016 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
1017 return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
1018}
1019
1020static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
1021 struct nfsd_net *nn)
1022{
1023 char *mesg = buf;
1024 char *recdir;
1025 int len, status;
1026
1027 if (size > 0) {
1028 if (nn->nfsd_serv)
1029 return -EBUSY;
1030 if (size > PATH_MAX || buf[size-1] != '\n')
1031 return -EINVAL;
1032 buf[size-1] = 0;
1033
1034 recdir = mesg;
1035 len = qword_get(&mesg, recdir, size);
1036 if (len <= 0)
1037 return -EINVAL;
1038
1039 status = nfs4_reset_recoverydir(recdir);
1040 if (status)
1041 return status;
1042 }
1043
1044 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1045 nfs4_recoverydir());
1046}
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1070{
1071 ssize_t rv;
1072 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
1073
1074 mutex_lock(&nfsd_mutex);
1075 rv = __write_recoverydir(file, buf, size, nn);
1076 mutex_unlock(&nfsd_mutex);
1077 return rv;
1078}
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
1101{
1102 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
1103
1104 if (size > 0) {
1105 switch(buf[0]) {
1106 case 'Y':
1107 case 'y':
1108 case '1':
1109 nfsd4_end_grace(nn);
1110 break;
1111 default:
1112 return -EINVAL;
1113 }
1114 }
1115
1116 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%c\n",
1117 nn->grace_ended ? 'Y' : 'N');
1118}
1119
1120#endif
1121
1122
1123
1124
1125
1126
1127static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1128{
1129 static struct tree_descr nfsd_files[] = {
1130 [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
1131 [NFSD_Export_features] = {"export_features",
1132 &export_features_operations, S_IRUGO},
1133 [NFSD_FO_UnlockIP] = {"unlock_ip",
1134 &transaction_ops, S_IWUSR|S_IRUSR},
1135 [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1136 &transaction_ops, S_IWUSR|S_IRUSR},
1137 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1138 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
1139 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
1140 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
1141 [NFSD_Reply_Cache_Stats] = {"reply_cache_stats", &reply_cache_stats_operations, S_IRUGO},
1142 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
1143 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
1144 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
1145 [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
1146#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
1147 [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
1148#endif
1149#ifdef CONFIG_NFSD_V4
1150 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
1151 [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
1152 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1153 [NFSD_V4EndGrace] = {"v4_end_grace", &transaction_ops, S_IWUSR|S_IRUGO},
1154#endif
1155 {""}
1156 };
1157 struct net *net = data;
1158 int ret;
1159
1160 ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
1161 if (ret)
1162 return ret;
1163 sb->s_fs_info = get_net(net);
1164 return 0;
1165}
1166
1167static struct dentry *nfsd_mount(struct file_system_type *fs_type,
1168 int flags, const char *dev_name, void *data)
1169{
1170 return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super);
1171}
1172
1173static void nfsd_umount(struct super_block *sb)
1174{
1175 struct net *net = sb->s_fs_info;
1176
1177 kill_litter_super(sb);
1178 put_net(net);
1179}
1180
1181static struct file_system_type nfsd_fs_type = {
1182 .owner = THIS_MODULE,
1183 .name = "nfsd",
1184 .mount = nfsd_mount,
1185 .kill_sb = nfsd_umount,
1186};
1187MODULE_ALIAS_FS("nfsd");
1188
1189#ifdef CONFIG_PROC_FS
1190static int create_proc_exports_entry(void)
1191{
1192 struct proc_dir_entry *entry;
1193
1194 entry = proc_mkdir("fs/nfs", NULL);
1195 if (!entry)
1196 return -ENOMEM;
1197 entry = proc_create("exports", 0, entry,
1198 &exports_proc_operations);
1199 if (!entry) {
1200 remove_proc_entry("fs/nfs", NULL);
1201 return -ENOMEM;
1202 }
1203 return 0;
1204}
1205#else
1206static int create_proc_exports_entry(void)
1207{
1208 return 0;
1209}
1210#endif
1211
1212int nfsd_net_id;
1213
1214static __net_init int nfsd_init_net(struct net *net)
1215{
1216 int retval;
1217 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1218
1219 retval = nfsd_export_init(net);
1220 if (retval)
1221 goto out_export_error;
1222 retval = nfsd_idmap_init(net);
1223 if (retval)
1224 goto out_idmap_error;
1225 nn->nfsd4_lease = 90;
1226 nn->nfsd4_grace = 90;
1227 return 0;
1228
1229out_idmap_error:
1230 nfsd_export_shutdown(net);
1231out_export_error:
1232 return retval;
1233}
1234
1235static __net_exit void nfsd_exit_net(struct net *net)
1236{
1237 nfsd_idmap_shutdown(net);
1238 nfsd_export_shutdown(net);
1239}
1240
1241static struct pernet_operations nfsd_net_ops = {
1242 .init = nfsd_init_net,
1243 .exit = nfsd_exit_net,
1244 .id = &nfsd_net_id,
1245 .size = sizeof(struct nfsd_net),
1246};
1247
1248static int __init init_nfsd(void)
1249{
1250 int retval;
1251 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1252
1253 retval = register_pernet_subsys(&nfsd_net_ops);
1254 if (retval < 0)
1255 return retval;
1256 retval = register_cld_notifier();
1257 if (retval)
1258 goto out_unregister_pernet;
1259 retval = nfsd4_init_slabs();
1260 if (retval)
1261 goto out_unregister_notifier;
1262 retval = nfsd4_init_pnfs();
1263 if (retval)
1264 goto out_free_slabs;
1265 retval = nfsd_fault_inject_init();
1266 if (retval)
1267 goto out_exit_pnfs;
1268 nfsd_stat_init();
1269 retval = nfsd_reply_cache_init();
1270 if (retval)
1271 goto out_free_stat;
1272 nfsd_lockd_init();
1273 retval = create_proc_exports_entry();
1274 if (retval)
1275 goto out_free_lockd;
1276 retval = register_filesystem(&nfsd_fs_type);
1277 if (retval)
1278 goto out_free_all;
1279 return 0;
1280out_free_all:
1281 remove_proc_entry("fs/nfs/exports", NULL);
1282 remove_proc_entry("fs/nfs", NULL);
1283out_free_lockd:
1284 nfsd_lockd_shutdown();
1285 nfsd_reply_cache_shutdown();
1286out_free_stat:
1287 nfsd_stat_shutdown();
1288 nfsd_fault_inject_cleanup();
1289out_exit_pnfs:
1290 nfsd4_exit_pnfs();
1291out_free_slabs:
1292 nfsd4_free_slabs();
1293out_unregister_notifier:
1294 unregister_cld_notifier();
1295out_unregister_pernet:
1296 unregister_pernet_subsys(&nfsd_net_ops);
1297 return retval;
1298}
1299
1300static void __exit exit_nfsd(void)
1301{
1302 nfsd_reply_cache_shutdown();
1303 remove_proc_entry("fs/nfs/exports", NULL);
1304 remove_proc_entry("fs/nfs", NULL);
1305 nfsd_stat_shutdown();
1306 nfsd_lockd_shutdown();
1307 nfsd4_free_slabs();
1308 nfsd4_exit_pnfs();
1309 nfsd_fault_inject_cleanup();
1310 unregister_filesystem(&nfsd_fs_type);
1311 unregister_cld_notifier();
1312 unregister_pernet_subsys(&nfsd_net_ops);
1313}
1314
1315MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1316MODULE_LICENSE("GPL");
1317module_init(init_nfsd)
1318module_exit(exit_nfsd)
1319