1
2
3
4
5
6
7
8
9#include <linux/module.h>
10
11#include <linux/linkage.h>
12#include <linux/time.h>
13#include <linux/errno.h>
14#include <linux/fs.h>
15#include <linux/namei.h>
16#include <linux/fcntl.h>
17#include <linux/net.h>
18#include <linux/in.h>
19#include <linux/syscalls.h>
20#include <linux/unistd.h>
21#include <linux/slab.h>
22#include <linux/proc_fs.h>
23#include <linux/seq_file.h>
24#include <linux/pagemap.h>
25#include <linux/init.h>
26#include <linux/inet.h>
27#include <linux/string.h>
28#include <linux/ctype.h>
29
30#include <linux/nfs.h>
31#include <linux/nfsd_idmap.h>
32#include <linux/lockd/bind.h>
33#include <linux/sunrpc/svc.h>
34#include <linux/sunrpc/svcsock.h>
35#include <linux/nfsd/nfsd.h>
36#include <linux/nfsd/cache.h>
37#include <linux/nfsd/xdr.h>
38#include <linux/nfsd/syscall.h>
39#include <linux/lockd/lockd.h>
40#include <linux/sunrpc/clnt.h>
41
42#include <asm/uaccess.h>
43#include <net/ipv6.h>
44
45
46
47
48enum {
49 NFSD_Root = 1,
50 NFSD_Svc,
51 NFSD_Add,
52 NFSD_Del,
53 NFSD_Export,
54 NFSD_Unexport,
55 NFSD_Getfd,
56 NFSD_Getfs,
57 NFSD_List,
58 NFSD_Fh,
59 NFSD_FO_UnlockIP,
60 NFSD_FO_UnlockFS,
61 NFSD_Threads,
62 NFSD_Pool_Threads,
63 NFSD_Pool_Stats,
64 NFSD_Versions,
65 NFSD_Ports,
66 NFSD_MaxBlkSize,
67
68
69
70
71#ifdef CONFIG_NFSD_V4
72 NFSD_Leasetime,
73 NFSD_RecoveryDir,
74#endif
75};
76
77
78
79
80static ssize_t write_svc(struct file *file, char *buf, size_t size);
81static ssize_t write_add(struct file *file, char *buf, size_t size);
82static ssize_t write_del(struct file *file, char *buf, size_t size);
83static ssize_t write_export(struct file *file, char *buf, size_t size);
84static ssize_t write_unexport(struct file *file, char *buf, size_t size);
85static ssize_t write_getfd(struct file *file, char *buf, size_t size);
86static ssize_t write_getfs(struct file *file, char *buf, size_t size);
87static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
88static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
89static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
90static ssize_t write_threads(struct file *file, char *buf, size_t size);
91static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
92static ssize_t write_versions(struct file *file, char *buf, size_t size);
93static ssize_t write_ports(struct file *file, char *buf, size_t size);
94static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
95#ifdef CONFIG_NFSD_V4
96static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
97static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
98#endif
99
100static ssize_t (*write_op[])(struct file *, char *, size_t) = {
101 [NFSD_Svc] = write_svc,
102 [NFSD_Add] = write_add,
103 [NFSD_Del] = write_del,
104 [NFSD_Export] = write_export,
105 [NFSD_Unexport] = write_unexport,
106 [NFSD_Getfd] = write_getfd,
107 [NFSD_Getfs] = write_getfs,
108 [NFSD_Fh] = write_filehandle,
109 [NFSD_FO_UnlockIP] = write_unlock_ip,
110 [NFSD_FO_UnlockFS] = write_unlock_fs,
111 [NFSD_Threads] = write_threads,
112 [NFSD_Pool_Threads] = write_pool_threads,
113 [NFSD_Versions] = write_versions,
114 [NFSD_Ports] = write_ports,
115 [NFSD_MaxBlkSize] = write_maxblksize,
116#ifdef CONFIG_NFSD_V4
117 [NFSD_Leasetime] = write_leasetime,
118 [NFSD_RecoveryDir] = write_recoverydir,
119#endif
120};
121
122static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
123{
124 ino_t ino = file->f_path.dentry->d_inode->i_ino;
125 char *data;
126 ssize_t rv;
127
128 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
129 return -EINVAL;
130
131 data = simple_transaction_get(file, buf, size);
132 if (IS_ERR(data))
133 return PTR_ERR(data);
134
135 rv = write_op[ino](file, data, size);
136 if (rv >= 0) {
137 simple_transaction_set(file, rv);
138 rv = size;
139 }
140 return rv;
141}
142
143static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
144{
145 if (! file->private_data) {
146
147
148
149
150 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
151 if (rv < 0)
152 return rv;
153 }
154 return simple_transaction_read(file, buf, size, pos);
155}
156
157static const struct file_operations transaction_ops = {
158 .write = nfsctl_transaction_write,
159 .read = nfsctl_transaction_read,
160 .release = simple_transaction_release,
161};
162
163static int exports_open(struct inode *inode, struct file *file)
164{
165 return seq_open(file, &nfs_exports_op);
166}
167
168static const struct file_operations exports_operations = {
169 .open = exports_open,
170 .read = seq_read,
171 .llseek = seq_lseek,
172 .release = seq_release,
173 .owner = THIS_MODULE,
174};
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
207
208static ssize_t write_svc(struct file *file, char *buf, size_t size)
209{
210 struct nfsctl_svc *data;
211 int err;
212 if (size < sizeof(*data))
213 return -EINVAL;
214 data = (struct nfsctl_svc*) buf;
215 err = nfsd_svc(data->svc_port, data->svc_nthreads);
216 if (err < 0)
217 return err;
218 return 0;
219}
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245static ssize_t write_add(struct file *file, char *buf, size_t size)
246{
247 struct nfsctl_client *data;
248 if (size < sizeof(*data))
249 return -EINVAL;
250 data = (struct nfsctl_client *)buf;
251 return exp_addclient(data);
252}
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278static ssize_t write_del(struct file *file, char *buf, size_t size)
279{
280 struct nfsctl_client *data;
281 if (size < sizeof(*data))
282 return -EINVAL;
283 data = (struct nfsctl_client *)buf;
284 return exp_delclient(data);
285}
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314static ssize_t write_export(struct file *file, char *buf, size_t size)
315{
316 struct nfsctl_export *data;
317 if (size < sizeof(*data))
318 return -EINVAL;
319 data = (struct nfsctl_export*)buf;
320 return exp_export(data);
321}
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348static ssize_t write_unexport(struct file *file, char *buf, size_t size)
349{
350 struct nfsctl_export *data;
351
352 if (size < sizeof(*data))
353 return -EINVAL;
354 data = (struct nfsctl_export*)buf;
355 return exp_unexport(data);
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
382static ssize_t write_getfs(struct file *file, char *buf, size_t size)
383{
384 struct nfsctl_fsparm *data;
385 struct sockaddr_in *sin;
386 struct auth_domain *clp;
387 int err = 0;
388 struct knfsd_fh *res;
389 struct in6_addr in6;
390
391 if (size < sizeof(*data))
392 return -EINVAL;
393 data = (struct nfsctl_fsparm*)buf;
394 err = -EPROTONOSUPPORT;
395 if (data->gd_addr.sa_family != AF_INET)
396 goto out;
397 sin = (struct sockaddr_in *)&data->gd_addr;
398 if (data->gd_maxlen > NFS3_FHSIZE)
399 data->gd_maxlen = NFS3_FHSIZE;
400
401 res = (struct knfsd_fh*)buf;
402
403 exp_readlock();
404
405 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
406
407 clp = auth_unix_lookup(&in6);
408 if (!clp)
409 err = -EPERM;
410 else {
411 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
412 auth_domain_put(clp);
413 }
414 exp_readunlock();
415 if (err == 0)
416 err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
417 out:
418 return err;
419}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444static ssize_t write_getfd(struct file *file, char *buf, size_t size)
445{
446 struct nfsctl_fdparm *data;
447 struct sockaddr_in *sin;
448 struct auth_domain *clp;
449 int err = 0;
450 struct knfsd_fh fh;
451 char *res;
452 struct in6_addr in6;
453
454 if (size < sizeof(*data))
455 return -EINVAL;
456 data = (struct nfsctl_fdparm*)buf;
457 err = -EPROTONOSUPPORT;
458 if (data->gd_addr.sa_family != AF_INET)
459 goto out;
460 err = -EINVAL;
461 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
462 goto out;
463
464 res = buf;
465 sin = (struct sockaddr_in *)&data->gd_addr;
466 exp_readlock();
467
468 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
469
470 clp = auth_unix_lookup(&in6);
471 if (!clp)
472 err = -EPERM;
473 else {
474 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
475 auth_domain_put(clp);
476 }
477 exp_readunlock();
478
479 if (err == 0) {
480 memset(res,0, NFS_FHSIZE);
481 memcpy(res, &fh.fh_base, fh.fh_size);
482 err = NFS_FHSIZE;
483 }
484 out:
485 return err;
486}
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
503{
504 struct sockaddr_storage address;
505 struct sockaddr *sap = (struct sockaddr *)&address;
506 size_t salen = sizeof(address);
507 char *fo_path;
508
509
510 if (size == 0)
511 return -EINVAL;
512
513 if (buf[size-1] != '\n')
514 return -EINVAL;
515
516 fo_path = buf;
517 if (qword_get(&buf, fo_path, size) < 0)
518 return -EINVAL;
519
520 if (rpc_pton(fo_path, size, sap, salen) == 0)
521 return -EINVAL;
522
523 return nlmsvc_unlock_all_by_ip(sap);
524}
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
541{
542 struct path path;
543 char *fo_path;
544 int error;
545
546
547 if (size == 0)
548 return -EINVAL;
549
550 if (buf[size-1] != '\n')
551 return -EINVAL;
552
553 fo_path = buf;
554 if (qword_get(&buf, fo_path, size) < 0)
555 return -EINVAL;
556
557 error = kern_path(fo_path, 0, &path);
558 if (error)
559 return error;
560
561
562
563
564
565
566
567
568
569
570 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
571
572 path_put(&path);
573 return error;
574}
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
598{
599 char *dname, *path;
600 int uninitialized_var(maxsize);
601 char *mesg = buf;
602 int len;
603 struct auth_domain *dom;
604 struct knfsd_fh fh;
605
606 if (size == 0)
607 return -EINVAL;
608
609 if (buf[size-1] != '\n')
610 return -EINVAL;
611 buf[size-1] = 0;
612
613 dname = mesg;
614 len = qword_get(&mesg, dname, size);
615 if (len <= 0)
616 return -EINVAL;
617
618 path = dname+len+1;
619 len = qword_get(&mesg, path, size);
620 if (len <= 0)
621 return -EINVAL;
622
623 len = get_int(&mesg, &maxsize);
624 if (len)
625 return len;
626
627 if (maxsize < NFS_FHSIZE)
628 return -EINVAL;
629 if (maxsize > NFS3_FHSIZE)
630 maxsize = NFS3_FHSIZE;
631
632 if (qword_get(&mesg, mesg, size)>0)
633 return -EINVAL;
634
635
636 dom = unix_domain_find(dname);
637 if (!dom)
638 return -ENOMEM;
639
640 len = exp_rootfh(dom, path, &fh, maxsize);
641 auth_domain_put(dom);
642 if (len)
643 return len;
644
645 mesg = buf;
646 len = SIMPLE_TRANSACTION_LIMIT;
647 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
648 mesg[-1] = '\n';
649 return mesg - buf;
650}
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680static ssize_t write_threads(struct file *file, char *buf, size_t size)
681{
682 char *mesg = buf;
683 int rv;
684 if (size > 0) {
685 int newthreads;
686 rv = get_int(&mesg, &newthreads);
687 if (rv)
688 return rv;
689 if (newthreads < 0)
690 return -EINVAL;
691 rv = nfsd_svc(NFS_PORT, newthreads);
692 if (rv < 0)
693 return rv;
694 } else
695 rv = nfsd_nrthreads();
696
697 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
698}
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
723{
724
725
726
727 char *mesg = buf;
728 int i;
729 int rv;
730 int len;
731 int npools;
732 int *nthreads;
733
734 mutex_lock(&nfsd_mutex);
735 npools = nfsd_nrpools();
736 if (npools == 0) {
737
738
739
740
741
742 mutex_unlock(&nfsd_mutex);
743 strcpy(buf, "0\n");
744 return strlen(buf);
745 }
746
747 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
748 rv = -ENOMEM;
749 if (nthreads == NULL)
750 goto out_free;
751
752 if (size > 0) {
753 for (i = 0; i < npools; i++) {
754 rv = get_int(&mesg, &nthreads[i]);
755 if (rv == -ENOENT)
756 break;
757 if (rv)
758 goto out_free;
759 rv = -EINVAL;
760 if (nthreads[i] < 0)
761 goto out_free;
762 }
763 rv = nfsd_set_nrthreads(i, nthreads);
764 if (rv)
765 goto out_free;
766 }
767
768 rv = nfsd_get_nrthreads(npools, nthreads);
769 if (rv)
770 goto out_free;
771
772 mesg = buf;
773 size = SIMPLE_TRANSACTION_LIMIT;
774 for (i = 0; i < npools && size > 0; i++) {
775 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
776 len = strlen(mesg);
777 size -= len;
778 mesg += len;
779 }
780 rv = mesg - buf;
781out_free:
782 kfree(nthreads);
783 mutex_unlock(&nfsd_mutex);
784 return rv;
785}
786
787static ssize_t __write_versions(struct file *file, char *buf, size_t size)
788{
789 char *mesg = buf;
790 char *vers, *minorp, sign;
791 int len, num, remaining;
792 unsigned minor;
793 ssize_t tlen = 0;
794 char *sep;
795
796 if (size>0) {
797 if (nfsd_serv)
798
799
800
801
802 return -EBUSY;
803 if (buf[size-1] != '\n')
804 return -EINVAL;
805 buf[size-1] = 0;
806
807 vers = mesg;
808 len = qword_get(&mesg, vers, size);
809 if (len <= 0) return -EINVAL;
810 do {
811 sign = *vers;
812 if (sign == '+' || sign == '-')
813 num = simple_strtol((vers+1), &minorp, 0);
814 else
815 num = simple_strtol(vers, &minorp, 0);
816 if (*minorp == '.') {
817 if (num < 4)
818 return -EINVAL;
819 minor = simple_strtoul(minorp+1, NULL, 0);
820 if (minor == 0)
821 return -EINVAL;
822 if (nfsd_minorversion(minor, sign == '-' ?
823 NFSD_CLEAR : NFSD_SET) < 0)
824 return -EINVAL;
825 goto next;
826 }
827 switch(num) {
828 case 2:
829 case 3:
830 case 4:
831 nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
832 break;
833 default:
834 return -EINVAL;
835 }
836 next:
837 vers += len + 1;
838 } while ((len = qword_get(&mesg, vers, size)) > 0);
839
840
841
842 nfsd_reset_versions();
843 }
844
845
846 len = 0;
847 sep = "";
848 remaining = SIMPLE_TRANSACTION_LIMIT;
849 for (num=2 ; num <= 4 ; num++)
850 if (nfsd_vers(num, NFSD_AVAIL)) {
851 len = snprintf(buf, remaining, "%s%c%d", sep,
852 nfsd_vers(num, NFSD_TEST)?'+':'-',
853 num);
854 sep = " ";
855
856 if (len > remaining)
857 break;
858 remaining -= len;
859 buf += len;
860 tlen += len;
861 }
862 if (nfsd_vers(4, NFSD_AVAIL))
863 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
864 minor++) {
865 len = snprintf(buf, remaining, " %c4.%u",
866 (nfsd_vers(4, NFSD_TEST) &&
867 nfsd_minorversion(minor, NFSD_TEST)) ?
868 '+' : '-',
869 minor);
870
871 if (len > remaining)
872 break;
873 remaining -= len;
874 buf += len;
875 tlen += len;
876 }
877
878 len = snprintf(buf, remaining, "\n");
879 if (len > remaining)
880 return -EINVAL;
881 return tlen + len;
882}
883
884
885
886
887
888
889
890
891
892
893
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_versions(struct file *file, char *buf, size_t size)
917{
918 ssize_t rv;
919
920 mutex_lock(&nfsd_mutex);
921 rv = __write_versions(file, buf, size);
922 mutex_unlock(&nfsd_mutex);
923 return rv;
924}
925
926
927
928
929
930static ssize_t __write_ports_names(char *buf)
931{
932 if (nfsd_serv == NULL)
933 return 0;
934 return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
935}
936
937
938
939
940
941
942static ssize_t __write_ports_addfd(char *buf)
943{
944 char *mesg = buf;
945 int fd, err;
946
947 err = get_int(&mesg, &fd);
948 if (err != 0 || fd < 0)
949 return -EINVAL;
950
951 err = nfsd_create_serv();
952 if (err != 0)
953 return err;
954
955 err = lockd_up();
956 if (err != 0)
957 goto out;
958
959 err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
960 if (err < 0)
961 lockd_down();
962
963out:
964
965 nfsd_serv->sv_nrthreads--;
966 return err;
967}
968
969
970
971
972static ssize_t __write_ports_delfd(char *buf)
973{
974 char *toclose;
975 int len = 0;
976
977 toclose = kstrdup(buf + 1, GFP_KERNEL);
978 if (toclose == NULL)
979 return -ENOMEM;
980
981 if (nfsd_serv != NULL)
982 len = svc_sock_names(nfsd_serv, buf,
983 SIMPLE_TRANSACTION_LIMIT, toclose);
984 if (len >= 0)
985 lockd_down();
986
987 kfree(toclose);
988 return len;
989}
990
991
992
993
994
995static ssize_t __write_ports_addxprt(char *buf)
996{
997 char transport[16];
998 int port, err;
999
1000 if (sscanf(buf, "%15s %4u", transport, &port) != 2)
1001 return -EINVAL;
1002
1003 if (port < 1 || port > USHORT_MAX)
1004 return -EINVAL;
1005
1006 err = nfsd_create_serv();
1007 if (err != 0)
1008 return err;
1009
1010 err = svc_create_xprt(nfsd_serv, transport,
1011 PF_INET, port, SVC_SOCK_ANONYMOUS);
1012 if (err < 0) {
1013
1014 if (err == -ENOENT)
1015 err = -EPROTONOSUPPORT;
1016 return err;
1017 }
1018 return 0;
1019}
1020
1021
1022
1023
1024
1025static ssize_t __write_ports_delxprt(char *buf)
1026{
1027 struct svc_xprt *xprt;
1028 char transport[16];
1029 int port;
1030
1031 if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
1032 return -EINVAL;
1033
1034 if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
1035 return -EINVAL;
1036
1037 xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
1038 if (xprt == NULL)
1039 return -ENOTCONN;
1040
1041 svc_close_xprt(xprt);
1042 svc_xprt_put(xprt);
1043 return 0;
1044}
1045
1046static ssize_t __write_ports(struct file *file, char *buf, size_t size)
1047{
1048 if (size == 0)
1049 return __write_ports_names(buf);
1050
1051 if (isdigit(buf[0]))
1052 return __write_ports_addfd(buf);
1053
1054 if (buf[0] == '-' && isdigit(buf[1]))
1055 return __write_ports_delfd(buf);
1056
1057 if (isalpha(buf[0]))
1058 return __write_ports_addxprt(buf);
1059
1060 if (buf[0] == '-' && isalpha(buf[1]))
1061 return __write_ports_delxprt(buf);
1062
1063 return -EINVAL;
1064}
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137static ssize_t write_ports(struct file *file, char *buf, size_t size)
1138{
1139 ssize_t rv;
1140
1141 mutex_lock(&nfsd_mutex);
1142 rv = __write_ports(file, buf, size);
1143 mutex_unlock(&nfsd_mutex);
1144 return rv;
1145}
1146
1147
1148int nfsd_max_blksize;
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
1172{
1173 char *mesg = buf;
1174 if (size > 0) {
1175 int bsize;
1176 int rv = get_int(&mesg, &bsize);
1177 if (rv)
1178 return rv;
1179
1180
1181
1182 if (bsize < 1024)
1183 bsize = 1024;
1184 if (bsize > NFSSVC_MAXBLKSIZE)
1185 bsize = NFSSVC_MAXBLKSIZE;
1186 bsize &= ~(1024-1);
1187 mutex_lock(&nfsd_mutex);
1188 if (nfsd_serv && nfsd_serv->sv_nrthreads) {
1189 mutex_unlock(&nfsd_mutex);
1190 return -EBUSY;
1191 }
1192 nfsd_max_blksize = bsize;
1193 mutex_unlock(&nfsd_mutex);
1194 }
1195
1196 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
1197 nfsd_max_blksize);
1198}
1199
1200#ifdef CONFIG_NFSD_V4
1201extern time_t nfs4_leasetime(void);
1202
1203static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
1204{
1205
1206
1207
1208 char *mesg = buf;
1209 int rv, lease;
1210
1211 if (size > 0) {
1212 if (nfsd_serv)
1213 return -EBUSY;
1214 rv = get_int(&mesg, &lease);
1215 if (rv)
1216 return rv;
1217 if (lease < 10 || lease > 3600)
1218 return -EINVAL;
1219 nfs4_reset_lease(lease);
1220 }
1221
1222 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n",
1223 nfs4_lease_time());
1224}
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
1248{
1249 ssize_t rv;
1250
1251 mutex_lock(&nfsd_mutex);
1252 rv = __write_leasetime(file, buf, size);
1253 mutex_unlock(&nfsd_mutex);
1254 return rv;
1255}
1256
1257extern char *nfs4_recoverydir(void);
1258
1259static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
1260{
1261 char *mesg = buf;
1262 char *recdir;
1263 int len, status;
1264
1265 if (size > 0) {
1266 if (nfsd_serv)
1267 return -EBUSY;
1268 if (size > PATH_MAX || buf[size-1] != '\n')
1269 return -EINVAL;
1270 buf[size-1] = 0;
1271
1272 recdir = mesg;
1273 len = qword_get(&mesg, recdir, size);
1274 if (len <= 0)
1275 return -EINVAL;
1276
1277 status = nfs4_reset_recoverydir(recdir);
1278 }
1279
1280 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1281 nfs4_recoverydir());
1282}
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1306{
1307 ssize_t rv;
1308
1309 mutex_lock(&nfsd_mutex);
1310 rv = __write_recoverydir(file, buf, size);
1311 mutex_unlock(&nfsd_mutex);
1312 return rv;
1313}
1314
1315#endif
1316
1317
1318
1319
1320
1321
1322static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1323{
1324 static struct tree_descr nfsd_files[] = {
1325 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
1326 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
1327 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
1328 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
1329 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
1330 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
1331 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
1332 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
1333 [NFSD_FO_UnlockIP] = {"unlock_ip",
1334 &transaction_ops, S_IWUSR|S_IRUSR},
1335 [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1336 &transaction_ops, S_IWUSR|S_IRUSR},
1337 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1338 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
1339 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
1340 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
1341 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
1342 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
1343 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
1344#ifdef CONFIG_NFSD_V4
1345 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
1346 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1347#endif
1348 {""}
1349 };
1350 return simple_fill_super(sb, 0x6e667364, nfsd_files);
1351}
1352
1353static int nfsd_get_sb(struct file_system_type *fs_type,
1354 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
1355{
1356 return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt);
1357}
1358
1359static struct file_system_type nfsd_fs_type = {
1360 .owner = THIS_MODULE,
1361 .name = "nfsd",
1362 .get_sb = nfsd_get_sb,
1363 .kill_sb = kill_litter_super,
1364};
1365
1366#ifdef CONFIG_PROC_FS
1367static int create_proc_exports_entry(void)
1368{
1369 struct proc_dir_entry *entry;
1370
1371 entry = proc_mkdir("fs/nfs", NULL);
1372 if (!entry)
1373 return -ENOMEM;
1374 entry = proc_create("exports", 0, entry, &exports_operations);
1375 if (!entry)
1376 return -ENOMEM;
1377 return 0;
1378}
1379#else
1380static int create_proc_exports_entry(void)
1381{
1382 return 0;
1383}
1384#endif
1385
1386static int __init init_nfsd(void)
1387{
1388 int retval;
1389 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1390
1391 retval = nfs4_state_init();
1392 if (retval)
1393 return retval;
1394 nfsd_stat_init();
1395 retval = nfsd_reply_cache_init();
1396 if (retval)
1397 goto out_free_stat;
1398 retval = nfsd_export_init();
1399 if (retval)
1400 goto out_free_cache;
1401 nfsd_lockd_init();
1402 retval = nfsd_idmap_init();
1403 if (retval)
1404 goto out_free_lockd;
1405 retval = create_proc_exports_entry();
1406 if (retval)
1407 goto out_free_idmap;
1408 retval = register_filesystem(&nfsd_fs_type);
1409 if (retval)
1410 goto out_free_all;
1411 return 0;
1412out_free_all:
1413 remove_proc_entry("fs/nfs/exports", NULL);
1414 remove_proc_entry("fs/nfs", NULL);
1415out_free_idmap:
1416 nfsd_idmap_shutdown();
1417out_free_lockd:
1418 nfsd_lockd_shutdown();
1419 nfsd_export_shutdown();
1420out_free_cache:
1421 nfsd_reply_cache_shutdown();
1422out_free_stat:
1423 nfsd_stat_shutdown();
1424 nfsd4_free_slabs();
1425 return retval;
1426}
1427
1428static void __exit exit_nfsd(void)
1429{
1430 nfsd_export_shutdown();
1431 nfsd_reply_cache_shutdown();
1432 remove_proc_entry("fs/nfs/exports", NULL);
1433 remove_proc_entry("fs/nfs", NULL);
1434 nfsd_stat_shutdown();
1435 nfsd_lockd_shutdown();
1436 nfsd_idmap_shutdown();
1437 nfsd4_free_slabs();
1438 unregister_filesystem(&nfsd_fs_type);
1439}
1440
1441MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1442MODULE_LICENSE("GPL");
1443module_init(init_nfsd)
1444module_exit(exit_nfsd)
1445