=== KERNEL ===


diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 51042f0..f590463 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -351,8 +351,14 @@ static int __devinit virtblk_probe(struct
virtio_device *vdev)
      /* No need to bounce any requests */
      blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);

-	/* No real sector limit. */
-     blk_queue_max_sectors(vblk->disk->queue, -1U);
+	/* Host can optionally specify maximum sector size for I/Os. */
+     err = virtio_config_val(vdev, VIRTIO_BLK_F_SECTOR_MAX,
+                       offsetof(struct virtio_blk_config, sectors_max),
+                       &v);
+     if (!err)
+           blk_queue_max_sectors(vblk->disk->queue, v);
+     else
+           blk_queue_max_sectors(vblk->disk->queue, -1U);

      /* Host can optionally specify maximum segment size and number of
       * segments. */
@@ -412,7 +418,7 @@ static struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
      VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
      VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
-     VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
+     VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_SECTOR_MAX
 };

 /*
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index fd294c5..22cde32 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -15,6 +15,7 @@
 #define VIRTIO_BLK_F_BLK_SIZE      6	/* Block size of disk is available*/
 #define VIRTIO_BLK_F_SCSI    7	/* Supports scsi command passthru */
 #define VIRTIO_BLK_F_FLUSH   9	/* Cache flush command support */
+#define VIRTIO_BLK_F_SECTOR_MAX    10	/* Maximum # of sectors per I/O */

 struct virtio_blk_config {
      /* The capacity (in 512-byte sectors). */
@@ -29,6 +30,7 @@ struct virtio_blk_config {
            __u8 heads;
            __u8 sectors;
      } geometry;
+     __u32 sectors_max;
      /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
      __u32 blk_size;
 } __attribute__((packed));


=== USER-SPACE ===


diff --git a/block.c b/block.c
index 6fdabff..e63ca3b 100644
--- a/block.c
+++ b/block.c
@@ -800,6 +800,26 @@ int64_t bdrv_getlength(BlockDriverState *bs)
     return drv->bdrv_getlength(bs);
 }

+/**
+ * Maximum length of an I/O in sectors. Return -1 if not specified.
+ */
+void bdrv_get_max_sectors(BlockDriverState *bs, uint32_t *sectors_max)
+{
+    BlockDriver *drv = bs->drv;
+    if ((!drv) || (!drv->bdrv_get_max_sectors))
+        *sectors_max = -1;
+    else
+        * sectors_max = drv->bdrv_get_max_sectors(bs);
+}
+
+int bdrv_uses_max_sectors(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if ((!drv) || (!drv->bdrv_get_max_sectors))
+        return 0;
+    return 1;
+}
+
 /* return 0 as number of sectors if no device present or error */
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
 {
diff --git a/block.h b/block.h
index 2d4f066..21c6b40 100644
--- a/block.h
+++ b/block.h
@@ -72,6 +72,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
+void bdrv_get_max_sectors(BlockDriverState *bs, uint32_t *sectors_max);
+int bdrv_uses_max_sectors(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
 void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads,
int *psecs);
 int bdrv_commit(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index 7ebe926..c7c4eb9 100644
--- a/block_int.h
+++ b/block_int.h
@@ -81,6 +81,7 @@ struct BlockDriver {
     const char *protocol_name;
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    uint32_t (*bdrv_get_max_sectors)(BlockDriverState *bs);
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors);

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 42b766f..b2c0933 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -413,13 +413,16 @@ static void virtio_blk_update_config(VirtIODevice
*vdev, uint8_t *config)
     struct virtio_blk_config blkcfg;
     uint64_t capacity;
     int cylinders, heads, secs;
+    uint32_t sectors_max;

     bdrv_get_geometry(s->bs, &capacity);
     bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
+    bdrv_get_max_sectors(s->bs, &sectors_max);
     memset(&blkcfg, 0, sizeof(blkcfg));
     stq_raw(&blkcfg.capacity, capacity);
     stl_raw(&blkcfg.seg_max, 128 - 2);
     stw_raw(&blkcfg.cylinders, cylinders);
+    stl_raw(&blkcfg.sectors_max, sectors_max);
     blkcfg.heads = heads;
     blkcfg.sectors = secs;
     blkcfg.size_max = 0;
@@ -448,6 +451,9 @@ static uint32_t virtio_blk_get_features(VirtIODevice
*vdev)
     if (bdrv_is_read_only(s->bs))
         features |= 1 << VIRTIO_BLK_F_RO;

+    if (bdrv_uses_max_sectors(s->bs))
+        features |= 1 << VIRTIO_BLK_F_SECTOR_MAX;
+
     return features;
 }

diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 23ad74c..21cf5a8 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -32,6 +32,7 @@
 #define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru
*/
 #define VIRTIO_BLK_F_IDENTIFY   8       /* ATA IDENTIFY supported */
 #define VIRTIO_BLK_F_WCACHE     9       /* write cache enabled */
+#define VIRTIO_BLK_F_SECTOR_MAX    10	/* Maximum # of sectors per I/O */

 #define VIRTIO_BLK_ID_LEN       256     /* length of identify u16 array */
