[PATCH] blkdev_size_in_bytes

2001-06-15 Thread Andries . Brouwer

People want to read the last sector on a disk, but our present
code does not easily allow that, since size checking is done
in units of 1024 bytes, not in units of 512 bytes.

We have seen very ugly solutions ("add an ioctl to read the last sector")
and very kludgy solutions ("create a partition that starts at an odd sector,
just before the end of the disk").

In reality of course we just want to have finer grainer information
and do the checking right.

Below an example.

[blk_size can be replaced by blk_size_in_bytes once all drivers
have been adapted; here I only did the ide part]

[By the way, this presupposes the presence of the BLKGETBSZ/BLKSETBSZ
ioctls. We have seen several versions of that patch already.
My current version can be found on ftp.kernel.org under people/aeb.]

Andries

--
diff -u --recursive --new-file ../linux-2.4.6-pre3a/linux/drivers/block/blkpg.c 
./linux/drivers/block/blkpg.c
--- ../linux-2.4.6-pre3a/linux/drivers/block/blkpg.cSat Jun 16 00:16:08 2001
+++ ./linux/drivers/block/blkpg.c   Sat Jun 16 00:43:37 2001
@@ -207,6 +207,7 @@
 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
 {
int intval;
+   long longval;
 
switch (cmd) {
case BLKROSET:
@@ -242,21 +243,14 @@
return 0;
 
case BLKSSZGET:
-   /* get block device sector size as needed e.g. by fdisk */
+   /* get block device hardware sector size */
intval = get_hardsect_size(dev);
return put_user(intval, (int *) arg);
 
-#if 0
case BLKGETSIZE:
-   /* Today get_gendisk() requires a linear scan;
-  add this when dev has pointer type. */
-   g = get_gendisk(dev);
-   if (!g)
-   longval = 0;
-   else
-   longval = g->part[MINOR(dev)].nr_sects;
+   /* get block device size in 512-byte sectors */
+   longval = (blkdev_size_in_bytes(dev) >> 9);
return put_user(longval, (long *) arg);
-#endif
 #if 0
case BLKRRPART: /* Re-read partition tables */
if (!capable(CAP_SYS_ADMIN)) 
diff -u --recursive --new-file ../linux-2.4.6-pre3a/linux/drivers/block/ll_rw_blk.c 
./linux/drivers/block/ll_rw_blk.c
--- ../linux-2.4.6-pre3a/linux/drivers/block/ll_rw_blk.cSat Jun 16 00:16:02 
2001
+++ ./linux/drivers/block/ll_rw_blk.c   Sat Jun 16 00:38:04 2001
@@ -76,7 +76,7 @@
 
 /*
  * blk_size contains the size of all block-devices in units of 1024 byte
- * sectors:
+ * blocks; it is obsoleted by blk_size_in_bytes
  *
  * blk_size[MAJOR][MINOR]
  *
@@ -85,6 +85,17 @@
 int * blk_size[MAX_BLKDEV];
 
 /*
+ * blk_size_in_bytes contains the size of all block-devices in bytes
+ * (blk_size has too low a resolution, since we really need the size
+ * in 512 byte sectors, and fails on devices > 2 TB)
+ *
+ * blk_size_in_bytes[MAJOR][MINOR]
+ *
+ * if (!blk_size_in_bytes[MAJOR]) then no minor size checking is done.
+ */
+loff_t * blk_size_in_bytes[MAX_BLKDEV];
+
+/*
  * blksize_size contains the size of all block-devices:
  *
  * blksize_size[MAJOR][MINOR]
@@ -858,35 +869,29 @@
  * */
 void generic_make_request (int rw, struct buffer_head * bh)
 {
-   int major = MAJOR(bh->b_rdev);
-   int minorsize = 0;
+   unsigned long maxsector;
request_queue_t *q;
 
if (!bh->b_end_io)
BUG();
 
/* Test device size, when known. */
-   if (blk_size[major])
-   minorsize = blk_size[major][MINOR(bh->b_rdev)];
-   if (minorsize) {
-   unsigned long maxsector = (minorsize << 1) + 1;
+   maxsector = (blkdev_size_in_bytes(bh->b_rdev) >> 9);
+   if (maxsector) {
unsigned long sector = bh->b_rsector;
unsigned int count = bh->b_size >> 9;
 
if (maxsector < count || maxsector - count < sector) {
-   /* Yecch */
-   bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
-
/* This may well happen - the kernel calls bread()
   without checking the size of the device, e.g.,
   when mounting a device. */
printk(KERN_INFO
   "attempt to access beyond end of device\n");
-   printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n",
+   printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%ld\n",
   kdevname(bh->b_rdev), rw,
-  (sector + count)>>1, minorsize);
+  (sector + count)>>1, maxsector>>1);
 
-   /* Yecch again */
+   

[PATCH] blkdev_size_in_bytes

2001-06-15 Thread Andries . Brouwer

People want to read the last sector on a disk, but our present
code does not easily allow that, since size checking is done
in units of 1024 bytes, not in units of 512 bytes.

We have seen very ugly solutions (add an ioctl to read the last sector)
and very kludgy solutions (create a partition that starts at an odd sector,
just before the end of the disk).

In reality of course we just want to have finer grainer information
and do the checking right.

Below an example.

[blk_size can be replaced by blk_size_in_bytes once all drivers
have been adapted; here I only did the ide part]

[By the way, this presupposes the presence of the BLKGETBSZ/BLKSETBSZ
ioctls. We have seen several versions of that patch already.
My current version can be found on ftp.kernel.org under people/aeb.]

Andries

--
diff -u --recursive --new-file ../linux-2.4.6-pre3a/linux/drivers/block/blkpg.c 
./linux/drivers/block/blkpg.c
--- ../linux-2.4.6-pre3a/linux/drivers/block/blkpg.cSat Jun 16 00:16:08 2001
+++ ./linux/drivers/block/blkpg.c   Sat Jun 16 00:43:37 2001
@@ -207,6 +207,7 @@
 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
 {
int intval;
+   long longval;
 
switch (cmd) {
case BLKROSET:
@@ -242,21 +243,14 @@
return 0;
 
case BLKSSZGET:
-   /* get block device sector size as needed e.g. by fdisk */
+   /* get block device hardware sector size */
intval = get_hardsect_size(dev);
return put_user(intval, (int *) arg);
 
-#if 0
case BLKGETSIZE:
-   /* Today get_gendisk() requires a linear scan;
-  add this when dev has pointer type. */
-   g = get_gendisk(dev);
-   if (!g)
-   longval = 0;
-   else
-   longval = g-part[MINOR(dev)].nr_sects;
+   /* get block device size in 512-byte sectors */
+   longval = (blkdev_size_in_bytes(dev)  9);
return put_user(longval, (long *) arg);
-#endif
 #if 0
case BLKRRPART: /* Re-read partition tables */
if (!capable(CAP_SYS_ADMIN)) 
diff -u --recursive --new-file ../linux-2.4.6-pre3a/linux/drivers/block/ll_rw_blk.c 
./linux/drivers/block/ll_rw_blk.c
--- ../linux-2.4.6-pre3a/linux/drivers/block/ll_rw_blk.cSat Jun 16 00:16:02 
2001
+++ ./linux/drivers/block/ll_rw_blk.c   Sat Jun 16 00:38:04 2001
@@ -76,7 +76,7 @@
 
 /*
  * blk_size contains the size of all block-devices in units of 1024 byte
- * sectors:
+ * blocks; it is obsoleted by blk_size_in_bytes
  *
  * blk_size[MAJOR][MINOR]
  *
@@ -85,6 +85,17 @@
 int * blk_size[MAX_BLKDEV];
 
 /*
+ * blk_size_in_bytes contains the size of all block-devices in bytes
+ * (blk_size has too low a resolution, since we really need the size
+ * in 512 byte sectors, and fails on devices  2 TB)
+ *
+ * blk_size_in_bytes[MAJOR][MINOR]
+ *
+ * if (!blk_size_in_bytes[MAJOR]) then no minor size checking is done.
+ */
+loff_t * blk_size_in_bytes[MAX_BLKDEV];
+
+/*
  * blksize_size contains the size of all block-devices:
  *
  * blksize_size[MAJOR][MINOR]
@@ -858,35 +869,29 @@
  * */
 void generic_make_request (int rw, struct buffer_head * bh)
 {
-   int major = MAJOR(bh-b_rdev);
-   int minorsize = 0;
+   unsigned long maxsector;
request_queue_t *q;
 
if (!bh-b_end_io)
BUG();
 
/* Test device size, when known. */
-   if (blk_size[major])
-   minorsize = blk_size[major][MINOR(bh-b_rdev)];
-   if (minorsize) {
-   unsigned long maxsector = (minorsize  1) + 1;
+   maxsector = (blkdev_size_in_bytes(bh-b_rdev)  9);
+   if (maxsector) {
unsigned long sector = bh-b_rsector;
unsigned int count = bh-b_size  9;
 
if (maxsector  count || maxsector - count  sector) {
-   /* Yecch */
-   bh-b_state = (1  BH_Lock) | (1  BH_Mapped);
-
/* This may well happen - the kernel calls bread()
   without checking the size of the device, e.g.,
   when mounting a device. */
printk(KERN_INFO
   attempt to access beyond end of device\n);
-   printk(KERN_INFO %s: rw=%d, want=%ld, limit=%d\n,
+   printk(KERN_INFO %s: rw=%d, want=%ld, limit=%ld\n,
   kdevname(bh-b_rdev), rw,
-  (sector + count)1, minorsize);
+  (sector + count)1, maxsector1);
 
-   /* Yecch again */
+   bh-b_state = (1  BH_Lock) | (1  BH_Mapped);