diff -ur linux.orig/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- linux.orig/arch/i386/vmlinux.lds	Thu Nov 29 13:50:24 2001
+++ linux/arch/i386/vmlinux.lds	Thu Nov 29 19:28:16 2001
@@ -23,7 +23,7 @@
   __start___ksymtab = .; /* Kernel symbol table */
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
-   __start___kallsyms = .;	/* All kernel symbols */
+   __start___kallsyms = .; /* All kernel symbols */
    __kallsyms : { *(__kallsyms) }
    __stop___kallsyms = .;
   _etext = .; /* End of text section */
diff -ur linux.orig/fs/block_dev.c linux/fs/block_dev.c
--- linux.orig/fs/block_dev.c	Thu Nov 29 13:50:25 2001
+++ linux/fs/block_dev.c	Thu Nov 29 19:28:04 2001
@@ -14,6 +14,8 @@
 #include <linux/major.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
 
 #include <asm/uaccess.h>
 
@@ -22,13 +24,124 @@
 
 #define NBUF 64
 
+/*******
+ * kludge: this is a horribly ugly pasty vomit infested kludge to 
+ * read the last few 512 byte sectors on a device.  Gross gross
+ * gross gross gross!!!!!!!!!!!  But it's better than the ioctl.
+ * Fix properly in 2.5.  -ben
+ */
+
+ /*********************
+  * get_last_sector()
+  *  
+  * Description: This function will read any inaccessible blocks at the end
+  * 	of a device
+  * Why: Normal read/write calls through the block layer will not read the 
+  *      last sector of an odd-size disk. 
+  * parameters: 
+  *    dev: kdev_t -- which device to read
+  *    param: a pointer to a userspace struct. The struct has these members: 
+  *	block:  an int which denotes which block to return:
+  *		0 == Last block
+  * 		1 == Last block - 1
+  * 		n == Last block - n
+  *		This is validated so that only values of 
+  *		  <= ((total_sects + 1) % logical_block_size)  ||  0
+  *		  are allowed.
+  * 	block_contents: a pointer to userspace char*, this is where we write 
+  *	 returned blocks to.
+  * 	content_length: How big the userspace buffer is.
+  * return: 
+  *    0 on success
+  *   -ERRVAL on error.
+  *********************/
+
+/* size == device size in 512 byte blocks
+ * Note that this crappy code only reads up to 512 bytes at a time.
+ */
+ssize_t block_rw_kludge(int rw, kdev_t dev, loff_t blks, char * buf,
+		    size_t count, loff_t *ppos)
+{   
+        struct buffer_head *bh;
+        struct gendisk *g;
+        int rc = 0;
+        unsigned int lastlba;
+        int orig_blksize = BLOCK_SIZE;
+        int hardblocksize;
+	loff_t sector = *ppos >> 9;
+	unsigned offset = *ppos & 511;
+
+	count = (count > (512 - offset)) ? (512 - offset) : count;
+
+	blks >>= 9;
+
+	g = get_gendisk(dev);
+	if (g)
+		blks = g->part[MINOR(dev)].nr_sects;
+
+        if( !blks ) return 0;
+
+	if (sector >= blks)
+		return 0;
+
+        hardblocksize = get_hardsect_size(dev);
+        if( ! hardblocksize ) hardblocksize = 512;
+
+         /* Need to change the block size that the block layer uses */
+        if (blksize_size[MAJOR(dev)])
+                orig_blksize = blksize_size[MAJOR(dev)][MINOR(dev)];
+
+	if (orig_blksize != hardblocksize)
+		set_blocksize(dev, hardblocksize);
+
+       	bh =  bread(dev, sector, hardblocksize);
+       	if (!bh) {
+		/* We hit the end of the disk */
+		printk(KERN_WARNING
+			"get_last_sector ioctl: bread returned NULL.\n");
+		rc = -EIO;
+       	} else {
+		printk("read: %lu at sector %Ld offset %u\n",
+			(unsigned long)count, sector, offset);
+		rc = -EIO;
+		if (buffer_uptodate(bh)) {
+			if (WRITE == rw) {
+				rc = copy_from_user(bh->b_data + offset, buf, count) ? -EFAULT : count;
+				mark_buffer_dirty(bh);
+				ll_rw_block(WRITE, 1, &bh);
+				wait_on_buffer(bh);
+			} else
+				rc = copy_to_user(buf, bh->b_data + offset, count) ? -EFAULT : count;
+		}
+
+		printk("rc= %ld\n", (long)rc);
+		if (!buffer_uptodate(bh))
+			rc = -EIO;
+
+		brelse(bh);
+		if (rc > 0)
+			*ppos += rc;
+	}
+
+        /* change block size back */
+        if (orig_blksize != hardblocksize)
+                   set_blocksize(dev, orig_blksize);
+   
+        return rc;
+}
+
+
+
+/****** end kludge of disgusting pain ******/
+
+
 ssize_t block_write(struct file * filp, const char * buf,
 		    size_t count, loff_t *ppos)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
 	ssize_t blocksize, blocksize_bits, i, buffercount, write_error;
 	ssize_t block, blocks;
-	loff_t offset;
+	loff_t offset, real_size;
 	ssize_t chars;
 	ssize_t written, retval;
 	struct buffer_head * bhlist[NBUF];
@@ -55,10 +168,12 @@
 	block = *ppos >> blocksize_bits;
 	offset = *ppos & (blocksize-1);
 
-	if (blk_size[MAJOR(dev)])
+	if (blk_size[MAJOR(dev)]) {
 		size = ((loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits;
-	else
-		size = INT_MAX;
+		real_size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
+	} else
+		real_size = size = INT_MAX;
+
 	while (count>0) {
 		if (block >= size) {
 			retval = -ENOSPC;
@@ -170,6 +285,11 @@
 		filp->f_reada = 1;
 	if(write_error)
 		return -EIO;
+	if (retval == -ENOSPC) {
+		retval = block_rw_kludge(WRITE, dev, real_size, buf, count, ppos);
+		if (!retval)
+			retval = -ENOSPC;
+	}
 	return written ? written : retval;
 }
 
@@ -186,7 +306,7 @@
 	struct buffer_head * buflist[NBUF];
 	struct buffer_head * bhreq[NBUF];
 	unsigned int chars;
-	loff_t size;
+	loff_t size, real_size;
 	kdev_t dev;
 	ssize_t read;
 
@@ -221,6 +341,7 @@
 	read = 0;
 	block = offset >> blocksize_bits;
 	offset &= blocksize-1;
+	real_size = size;
 	size >>= blocksize_bits;
 	rblocks = blocks = (left + offset + blocksize - 1) >> blocksize_bits;
 	bhb = bhe = buflist;
@@ -233,8 +354,16 @@
 	}
 	if (block + blocks > size) {
 		blocks = size - block;
-		if (blocks == 0)
-			return 0;
+		if (blocks == 0) {
+			ssize_t res = 0, got;
+
+			do {
+				got = block_rw_kludge(READ, dev, real_size, buf+res, count-res, ppos);
+				if (got > 0)
+					res += got;
+			} while (got > 0 && res < count) ;
+			return res ? res : got;
+		}
 	}
 
 	/* We do this in a two stage process.  We first try to request
