diff options
Diffstat (limited to 'fs/nfsd/nfsctl.c')
-rw-r--r-- | fs/nfsd/nfsctl.c | 294 |
1 files changed, 181 insertions, 113 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index af16849d243a..1250fb978ac1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -207,10 +207,14 @@ static struct file_operations pool_stats_operations = { | |||
207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) | 207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) |
208 | { | 208 | { |
209 | struct nfsctl_svc *data; | 209 | struct nfsctl_svc *data; |
210 | int err; | ||
210 | if (size < sizeof(*data)) | 211 | if (size < sizeof(*data)) |
211 | return -EINVAL; | 212 | return -EINVAL; |
212 | data = (struct nfsctl_svc*) buf; | 213 | data = (struct nfsctl_svc*) buf; |
213 | return nfsd_svc(data->svc_port, data->svc_nthreads); | 214 | err = nfsd_svc(data->svc_port, data->svc_nthreads); |
215 | if (err < 0) | ||
216 | return err; | ||
217 | return 0; | ||
214 | } | 218 | } |
215 | 219 | ||
216 | /** | 220 | /** |
@@ -692,11 +696,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
692 | if (newthreads < 0) | 696 | if (newthreads < 0) |
693 | return -EINVAL; | 697 | return -EINVAL; |
694 | rv = nfsd_svc(NFS_PORT, newthreads); | 698 | rv = nfsd_svc(NFS_PORT, newthreads); |
695 | if (rv) | 699 | if (rv < 0) |
696 | return rv; | 700 | return rv; |
697 | } | 701 | } else |
698 | sprintf(buf, "%d\n", nfsd_nrthreads()); | 702 | rv = nfsd_nrthreads(); |
699 | return strlen(buf); | 703 | |
704 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | ||
700 | } | 705 | } |
701 | 706 | ||
702 | /** | 707 | /** |
@@ -793,7 +798,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
793 | { | 798 | { |
794 | char *mesg = buf; | 799 | char *mesg = buf; |
795 | char *vers, *minorp, sign; | 800 | char *vers, *minorp, sign; |
796 | int len, num; | 801 | int len, num, remaining; |
797 | unsigned minor; | 802 | unsigned minor; |
798 | ssize_t tlen = 0; | 803 | ssize_t tlen = 0; |
799 | char *sep; | 804 | char *sep; |
@@ -840,32 +845,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
840 | } | 845 | } |
841 | next: | 846 | next: |
842 | vers += len + 1; | 847 | vers += len + 1; |
843 | tlen += len; | ||
844 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 848 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
845 | /* If all get turned off, turn them back on, as | 849 | /* If all get turned off, turn them back on, as |
846 | * having no versions is BAD | 850 | * having no versions is BAD |
847 | */ | 851 | */ |
848 | nfsd_reset_versions(); | 852 | nfsd_reset_versions(); |
849 | } | 853 | } |
854 | |||
850 | /* Now write current state into reply buffer */ | 855 | /* Now write current state into reply buffer */ |
851 | len = 0; | 856 | len = 0; |
852 | sep = ""; | 857 | sep = ""; |
858 | remaining = SIMPLE_TRANSACTION_LIMIT; | ||
853 | for (num=2 ; num <= 4 ; num++) | 859 | for (num=2 ; num <= 4 ; num++) |
854 | if (nfsd_vers(num, NFSD_AVAIL)) { | 860 | if (nfsd_vers(num, NFSD_AVAIL)) { |
855 | len += sprintf(buf+len, "%s%c%d", sep, | 861 | len = snprintf(buf, remaining, "%s%c%d", sep, |
856 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 862 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
857 | num); | 863 | num); |
858 | sep = " "; | 864 | sep = " "; |
865 | |||
866 | if (len > remaining) | ||
867 | break; | ||
868 | remaining -= len; | ||
869 | buf += len; | ||
870 | tlen += len; | ||
859 | } | 871 | } |
860 | if (nfsd_vers(4, NFSD_AVAIL)) | 872 | if (nfsd_vers(4, NFSD_AVAIL)) |
861 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) | 873 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
862 | len += sprintf(buf+len, " %c4.%u", | 874 | minor++) { |
875 | len = snprintf(buf, remaining, " %c4.%u", | ||
863 | (nfsd_vers(4, NFSD_TEST) && | 876 | (nfsd_vers(4, NFSD_TEST) && |
864 | nfsd_minorversion(minor, NFSD_TEST)) ? | 877 | nfsd_minorversion(minor, NFSD_TEST)) ? |
865 | '+' : '-', | 878 | '+' : '-', |
866 | minor); | 879 | minor); |
867 | len += sprintf(buf+len, "\n"); | 880 | |
868 | return len; | 881 | if (len > remaining) |
882 | break; | ||
883 | remaining -= len; | ||
884 | buf += len; | ||
885 | tlen += len; | ||
886 | } | ||
887 | |||
888 | len = snprintf(buf, remaining, "\n"); | ||
889 | if (len > remaining) | ||
890 | return -EINVAL; | ||
891 | return tlen + len; | ||
869 | } | 892 | } |
870 | 893 | ||
871 | /** | 894 | /** |
@@ -910,104 +933,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
910 | return rv; | 933 | return rv; |
911 | } | 934 | } |
912 | 935 | ||
913 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 936 | /* |
937 | * Zero-length write. Return a list of NFSD's current listener | ||
938 | * transports. | ||
939 | */ | ||
940 | static ssize_t __write_ports_names(char *buf) | ||
914 | { | 941 | { |
915 | if (size == 0) { | 942 | if (nfsd_serv == NULL) |
916 | int len = 0; | 943 | return 0; |
944 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | ||
945 | } | ||
917 | 946 | ||
918 | if (nfsd_serv) | 947 | /* |
919 | len = svc_xprt_names(nfsd_serv, buf, 0); | 948 | * A single 'fd' number was written, in which case it must be for |
920 | return len; | 949 | * a socket of a supported family/protocol, and we use it as an |
921 | } | 950 | * nfsd listener. |
922 | /* Either a single 'fd' number is written, in which | 951 | */ |
923 | * case it must be for a socket of a supported family/protocol, | 952 | static ssize_t __write_ports_addfd(char *buf) |
924 | * and we use it as an nfsd socket, or | 953 | { |
925 | * A '-' followed by the 'name' of a socket in which case | 954 | char *mesg = buf; |
926 | * we close the socket. | 955 | int fd, err; |
927 | */ | 956 | |
928 | if (isdigit(buf[0])) { | 957 | err = get_int(&mesg, &fd); |
929 | char *mesg = buf; | 958 | if (err != 0 || fd < 0) |
930 | int fd; | 959 | return -EINVAL; |
931 | int err; | 960 | |
932 | err = get_int(&mesg, &fd); | 961 | err = nfsd_create_serv(); |
933 | if (err) | 962 | if (err != 0) |
934 | return -EINVAL; | 963 | return err; |
935 | if (fd < 0) | 964 | |
936 | return -EINVAL; | 965 | err = lockd_up(); |
937 | err = nfsd_create_serv(); | 966 | if (err != 0) |
938 | if (!err) { | 967 | goto out; |
939 | err = svc_addsock(nfsd_serv, fd, buf); | 968 | |
940 | if (err >= 0) { | 969 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
941 | err = lockd_up(); | 970 | if (err < 0) |
942 | if (err < 0) | 971 | lockd_down(); |
943 | svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); | 972 | |
944 | } | 973 | out: |
945 | /* Decrease the count, but don't shutdown the | 974 | /* Decrease the count, but don't shut down the service */ |
946 | * the service | 975 | nfsd_serv->sv_nrthreads--; |
947 | */ | 976 | return err; |
948 | nfsd_serv->sv_nrthreads--; | 977 | } |
949 | } | 978 | |
950 | return err < 0 ? err : 0; | 979 | /* |
951 | } | 980 | * A '-' followed by the 'name' of a socket means we close the socket. |
952 | if (buf[0] == '-' && isdigit(buf[1])) { | 981 | */ |
953 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 982 | static ssize_t __write_ports_delfd(char *buf) |
954 | int len = 0; | 983 | { |
955 | if (!toclose) | 984 | char *toclose; |
956 | return -ENOMEM; | 985 | int len = 0; |
957 | if (nfsd_serv) | 986 | |
958 | len = svc_sock_names(buf, nfsd_serv, toclose); | 987 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
959 | if (len >= 0) | 988 | if (toclose == NULL) |
960 | lockd_down(); | 989 | return -ENOMEM; |
961 | kfree(toclose); | 990 | |
962 | return len; | 991 | if (nfsd_serv != NULL) |
963 | } | 992 | len = svc_sock_names(nfsd_serv, buf, |
964 | /* | 993 | SIMPLE_TRANSACTION_LIMIT, toclose); |
965 | * Add a transport listener by writing it's transport name | 994 | if (len >= 0) |
966 | */ | 995 | lockd_down(); |
967 | if (isalpha(buf[0])) { | 996 | |
968 | int err; | 997 | kfree(toclose); |
969 | char transport[16]; | 998 | return len; |
970 | int port; | 999 | } |
971 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | 1000 | |
972 | if (port < 1 || port > 65535) | 1001 | /* |
973 | return -EINVAL; | 1002 | * A transport listener is added by writing it's transport name and |
974 | err = nfsd_create_serv(); | 1003 | * a port number. |
975 | if (!err) { | 1004 | */ |
976 | err = svc_create_xprt(nfsd_serv, | 1005 | static ssize_t __write_ports_addxprt(char *buf) |
977 | transport, PF_INET, port, | 1006 | { |
978 | SVC_SOCK_ANONYMOUS); | 1007 | char transport[16]; |
979 | if (err == -ENOENT) | 1008 | int port, err; |
980 | /* Give a reasonable perror msg for | 1009 | |
981 | * bad transport string */ | 1010 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
982 | err = -EPROTONOSUPPORT; | 1011 | return -EINVAL; |
983 | } | 1012 | |
984 | return err < 0 ? err : 0; | 1013 | if (port < 1 || port > USHORT_MAX) |
985 | } | 1014 | return -EINVAL; |
986 | } | 1015 | |
987 | /* | 1016 | err = nfsd_create_serv(); |
988 | * Remove a transport by writing it's transport name and port number | 1017 | if (err != 0) |
989 | */ | 1018 | return err; |
990 | if (buf[0] == '-' && isalpha(buf[1])) { | 1019 | |
991 | struct svc_xprt *xprt; | 1020 | err = svc_create_xprt(nfsd_serv, transport, |
992 | int err = -EINVAL; | 1021 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
993 | char transport[16]; | 1022 | if (err < 0) { |
994 | int port; | 1023 | /* Give a reasonable perror msg for bad transport string */ |
995 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 1024 | if (err == -ENOENT) |
996 | if (port < 1 || port > 65535) | 1025 | err = -EPROTONOSUPPORT; |
997 | return -EINVAL; | 1026 | return err; |
998 | if (nfsd_serv) { | ||
999 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
1000 | AF_UNSPEC, port); | ||
1001 | if (xprt) { | ||
1002 | svc_close_xprt(xprt); | ||
1003 | svc_xprt_put(xprt); | ||
1004 | err = 0; | ||
1005 | } else | ||
1006 | err = -ENOTCONN; | ||
1007 | } | ||
1008 | return err < 0 ? err : 0; | ||
1009 | } | ||
1010 | } | 1027 | } |
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * A transport listener is removed by writing a "-", it's transport | ||
1033 | * name, and it's port number. | ||
1034 | */ | ||
1035 | static ssize_t __write_ports_delxprt(char *buf) | ||
1036 | { | ||
1037 | struct svc_xprt *xprt; | ||
1038 | char transport[16]; | ||
1039 | int port; | ||
1040 | |||
1041 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | ||
1042 | return -EINVAL; | ||
1043 | |||
1044 | if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL) | ||
1045 | return -EINVAL; | ||
1046 | |||
1047 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | ||
1048 | if (xprt == NULL) | ||
1049 | return -ENOTCONN; | ||
1050 | |||
1051 | svc_close_xprt(xprt); | ||
1052 | svc_xprt_put(xprt); | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | ||
1057 | { | ||
1058 | if (size == 0) | ||
1059 | return __write_ports_names(buf); | ||
1060 | |||
1061 | if (isdigit(buf[0])) | ||
1062 | return __write_ports_addfd(buf); | ||
1063 | |||
1064 | if (buf[0] == '-' && isdigit(buf[1])) | ||
1065 | return __write_ports_delfd(buf); | ||
1066 | |||
1067 | if (isalpha(buf[0])) | ||
1068 | return __write_ports_addxprt(buf); | ||
1069 | |||
1070 | if (buf[0] == '-' && isalpha(buf[1])) | ||
1071 | return __write_ports_delxprt(buf); | ||
1072 | |||
1011 | return -EINVAL; | 1073 | return -EINVAL; |
1012 | } | 1074 | } |
1013 | 1075 | ||
@@ -1030,7 +1092,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
1030 | * buf: C string containing an unsigned | 1092 | * buf: C string containing an unsigned |
1031 | * integer value representing a bound | 1093 | * integer value representing a bound |
1032 | * but unconnected socket that is to be | 1094 | * but unconnected socket that is to be |
1033 | * used as an NFSD listener | 1095 | * used as an NFSD listener; listen(3) |
1096 | * must be called for a SOCK_STREAM | ||
1097 | * socket, otherwise it is ignored | ||
1034 | * size: non-zero length of C string in @buf | 1098 | * size: non-zero length of C string in @buf |
1035 | * Output: | 1099 | * Output: |
1036 | * On success: NFS service is started; | 1100 | * On success: NFS service is started; |
@@ -1138,7 +1202,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
1138 | nfsd_max_blksize = bsize; | 1202 | nfsd_max_blksize = bsize; |
1139 | mutex_unlock(&nfsd_mutex); | 1203 | mutex_unlock(&nfsd_mutex); |
1140 | } | 1204 | } |
1141 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 1205 | |
1206 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | ||
1207 | nfsd_max_blksize); | ||
1142 | } | 1208 | } |
1143 | 1209 | ||
1144 | #ifdef CONFIG_NFSD_V4 | 1210 | #ifdef CONFIG_NFSD_V4 |
@@ -1162,8 +1228,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) | |||
1162 | return -EINVAL; | 1228 | return -EINVAL; |
1163 | nfs4_reset_lease(lease); | 1229 | nfs4_reset_lease(lease); |
1164 | } | 1230 | } |
1165 | sprintf(buf, "%ld\n", nfs4_lease_time()); | 1231 | |
1166 | return strlen(buf); | 1232 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", |
1233 | nfs4_lease_time()); | ||
1167 | } | 1234 | } |
1168 | 1235 | ||
1169 | /** | 1236 | /** |
@@ -1219,8 +1286,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
1219 | 1286 | ||
1220 | status = nfs4_reset_recoverydir(recdir); | 1287 | status = nfs4_reset_recoverydir(recdir); |
1221 | } | 1288 | } |
1222 | sprintf(buf, "%s\n", nfs4_recoverydir()); | 1289 | |
1223 | return strlen(buf); | 1290 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
1291 | nfs4_recoverydir()); | ||
1224 | } | 1292 | } |
1225 | 1293 | ||
1226 | /** | 1294 | /** |