[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 08/10] blktap: Set up physical sector size and alignment offsets.



Misaligned access wrt to physical block size is a major performance
killer. Alignment offsets is for devices which are 'naturally
misaligned', e.g. to compensate for stuff like DOS 63S/track
partitioning. Accept a BLKTAP_DEVICE_FLAG_PSZ here, and expect
userspace to figure out the physical details.

Signed-off-by: Daniel Stodden <daniel.stodden@xxxxxxxxxx>
---
 drivers/block/blktap/device.c |   37 +++++++++++++++++++++++++++++++++----
 drivers/block/blktap/ring.c   |    4 ++++
 include/linux/blktap.h        |    3 +++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/block/blktap/device.c b/drivers/block/blktap/device.c
index fcf16c9..0e8eb0a 100644
--- a/drivers/block/blktap/device.c
+++ b/drivers/block/blktap/device.c
@@ -285,10 +285,13 @@ blktap_device_configure(struct blktap *tap,
        set_capacity(gd, info->capacity);
        set_disk_ro(gd, !!(info->flags & BLKTAP_DEVICE_FLAG_RO));
 
-       /* Hard sector size and max sectors impersonate the equiv. hardware. */
        blk_queue_logical_block_size(rq, info->sector_size);
        blk_queue_max_sectors(rq, 512);
 
+       /* Hard sector size and alignment in hardware */
+       blk_queue_physical_block_size(rq, info->phys_sector_size);
+       blk_queue_alignment_offset(rq, info->phys_sector_offset);
+
        /* Each segment in a request is up to an aligned page in size. */
        blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
        blk_queue_max_segment_size(rq, PAGE_SIZE);
@@ -309,6 +312,7 @@ blktap_device_validate_info(struct blktap *tap,
                            struct blktap_device_info *info)
 {
        struct device *dev = tap->ring.dev;
+       unsigned int phys_mask;
        int sector_order;
 
        sector_order = ffs(info->sector_size) - 1;
@@ -321,11 +325,34 @@ blktap_device_validate_info(struct blktap *tap,
            (info->capacity > ULLONG_MAX >> sector_order))
                goto fail;
 
+       /* physical blocks default to logical ones */
+       if (!(info->flags & BLKTAP_DEVICE_FLAG_PSZ)) {
+               info->phys_sector_size   = info->sector_size;
+               info->phys_sector_offset = 0;
+       }
+
+       /* phys block size is 2^n and >= logical */
+       sector_order = ilog2(info->phys_sector_size);
+       if (sector_order <  9 ||
+           info->phys_sector_size != 1U<<sector_order ||
+           info->phys_sector_size < info->sector_size)
+               goto fail;
+
+       /* alignment offset < physical/logical */
+       phys_mask = (info->phys_sector_size /
+                    info->sector_size) - 1;
+       if ((info->phys_sector_offset & ~phys_mask) != 0)
+               goto fail;
+
        return 0;
 
 fail:
-       dev_err(dev, "capacity: %llu, sector-size: %u\n",
-               info->capacity, info->sector_size);
+       dev_err(dev,
+               "capacity: %llu, sector-size: %u/%u, "
+               "phys-offset: %u\n",
+               info->capacity, info->sector_size,
+               info->phys_sector_size, info->phys_sector_offset);
+
        return -EINVAL;
 }
 
@@ -473,9 +500,11 @@ blktap_device_create(struct blktap *tap, struct 
blktap_device_info *info)
 
        set_bit(BLKTAP_DEVICE, &tap->dev_inuse);
 
-       dev_info(disk_to_dev(gd), "sector-size: %u/%u capacity: %llu\n",
+       dev_info(disk_to_dev(gd),
+                "sector-size: %u/%u phys-offset: %d capacity: %llu\n",
                 queue_logical_block_size(rq),
                 queue_physical_block_size(rq),
+                queue_alignment_offset(rq),
                 (unsigned long long)get_capacity(gd));
 
        return 0;
diff --git a/drivers/block/blktap/ring.c b/drivers/block/blktap/ring.c
index 134583d..25bd311 100644
--- a/drivers/block/blktap/ring.c
+++ b/drivers/block/blktap/ring.c
@@ -446,6 +446,7 @@ blktap_ring_ioctl(struct inode *inode, struct file *filp,
                size_t base_sz, sz;
 
                mask  = BLKTAP_DEVICE_FLAG_RO;
+               mask |= BLKTAP_DEVICE_FLAG_PSZ;
 
                memset(&info, 0, sizeof(info));
                sz = base_sz = BLKTAP_INFO_SIZE_AT(flags);
@@ -453,6 +454,9 @@ blktap_ring_ioctl(struct inode *inode, struct file *filp,
                if (copy_from_user(&info, ptr, sz))
                        return -EFAULT;
 
+               if ((info.flags & BLKTAP_DEVICE_FLAG_PSZ) != 0)
+                       sz = BLKTAP_INFO_SIZE_AT(phys_sector_offset);
+
                if (sz > base_sz)
                        if (copy_from_user(&info, ptr, sz))
                                return -EFAULT;
diff --git a/include/linux/blktap.h b/include/linux/blktap.h
index 2c3c924..9a280d9 100644
--- a/include/linux/blktap.h
+++ b/include/linux/blktap.h
@@ -17,6 +17,7 @@
 #define BLKTAP_IOCTL_REMOVE_DEVICE  207
 
 #define BLKTAP_DEVICE_FLAG_RO       0x00000001UL /* disk is R/O */
+#define BLKTAP_DEVICE_FLAG_PSZ      0x00000002UL /* physical sector size */
 
 struct blktap_info {
        unsigned int            ring_major;
@@ -28,6 +29,8 @@ struct blktap_device_info {
        unsigned long long      capacity;
        unsigned int            sector_size;
        unsigned long           flags;
+       unsigned int            phys_sector_size;
+       unsigned int            phys_sector_offset;
 };
 
 /*
-- 
1.7.0.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.