loop: fix NULL dereference if mount fails
[safe/jmp/linux-2.6] / net / dccp / proto.c
index 775eaa3..a156319 100644 (file)
@@ -40,16 +40,10 @@ DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
 
 EXPORT_SYMBOL_GPL(dccp_statistics);
 
-atomic_t dccp_orphan_count = ATOMIC_INIT(0);
-
+struct percpu_counter dccp_orphan_count;
 EXPORT_SYMBOL_GPL(dccp_orphan_count);
 
-struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
-       .lhash_lock     = RW_LOCK_UNLOCKED,
-       .lhash_users    = ATOMIC_INIT(0),
-       .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
-};
-
+struct inet_hashinfo dccp_hashinfo;
 EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
 /* the maximum queue length for tx in packets. 0 is no limit */
@@ -130,7 +124,7 @@ EXPORT_SYMBOL_GPL(dccp_done);
 
 const char *dccp_packet_name(const int type)
 {
-       static const char *dccp_packet_names[] = {
+       static const char *const dccp_packet_names[] = {
                [DCCP_PKT_REQUEST]  = "REQUEST",
                [DCCP_PKT_RESPONSE] = "RESPONSE",
                [DCCP_PKT_DATA]     = "DATA",
@@ -153,7 +147,7 @@ EXPORT_SYMBOL_GPL(dccp_packet_name);
 
 const char *dccp_state_name(const int state)
 {
-       static char *dccp_state_names[] = {
+       static const char *const dccp_state_names[] = {
        [DCCP_OPEN]             = "OPEN",
        [DCCP_REQUESTING]       = "REQUESTING",
        [DCCP_PARTOPEN]         = "PARTOPEN",
@@ -180,8 +174,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
        struct dccp_sock *dp = dccp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
 
-       dccp_minisock_init(&dp->dccps_minisock);
-
        icsk->icsk_rto          = DCCP_TIMEOUT_INIT;
        icsk->icsk_syn_retries  = sysctl_dccp_request_retries;
        sk->sk_state            = DCCP_CLOSED;
@@ -319,7 +311,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == DCCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
@@ -401,7 +393,7 @@ out:
 EXPORT_SYMBOL_GPL(dccp_ioctl);
 
 static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
-                                  char __user *optval, int optlen)
+                                  char __user *optval, unsigned int optlen)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_service_list *sl = NULL;
@@ -472,7 +464,7 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 }
 
 static int dccp_setsockopt_ccid(struct sock *sk, int type,
-                               char __user *optval, int optlen)
+                               char __user *optval, unsigned int optlen)
 {
        u8 *val;
        int rc = 0;
@@ -502,7 +494,7 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
 }
 
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
-               char __user *optval, int optlen)
+               char __user *optval, unsigned int optlen)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        int val, err = 0;
@@ -554,7 +546,7 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 }
 
 int dccp_setsockopt(struct sock *sk, int level, int optname,
-                   char __user *optval, int optlen)
+                   char __user *optval, unsigned int optlen)
 {
        if (level != SOL_DCCP)
                return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
@@ -567,7 +559,7 @@ EXPORT_SYMBOL_GPL(dccp_setsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
-                          char __user *optval, int optlen)
+                          char __user *optval, unsigned int optlen)
 {
        if (level != SOL_DCCP)
                return inet_csk_compat_setsockopt(sk, level, optname,
@@ -970,7 +962,6 @@ adjudge_to_death:
        state = sk->sk_state;
        sock_hold(sk);
        sock_orphan(sk);
-       atomic_inc(sk->sk_prot->orphan_count);
 
        /*
         * It is the last release_sock in its life. It will remove backlog.
@@ -984,6 +975,8 @@ adjudge_to_death:
        bh_lock_sock(sk);
        WARN_ON(sock_owned_by_user(sk));
 
+       percpu_counter_inc(sk->sk_prot->orphan_count);
+
        /* Have we already been destroyed by a softirq or backlog? */
        if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
                goto out;
@@ -1034,17 +1027,21 @@ static int __init dccp_init(void)
 {
        unsigned long goal;
        int ehash_order, bhash_order, i;
-       int rc = -ENOBUFS;
+       int rc;
 
        BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
                     FIELD_SIZEOF(struct sk_buff, cb));
-
+       rc = percpu_counter_init(&dccp_orphan_count, 0);
+       if (rc)
+               goto out;
+       rc = -ENOBUFS;
+       inet_hashinfo_init(&dccp_hashinfo);
        dccp_hashinfo.bind_bucket_cachep =
                kmem_cache_create("dccp_bind_bucket",
                                  sizeof(struct inet_bind_bucket), 0,
                                  SLAB_HWCACHE_ALIGN, NULL);
        if (!dccp_hashinfo.bind_bucket_cachep)
-               goto out;
+               goto out_free_percpu;
 
        /*
         * Size and allocate the main established and bind bucket
@@ -1052,10 +1049,10 @@ static int __init dccp_init(void)
         *
         * The methodology is similar to that of the buffer cache.
         */
-       if (num_physpages >= (128 * 1024))
-               goal = num_physpages >> (21 - PAGE_SHIFT);
+       if (totalram_pages >= (128 * 1024))
+               goal = totalram_pages >> (21 - PAGE_SHIFT);
        else
-               goal = num_physpages >> (23 - PAGE_SHIFT);
+               goal = totalram_pages >> (23 - PAGE_SHIFT);
 
        if (thash_entries)
                goal = (thash_entries *
@@ -1069,7 +1066,7 @@ static int __init dccp_init(void)
                       (dccp_hashinfo.ehash_size - 1))
                        dccp_hashinfo.ehash_size--;
                dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
-                       __get_free_pages(GFP_ATOMIC, ehash_order);
+                       __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
        } while (!dccp_hashinfo.ehash && --ehash_order > 0);
 
        if (!dccp_hashinfo.ehash) {
@@ -1078,8 +1075,8 @@ static int __init dccp_init(void)
        }
 
        for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
-               INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
-               INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain);
+               INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
+               INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i);
        }
 
        if (inet_ehash_locks_alloc(&dccp_hashinfo))
