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