diff -ruP linux/drivers/block/blkpg.c linux-meb-clean/drivers/block/blkpg.c --- linux/drivers/block/blkpg.c Fri Oct 27 01:35:47 2000 +++ linux-meb-clean/drivers/block/blkpg.c Mon Jan 22 10:00:04 2001 @@ -39,6 +39,9 @@ #include +static int set_last_sector( kdev_t dev, char *sect ); +static int get_last_sector( kdev_t dev, char *sect ); + /* * What is the data describing a partition? * @@ -208,8 +211,19 @@ int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg) { int intval; + unsigned long longval; switch (cmd) { + case BLKGETLASTSECT: + return get_last_sector(dev, (char *)(arg)); + + case BLKSETLASTSECT: + if( is_read_only(dev) ) + return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return set_last_sector(dev, (char *)(arg)); + case BLKROSET: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -281,3 +295,140 @@ } EXPORT_SYMBOL(blk_ioctl); + + /********************* + * get_last_sector() + * + * Description: This function will return the first 512 bytes of the last sector of + * a block device. + * Why: Normal read/write calls through the block layer will not read the last sector + * of an odd-size disk. + * parameters: + * dev: a kdev_t that represents the device for which we want the last sector + * sect: a userspace pointer, should be at least char[512] to hold the last sector contents + * return: + * 0 on success + * -ERRVAL on error. + *********************/ +int get_last_sector( kdev_t dev, char *sect ) +{ + struct buffer_head *bh; + struct gendisk *g; + int m, rc = 0; + unsigned int lba; + int orig_blksize = BLOCK_SIZE; + int hardblocksize; + + if( !dev ) return -EINVAL; + + m = MAJOR(dev); + for (g = gendisk_head; g; g = g->next) + if (g->major == m) + break; + + if( !g ) return -EINVAL; + + lba = g->part[MINOR(dev)].nr_sects - 1; + + if( !lba ) return -EINVAL; + + hardblocksize = get_hardblocksize(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, lba, hardblocksize); + if (!bh) { + /* We hit the end of the disk */ + printk(KERN_WARNING + "get_last_sector ioctl: bread returned NULL.\n"); + return -1; + } + + rc = copy_to_user(sect, bh->b_data, (bh->b_size > 512) ? 512 : bh->b_size ); + + brelse(bh); + + /* change block size back */ + if (orig_blksize != hardblocksize) + set_blocksize(dev, orig_blksize); + + return rc; +} + + + /********************* + * set_last_sector() + * + * Description: This function will write the first 512 bytes of the last sector of + * a block device. + * Why: Normal read/write calls through the block layer will not read the last sector + * of an odd-size disk. + * parameters: + * dev: a kdev_t that represents the device for which we want the last sector + * sect: a userspace pointer, should be at least char[512] to hold the last sector contents + * return: + * 0 on success + * -ERRVAL on error. + *********************/ +int set_last_sector( kdev_t dev, char *sect ) +{ + struct buffer_head *bh; + struct gendisk *g; + int m, rc = 0; + unsigned int lba; + int orig_blksize = BLOCK_SIZE; + int hardblocksize; + + if( !dev ) return -EINVAL; + + m = MAJOR(dev); + for (g = gendisk_head; g; g = g->next) + if (g->major == m) + break; + + if( !g ) return -EINVAL; + + lba = g->part[MINOR(dev)].nr_sects - 1; + + if( !lba ) return -EINVAL; + + hardblocksize = get_hardblocksize(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 = getblk(dev, lba, hardblocksize); + if (!bh) { + /* We hit the end of the disk */ + printk(KERN_WARNING + "get_last_sector ioctl: getblk returned NULL.\n"); + return -1; + } + + copy_from_user(bh->b_data, sect, (bh->b_size > 512) ? 512 : bh->b_size); + + mark_buffer_dirty(bh); + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) + rc=-1; + + brelse(bh); + + /* change block size back */ + if (orig_blksize != hardblocksize) + set_blocksize(dev, orig_blksize); + + return rc; +} diff -ruP linux/drivers/ide/ide.c linux-meb-clean/drivers/ide/ide.c --- linux/drivers/ide/ide.c Wed Dec 6 14:06:19 2000 +++ linux-meb-clean/drivers/ide/ide.c Fri Jan 19 16:18:51 2001 @@ -2665,6 +2665,8 @@ } return 0; + case BLKGETLASTSECT: + case BLKSETLASTSECT: case BLKROSET: case BLKROGET: case BLKFLSBUF: diff -ruP linux/drivers/scsi/sd.c linux-meb-clean/drivers/scsi/sd.c --- linux/drivers/scsi/sd.c Fri Oct 27 01:35:48 2000 +++ linux-meb-clean/drivers/scsi/sd.c Fri Jan 19 11:13:03 2001 @@ -225,6 +225,8 @@ return -EINVAL; return put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (long *) arg); + case BLKGETLASTSECT: + case BLKSETLASTSECT: case BLKROSET: case BLKROGET: case BLKRASET: diff -ruP linux/include/linux/fs.h linux-meb-clean/include/linux/fs.h --- linux/include/linux/fs.h Thu Jan 4 16:50:47 2001 +++ linux-meb-clean/include/linux/fs.h Fri Jan 19 22:23:48 2001 @@ -180,6 +180,8 @@ /* This was here just to show that the number is taken - probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ #endif +#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ +#define BLKSETLASTSECT _IO(0x12,109) /* get last sector of block device */ #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */