diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 161 |
1 files changed, 123 insertions, 38 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 9d504234af4a..23128ee191ae 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 | */ |
243 | static int one_sock_name(char *buf, struct svc_sock *svsk) | 243 | static 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 | ||
262 | int | 275 | /** |
263 | svc_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 | */ | ||
290 | int 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... |
@@ -346,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, | |||
346 | sock->sk->sk_sndbuf = snd * 2; | 380 | sock->sk->sk_sndbuf = snd * 2; |
347 | sock->sk->sk_rcvbuf = rcv * 2; | 381 | sock->sk->sk_rcvbuf = rcv * 2; |
348 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; | 382 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; |
383 | sock->sk->sk_write_space(sock->sk); | ||
349 | release_sock(sock->sk); | 384 | release_sock(sock->sk); |
350 | #endif | 385 | #endif |
351 | } | 386 | } |
@@ -387,6 +422,15 @@ static void svc_write_space(struct sock *sk) | |||
387 | } | 422 | } |
388 | } | 423 | } |
389 | 424 | ||
425 | static void svc_tcp_write_space(struct sock *sk) | ||
426 | { | ||
427 | struct socket *sock = sk->sk_socket; | ||
428 | |||
429 | if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) | ||
430 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
431 | svc_write_space(sk); | ||
432 | } | ||
433 | |||
390 | /* | 434 | /* |
391 | * Copy the UDP datagram's destination address to the rqstp structure. | 435 | * Copy the UDP datagram's destination address to the rqstp structure. |
392 | * The 'destination' address in this case is the address to which the | 436 | * The 'destination' address in this case is the address to which the |
@@ -427,13 +471,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
427 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | 471 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; |
428 | } buffer; | 472 | } buffer; |
429 | struct cmsghdr *cmh = &buffer.hdr; | 473 | struct cmsghdr *cmh = &buffer.hdr; |
430 | int err, len; | ||
431 | struct msghdr msg = { | 474 | struct msghdr msg = { |
432 | .msg_name = svc_addr(rqstp), | 475 | .msg_name = svc_addr(rqstp), |
433 | .msg_control = cmh, | 476 | .msg_control = cmh, |
434 | .msg_controllen = sizeof(buffer), | 477 | .msg_controllen = sizeof(buffer), |
435 | .msg_flags = MSG_DONTWAIT, | 478 | .msg_flags = MSG_DONTWAIT, |
436 | }; | 479 | }; |
480 | size_t len; | ||
481 | int err; | ||
437 | 482 | ||
438 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) | 483 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) |
439 | /* udp sockets need large rcvbuf as all pending | 484 | /* udp sockets need large rcvbuf as all pending |
@@ -465,8 +510,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
465 | return -EAGAIN; | 510 | return -EAGAIN; |
466 | } | 511 | } |
467 | len = svc_addr_len(svc_addr(rqstp)); | 512 | len = svc_addr_len(svc_addr(rqstp)); |
468 | if (len < 0) | 513 | if (len == 0) |
469 | return len; | 514 | return -EAFNOSUPPORT; |
470 | rqstp->rq_addrlen = len; | 515 | rqstp->rq_addrlen = len; |
471 | if (skb->tstamp.tv64 == 0) { | 516 | if (skb->tstamp.tv64 == 0) { |
472 | skb->tstamp = ktime_get_real(); | 517 | skb->tstamp = ktime_get_real(); |
@@ -980,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | |||
980 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | 1025 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) |
981 | { | 1026 | { |
982 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | 1027 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
983 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | 1028 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; |
984 | int required; | 1029 | int required; |
985 | int wspace; | ||
986 | 1030 | ||
987 | /* | 1031 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) |
988 | * Set the SOCK_NOSPACE flag before checking the available | 1032 | return 1; |
989 | * sock space. | 1033 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; |
990 | */ | 1034 | if (sk_stream_wspace(svsk->sk_sk) >= required) |
1035 | return 1; | ||
991 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 1036 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
992 | required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; | 1037 | return 0; |
993 | wspace = sk_stream_wspace(svsk->sk_sk); | ||
994 | |||
995 | if (wspace < sk_stream_min_wspace(svsk->sk_sk)) | ||
996 | return 0; | ||
997 | if (required * 2 > wspace) | ||
998 | return 0; | ||
999 | |||
1000 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
1001 | return 1; | ||
1002 | } | 1038 | } |
1003 | 1039 | ||
1004 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, | 1040 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, |
@@ -1054,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
1054 | dprintk("setting up TCP socket for reading\n"); | 1090 | dprintk("setting up TCP socket for reading\n"); |
1055 | sk->sk_state_change = svc_tcp_state_change; | 1091 | sk->sk_state_change = svc_tcp_state_change; |
1056 | sk->sk_data_ready = svc_tcp_data_ready; | 1092 | sk->sk_data_ready = svc_tcp_data_ready; |
1057 | sk->sk_write_space = svc_write_space; | 1093 | sk->sk_write_space = svc_tcp_write_space; |
1058 | 1094 | ||
1059 | svsk->sk_reclen = 0; | 1095 | svsk->sk_reclen = 0; |
1060 | svsk->sk_tcplen = 0; | 1096 | svsk->sk_tcplen = 0; |
@@ -1148,9 +1184,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | |||
1148 | return svsk; | 1184 | return svsk; |
1149 | } | 1185 | } |
1150 | 1186 | ||
1151 | int svc_addsock(struct svc_serv *serv, | 1187 | /** |
1152 | int fd, | 1188 | * svc_addsock - add a listener socket to an RPC service |
1153 | char *name_return) | 1189 | * @serv: pointer to RPC service to which to add a new listener |
1190 | * @fd: file descriptor of the new listener | ||
1191 | * @name_return: pointer to buffer to fill in with name of listener | ||
1192 | * @len: size of the buffer | ||
1193 | * | ||
1194 | * Fills in socket name and returns positive length of name if successful. | ||
1195 | * Name is terminated with '\n'. On error, returns a negative errno | ||
1196 | * value. | ||
1197 | */ | ||
1198 | int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, | ||
1199 | const size_t len) | ||
1154 | { | 1200 | { |
1155 | int err = 0; | 1201 | int err = 0; |
1156 | struct socket *so = sockfd_lookup(fd, &err); | 1202 | struct socket *so = sockfd_lookup(fd, &err); |
@@ -1190,7 +1236,7 @@ int svc_addsock(struct svc_serv *serv, | |||
1190 | sockfd_put(so); | 1236 | sockfd_put(so); |
1191 | return err; | 1237 | return err; |
1192 | } | 1238 | } |
1193 | return one_sock_name(name_return, svsk); | 1239 | return svc_one_sock_name(svsk, name_return, len); |
1194 | } | 1240 | } |
1195 | EXPORT_SYMBOL_GPL(svc_addsock); | 1241 | EXPORT_SYMBOL_GPL(svc_addsock); |
1196 | 1242 | ||
@@ -1327,3 +1373,42 @@ static void svc_sock_free(struct svc_xprt *xprt) | |||
1327 | sock_release(svsk->sk_sock); | 1373 | sock_release(svsk->sk_sock); |
1328 | kfree(svsk); | 1374 | kfree(svsk); |
1329 | } | 1375 | } |
1376 | |||
1377 | /* | ||
1378 | * Create a svc_xprt. | ||
1379 | * | ||
1380 | * For internal use only (e.g. nfsv4.1 backchannel). | ||
1381 | * Callers should typically use the xpo_create() method. | ||
1382 | */ | ||
1383 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot) | ||
1384 | { | ||
1385 | struct svc_sock *svsk; | ||
1386 | struct svc_xprt *xprt = NULL; | ||
1387 | |||
1388 | dprintk("svc: %s\n", __func__); | ||
1389 | svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); | ||
1390 | if (!svsk) | ||
1391 | goto out; | ||
1392 | |||
1393 | xprt = &svsk->sk_xprt; | ||
1394 | if (prot == IPPROTO_TCP) | ||
1395 | svc_xprt_init(&svc_tcp_class, xprt, serv); | ||
1396 | else if (prot == IPPROTO_UDP) | ||
1397 | svc_xprt_init(&svc_udp_class, xprt, serv); | ||
1398 | else | ||
1399 | BUG(); | ||
1400 | out: | ||
1401 | dprintk("svc: %s return %p\n", __func__, xprt); | ||
1402 | return xprt; | ||
1403 | } | ||
1404 | EXPORT_SYMBOL_GPL(svc_sock_create); | ||
1405 | |||
1406 | /* | ||
1407 | * Destroy a svc_sock. | ||
1408 | */ | ||
1409 | void svc_sock_destroy(struct svc_xprt *xprt) | ||
1410 | { | ||
1411 | if (xprt) | ||
1412 | kfree(container_of(xprt, struct svc_sock, sk_xprt)); | ||
1413 | } | ||
1414 | EXPORT_SYMBOL_GPL(svc_sock_destroy); | ||