diff options
author | Christoph Hellwig <hch@lst.de> | 2010-02-24 15:22:25 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-02-23 22:52:26 -0500 |
commit | 69740c8ba878f58bc3c71f74618fc2cd1da990da (patch) | |
tree | 95a86d35fe234db2fd08b10cab0400ad1b2e56dd | |
parent | d57ed95da483418e8b0433da693c9168dd0a2df6 (diff) |
virtio_blk: add block topology support
Allow reading various alignment values from the config page. This
allows the guest to much better align I/O requests depending on the
storage topology.
Note that the formats for the config values appear a bit messed up,
but we follow the formats used by ATA and SCSI so they are expected in
the storage world.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | drivers/block/virtio_blk.c | 61 | ||||
-rw-r--r-- | include/linux/virtio_blk.h | 13 |
2 files changed, 59 insertions, 15 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 51042f0ba7e1..7eff828b2117 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -243,10 +243,12 @@ static int index_to_minor(int index) | |||
243 | static int __devinit virtblk_probe(struct virtio_device *vdev) | 243 | static int __devinit virtblk_probe(struct virtio_device *vdev) |
244 | { | 244 | { |
245 | struct virtio_blk *vblk; | 245 | struct virtio_blk *vblk; |
246 | struct request_queue *q; | ||
246 | int err; | 247 | int err; |
247 | u64 cap; | 248 | u64 cap; |
248 | u32 v; | 249 | u32 v, blk_size, sg_elems, opt_io_size; |
249 | u32 blk_size, sg_elems; | 250 | u16 min_io_size; |
251 | u8 physical_block_exp, alignment_offset; | ||
250 | 252 | ||
251 | if (index_to_minor(index) >= 1 << MINORBITS) | 253 | if (index_to_minor(index) >= 1 << MINORBITS) |
252 | return -ENOSPC; | 254 | return -ENOSPC; |
@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
293 | goto out_mempool; | 295 | goto out_mempool; |
294 | } | 296 | } |
295 | 297 | ||
296 | vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); | 298 | q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); |
297 | if (!vblk->disk->queue) { | 299 | if (!q) { |
298 | err = -ENOMEM; | 300 | err = -ENOMEM; |
299 | goto out_put_disk; | 301 | goto out_put_disk; |
300 | } | 302 | } |
301 | 303 | ||
302 | vblk->disk->queue->queuedata = vblk; | 304 | q->queuedata = vblk; |
303 | 305 | ||
304 | if (index < 26) { | 306 | if (index < 26) { |
305 | sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); | 307 | sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); |
@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
323 | 325 | ||
324 | /* If barriers are supported, tell block layer that queue is ordered */ | 326 | /* If barriers are supported, tell block layer that queue is ordered */ |
325 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) | 327 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) |
326 | blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH, | 328 | blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, |
327 | virtblk_prepare_flush); | 329 | virtblk_prepare_flush); |
328 | else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) | 330 | else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) |
329 | blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); | 331 | blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL); |
330 | 332 | ||
331 | /* If disk is read-only in the host, the guest should obey */ | 333 | /* If disk is read-only in the host, the guest should obey */ |
332 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) | 334 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) |
@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
345 | set_capacity(vblk->disk, cap); | 347 | set_capacity(vblk->disk, cap); |
346 | 348 | ||
347 | /* We can handle whatever the host told us to handle. */ | 349 | /* We can handle whatever the host told us to handle. */ |
348 | blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2); | 350 | blk_queue_max_phys_segments(q, vblk->sg_elems-2); |
349 | blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2); | 351 | blk_queue_max_hw_segments(q, vblk->sg_elems-2); |
350 | 352 | ||
351 | /* No need to bounce any requests */ | 353 | /* No need to bounce any requests */ |
352 | blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY); | 354 | blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); |
353 | 355 | ||
354 | /* No real sector limit. */ | 356 | /* No real sector limit. */ |
355 | blk_queue_max_sectors(vblk->disk->queue, -1U); | 357 | blk_queue_max_sectors(q, -1U); |
356 | 358 | ||
357 | /* Host can optionally specify maximum segment size and number of | 359 | /* Host can optionally specify maximum segment size and number of |
358 | * segments. */ | 360 | * segments. */ |
@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
360 | offsetof(struct virtio_blk_config, size_max), | 362 | offsetof(struct virtio_blk_config, size_max), |
361 | &v); | 363 | &v); |
362 | if (!err) | 364 | if (!err) |
363 | blk_queue_max_segment_size(vblk->disk->queue, v); | 365 | blk_queue_max_segment_size(q, v); |
364 | else | 366 | else |
365 | blk_queue_max_segment_size(vblk->disk->queue, -1U); | 367 | blk_queue_max_segment_size(q, -1U); |
366 | 368 | ||
367 | /* Host can optionally specify the block size of the device */ | 369 | /* Host can optionally specify the block size of the device */ |
368 | err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, | 370 | err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, |
369 | offsetof(struct virtio_blk_config, blk_size), | 371 | offsetof(struct virtio_blk_config, blk_size), |
370 | &blk_size); | 372 | &blk_size); |
371 | if (!err) | 373 | if (!err) |
372 | blk_queue_logical_block_size(vblk->disk->queue, blk_size); | 374 | blk_queue_logical_block_size(q, blk_size); |
375 | else | ||
376 | blk_size = queue_logical_block_size(q); | ||
377 | |||
378 | /* Use topology information if available */ | ||
379 | err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, | ||
380 | offsetof(struct virtio_blk_config, physical_block_exp), | ||
381 | &physical_block_exp); | ||
382 | if (!err && physical_block_exp) | ||
383 | blk_queue_physical_block_size(q, | ||
384 | blk_size * (1 << physical_block_exp)); | ||
385 | |||
386 | err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, | ||
387 | offsetof(struct virtio_blk_config, alignment_offset), | ||
388 | &alignment_offset); | ||
389 | if (!err && alignment_offset) | ||
390 | blk_queue_alignment_offset(q, blk_size * alignment_offset); | ||
391 | |||
392 | err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, | ||
393 | offsetof(struct virtio_blk_config, min_io_size), | ||
394 | &min_io_size); | ||
395 | if (!err && min_io_size) | ||
396 | blk_queue_io_min(q, blk_size * min_io_size); | ||
397 | |||
398 | err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, | ||
399 | offsetof(struct virtio_blk_config, opt_io_size), | ||
400 | &opt_io_size); | ||
401 | if (!err && opt_io_size) | ||
402 | blk_queue_io_opt(q, blk_size * opt_io_size); | ||
403 | |||
373 | 404 | ||
374 | add_disk(vblk->disk); | 405 | add_disk(vblk->disk); |
375 | return 0; | 406 | return 0; |
@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = { | |||
412 | static unsigned int features[] = { | 443 | static unsigned int features[] = { |
413 | VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, | 444 | VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, |
414 | VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, | 445 | VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
415 | VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH | 446 | VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY |
416 | }; | 447 | }; |
417 | 448 | ||
418 | /* | 449 | /* |
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index fd294c56d571..e52029e98919 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ | 15 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ |
16 | #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ | 16 | #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ |
17 | #define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */ | 17 | #define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */ |
18 | #define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ | ||
18 | 19 | ||
19 | struct virtio_blk_config { | 20 | struct virtio_blk_config { |
20 | /* The capacity (in 512-byte sectors). */ | 21 | /* The capacity (in 512-byte sectors). */ |
@@ -29,8 +30,20 @@ struct virtio_blk_config { | |||
29 | __u8 heads; | 30 | __u8 heads; |
30 | __u8 sectors; | 31 | __u8 sectors; |
31 | } geometry; | 32 | } geometry; |
33 | |||
32 | /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ | 34 | /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ |
33 | __u32 blk_size; | 35 | __u32 blk_size; |
36 | |||
37 | /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */ | ||
38 | /* exponent for physical block per logical block. */ | ||
39 | __u8 physical_block_exp; | ||
40 | /* alignment offset in logical blocks. */ | ||
41 | __u8 alignment_offset; | ||
42 | /* minimum I/O size without performance penalty in logical blocks. */ | ||
43 | __u16 min_io_size; | ||
44 | /* optimal sustained I/O size in logical blocks. */ | ||
45 | __u32 opt_io_size; | ||
46 | |||
34 | } __attribute__((packed)); | 47 | } __attribute__((packed)); |
35 | 48 | ||
36 | /* | 49 | /* |