On labelled initialisers, gcc-2.7.2.3 and tcp_ipv4.c
Subsystems (2)
There is a bug in gcc-2.7.2.3. It incorrectly lays out structure initialisers when the `name:value;' construct is used.
Here is the degenerate case:
struct struct_1 { int a; };
struct thing {
int a;
struct struct_1 b;
};
struct thing a_thing = {
// a: 0, /* Uncomment this for correct code */
b: {0},
};Which produces:
.file "e.c" .version "01.01" gcc2_compiled.: .globl a_thing .data .align 4 .type a_thing,@object .size a_thing,8 a_thing: .zero 4 .zero 4 .long 0 .ident "GCC: (GNU) 2.7.2.3"
Note the extra `.zero 4'.
As far as I can tell the rule to follow is this:
If a structure has nested structures, and if you are initialising one of the nested structures then you _must_ initialise all fields which precede that nested structure.
There are five ways to fix this:
1: Remember to initialise all fields which precede
initialised structures.
2: Arrange your struct so that all nested structs come first
and remember to initialise them all.
3: Don't use gcc-2.7.2.3 (use one of the later compilers and
put up with 50% longer build times).
4: Fix gcc-2.7.2.3
5: Don't use named initialisers.
David, your recent changes to tcp_ipv4.c make 2.7.2.3-compiled kernels fail very strangely. I used option 2 to fix it:
include/net/tcp.h +21 -19
@@ -90,6 +90,24 @@ }; extern struct tcp_hashinfo { + rwlock_t __tcp_lhash_lock; + atomic_t __tcp_lhash_users; + wait_queue_head_t __tcp_lhash_wait; + spinlock_t __tcp_portalloc_lock; + + /* All sockets in TCP_LISTEN state will be in here. This is the only + * table where wildcard'd TCP sockets can exist. Hash function here + * is just local port number. + */ + struct sock *__tcp_listening_hash[TCP_LHTABLE_SIZE]; + + /* + * All the below members are written once at bootup and are + * never written again _or_ are predominantly read-access. + * Hence we align to a new cache line as all the preceding members + * are often dirty. + */ + /* This is for sockets with full identity only. Sockets here will * always be without wildcards and will have the following invariant: *
@@ -97,8 +115,10 @@* * First half of the table is for sockets not in TIME_WAIT, second half * is for TIME_WAIT sockets only. +* */ -struct tcp_ehash_bucket *__tcp_ehash; + struct tcp_ehash_bucket *__tcp_ehash + __attribute__((__aligned__(SMP_CACHE_BYTES)));/* Ok, let's try this, I give up, we do need a local binding * TCP hash as well as the others for fast bind/connect.
@@ -107,24 +127,6 @@int __tcp_bhash_size;int __tcp_ehash_size; - -/* All sockets in TCP_LISTEN state will be in here. This is the only -* table where wildcard'd TCP sockets can exist. Hash function here -* is just local port number. -*/ -struct sock *__tcp_listening_hash[TCP_LHTABLE_SIZE ]; - -/* All the above members are written once at bootup and -* never written again _or_ are predominantly read-access. -* -* Now align to a new cache line as all the following members -* are often dirty. -*/ - rwlock_t __tcp_lhash_lock - __attribute__((__aligned__(SMP_CACHE_BYTES))); -atomic_t __tcp_lhash_users; -wait_queue_head_t __tcp_lhash_wait; -spinlock_t __tcp_portalloc_lock; } tcp_hashinfo;#define tcp_ehash (tcp_hashinfo.__tcp_ehash)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
Please read the FAQ at http://www.tux.org/lkml/