Blame view

drivers/block/virtio_blk.c 9.41 KB
e467cde23   Rusty Russell   Block driver usin...
1
2
3
4
5
6
  //#define DEBUG
  #include <linux/spinlock.h>
  #include <linux/blkdev.h>
  #include <linux/hdreg.h>
  #include <linux/virtio.h>
  #include <linux/virtio_blk.h>
3d1266c70   Jens Axboe   SG: audit of driv...
7
  #include <linux/scatterlist.h>
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
8
  #define PART_BITS 4
e467cde23   Rusty Russell   Block driver usin...
9

d50ed907d   Christian Borntraeger   virtio_blk: imple...
10
  static int major, index;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
11

e467cde23   Rusty Russell   Block driver usin...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  struct virtio_blk
  {
  	spinlock_t lock;
  
  	struct virtio_device *vdev;
  	struct virtqueue *vq;
  
  	/* The disk structure for the kernel. */
  	struct gendisk *disk;
  
  	/* Request tracking. */
  	struct list_head reqs;
  
  	mempool_t *pool;
0864b79a1   Rusty Russell   virtio: block: dy...
26
27
  	/* What host tells us, plus 2 for header & tailer. */
  	unsigned int sg_elems;
e467cde23   Rusty Russell   Block driver usin...
28
  	/* Scatterlist: can be too big for stack. */
0864b79a1   Rusty Russell   virtio: block: dy...
29
  	struct scatterlist sg[/*sg_elems*/];
e467cde23   Rusty Russell   Block driver usin...
30
31
32
33
34
35
36
  };
  
  struct virtblk_req
  {
  	struct list_head list;
  	struct request *req;
  	struct virtio_blk_outhdr out_hdr;
cb38fa23c   Rusty Russell   virtio: de-struct...
37
  	u8 status;
e467cde23   Rusty Russell   Block driver usin...
38
  };
18445c4d5   Rusty Russell   virtio: explicit ...
39
  static void blk_done(struct virtqueue *vq)
e467cde23   Rusty Russell   Block driver usin...
40
41
42
43
44
45
46
47
  {
  	struct virtio_blk *vblk = vq->vdev->priv;
  	struct virtblk_req *vbr;
  	unsigned int len;
  	unsigned long flags;
  
  	spin_lock_irqsave(&vblk->lock, flags);
  	while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
8316982ac   Kiyoshi Ueda   virtio_blk: chang...
48
  		int error;
cb38fa23c   Rusty Russell   virtio: de-struct...
49
  		switch (vbr->status) {
e467cde23   Rusty Russell   Block driver usin...
50
  		case VIRTIO_BLK_S_OK:
8316982ac   Kiyoshi Ueda   virtio_blk: chang...
51
  			error = 0;
e467cde23   Rusty Russell   Block driver usin...
52
53
  			break;
  		case VIRTIO_BLK_S_UNSUPP:
8316982ac   Kiyoshi Ueda   virtio_blk: chang...
54
  			error = -ENOTTY;
e467cde23   Rusty Russell   Block driver usin...
55
56
  			break;
  		default:
8316982ac   Kiyoshi Ueda   virtio_blk: chang...
57
  			error = -EIO;
e467cde23   Rusty Russell   Block driver usin...
58
59
  			break;
  		}
8316982ac   Kiyoshi Ueda   virtio_blk: chang...
60
  		__blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
e467cde23   Rusty Russell   Block driver usin...
61
62
63
64
65
66
  		list_del(&vbr->list);
  		mempool_free(vbr, vblk->pool);
  	}
  	/* In case queue is stopped waiting for more buffers. */
  	blk_start_queue(vblk->disk->queue);
  	spin_unlock_irqrestore(&vblk->lock, flags);
