Module Name:    src
Committed By:   matt
Date:           Tue Jan 18 19:52:24 UTC 2011

Modified Files:
        src/sys/compat/netbsd32: netbsd32_ioctl.c
        src/sys/kern: sys_generic.c
        src/sys/sys: disklabel.h dkio.h

Log Message:
Make struct disklabel 8 byte aligned.  This increases its size by 4 bytes
on IPL32 platforms so add code in sys_ioctl (and netbsd32_ioctl) to deal
with the older/smaller diskabel size.  This change makes disklabel the
same for both IPL32 and LP64 platforms.


To generate a diff of this commit:
cvs rdiff -u -r1.51 -r1.52 src/sys/compat/netbsd32/netbsd32_ioctl.c
cvs rdiff -u -r1.124 -r1.125 src/sys/kern/sys_generic.c
cvs rdiff -u -r1.107 -r1.108 src/sys/sys/disklabel.h
cvs rdiff -u -r1.16 -r1.17 src/sys/sys/dkio.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/compat/netbsd32/netbsd32_ioctl.c
diff -u src/sys/compat/netbsd32/netbsd32_ioctl.c:1.51 src/sys/compat/netbsd32/netbsd32_ioctl.c:1.52
--- src/sys/compat/netbsd32/netbsd32_ioctl.c:1.51	Fri Sep 24 13:12:53 2010
+++ src/sys/compat/netbsd32/netbsd32_ioctl.c	Tue Jan 18 19:52:24 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_ioctl.c,v 1.51 2010/09/24 13:12:53 njoly Exp $	*/
+/*	$NetBSD: netbsd32_ioctl.c,v 1.52 2011/01/18 19:52:24 matt Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.51 2010/09/24 13:12:53 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.52 2011/01/18 19:52:24 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -437,10 +437,11 @@
 	struct filedesc *fdp;
 	u_long com;
 	int error = 0;
-	u_int size, size32;
+	size_t size;
+	size_t alloc_size32, size32;
 	void *data, *memp = NULL;
 	void *data32, *memp32 = NULL;
-	unsigned fd;
+	unsigned int fd;
 	fdfile_t *ff;
 	int tmp;
 #define STK_PARAMS	128
@@ -453,17 +454,26 @@
 	 */
 #if 0
 	{
-char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!",
-		"INOUT", "VOID|IN|OUT!" };
-
-printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n",
-       SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data),
-       dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)],
-       IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)),
-       IOCPARM_LEN(SCARG(uap, com)));
+		const char * const dirs[8] = {
+		    "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!",
+		    "INOUT", "VOID|IN|OUT!"
+		};
+
+		printf("netbsd32_ioctl(%d, %x, %x): "
+		    "%s group %c base %d len %d\n",
+		    SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data).i32,
+		    dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)],
+		    IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)),
+		    IOCPARM_LEN(SCARG(uap, com)));
 	}
 #endif
 
+	memp = NULL;
+	memp32 = NULL;
+	alloc_size32 = 0;
+	size32 = 0;
+	size = 0;
+
 	fdp = p->p_fd;
 	fd = SCARG(uap, fd);
 	if ((fp = fd_getfile(fd)) == NULL)
@@ -489,37 +499,72 @@
 	 * Interpret high order word to find amount of data to be
 	 * copied to/from the user's address space.
 	 */
-	size = 0;
 	size32 = IOCPARM_LEN(com);
-	if (size32 > IOCPARM_MAX) {
+	alloc_size32 = size32;
+
+	/*
+	 * The disklabel is now padded to a multiple of 8 bytes however the old
+	 * disklabel on 32bit platforms wasn't.  This leaves a difference in
+	 * size of 4 bytes between the two but are otherwise identical.
+	 * To deal with this, we allocate enough space for the new disklabel
+	 * but only copyin/out the smaller amount.
+	 */
+	if (IOCGROUP(com) == 'd') {
+		u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32);
+		switch (ncom) {
+		case DIOCGDINFO:
+		case DIOCWDINFO:
+		case DIOCSDINFO:
+		case DIOCGDEFLABEL:
+			com = ncom;
+			if (IOCPARM_LEN(DIOCGDINFO32) < IOCPARM_LEN(DIOCGDINFO))
+				alloc_size32 = IOCPARM_LEN(DIOCGDINFO);
+			break;
+		}
+	}
+	if (alloc_size32 > IOCPARM_MAX) {
 		error = ENOTTY;
 		goto out;
 	}
