real-root-dev patches (another approach)

Brad Midgley brad at pht.com
Wed Jan 6 01:36:53 EST 1999


i emailed this to alan cox. i will send it to linus and the lists later.

Reading or writing /proc/sys/kernel/real-root-dev does not work on
big-endian architectures. I propose a multiplatform solution.

The reason it doesn't work is that sysctl is told to treat the
corresponding variable, real_root_dev, as if it's an int. It's
actually of type kdev_t which is ultimately an unsigned short
int. Treating it like an int only works on x86 because of
(unfortunate?) alignment coincidence. Even on intel where this code
works, two adjacent bytes that don't really belong to real_root_dev
are being read and modified as if they do.

This code needs to work on all platforms because it is extremely
important for makers of linux distributions to offer convenient
startup options.

As I see it there are three ways to fix the problem:

1. Change real_root_dev to type int 
(ugly, it really should be a kdev_t)

2. Change the definition of kdev_t from an unsigned short to an int 
(ugly, affects large amounts of code)

3. make sysctl treat real_root_dev properly as it is.

I show an implementation for (3). I think it's the best solution and
it's the most localized solution.

All my changes are in kernel/sysctl.c. The version is 2.2.0p4.

First I made the change to have the real size of real_root_dev
reflected in its entry in the table:

-{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
+{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(real_root_dev),

If the size of kdev_t ever does change to a whole int or multiple
ints, the sysctl code won't need changes. (there's an assumption that
userland programs understand how real_root_dev is represented but
that's an entirely different problem)

Next I make the code that parses and outputs values able to deal with
a data chunk smaller than an int. I have it assume that a chunk of
data smaller than an int is an unsigned short. All the other entries
in the sysctl table report their size as multiples of sizeof(int) so
this doesn't affect any other entries.

vleft now represents the number of bytes, not ints, that need to be
filled:

-	vleft = table->maxlen / sizeof(int);
+	vleft = table->maxlen;
 	left = *lenp;
 	
-	for (; left && vleft--; i++, first=0) {
+	for (; left && vleft > 0; i++, first=0) {
+		vleft -= sizeof(int);
 		if (write) {
...
 			left -= len;
-			*i = val;
+			if(vleft >= 0)
+				*i = val;
+			else
+				*((unsigned short *)i) = val;
 		} else {
 			p = buf;
 			if (!first)
 				*p++ = '\t';
-			sprintf(p, "%d", (*i) / conv);
+			if(vleft >= 0)
+				sprintf(p, "%d", (*i) / conv);
+			else
+				sprintf(p, "%hd", (*((unsigned short *)i)) / conv);
 			len = strlen(buf);
 			if (len > left)
 				len = left;

a proper patch is attached.

brad
-------------- next part --------------
--- kernel/sysctl.c.orig	Mon Jan  4 20:02:02 1999
+++ kernel/sysctl.c	Tue Jan  5 03:42:16 1999
@@ -162,7 +162,7 @@
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 #ifdef CONFIG_BLK_DEV_INITRD
-	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
+	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(real_root_dev),
 	 0644, NULL, &proc_dointvec},
 #endif
 #ifdef CONFIG_BINFMT_JAVA
@@ -688,10 +688,11 @@
 	}
 	
 	i = (int *) table->data;
-	vleft = table->maxlen / sizeof(int);
+	vleft = table->maxlen;
 	left = *lenp;
 	
-	for (; left && vleft--; i++, first=0) {
+	for (; left && vleft > 0; i++, first=0) {
+		vleft -= sizeof(int);
 		if (write) {
 			while (left) {
 				char c;
@@ -726,12 +727,18 @@
 				val = -val;
 			buffer += len;
 			left -= len;
-			*i = val;
+			if(vleft >= 0)
+				*i = val;
+			else
+				*((unsigned short *)i) = val;
 		} else {
 			p = buf;
 			if (!first)
 				*p++ = '\t';
-			sprintf(p, "%d", (*i) / conv);
+			if(vleft >= 0)
+				sprintf(p, "%d", (*i) / conv);
+			else
+				sprintf(p, "%hd", (*((unsigned short *)i)) / conv);
 			len = strlen(buf);
 			if (len > left)
 				len = left;


More information about the Linuxppc-dev mailing list