aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfsctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfsctl.c')
-rw-r--r--fs/nfsd/nfsctl.c294
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 = {
207static ssize_t write_svc(struct file *file, char *buf, size_t size) 207static 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
913static 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 */
940static 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, 952static 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 } 973out:
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); 982static 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, 1005static 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 */
1035static 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
1056static 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/**