e467cde23   Rusty Russell   Block driver usin...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  }
  
  static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
  		   struct request *req)
  {
  	unsigned long num, out, in;
  	struct virtblk_req *vbr;
  
  	vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
  	if (!vbr)
  		/* When another request finishes we'll try again. */
  		return false;
  
  	vbr->req = req;
  	if (blk_fs_request(vbr->req)) {
  		vbr->out_hdr.type = 0;
  		vbr->out_hdr.sector = vbr->req->sector;
766ca4428   Fernando Luis Vázquez Cao   virtio_blk: use a...
84
  		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
e467cde23   Rusty Russell   Block driver usin...
85
86
87
  	} else if (blk_pc_request(vbr->req)) {
  		vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
  		vbr->out_hdr.sector = 0;
766ca4428   Fernando Luis Vázquez Cao   virtio_blk: use a...
88
  		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
e467cde23   Rusty Russell   Block driver usin...
89
90
91
92
93
94
95
  	} else {
  		/* We don't put anything else in the queue. */
  		BUG();
  	}
  
  	if (blk_barrier_rq(vbr->req))
  		vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
e467cde23   Rusty Russell   Block driver usin...
96
97
  	sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
  	num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
cb38fa23c   Rusty Russell   virtio: de-struct...
98
  	sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
e467cde23   Rusty Russell   Block driver usin...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  
  	if (rq_data_dir(vbr->req) == WRITE) {
  		vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
  		out = 1 + num;
  		in = 1;
  	} else {
  		vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
  		out = 1;
  		in = 1 + num;
  	}
  
  	if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
  		mempool_free(vbr, vblk->pool);
  		return false;
  	}
  
  	list_add_tail(&vbr->list, &vblk->reqs);
  	return true;
  }
  
  static void do_virtblk_request(struct request_queue *q)
  {
  	struct virtio_blk *vblk = NULL;
  	struct request *req;
  	unsigned int issued = 0;
  
  	while ((req = elv_next_request(q)) != NULL) {
  		vblk = req->rq_disk->private_data;
0864b79a1   Rusty Russell   virtio: block: dy...
127
  		BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
e467cde23   Rusty Russell   Block driver usin...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  
  		/* If this request fails, stop queue and wait for something to
  		   finish to restart it. */
  		if (!do_req(q, vblk, req)) {
  			blk_stop_queue(q);
  			break;
  		}
  		blkdev_dequeue_request(req);
  		issued++;
  	}
  
  	if (issued)
  		vblk->vq->vq_ops->kick(vblk->vq);
  }
4e1098529   Al Viro   [PATCH] switch vi...
142
  static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
e467cde23   Rusty Russell   Block driver usin...
143
144
  			 unsigned cmd, unsigned long data)
  {
4e1098529   Al Viro   [PATCH] switch vi...
145
146
  	return scsi_cmd_ioctl(bdev->bd_disk->queue,
  			      bdev->bd_disk, mode, cmd,
e467cde23   Rusty Russell   Block driver usin...
147
148
  			      (void __user *)data);
  }
135da0b03   Christian Borntraeger   virtio_blk: provi...
149
150
151
  /* We provide getgeo only to please some old bootloader/partitioning tools */
  static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
  {
48e4043d4   Ryan Harper   virtio: add virti...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  	struct virtio_blk *vblk = bd->bd_disk->private_data;
  	struct virtio_blk_geometry vgeo;
  	int err;
  
  	/* see if the host passed in geometry config */
  	err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
  				offsetof(struct virtio_blk_config, geometry),
  				&vgeo);
  
  	if (!err) {
  		geo->heads = vgeo.heads;
  		geo->sectors = vgeo.sectors;
  		geo->cylinders = vgeo.cylinders;
  	} else {
  		/* some standard values, similar to sd */
  		geo->heads = 1 << 6;
  		geo->sectors = 1 << 5;
  		geo->cylinders = get_capacity(bd->bd_disk) >> 11;
  	}
135da0b03   Christian Borntraeger   virtio_blk: provi...
171
172
  	return 0;
  }
e467cde23   Rusty Russell   Block driver usin...
173
  static struct block_device_operations virtblk_fops = {
4e1098529   Al Viro   [PATCH] switch vi...
174
  	.locked_ioctl = virtblk_ioctl,
135da0b03   Christian Borntraeger   virtio_blk: provi...
175
176
  	.owner  = THIS_MODULE,
  	.getgeo = virtblk_getgeo,
e467cde23   Rusty Russell   Block driver usin...
177
  };
d50ed907d   Christian Borntraeger   virtio_blk: imple...
178
179
180
181
  static int index_to_minor(int index)
  {
  	return index << PART_BITS;
  }
e467cde23   Rusty Russell   Block driver usin...
182
183
184
  static int virtblk_probe(struct virtio_device *vdev)
  {
  	struct virtio_blk *vblk;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
185
  	int err;
e467cde23   Rusty Russell   Block driver usin...
186
187
  	u64 cap;
  	u32 v;
0864b79a1   Rusty Russell   virtio: block: dy...
188
  	u32 blk_size, sg_elems;
e467cde23   Rusty Russell   Block driver usin...
189

d50ed907d   Christian Borntraeger   virtio_blk: imple...
190
  	if (index_to_minor(index) >= 1 << MINORBITS)
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
191
  		return -ENOSPC;
0864b79a1   Rusty Russell   virtio: block: dy...
192
193
194
195
196
197
198
199
200
201
202
  	/* We need to know how many segments before we allocate. */
  	err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
  				offsetof(struct virtio_blk_config, seg_max),
  				&sg_elems);
  	if (err)
  		sg_elems = 1;
  
  	/* We need an extra sg elements at head and tail. */
  	sg_elems += 2;
  	vdev->priv = vblk = kmalloc(sizeof(*vblk) +
  				    sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL);