-	if (size32 > sizeof(stkbuf)) {
-		memp32 = kmem_alloc((size_t)size32, KM_SLEEP);
+	if (alloc_size32 > sizeof(stkbuf)) {
+		memp32 = kmem_alloc(alloc_size32, KM_SLEEP);
 		data32 = memp32;
 	} else
 		data32 = (void *)stkbuf32;
-	if (com&IOC_IN) {
-		if (size32) {
-			error = copyin(SCARG_P32(uap, data), data32, size32);
-			if (error) {
-				if (memp32)
-					kmem_free(memp32, (size_t)size32);
-				goto out;
-			}
-			ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data),
-			    size32, 0);
-		} else
+	if ((com >> IOCPARM_SHIFT) == 0)  {
+		/* UNIX-style ioctl. */
+		data32 = SCARG_P32(uap, data);
+	} else {
+		if (com&IOC_IN) {
+			if (size32) {
+				error = copyin(SCARG_P32(uap, data), data32,
+				    size32);
+				if (error) {
+					goto out;
+				}
+				/*
+				 * The data between size and alloc_size has
+				 * not been overwritten.  It shouldn't matter
+				 * but let's clear that anyway.
+				 */
+				if (__predict_false(size32 < alloc_size32)) {
+					memset((char *)data32+size32, 0,
+					    alloc_size32 - size32);
+				}
+				ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data),
+				    size32, 0);
+			} else
+				*(void **)data32 = SCARG_P32(uap, data);
+		} else if ((com&IOC_OUT) && size32) {
+			/*
+			 * Zero the buffer so the user always
+			 * gets back something deterministic.
+			 */
+			memset(data32, 0, alloc_size32);
+		} else if (com&IOC_VOID) {
 			*(void **)data32 = SCARG_P32(uap, data);
-	} else if ((com&IOC_OUT) && size32)
-		/*
-		 * Zero the buffer so the user always
-		 * gets back something deterministic.
-		 */
-		memset(data32, 0, size32);
-	else if (com&IOC_VOID)
-		*(void **)data32 = SCARG_P32(uap, data);
+		}
+	}
 
 	/*
 	 * convert various structures, pointers, and other objects that
@@ -690,12 +735,12 @@
 		    size32, error);
 	}
 
+ out:
 	/* If we allocated data, free it here. */
 	if (memp32)
-		kmem_free(memp32, (size_t)size32);
+		kmem_free(memp32, alloc_size32);
 	if (memp)
-		kmem_free(memp, (size_t)size);
- out:
+		kmem_free(memp32, size);
 	fd_putfile(fd);
 	return (error);
 }

Index: src/sys/kern/sys_generic.c
diff -u src/sys/kern/sys_generic.c:1.124 src/sys/kern/sys_generic.c:1.125
--- src/sys/kern/sys_generic.c:1.124	Thu Aug 13 08:57:43 2009
+++ src/sys/kern/sys_generic.c	Tue Jan 18 19:52:23 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_generic.c,v 1.124 2009/08/13 08:57:43 haad Exp $	*/
+/*	$NetBSD: sys_generic.c,v 1.125 2011/01/18 19:52:23 matt Exp $	*/
 
 /*-
  * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.124 2009/08/13 08:57:43 haad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.125 2011/01/18 19:52:23 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -90,6 +90,7 @@
 #include <sys/syscallargs.h>
 #include <sys/ktrace.h>
 #include <sys/atomic.h>
+#include <sys/disklabel.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -524,12 +525,14 @@
 	struct filedesc	*fdp;
 	u_long		com;
 	int		error;
-	u_int		size;
+	size_t		size, alloc_size;
 	void 		*data, *memp;
 #define	STK_PARAMS	128
 	u_long		stkbuf[STK_PARAMS/sizeof(u_long)];
 	fdfile_t	*ff;
 
+	memp = NULL;
+	alloc_size = 0;
 	error = 0;
 	p = l->l_proc;
 	fdp = p->p_fd;
@@ -560,6 +563,28 @@
 	 * copied to/from the user's address space.
 	 */
 	size = IOCPARM_LEN(com);
