aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sock.h2
-rw-r--r--net/core/sock.c74
-rw-r--r--net/ipv4/tcp_minisocks.c70
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);
739extern void sk_free(struct sock *sk); 739extern void sk_free(struct sock *sk);
740extern struct sock *sk_clone(const struct sock *sk,
741 const unsigned int __nocast priority);
740 742
741extern struct sk_buff *sock_wmalloc(struct sock *sk, 743extern 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
703struct 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 }
771out:
772 return newsk;
773}
774
775EXPORT_SYMBOL_GPL(sk_clone);
776
703void __init sk_init(void) 777void __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 */
600struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb) 600struct 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) {