e467cde23   Rusty Russell   Block driver usin...
203
204
205
206
207
208
209
210
  	if (!vblk) {
  		err = -ENOMEM;
  		goto out;
  	}
  
  	INIT_LIST_HEAD(&vblk->reqs);
  	spin_lock_init(&vblk->lock);
  	vblk->vdev = vdev;
0864b79a1   Rusty Russell   virtio: block: dy...
211
212
  	vblk->sg_elems = sg_elems;
  	sg_init_table(vblk->sg, vblk->sg_elems);
e467cde23   Rusty Russell   Block driver usin...
213
214
  
  	/* We expect one virtqueue, for output. */
a586d4f60   Rusty Russell   virtio: simplify ...
215
  	vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
e467cde23   Rusty Russell   Block driver usin...
216
217
218
219
220
221
222
223
224
225
  	if (IS_ERR(vblk->vq)) {
  		err = PTR_ERR(vblk->vq);
  		goto out_free_vblk;
  	}
  
  	vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
  	if (!vblk->pool) {
  		err = -ENOMEM;
  		goto out_free_vq;
  	}
e467cde23   Rusty Russell   Block driver usin...
226
  	/* FIXME: How many partitions?  How long is a piece of string? */
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
227
  	vblk->disk = alloc_disk(1 << PART_BITS);
e467cde23   Rusty Russell   Block driver usin...
228
229
  	if (!vblk->disk) {
  		err = -ENOMEM;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
230
  		goto out_mempool;
e467cde23   Rusty Russell   Block driver usin...
231
232
233
234
235
236
237
  	}
  
  	vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
  	if (!vblk->disk->queue) {
  		err = -ENOMEM;
  		goto out_put_disk;
  	}
7d116b626   Fernando Luis Vázquez Cao   virtio_blk: set q...
238
  	queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
d50ed907d   Christian Borntraeger   virtio_blk: imple...
239
240
241
242
243
244
245
246
247
248
249
250
  	if (index < 26) {
  		sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
  	} else if (index < (26 + 1) * 26) {
  		sprintf(vblk->disk->disk_name, "vd%c%c",
  			'a' + index / 26 - 1, 'a' + index % 26);
  	} else {
  		const unsigned int m1 = (index / 26 - 1) / 26 - 1;
  		const unsigned int m2 = (index / 26 - 1) % 26;
  		const unsigned int m3 =  index % 26;
  		sprintf(vblk->disk->disk_name, "vd%c%c%c",
  			'a' + m1, 'a' + m2, 'a' + m3);
  	}
e467cde23   Rusty Russell   Block driver usin...
251
  	vblk->disk->major = major;
d50ed907d   Christian Borntraeger   virtio_blk: imple...
252
  	vblk->disk->first_minor = index_to_minor(index);
e467cde23   Rusty Russell   Block driver usin...
253
254
  	vblk->disk->private_data = vblk;
  	vblk->disk->fops = &virtblk_fops;
c48393467   Jeremy Katz   virtio: Fix sysfs...
255
  	vblk->disk->driverfs_dev = &vdev->dev;
d50ed907d   Christian Borntraeger   virtio_blk: imple...
256
  	index++;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
257

e467cde23   Rusty Russell   Block driver usin...
258
  	/* If barriers are supported, tell block layer that queue is ordered */
c45a6816c   Rusty Russell   virtio: explicit ...
259
  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
e467cde23   Rusty Russell   Block driver usin...
260
  		blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
3ef536095   Christian Borntraeger   virtio_blk: allow...
261
262
263
  	/* If disk is read-only in the host, the guest should obey */
  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
  		set_disk_ro(vblk->disk, 1);
a586d4f60   Rusty Russell   virtio: simplify ...
264
  	/* Host must always specify the capacity. */
72e61eb40   Rusty Russell   virtio: change co...
265
266
  	vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
  			  &cap, sizeof(cap));
e467cde23   Rusty Russell   Block driver usin...
267
268
269
270
271
272
273
274
275
  
  	/* If capacity is too big, truncate with warning. */
  	if ((sector_t)cap != cap) {
  		dev_warn(&vdev->dev, "Capacity %llu too large: truncating
  ",
  			 (unsigned long long)cap);
  		cap = (sector_t)-1;
  	}
  	set_capacity(vblk->disk, cap);
0864b79a1   Rusty Russell   virtio: block: dy...
276
277
278
  	/* We can handle whatever the host told us to handle. */
  	blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
  	blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
