diff options
| -rw-r--r-- | net/tipc/socket.c | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3e019737e4b3..c4803101fbdf 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -695,6 +695,34 @@ exit: | |||
| 695 | return res; | 695 | return res; |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | ||
| 699 | { | ||
| 700 | struct sock *sk = sock->sk; | ||
| 701 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 702 | DEFINE_WAIT(wait); | ||
| 703 | int done; | ||
| 704 | |||
| 705 | do { | ||
| 706 | int err = sock_error(sk); | ||
| 707 | if (err) | ||
| 708 | return err; | ||
| 709 | if (sock->state == SS_DISCONNECTING) | ||
| 710 | return -EPIPE; | ||
| 711 | else if (sock->state != SS_CONNECTED) | ||
| 712 | return -ENOTCONN; | ||
| 713 | if (!*timeo_p) | ||
| 714 | return -EAGAIN; | ||
| 715 | if (signal_pending(current)) | ||
| 716 | return sock_intr_errno(*timeo_p); | ||
| 717 | |||
| 718 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 719 | done = sk_wait_event(sk, timeo_p, | ||
| 720 | (!tport->congested || !tport->connected)); | ||
| 721 | finish_wait(sk_sleep(sk), &wait); | ||
| 722 | } while (!done); | ||
| 723 | return 0; | ||
| 724 | } | ||
| 725 | |||
| 698 | /** | 726 | /** |
| 699 | * send_packet - send a connection-oriented message | 727 | * send_packet - send a connection-oriented message |
| 700 | * @iocb: if NULL, indicates that socket lock is already held | 728 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -712,8 +740,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 712 | struct sock *sk = sock->sk; | 740 | struct sock *sk = sock->sk; |
| 713 | struct tipc_port *tport = tipc_sk_port(sk); | 741 | struct tipc_port *tport = tipc_sk_port(sk); |
| 714 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 742 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; |
| 715 | long timeout_val; | 743 | int res = -EINVAL; |
| 716 | int res; | 744 | long timeo; |
| 717 | 745 | ||
| 718 | /* Handle implied connection establishment */ | 746 | /* Handle implied connection establishment */ |
| 719 | if (unlikely(dest)) | 747 | if (unlikely(dest)) |
| @@ -725,30 +753,24 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 725 | if (iocb) | 753 | if (iocb) |
| 726 | lock_sock(sk); | 754 | lock_sock(sk); |
| 727 | 755 | ||
| 728 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 756 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 757 | if (sock->state == SS_DISCONNECTING) | ||
| 758 | res = -EPIPE; | ||
| 759 | else | ||
| 760 | res = -ENOTCONN; | ||
| 761 | goto exit; | ||
| 762 | } | ||
| 729 | 763 | ||
| 764 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | ||
| 730 | do { | 765 | do { |
| 731 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 732 | if (sock->state == SS_DISCONNECTING) | ||
| 733 | res = -EPIPE; | ||
| 734 | else | ||
| 735 | res = -ENOTCONN; | ||
| 736 | break; | ||
| 737 | } | ||
| 738 | |||
| 739 | res = tipc_send(tport->ref, m->msg_iov, total_len); | 766 | res = tipc_send(tport->ref, m->msg_iov, total_len); |
| 740 | if (likely(res != -ELINKCONG)) | 767 | if (likely(res != -ELINKCONG)) |
| 741 | break; | 768 | break; |
| 742 | if (timeout_val <= 0L) { | 769 | res = tipc_wait_for_sndpkt(sock, &timeo); |
| 743 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 770 | if (res) |
| 744 | break; | 771 | break; |
| 745 | } | ||
| 746 | release_sock(sk); | ||
| 747 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 748 | (!tport->congested || !tport->connected), timeout_val); | ||
| 749 | lock_sock(sk); | ||
| 750 | } while (1); | 772 | } while (1); |
| 751 | 773 | exit: | |
| 752 | if (iocb) | 774 | if (iocb) |
| 753 | release_sock(sk); | 775 | release_sock(sk); |
| 754 | return res; | 776 | return res; |
