diff options
author | Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 2005-08-09 23:10:12 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:42:36 -0400 |
commit | 87d11ceb9deb7a3f13fdee6e89d9bb6be7d27a71 (patch) | |
tree | 3b5f6f15a76e6d58e5088cad707859390757181a /net/core/sock.c | |
parent | c676270bcd25015b978722ec0352c330dcc87883 (diff) |
[SOCK]: Introduce sk_clone
Out of tcp_create_openreq_child, will be used in
dccp_create_openreq_child, and is a nice sock function anyway.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/sock.c')
-rw-r--r-- | net/core/sock.c | 74 |
1 files changed, 74 insertions, 0 deletions
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) { |