+	alloc_size = size;
+
+	/*
+	 * The disklabel is now padded to a multiple of 8 bytes however the old
+	 * disklabel on 32bit platforms wasn't.  This leaves a difference in
+	 * size of 4 bytes between the two but are otherwise identical.
+	 * To deal with this, we allocate enough space for the new disklabel
+	 * but only copyin/out the smaller amount.
+	 */
+	if (IOCGROUP(com) == 'd') {
+		u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32);
+		switch (ncom) {
+		case DIOCGDINFO:
+		case DIOCWDINFO:
+		case DIOCSDINFO:
+		case DIOCGDEFLABEL:
+			com = ncom;
+			if (IOCPARM_LEN(DIOCGDINFO32) < IOCPARM_LEN(DIOCGDINFO))
+				alloc_size = IOCPARM_LEN(DIOCGDINFO);
+			break;
+		}
+	}
 	if (size > IOCPARM_MAX) {
 		error = ENOTTY;
 		goto out;
@@ -569,8 +594,8 @@
 		/* UNIX-style ioctl. */
 		data = SCARG(uap, data);
 	} else {
-		if (size > sizeof(stkbuf)) {
-			memp = kmem_alloc(size, KM_SLEEP);
+		if (alloc_size > sizeof(stkbuf)) {
+			memp = kmem_alloc(alloc_size, KM_SLEEP);
 			data = memp;
 		} else {
 			data = (void *)stkbuf;
@@ -579,11 +604,17 @@
 			if (size) {
 				error = copyin(SCARG(uap, data), data, size);
 				if (error) {
-					if (memp) {
-						kmem_free(memp, size);
-					}
 					goto out;
 				}
+				/*
+				 * The data between size and alloc_size has
+				 * not been overwritten.  It shouldn't matter
+				 * but let's clear that anyway.
+				 */
+				if (__predict_false(size < alloc_size)) {
+					memset((char *)data+size, 0,
+					    alloc_size - size);
+				}
 				ktrgenio(SCARG(uap, fd), UIO_WRITE,
 				    SCARG(uap, data), size, 0);
 			} else {
@@ -633,9 +664,9 @@
 		}
 		break;
 	}
-	if (memp)
-		kmem_free(memp, size);
  out:
+	if (memp)
+		kmem_free(memp, alloc_size);
 	fd_putfile(SCARG(uap, fd));
 	switch (error) {
 	case -1:

Index: src/sys/sys/disklabel.h
diff -u src/sys/sys/disklabel.h:1.107 src/sys/sys/disklabel.h:1.108
--- src/sys/sys/disklabel.h:1.107	Tue Dec 22 18:55:25 2009
+++ src/sys/sys/disklabel.h	Tue Jan 18 19:52:24 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: disklabel.h,v 1.107 2009/12/22 18:55:25 pooka Exp $	*/
+/*	$NetBSD: disklabel.h,v 1.108 2011/01/18 19:52:24 matt Exp $	*/
 
 /*
  * Copyright (c) 1987, 1988, 1993
@@ -117,6 +117,7 @@
 			char *un_d_boot0;	/* primary bootstrap name */
 			char *un_d_boot1;	/* secondary bootstrap name */
 		} un_b;
+		uint64_t un_d_pad;		/* force 8 byte alignment */
 	} d_un;
 #define	d_packname	d_un.un_d_packname
 #define	d_boot0		d_un.un_b.un_d_boot0

Index: src/sys/sys/dkio.h
diff -u src/sys/sys/dkio.h:1.16 src/sys/sys/dkio.h:1.17
--- src/sys/sys/dkio.h:1.16	Mon Mar 22 16:49:41 2010
+++ src/sys/sys/dkio.h	Tue Jan 18 19:52:24 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: dkio.h,v 1.16 2010/03/22 16:49:41 martin Exp $	*/
+/*	$NetBSD: dkio.h,v 1.17 2011/01/18 19:52:24 matt Exp $	*/
 
 /*
  * Copyright (c) 1987, 1988, 1993
@@ -44,6 +44,7 @@
 #define DIOCWDINFO	_IOW('d', 103, struct disklabel)/* set, update disk */
 
 #ifdef _KERNEL
+#define DIOCGDINFO32	(DIOCGDINFO - (sizeof(uint32_t) << IOCPARM_SHIFT))
 #define DIOCGPART	_IOW('d', 104, struct partinfo)	/* get partition */
 #endif
 

Reply via email to