aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svc_xprt.c57
-rw-r--r--net/sunrpc/svcsock.c87
2 files changed, 106 insertions, 38 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index c200d92e57e4..6f33d33cc064 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -11,6 +11,7 @@
11#include <net/sock.h> 11#include <net/sock.h>
12#include <linux/sunrpc/stats.h> 12#include <linux/sunrpc/stats.h>
13#include <linux/sunrpc/svc_xprt.h> 13#include <linux/sunrpc/svc_xprt.h>
14#include <linux/sunrpc/svcsock.h>
14 15
15#define RPCDBG_FACILITY RPCDBG_SVCXPRT 16#define RPCDBG_FACILITY RPCDBG_SVCXPRT
16 17
@@ -1097,36 +1098,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
1097} 1098}
1098EXPORT_SYMBOL_GPL(svc_find_xprt); 1099EXPORT_SYMBOL_GPL(svc_find_xprt);
1099 1100
1100/* 1101static int svc_one_xprt_name(const struct svc_xprt *xprt,
1101 * Format a buffer with a list of the active transports. A zero for 1102 char *pos, int remaining)
1102 * the buflen parameter disables target buffer overflow checking. 1103{
1104 int len;
1105
1106 len = snprintf(pos, remaining, "%s %u\n",
1107 xprt->xpt_class->xcl_name,
1108 svc_xprt_local_port(xprt));
1109 if (len >= remaining)
1110 return -ENAMETOOLONG;
1111 return len;
1112}
1113
1114/**
1115 * svc_xprt_names - format a buffer with a list of transport names
1116 * @serv: pointer to an RPC service
1117 * @buf: pointer to a buffer to be filled in
1118 * @buflen: length of buffer to be filled in
1119 *
1120 * Fills in @buf with a string containing a list of transport names,
1121 * each name terminated with '\n'.
1122 *
1123 * Returns positive length of the filled-in string on success; otherwise
1124 * a negative errno value is returned if an error occurs.
1103 */ 1125 */
1104int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen) 1126int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
1105{ 1127{
1106 struct svc_xprt *xprt; 1128 struct svc_xprt *xprt;
1107 char xprt_str[64]; 1129 int len, totlen;
1108 int totlen = 0; 1130 char *pos;
1109 int len;
1110 1131
1111 /* Sanity check args */ 1132 /* Sanity check args */
1112 if (!serv) 1133 if (!serv)
1113 return 0; 1134 return 0;
1114 1135
1115 spin_lock_bh(&serv->sv_lock); 1136 spin_lock_bh(&serv->sv_lock);
1137
1138 pos = buf;
1139 totlen = 0;
1116 list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { 1140 list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
1117 len = snprintf(xprt_str, sizeof(xprt_str), 1141 len = svc_one_xprt_name(xprt, pos, buflen - totlen);
1118 "%s %d\n", xprt->xpt_class->xcl_name, 1142 if (len < 0) {
1119 svc_xprt_local_port(xprt)); 1143 *buf = '\0';
1120 /* If the string was truncated, replace with error string */ 1144 totlen = len;
1121 if (len >= sizeof(xprt_str)) 1145 }
1122 strcpy(xprt_str, "name-too-long\n"); 1146 if (len <= 0)
1123 /* Don't overflow buffer */
1124 len = strlen(xprt_str);
1125 if (buflen && (len + totlen >= buflen))
1126 break; 1147 break;
1127 strcpy(buf+totlen, xprt_str); 1148
1149 pos += len;
1128 totlen += len; 1150 totlen += len;
1129 } 1151 }
1152
1130 spin_unlock_bh(&serv->sv_lock); 1153 spin_unlock_bh(&serv->sv_lock);
1131 return totlen; 1154 return totlen;
1132} 1155}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 9d504234af4a..004a2f9dc432 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -240,42 +240,76 @@ out:
240/* 240/*
241 * Report socket names for nfsdfs 241 * Report socket names for nfsdfs
242 */ 242 */
243static int one_sock_name(char *buf, struct svc_sock *svsk) 243static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
244{ 244{
245 const struct sock *sk = svsk->sk_sk;
246 const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
247 "udp" : "tcp";
245 int len; 248 int len;
246 249
247 switch(svsk->sk_sk->sk_family) { 250 switch (sk->sk_family) {
248 case AF_INET: 251 case PF_INET:
249 len = sprintf(buf, "ipv4 %s %pI4 %d\n", 252 len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n",
250 svsk->sk_sk->sk_protocol == IPPROTO_UDP ? 253 proto_name,
251 "udp" : "tcp", 254 &inet_sk(sk)->rcv_saddr,
252 &inet_sk(svsk->sk_sk)->rcv_saddr, 255 inet_sk(sk)->num);
253 inet_sk(svsk->sk_sk)->num); 256 break;
257 case PF_INET6:
258 len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n",
259 proto_name,
260 &inet6_sk(sk)->rcv_saddr,
261 inet_sk(sk)->num);
254 break; 262 break;
255 default: 263 default:
256 len = sprintf(buf, "*unknown-%d*\n", 264 len = snprintf(buf, remaining, "*unknown-%d*\n",
257 svsk->sk_sk->sk_family); 265 sk->sk_family);
266 }
267
268 if (len >= remaining) {
269 *buf = '\0';
270 return -ENAMETOOLONG;
258 } 271 }
259 return len; 272 return len;
260} 273}
261 274
262int 275/**
263svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) 276 * svc_sock_names - construct a list of listener names in a string
277 * @serv: pointer to RPC service
278 * @buf: pointer to a buffer to fill in with socket names
279 * @buflen: size of the buffer to be filled
280 * @toclose: pointer to '\0'-terminated C string containing the name
281 * of a listener to be closed
282 *
283 * Fills in @buf with a '\n'-separated list of names of listener
284 * sockets. If @toclose is not NULL, the socket named by @toclose
285 * is closed, and is not included in the output list.
286 *
287 * Returns positive length of the socket name string, or a negative
288 * errno value on error.
289 */
290int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
291 const char *toclose)
264{ 292{
265 struct svc_sock *svsk, *closesk = NULL; 293 struct svc_sock *svsk, *closesk = NULL;
266 int len = 0; 294 int len = 0;
267 295
268 if (!serv) 296 if (!serv)
269 return 0; 297 return 0;
298
270 spin_lock_bh(&serv->sv_lock); 299 spin_lock_bh(&serv->sv_lock);
271 list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { 300 list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
272 int onelen = one_sock_name(buf+len, svsk); 301 int onelen = svc_one_sock_name(svsk, buf + len, buflen - len);
273 if (toclose && strcmp(toclose, buf+len) == 0) 302 if (onelen < 0) {
303 len = onelen;
304 break;
305 }
306 if (toclose && strcmp(toclose, buf + len) == 0)
274 closesk = svsk; 307 closesk = svsk;
275 else 308 else
276 len += onelen; 309 len += onelen;
277 } 310 }
278 spin_unlock_bh(&serv->sv_lock); 311 spin_unlock_bh(&serv->sv_lock);
312
279 if (closesk) 313 if (closesk)
280 /* Should unregister with portmap, but you cannot 314 /* Should unregister with portmap, but you cannot
281 * unregister just one protocol... 315 * unregister just one protocol...
@@ -427,13 +461,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
427 long all[SVC_PKTINFO_SPACE / sizeof(long)]; 461 long all[SVC_PKTINFO_SPACE / sizeof(long)];
428 } buffer; 462 } buffer;
429 struct cmsghdr *cmh = &buffer.hdr; 463 struct cmsghdr *cmh = &buffer.hdr;
430 int err, len;
431 struct msghdr msg = { 464 struct msghdr msg = {
432 .msg_name = svc_addr(rqstp), 465 .msg_name = svc_addr(rqstp),
433 .msg_control = cmh, 466 .msg_control = cmh,
434 .msg_controllen = sizeof(buffer), 467 .msg_controllen = sizeof(buffer),
435 .msg_flags = MSG_DONTWAIT, 468 .msg_flags = MSG_DONTWAIT,
436 }; 469 };
470 size_t len;
471 int err;
437 472
438 if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) 473 if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
439 /* udp sockets need large rcvbuf as all pending 474 /* udp sockets need large rcvbuf as all pending
@@ -465,8 +500,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
465 return -EAGAIN; 500 return -EAGAIN;
466 } 501 }
467 len = svc_addr_len(svc_addr(rqstp)); 502 len = svc_addr_len(svc_addr(rqstp));
468 if (len < 0) 503 if (len == 0)
469 return len; 504 return -EAFNOSUPPORT;
470 rqstp->rq_addrlen = len; 505 rqstp->rq_addrlen = len;
471 if (skb->tstamp.tv64 == 0) { 506 if (skb->tstamp.tv64 == 0) {
472 skb->tstamp = ktime_get_real(); 507 skb->tstamp = ktime_get_real();
@@ -1148,9 +1183,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
1148 return svsk; 1183 return svsk;
1149} 1184}
1150 1185
1151int svc_addsock(struct svc_serv *serv, 1186/**
1152 int fd, 1187 * svc_addsock - add a listener socket to an RPC service
1153 char *name_return) 1188 * @serv: pointer to RPC service to which to add a new listener
1189 * @fd: file descriptor of the new listener
1190 * @name_return: pointer to buffer to fill in with name of listener
1191 * @len: size of the buffer
1192 *
1193 * Fills in socket name and returns positive length of name if successful.
1194 * Name is terminated with '\n'. On error, returns a negative errno
1195 * value.
1196 */
1197int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
1198 const size_t len)
1154{ 1199{
1155 int err = 0; 1200 int err = 0;
1156 struct socket *so = sockfd_lookup(fd, &err); 1201 struct socket *so = sockfd_lookup(fd, &err);
@@ -1190,7 +1235,7 @@ int svc_addsock(struct svc_serv *serv,
1190 sockfd_put(so); 1235 sockfd_put(so);
1191 return err; 1236 return err;
1192 } 1237 }
1193 return one_sock_name(name_return, svsk); 1238 return svc_one_sock_name(svsk, name_return, len);
1194} 1239}
1195EXPORT_SYMBOL_GPL(svc_addsock); 1240EXPORT_SYMBOL_GPL(svc_addsock);
1196 1241