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 #include #include +#include +#include #include @@ -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