diff options
-rw-r--r-- | include/net/sock.h | 2 | ||||
-rw-r--r-- | net/core/sock.c | 74 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 70 |
3 files changed, 79 insertions, 67 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index bdae0a5eadf5..828dc082fcb7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -737,6 +737,8 @@ extern struct sock *sk_alloc(int family, | |||
737 | unsigned int __nocast priority, | 737 | unsigned int __nocast priority, |
738 | struct proto *prot, int zero_it); | 738 | struct proto *prot, int zero_it); |
739 | extern void sk_free(struct sock *sk); | 739 | extern void sk_free(struct sock *sk); |
740 | extern struct sock *sk_clone(const struct sock *sk, | ||
741 | const unsigned int __nocast priority); | ||
740 | 742 | ||
741 | extern struct sk_buff *sock_wmalloc(struct sock *sk, | 743 | extern struct sk_buff *sock_wmalloc(struct sock *sk, |
742 | unsigned long size, int force, | 744 | unsigned long size, int force, |
diff --git a/net/core/sock.c b/net/core/sock.c index aba31fedf2ac..ccd10fd65682 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -700,6 +700,80 @@ void sk_free(struct sock *sk) | |||
700 | module_put(owner); | 700 | module_put(owner); |
701 | } | 701 | } |
702 | 702 | ||
703 | struct sock *sk_clone(const struct sock *sk, const unsigned int __nocast priority) | ||
704 | { | ||
705 | struct sock *newsk = sk_alloc(sk->sk_family, priority, sk->sk_prot, 0); | ||
706 | |||
707 | if (newsk != NULL) { | ||
708 | struct sk_filter *filter; | ||
709 | |||
710 | memcpy(newsk, sk, sk->sk_prot->obj_size); | ||
711 | |||
712 | /* SANITY */ | ||
713 | sk_node_init(&newsk->sk_node); | ||
714 | sock_lock_init(newsk); | ||
715 | bh_lock_sock(newsk); | ||
716 | |||
717 | atomic_set(&newsk->sk_rmem_alloc, 0); | ||
718 | atomic_set(&newsk->sk_wmem_alloc, 0); | ||
719 | atomic_set(&newsk->sk_omem_alloc, 0); | ||
720 | skb_queue_head_init(&newsk->sk_receive_queue); | ||
721 | skb_queue_head_init(&newsk->sk_write_queue); | ||
722 | |||
723 | rwlock_init(&newsk->sk_dst_lock); | ||
724 | rwlock_init(&newsk->sk_callback_lock); | ||
725 | |||
726 | newsk->sk_dst_cache = NULL; | ||
727 | newsk->sk_wmem_queued = 0; | ||
728 | newsk->sk_forward_alloc = 0; | ||
729 | newsk->sk_send_head = NULL; | ||
730 | newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; | ||
731 | newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; | ||
732 | |||
733 | sock_reset_flag(newsk, SOCK_DONE); | ||
734 | skb_queue_head_init(&newsk->sk_error_queue); | ||
735 | |||
736 | filter = newsk->sk_filter; | ||
737 | if (filter != NULL) | ||
738 | sk_filter_charge(newsk, filter); | ||
739 | |||
740 | if (unlikely(xfrm_sk_clone_policy(newsk))) { | ||
741 | /* It is still raw copy of parent, so invalidate | ||
742 | * destructor and make plain sk_free() */ | ||
743 | newsk->sk_destruct = NULL; | ||
744 | sk_free(newsk); | ||
745 | newsk = NULL; | ||
746 | goto out; | ||
747 | } | ||
748 | |||
749 | newsk->sk_err = 0; | ||
750 | newsk->sk_priority = 0; | ||
751 | atomic_set(&newsk->sk_refcnt, 2); | ||
752 | |||
753 | /* | ||
754 | * Increment the counter in the same struct proto as the master | ||
755 | * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that | ||
756 | * is the same as sk->sk_prot->socks, as this field was copied | ||
757 | * with memcpy). | ||
758 | * | ||
759 | * This _changes_ the previous behaviour, where | ||
760 | * tcp_create_openreq_child always was incrementing the | ||
761 | * equivalent to tcp_prot->socks (inet_sock_nr), so this have | ||
762 | * to be taken into account in all callers. -acme | ||
763 | */ | ||
764 | sk_refcnt_debug_inc(newsk); | ||
765 | newsk->sk_socket = NULL; | ||
766 | newsk->sk_sleep = NULL; | ||
767 | |||
768 | if (newsk->sk_prot->sockets_allocated) | ||
769 | atomic_inc(newsk->sk_prot->sockets_allocated); | ||
770 | } | ||
771 | out: | ||
772 | return newsk; | ||
773 | } | ||
774 | |||
775 | EXPORT_SYMBOL_GPL(sk_clone); | ||
776 | |||
703 | void __init sk_init(void) | 777 | void __init sk_init(void) |
704 | { | 778 | { |
705 | if (num_physpages <= 4096) { | 779 | if (num_physpages <= 4096) { |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 66ce1790a94f..8b6cd8d80662 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -599,67 +599,26 @@ out: | |||
599 | */ | 599 | */ |
600 | struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb) | 600 | struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb) |
601 | { | 601 | { |
602 | /* allocate the newsk from the same slab of the master sock, | 602 | struct sock *newsk = sk_clone(sk, GFP_ATOMIC); |
603 | * if not, at sk_free time we'll try to free it from the wrong | ||
604 | * slabcache (i.e. is it TCPv4 or v6?), this is handled thru sk->sk_prot -acme */ | ||
605 | struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, sk->sk_prot, 0); | ||
606 | 603 | ||
607 | if(newsk != NULL) { | 604 | if (newsk != NULL) { |
608 | struct inet_request_sock *ireq = inet_rsk(req); | 605 | struct inet_request_sock *ireq = inet_rsk(req); |
609 | struct tcp_request_sock *treq = tcp_rsk(req); | 606 | struct tcp_request_sock *treq = tcp_rsk(req); |
610 | struct inet_sock *newinet = inet_sk(newsk); | 607 | struct inet_sock *newinet = inet_sk(newsk); |
611 | struct tcp_sock *newtp; | 608 | struct tcp_sock *newtp; |
612 | struct sk_filter *filter; | ||
613 | 609 | ||
614 | memcpy(newsk, sk, sizeof(struct tcp_sock)); | ||
615 | newsk->sk_state = TCP_SYN_RECV; | 610 | newsk->sk_state = TCP_SYN_RECV; |
616 | |||
617 | /* SANITY */ | ||
618 | sk_node_init(&newsk->sk_node); | ||
619 | newinet->bind_hash = NULL; | 611 | newinet->bind_hash = NULL; |
620 | 612 | ||
621 | /* Clone the TCP header template */ | 613 | /* Clone the TCP header template */ |
622 | newinet->dport = ireq->rmt_port; | 614 | newinet->dport = ireq->rmt_port; |
623 | |||
624 | sock_lock_init(newsk); | ||
625 | bh_lock_sock(newsk); | ||
626 | |||
627 | rwlock_init(&newsk->sk_dst_lock); | ||
628 | newsk->sk_dst_cache = NULL; | ||
629 | atomic_set(&newsk->sk_rmem_alloc, 0); | ||
630 | skb_queue_head_init(&newsk->sk_receive_queue); | ||
631 | atomic_set(&newsk->sk_wmem_alloc, 0); | ||
632 | skb_queue_head_init(&newsk->sk_write_queue); | ||
633 | atomic_set(&newsk->sk_omem_alloc, 0); | ||
634 | newsk->sk_wmem_queued = 0; | ||
635 | newsk->sk_forward_alloc = 0; | ||
636 | |||
637 | sock_reset_flag(newsk, SOCK_DONE); | ||
638 | newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; | ||
639 | newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; | ||
640 | newsk->sk_send_head = NULL; | ||
641 | rwlock_init(&newsk->sk_callback_lock); | ||
642 | skb_queue_head_init(&newsk->sk_error_queue); | ||
643 | newsk->sk_write_space = sk_stream_write_space; | 615 | newsk->sk_write_space = sk_stream_write_space; |
644 | 616 | ||
645 | if ((filter = newsk->sk_filter) != NULL) | ||
646 | sk_filter_charge(newsk, filter); | ||
647 | |||
648 | if (unlikely(xfrm_sk_clone_policy(newsk))) { | ||
649 | /* It is still raw copy of parent, so invalidate | ||
650 | * destructor and make plain sk_free() */ | ||
651 | newsk->sk_destruct = NULL; | ||
652 | sk_free(newsk); | ||
653 | return NULL; | ||
654 | } | ||
655 | |||
656 | /* Now setup tcp_sock */ | 617 | /* Now setup tcp_sock */ |
657 | newtp = tcp_sk(newsk); | 618 | newtp = tcp_sk(newsk); |
658 | newtp->pred_flags = 0; | 619 | newtp->pred_flags = 0; |
659 | newtp->rcv_nxt = treq->rcv_isn + 1; | 620 | newtp->rcv_nxt = treq->rcv_isn + 1; |
660 | newtp->snd_nxt = treq->snt_isn + 1; | 621 | newtp->snd_nxt = newtp->snd_una = newtp->snd_sml = treq->snt_isn + 1; |
661 | newtp->snd_una = treq->snt_isn + 1; | ||
662 | newtp->snd_sml = treq->snt_isn + 1; | ||
663 | 622 | ||
664 | tcp_prequeue_init(newtp); | 623 | tcp_prequeue_init(newtp); |
665 | 624 | ||
@@ -710,32 +669,9 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
710 | /* Deinitialize accept_queue to trap illegal accesses. */ | 669 | /* Deinitialize accept_queue to trap illegal accesses. */ |
711 | memset(&newtp->accept_queue, 0, sizeof(newtp->accept_queue)); | 670 | memset(&newtp->accept_queue, 0, sizeof(newtp->accept_queue)); |
712 | 671 | ||
713 | /* Back to base struct sock members. */ | ||
714 | newsk->sk_err = 0; | ||
715 | newsk->sk_priority = 0; | ||
716 | atomic_set(&newsk->sk_refcnt, 2); | ||
717 | |||
718 | /* | ||
719 | * Increment the counter in the same struct proto as the master | ||
720 | * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that | ||
721 | * is the same as sk->sk_prot->socks, as this field was copied | ||
722 | * with memcpy), same rationale as the first comment in this | ||
723 | * function. | ||
724 | * | ||
725 | * This _changes_ the previous behaviour, where | ||
726 | * tcp_create_openreq_child always was incrementing the | ||
727 | * equivalent to tcp_prot->socks (inet_sock_nr), so this have | ||
728 | * to be taken into account in all callers. -acme | ||
729 | */ | ||
730 | sk_refcnt_debug_inc(newsk); | ||
731 | |||
732 | atomic_inc(&tcp_sockets_allocated); | ||
733 | |||
734 | if (sock_flag(newsk, SOCK_KEEPOPEN)) | 672 | if (sock_flag(newsk, SOCK_KEEPOPEN)) |
735 | tcp_reset_keepalive_timer(newsk, | 673 | tcp_reset_keepalive_timer(newsk, |
736 | keepalive_time_when(newtp)); | 674 | keepalive_time_when(newtp)); |
737 | newsk->sk_socket = NULL; | ||
738 | newsk->sk_sleep = NULL; | ||
739 | 675 | ||
740 | newtp->rx_opt.tstamp_ok = ireq->tstamp_ok; | 676 | newtp->rx_opt.tstamp_ok = ireq->tstamp_ok; |
741 | if((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) { | 677 | if((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) { |