4b7f7e204   Rusty Russell   virtio: set max_s...
279
280
  	/* No real sector limit. */
  	blk_queue_max_sectors(vblk->disk->queue, -1U);
a586d4f60   Rusty Russell   virtio: simplify ...
281
282
283
284
285
  	/* Host can optionally specify maximum segment size and number of
  	 * segments. */
  	err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
  				offsetof(struct virtio_blk_config, size_max),
  				&v);
e467cde23   Rusty Russell   Block driver usin...
286
287
  	if (!err)
  		blk_queue_max_segment_size(vblk->disk->queue, v);
4b7f7e204   Rusty Russell   virtio: set max_s...
288
  	else
b194aee95   Randy Dunlap   virtio_blk: fix t...
289
  		blk_queue_max_segment_size(vblk->disk->queue, -1U);
e467cde23   Rusty Russell   Block driver usin...
290

066f4d82a   Christian Borntraeger   virtio_blk: check...
291
292
293
294
295
296
  	/* Host can optionally specify the block size of the device */
  	err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
  				offsetof(struct virtio_blk_config, blk_size),
  				&blk_size);
  	if (!err)
  		blk_queue_hardsect_size(vblk->disk->queue, blk_size);
e467cde23   Rusty Russell   Block driver usin...
297
298
299
300
301
  	add_disk(vblk->disk);
  	return 0;
  
  out_put_disk:
  	put_disk(vblk->disk);
e467cde23   Rusty Russell   Block driver usin...
302
303
304
305
306
307
308
309
310
311
312
313
314
  out_mempool:
  	mempool_destroy(vblk->pool);
  out_free_vq:
  	vdev->config->del_vq(vblk->vq);
  out_free_vblk:
  	kfree(vblk);
  out:
  	return err;
  }
  
  static void virtblk_remove(struct virtio_device *vdev)
  {
  	struct virtio_blk *vblk = vdev->priv;
e467cde23   Rusty Russell   Block driver usin...
315

6e5aa7efb   Rusty Russell   virtio: reset fun...
316
  	/* Nothing should be pending. */
e467cde23   Rusty Russell   Block driver usin...
317
  	BUG_ON(!list_empty(&vblk->reqs));
6e5aa7efb   Rusty Russell   virtio: reset fun...
318
319
320
  
  	/* Stop all the virtqueues. */
  	vdev->config->reset(vdev);
ac9d463af   Chris Lalancette   Fix crash in virt...
321
  	del_gendisk(vblk->disk);
e467cde23   Rusty Russell   Block driver usin...
322
323
  	blk_cleanup_queue(vblk->disk->queue);
  	put_disk(vblk->disk);
e467cde23   Rusty Russell   Block driver usin...
324
  	mempool_destroy(vblk->pool);
74b2553f1   Rusty Russell   virtio: fix modul...
325
  	vdev->config->del_vq(vblk->vq);
e467cde23   Rusty Russell   Block driver usin...
326
327
328
329
330
331
332
  	kfree(vblk);
  }
  
  static struct virtio_device_id id_table[] = {
  	{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
  	{ 0 },
  };
c45a6816c   Rusty Russell   virtio: explicit ...
333
334
  static unsigned int features[] = {
  	VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
066f4d82a   Christian Borntraeger   virtio_blk: check...
335
  	VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
c45a6816c   Rusty Russell   virtio: explicit ...
336
  };
e467cde23   Rusty Russell   Block driver usin...
337
  static struct virtio_driver virtio_blk = {
c45a6816c   Rusty Russell   virtio: explicit ...
338
339
  	.feature_table = features,
  	.feature_table_size = ARRAY_SIZE(features),
e467cde23   Rusty Russell   Block driver usin...
340
341
342
343
344
345
346
347
348
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
  	.probe =	virtblk_probe,
  	.remove =	__devexit_p(virtblk_remove),
  };
  
  static int __init init(void)
  {
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
349
350
351
  	major = register_blkdev(0, "virtblk");
  	if (major < 0)
  		return major;
e467cde23   Rusty Russell   Block driver usin...
352
353
354
355
356
  	return register_virtio_driver(&virtio_blk);
  }
  
  static void __exit fini(void)
  {
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
357
  	unregister_blkdev(major, "virtblk");
e467cde23   Rusty Russell   Block driver usin...
358
359
360
361
362
363
364
365
  	unregister_virtio_driver(&virtio_blk);
  }
  module_init(init);
  module_exit(fini);
  
  MODULE_DEVICE_TABLE(virtio, id_table);
  MODULE_DESCRIPTION("Virtio block driver");
  MODULE_LICENSE("GPL");