@@ -1094,7 +1091,7 @@ static int __init dccp_init(void)
                    bhash_order > 0)
                        continue;
                dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
-                       __get_free_pages(GFP_ATOMIC, bhash_order);
+                       __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, bhash_order);
        } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
 
        if (!dccp_hashinfo.bhash) {
@@ -1119,9 +1116,15 @@ static int __init dccp_init(void)
        if (rc)
                goto out_ackvec_exit;
 
+       rc = ccid_initialize_builtins();
+       if (rc)
+               goto out_sysctl_exit;
+
        dccp_timestamping_init();
 out:
        return rc;
+out_sysctl_exit:
+       dccp_sysctl_exit();
 out_ackvec_exit:
        dccp_ackvec_exit();
 out_free_dccp_mib:
@@ -1137,11 +1140,14 @@ out_free_dccp_ehash:
 out_free_bind_bucket_cachep:
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
        dccp_hashinfo.bind_bucket_cachep = NULL;
+out_free_percpu:
+       percpu_counter_destroy(&dccp_orphan_count);
        goto out;
 }
 
 static void __exit dccp_fini(void)
 {
+       ccid_cleanup_builtins();
        dccp_mib_exit();
        free_pages((unsigned long)dccp_hashinfo.bhash,
                   get_order(dccp_hashinfo.bhash_size *
@@ -1153,6 +1159,7 @@ static void __exit dccp_fini(void)
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
        dccp_ackvec_exit();
        dccp_sysctl_exit();
+       percpu_counter_destroy(&dccp_orphan_count);
 }
 
 module_init(dccp_init);