[ROSE]: Socket locking is a great invention.

Especially if you actually try to do it ;-)

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Ralf Baechle and committed by David S. Miller 2536b94a 6cee77db

+50 -28
+50 -28
net/rose/af_rose.c
··· 700 700 unsigned char cause, diagnostic; 701 701 struct net_device *dev; 702 702 ax25_uid_assoc *user; 703 - int n; 704 - 705 - if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { 706 - sock->state = SS_CONNECTED; 707 - return 0; /* Connect completed during a ERESTARTSYS event */ 708 - } 709 - 710 - if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { 711 - sock->state = SS_UNCONNECTED; 712 - return -ECONNREFUSED; 713 - } 714 - 715 - if (sk->sk_state == TCP_ESTABLISHED) 716 - return -EISCONN; /* No reconnect on a seqpacket socket */ 717 - 718 - sk->sk_state = TCP_CLOSE; 719 - sock->state = SS_UNCONNECTED; 703 + int n, err = 0; 720 704 721 705 if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) 722 706 return -EINVAL; ··· 718 734 if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS) 719 735 return -EINVAL; 720 736 737 + lock_sock(sk); 738 + 739 + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { 740 + /* Connect completed during a ERESTARTSYS event */ 741 + sock->state = SS_CONNECTED; 742 + goto out_release; 743 + } 744 + 745 + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { 746 + sock->state = SS_UNCONNECTED; 747 + err = -ECONNREFUSED; 748 + goto out_release; 749 + } 750 + 751 + if (sk->sk_state == TCP_ESTABLISHED) { 752 + /* No reconnect on a seqpacket socket */ 753 + err = -EISCONN; 754 + goto out_release; 755 + } 756 + 757 + sk->sk_state = TCP_CLOSE; 758 + sock->state = SS_UNCONNECTED; 759 + 721 760 rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, 722 761 &diagnostic); 723 762 if (!rose->neighbour) 724 763 return -ENETUNREACH; 725 764 726 765 rose->lci = rose_new_lci(rose->neighbour); 727 - if (!rose->lci) 728 - return -ENETUNREACH; 766 + if (!rose->lci) { 767 + err = -ENETUNREACH; 768 + goto out_release; 769 + } 729 770 730 771 if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */ 731 772 sock_reset_flag(sk, SOCK_ZAPPED); 732 773 733 - if ((dev = rose_dev_first()) == NULL) 734 - return -ENETUNREACH; 774 + if ((dev = rose_dev_first()) == NULL) { 775 + err = -ENETUNREACH; 776 + goto out_release; 777 + } 735 778 736 779 user = ax25_findbyuid(current->euid); 737 - if (!user) 738 - return -EINVAL; 780 + if (!user) { 781 + err = -EINVAL; 782 + goto out_release; 783 + } 739 784 740 785 memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); 741 786 rose->source_call = user->call; ··· 802 789 rose_start_t1timer(sk); 803 790 804 791 /* Now the loop */ 805 - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) 806 - return -EINPROGRESS; 792 + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { 793 + err = -EINPROGRESS; 794 + goto out_release; 795 + } 807 796 808 797 /* 809 798 * A Connect Ack with Choke or timeout or failed routing will go to ··· 820 805 set_current_state(TASK_INTERRUPTIBLE); 821 806 if (sk->sk_state != TCP_SYN_SENT) 822 807 break; 808 + release_sock(sk); 823 809 if (!signal_pending(tsk)) { 824 810 schedule(); 811 + lock_sock(sk); 825 812 continue; 826 813 } 827 814 current->state = TASK_RUNNING; ··· 839 822 rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic); 840 823 if (rose->neighbour) 841 824 goto rose_try_next_neigh; 842 - /* No more neighbour */ 825 + 826 + /* No more neighbours */ 843 827 sock->state = SS_UNCONNECTED; 844 - return sock_error(sk); /* Always set at this point */ 828 + err = sock_error(sk); /* Always set at this point */ 829 + goto out_release; 845 830 } 846 831 847 832 sock->state = SS_CONNECTED; 848 833 849 - return 0; 834 + out_release: 835 + release_sock(sk); 836 + 837 + return err; 850 838 } 851 839 852 840 static int rose_accept(struct socket *sock, struct socket *newsock, int flags)