Skip to contentSkip to conversation

2.5 fast poll on ppc64

PATCH In review Anton Blanchard 2 participants 2 messages Dec 26, 2002 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 2.5 fast poll on ppc64

Hi,

I was unable to boot 2.5-BK on ppc64 and narrowed it down to the fast poll patch. I found:

offsetof(struct poll_list, entries) == 12 but
sizeof(struct poll_list) == 16

This means pp+1 did not match up with pp->entries. Im not sure what the alignment requirements are for a zero length struct (ie is this a compiler bug) but the following patch fixes the problem and also changes ->len to a long to ensure 8 byte alignment of ->entries on 64bit archs.

Anton

===== fs/select.c 1.15 vs edited =====

fs/select.c +2 -2
@@ -362,7 +362,7 @@
 
 struct poll_list {
 	struct poll_list *next;
-	int len;
+	long len;
 	struct pollfd entries[0];
 };
 
@@ -471,7 +471,7 @@
 			walk->next = pp;
 
 		walk = pp;
-		if (copy_from_user(pp+1, ufds + nfds-i, 
+		if (copy_from_user(pp->entries, ufds + nfds-i, 
 				sizeof(struct pollfd)*pp->len)) {
 			err = -EFAULT;
 			goto out_fds;
#1 lore raw
Quoted 5 lines · Anton Blanchard

Hi,

I was unable to boot 2.5-BK on ppc64 and narrowed it down to the fast poll patch. I found:

Quoted 9 lines

offsetof(struct poll_list, entries) == 12 but
sizeof(struct poll_list) == 16

This means pp+1 did not match up with pp->entries. Im not sure what the alignment requirements are for a zero length struct (ie is this a compiler bug) but the following patch fixes the problem and also changes ->len to a long to ensure 8 byte alignment of ->entries on 64bit archs.

That seems to be the root of the problem: ->entries requires 4 byte alignment, while struct poll_list requires 8 byte alignment. Thus the compiler aligns entries to a 4-byte boundary, and rounds up sizeof(struct poll_list) to 16.

Attached is a small test case that shows the problem on both 64-bit and 32-bit platforms. I'm not sure if this is a gcc bug: the Compaq C compiler on Tru64 and MSVC on Windows generate the same structure layout.

--
Manfred

/*
* Testcase for a possible compiler bug:
* structure with flexible array member.
* offsetof(struct,flexible_member) != sizeof(struct).
*
* That seems to be a violation of 6.7.2.1, constraint 16 of the C99
* standard:
* "First, the size of the structure shall be equal to the offset of the
* last element of an otherwise identical structure that replaces the
* flexible array member with an array of unspecified length. */
#include <stdio.h>

/*
* structure: sizeof() = 4.
* alignment: 2, due to the short.
*/

struct pollfd {
	short fd;
	char events;
	char revents;
};

/*
* sizeof: 12
* alignment: 4, due to the int.
*/

struct n2 {
	/* offset 0 */
	int m;
	/* offset 4 */
	char n;
	/* one byte padding, 'struct pollfd' requires 2 byte alignment */
	/* offset 6 */
	struct pollfd a[1];
	/* offset 10: two bytes padding for 4 byte alignment,
	 * required for the int in this structure */
};

/*
* sizeof: 8.
* XXX
* Is this correct?
* offsetof(struct n1, a) is 6
* --> offsetof(struct n1, a) != sizeof(struct n1)
* XXX
*/

struct n1 {
	/* offset 0 */
	int m;
	/* offset 4 */
	char n;
	/* one byte padding, 'struct pollfd' required 2 byte alignment */
	/* offset 6 */
	struct pollfd a[];
};
#define offsetof(a,b) \
		(int)&((a*)NULL)->b

int main(void)

{
	printf("pollfd: sizeof: %d.\n", sizeof(struct pollfd));
	printf("fix: sizeof: %d, offsetof: %d.\n", sizeof(struct n2), offsetof(struct n2, a));
	printf("var: sizeof: %d, offsetof: %d.\n", sizeof(struct n1), offsetof(struct n1, a));
	return 0;
}