aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-04 11:00:54 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-04 11:00:54 -0500
commit93890b71a34f9490673a6edd56b61c2124215e46 (patch)
treec5d82620f2cb69f0bf43639e63f54b0c0e2eb744 /drivers/block
parentf5bb3a5e9dcdb8435471562b6cada89525cf4df1 (diff)
parent6b35e40767c6c1ac783330109ae8e0c09ea6bc82 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: (25 commits) virtio: balloon driver virtio: Use PCI revision field to indicate virtio PCI ABI version virtio: PCI device virtio_blk: implement naming for vda-vdz,vdaa-vdzz,vdaaa-vdzzz virtio_blk: Dont waste major numbers virtio_blk: provide getgeo virtio_net: parametrize the napi_weight for virtio receive queue. virtio: free transmit skbs when notified, not on next xmit. virtio: flush buffers on open virtnet: remove double ether_setup virtio: Allow virtio to be modular and used by modules virtio: Use the sg_phys convenience function. virtio: Put the virtio under the virtualization menu virtio: handle interrupts after callbacks turned off virtio: reset function virtio: populate network rings in the probe routine, not open virtio: Tweak virtio_net defines virtio: Net header needs hdr_len virtio: remove unused id field from struct virtio_blk_outhdr virtio: clarify NO_NOTIFY flag usage ...
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/Kconfig3
-rw-r--r--drivers/block/virtio_blk.c106
2 files changed, 67 insertions, 42 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index f2122855d4ec..64e5148d82bc 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -440,6 +440,7 @@ config VIRTIO_BLK
440 tristate "Virtio block driver (EXPERIMENTAL)" 440 tristate "Virtio block driver (EXPERIMENTAL)"
441 depends on EXPERIMENTAL && VIRTIO 441 depends on EXPERIMENTAL && VIRTIO
442 ---help--- 442 ---help---
443 This is the virtual block driver for lguest. Say Y or M. 443 This is the virtual block driver for virtio. It can be used with
444 lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
444 445
445endif # BLK_DEV 446endif # BLK_DEV
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 924ddd8bccd2..3b1a68d6eddb 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -7,8 +7,10 @@
7#include <linux/scatterlist.h> 7#include <linux/scatterlist.h>
8 8
9#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS) 9#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS)
10#define PART_BITS 4
11
12static int major, index;
10 13
11static unsigned char virtblk_index = 'a';
12struct virtio_blk 14struct virtio_blk
13{ 15{
14 spinlock_t lock; 16 spinlock_t lock;
@@ -36,7 +38,7 @@ struct virtblk_req
36 struct virtio_blk_inhdr in_hdr; 38 struct virtio_blk_inhdr in_hdr;
37}; 39};
38 40
39static bool blk_done(struct virtqueue *vq) 41static void blk_done(struct virtqueue *vq)
40{ 42{
41 struct virtio_blk *vblk = vq->vdev->priv; 43 struct virtio_blk *vblk = vq->vdev->priv;
42 struct virtblk_req *vbr; 44 struct virtblk_req *vbr;
@@ -65,7 +67,6 @@ static bool blk_done(struct virtqueue *vq)
65 /* In case queue is stopped waiting for more buffers. */ 67 /* In case queue is stopped waiting for more buffers. */
66 blk_start_queue(vblk->disk->queue); 68 blk_start_queue(vblk->disk->queue);
67 spin_unlock_irqrestore(&vblk->lock, flags); 69 spin_unlock_irqrestore(&vblk->lock, flags);
68 return true;
69} 70}
70 71
71static bool do_req(struct request_queue *q, struct virtio_blk *vblk, 72static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -153,20 +154,37 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
153 (void __user *)data); 154 (void __user *)data);
154} 155}
155 156
157/* We provide getgeo only to please some old bootloader/partitioning tools */
158static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
159{
160 /* some standard values, similar to sd */
161 geo->heads = 1 << 6;
162 geo->sectors = 1 << 5;
163 geo->cylinders = get_capacity(bd->bd_disk) >> 11;
164 return 0;
165}
166
156static struct block_device_operations virtblk_fops = { 167static struct block_device_operations virtblk_fops = {
157 .ioctl = virtblk_ioctl, 168 .ioctl = virtblk_ioctl,
158 .owner = THIS_MODULE, 169 .owner = THIS_MODULE,
170 .getgeo = virtblk_getgeo,
159}; 171};
160 172
173static int index_to_minor(int index)
174{
175 return index << PART_BITS;
176}
177
161static int virtblk_probe(struct virtio_device *vdev) 178static int virtblk_probe(struct virtio_device *vdev)
162{ 179{
163 struct virtio_blk *vblk; 180 struct virtio_blk *vblk;
164 int err, major; 181 int err;
165 void *token;
166 unsigned int len;
167 u64 cap; 182 u64 cap;
168 u32 v; 183 u32 v;
169 184
185 if (index_to_minor(index) >= 1 << MINORBITS)
186 return -ENOSPC;
187
170 vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); 188 vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
171 if (!vblk) { 189 if (!vblk) {
172 err = -ENOMEM; 190 err = -ENOMEM;
@@ -178,7 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev)
178 vblk->vdev = vdev; 196 vblk->vdev = vdev;
179 197
180 /* We expect one virtqueue, for output. */ 198 /* We expect one virtqueue, for output. */
181 vblk->vq = vdev->config->find_vq(vdev, blk_done); 199 vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
182 if (IS_ERR(vblk->vq)) { 200 if (IS_ERR(vblk->vq)) {
183 err = PTR_ERR(vblk->vq); 201 err = PTR_ERR(vblk->vq);
184 goto out_free_vblk; 202 goto out_free_vblk;
@@ -190,17 +208,11 @@ static int virtblk_probe(struct virtio_device *vdev)
190 goto out_free_vq; 208 goto out_free_vq;
191 } 209 }
192 210
193 major = register_blkdev(0, "virtblk");
194 if (major < 0) {
195 err = major;
196 goto out_mempool;
197 }
198
199 /* FIXME: How many partitions? How long is a piece of string? */ 211 /* FIXME: How many partitions? How long is a piece of string? */
200 vblk->disk = alloc_disk(1 << 4); 212 vblk->disk = alloc_disk(1 << PART_BITS);
201 if (!vblk->disk) { 213 if (!vblk->disk) {
202 err = -ENOMEM; 214 err = -ENOMEM;
203 goto out_unregister_blkdev; 215 goto out_mempool;
204 } 216 }
205 217
206 vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); 218 vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
@@ -209,22 +221,32 @@ static int virtblk_probe(struct virtio_device *vdev)
209 goto out_put_disk; 221 goto out_put_disk;
210 } 222 }
211 223
212 sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++); 224 if (index < 26) {
225 sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
226 } else if (index < (26 + 1) * 26) {
227 sprintf(vblk->disk->disk_name, "vd%c%c",
228 'a' + index / 26 - 1, 'a' + index % 26);
229 } else {
230 const unsigned int m1 = (index / 26 - 1) / 26 - 1;
231 const unsigned int m2 = (index / 26 - 1) % 26;
232 const unsigned int m3 = index % 26;
233 sprintf(vblk->disk->disk_name, "vd%c%c%c",
234 'a' + m1, 'a' + m2, 'a' + m3);
235 }
236
213 vblk->disk->major = major; 237 vblk->disk->major = major;
214 vblk->disk->first_minor = 0; 238 vblk->disk->first_minor = index_to_minor(index);
215 vblk->disk->private_data = vblk; 239 vblk->disk->private_data = vblk;
216 vblk->disk->fops = &virtblk_fops; 240 vblk->disk->fops = &virtblk_fops;
241 index++;
217 242
218 /* If barriers are supported, tell block layer that queue is ordered */ 243 /* If barriers are supported, tell block layer that queue is ordered */
219 token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len); 244 if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
220 if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
221 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); 245 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
222 246
223 err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap); 247 /* Host must always specify the capacity. */
224 if (err) { 248 __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
225 dev_err(&vdev->dev, "Bad/missing capacity in config\n"); 249 &cap);
226 goto out_cleanup_queue;
227 }
228 250
229 /* If capacity is too big, truncate with warning. */ 251 /* If capacity is too big, truncate with warning. */
230 if ((sector_t)cap != cap) { 252 if ((sector_t)cap != cap) {
@@ -234,31 +256,25 @@ static int virtblk_probe(struct virtio_device *vdev)
234 } 256 }
235 set_capacity(vblk->disk, cap); 257 set_capacity(vblk->disk, cap);
236 258
237 err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v); 259 /* Host can optionally specify maximum segment size and number of
260 * segments. */
261 err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
262 offsetof(struct virtio_blk_config, size_max),
263 &v);
238 if (!err) 264 if (!err)
239 blk_queue_max_segment_size(vblk->disk->queue, v); 265 blk_queue_max_segment_size(vblk->disk->queue, v);
240 else if (err != -ENOENT) {
241 dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
242 goto out_cleanup_queue;
243 }
244 266
245 err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v); 267 err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
268 offsetof(struct virtio_blk_config, seg_max),
269 &v);
246 if (!err) 270 if (!err)
247 blk_queue_max_hw_segments(vblk->disk->queue, v); 271 blk_queue_max_hw_segments(vblk->disk->queue, v);
248 else if (err != -ENOENT) {
249 dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
250 goto out_cleanup_queue;
251 }
252 272
253 add_disk(vblk->disk); 273 add_disk(vblk->disk);
254 return 0; 274 return 0;
255 275
256out_cleanup_queue:
257 blk_cleanup_queue(vblk->disk->queue);
258out_put_disk: 276out_put_disk:
259 put_disk(vblk->disk); 277 put_disk(vblk->disk);
260out_unregister_blkdev:
261 unregister_blkdev(major, "virtblk");
262out_mempool: 278out_mempool:
263 mempool_destroy(vblk->pool); 279 mempool_destroy(vblk->pool);
264out_free_vq: 280out_free_vq:
@@ -274,12 +290,16 @@ static void virtblk_remove(struct virtio_device *vdev)
274 struct virtio_blk *vblk = vdev->priv; 290 struct virtio_blk *vblk = vdev->priv;
275 int major = vblk->disk->major; 291 int major = vblk->disk->major;
276 292
293 /* Nothing should be pending. */
277 BUG_ON(!list_empty(&vblk->reqs)); 294 BUG_ON(!list_empty(&vblk->reqs));
295
296 /* Stop all the virtqueues. */
297 vdev->config->reset(vdev);
298
278 blk_cleanup_queue(vblk->disk->queue); 299 blk_cleanup_queue(vblk->disk->queue);
279 put_disk(vblk->disk); 300 put_disk(vblk->disk);
280 unregister_blkdev(major, "virtblk"); 301 unregister_blkdev(major, "virtblk");
281 mempool_destroy(vblk->pool); 302 mempool_destroy(vblk->pool);
282 /* There should be nothing in the queue now, so no need to shutdown */
283 vdev->config->del_vq(vblk->vq); 303 vdev->config->del_vq(vblk->vq);
284 kfree(vblk); 304 kfree(vblk);
285} 305}
@@ -299,11 +319,15 @@ static struct virtio_driver virtio_blk = {
299 319
300static int __init init(void) 320static int __init init(void)
301{ 321{
322 major = register_blkdev(0, "virtblk");
323 if (major < 0)
324 return major;
302 return register_virtio_driver(&virtio_blk); 325 return register_virtio_driver(&virtio_blk);
303} 326}
304 327
305static void __exit fini(void) 328static void __exit fini(void)
306{ 329{
330 unregister_blkdev(major, "virtblk");
307 unregister_virtio_driver(&virtio_blk); 331 unregister_virtio_driver(&virtio_blk);
308} 332}
309module_init(init); 333module_init(init);