virtio_blk.c 11.4 KB
Newer Older
R
Rusty Russell 已提交
1 2 3 4 5
//#define DEBUG
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/virtio.h>
6
#include <linux/virtio_ids.h>
R
Rusty Russell 已提交
7
#include <linux/virtio_blk.h>
8 9
#include <linux/scatterlist.h>

10
#define PART_BITS 4
R
Rusty Russell 已提交
11

12
static int major, index;
13

R
Rusty Russell 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
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;

29 30 31
	/* What host tells us, plus 2 for header & tailer. */
	unsigned int sg_elems;

R
Rusty Russell 已提交
32
	/* Scatterlist: can be too big for stack. */
33
	struct scatterlist sg[/*sg_elems*/];
R
Rusty Russell 已提交
34 35 36 37 38 39 40
};

struct virtblk_req
{
	struct list_head list;
	struct request *req;
	struct virtio_blk_outhdr out_hdr;
41
	struct virtio_scsi_inhdr in_hdr;
42
	u8 status;
R
Rusty Russell 已提交
43 44
};

45
static void blk_done(struct virtqueue *vq)
R
Rusty Russell 已提交
46 47 48 49 50 51 52 53
{
	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) {
54
		int error;
55

56
		switch (vbr->status) {
R
Rusty Russell 已提交
57
		case VIRTIO_BLK_S_OK:
58
			error = 0;
R
Rusty Russell 已提交
59 60
			break;
		case VIRTIO_BLK_S_UNSUPP:
61
			error = -ENOTTY;
R
Rusty Russell 已提交
62 63
			break;
		default:
64
			error = -EIO;
R
Rusty Russell 已提交
65 66 67
			break;
		}

68 69 70 71 72 73
		if (blk_pc_request(vbr->req)) {
			vbr->req->resid_len = vbr->in_hdr.residual;
			vbr->req->sense_len = vbr->in_hdr.sense_len;
			vbr->req->errors = vbr->in_hdr.errors;
		}

74
		__blk_end_request_all(vbr->req, error);
R
Rusty Russell 已提交
75 76 77 78 79 80 81 82 83 84 85
		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);
}

static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
		   struct request *req)
{
86
	unsigned long num, out = 0, in = 0;
R
Rusty Russell 已提交
87 88 89 90 91 92 93 94 95 96
	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;
97
		vbr->out_hdr.sector = blk_rq_pos(vbr->req);
98
		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
R
Rusty Russell 已提交
99 100 101
	} else if (blk_pc_request(vbr->req)) {
		vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
		vbr->out_hdr.sector = 0;
102
		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
R
Rusty Russell 已提交
103 104 105 106 107 108 109 110
	} 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;

111
	sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr));
R
Rusty Russell 已提交
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	/*
	 * If this is a packet command we need a couple of additional headers.
	 * Behind the normal outhdr we put a segment with the scsi command
	 * block, and before the normal inhdr we put the sense data and the
	 * inhdr with additional status information before the normal inhdr.
	 */
	if (blk_pc_request(vbr->req))
		sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len);

	num = blk_rq_map_sg(q, vbr->req, vblk->sg + out);

	if (blk_pc_request(vbr->req)) {
		sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96);
		sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr,
			   sizeof(vbr->in_hdr));
	}

	sg_set_buf(&vblk->sg[num + out + in++], &vbr->status,
		   sizeof(vbr->status));

	if (num) {
		if (rq_data_dir(vbr->req) == WRITE) {
			vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
			out += num;
		} else {
			vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
			in += num;
		}
R
Rusty Russell 已提交
141 142
	}

143
	if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
R
Rusty Russell 已提交
144 145 146 147 148 149 150 151 152 153
		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)
{
154
	struct virtio_blk *vblk = q->queuedata;
R
Rusty Russell 已提交
155 156 157
	struct request *req;
	unsigned int issued = 0;

158
	while ((req = blk_peek_request(q)) != NULL) {
159
		BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
R
Rusty Russell 已提交
160 161 162 163 164 165 166

		/* 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;
		}
167
		blk_start_request(req);
R
Rusty Russell 已提交
168 169 170 171 172 173 174
		issued++;
	}

	if (issued)
		vblk->vq->vq_ops->kick(vblk->vq);
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
/* return ATA identify data
 */
static int virtblk_identify(struct gendisk *disk, void *argp)
{
	struct virtio_blk *vblk = disk->private_data;
	void *opaque;
	int err = -ENOMEM;

	opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
	if (!opaque)
		goto out;

	err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
		offsetof(struct virtio_blk_config, identify), opaque,
		VIRTIO_BLK_ID_BYTES);

	if (err)
		goto out_kfree;

	if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
		err = -EFAULT;

out_kfree:
	kfree(opaque);
out:
	return err;
}

A
Al Viro 已提交
203
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
R
Rusty Russell 已提交
204 205
			 unsigned cmd, unsigned long data)
{
206 207
	struct gendisk *disk = bdev->bd_disk;
	struct virtio_blk *vblk = disk->private_data;
208 209 210 211
	void __user *argp = (void __user *)data;

	if (cmd == HDIO_GET_IDENTITY)
		return virtblk_identify(disk, argp);
212 213 214 215 216

	/*
	 * Only allow the generic SCSI ioctls if the host can support it.
	 */
	if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
217
		return -ENOTTY;
218

219
	return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
R
Rusty Russell 已提交
220 221
}

222 223 224
/* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	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;
	}
244 245 246
	return 0;
}

R
Rusty Russell 已提交
247
static struct block_device_operations virtblk_fops = {
A
Al Viro 已提交
248
	.locked_ioctl = virtblk_ioctl,
249 250
	.owner  = THIS_MODULE,
	.getgeo = virtblk_getgeo,
R
Rusty Russell 已提交
251 252
};

253 254 255 256 257
static int index_to_minor(int index)
{
	return index << PART_BITS;
}

258
static int __devinit virtblk_probe(struct virtio_device *vdev)
R
Rusty Russell 已提交
259 260
{
	struct virtio_blk *vblk;
261
	int err;
R
Rusty Russell 已提交
262 263
	u64 cap;
	u32 v;
264
	u32 blk_size, sg_elems;
R
Rusty Russell 已提交
265

266
	if (index_to_minor(index) >= 1 << MINORBITS)
267 268
		return -ENOSPC;

269 270 271 272 273 274 275 276 277 278 279
	/* 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);
R
Rusty Russell 已提交
280 281 282 283 284 285 286 287
	if (!vblk) {
		err = -ENOMEM;
		goto out;
	}

	INIT_LIST_HEAD(&vblk->reqs);
	spin_lock_init(&vblk->lock);
	vblk->vdev = vdev;
288 289
	vblk->sg_elems = sg_elems;
	sg_init_table(vblk->sg, vblk->sg_elems);
R
Rusty Russell 已提交
290 291

	/* We expect one virtqueue, for output. */
292
	vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
R
Rusty Russell 已提交
293 294 295 296 297 298 299 300 301 302 303 304
	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;
	}

	/* FIXME: How many partitions?  How long is a piece of string? */
305
	vblk->disk = alloc_disk(1 << PART_BITS);
R
Rusty Russell 已提交
306 307
	if (!vblk->disk) {
		err = -ENOMEM;
308
		goto out_mempool;
R
Rusty Russell 已提交
309 310 311 312 313 314 315 316
	}

	vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
	if (!vblk->disk->queue) {
		err = -ENOMEM;
		goto out_put_disk;
	}

317
	vblk->disk->queue->queuedata = vblk;
318 319
	queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);

320 321 322 323 324 325 326 327 328 329 330 331 332
	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);
	}

R
Rusty Russell 已提交
333
	vblk->disk->major = major;
334
	vblk->disk->first_minor = index_to_minor(index);
R
Rusty Russell 已提交
335 336
	vblk->disk->private_data = vblk;
	vblk->disk->fops = &virtblk_fops;
337
	vblk->disk->driverfs_dev = &vdev->dev;
338
	index++;
339

R
Rusty Russell 已提交
340
	/* If barriers are supported, tell block layer that queue is ordered */
341
	if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
R
Rusty Russell 已提交
342 343
		blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);

344 345 346 347
	/* 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);

348
	/* Host must always specify the capacity. */
349 350
	vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
			  &cap, sizeof(cap));
R
Rusty Russell 已提交
351 352 353 354 355 356 357 358 359

	/* If capacity is too big, truncate with warning. */
	if ((sector_t)cap != cap) {
		dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
			 (unsigned long long)cap);
		cap = (sector_t)-1;
	}
	set_capacity(vblk->disk, cap);

360 361 362 363
	/* 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);

364 365 366
	/* No need to bounce any requests */
	blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);

367 368 369
	/* No real sector limit. */
	blk_queue_max_sectors(vblk->disk->queue, -1U);

370 371 372 373 374
	/* 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);
R
Rusty Russell 已提交
375 376
	if (!err)
		blk_queue_max_segment_size(vblk->disk->queue, v);
377
	else
R
Randy Dunlap 已提交
378
		blk_queue_max_segment_size(vblk->disk->queue, -1U);
R
Rusty Russell 已提交
379

380 381 382 383 384
	/* 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)
385
		blk_queue_logical_block_size(vblk->disk->queue, blk_size);
386

R
Rusty Russell 已提交
387 388 389 390 391 392 393 394
	add_disk(vblk->disk);
	return 0;

out_put_disk:
	put_disk(vblk->disk);
out_mempool:
	mempool_destroy(vblk->pool);
out_free_vq:
395
	vdev->config->del_vqs(vdev);
R
Rusty Russell 已提交
396 397 398 399 400 401
out_free_vblk:
	kfree(vblk);
out:
	return err;
}

402
static void __devexit virtblk_remove(struct virtio_device *vdev)
R
Rusty Russell 已提交
403 404 405
{
	struct virtio_blk *vblk = vdev->priv;

R
Rusty Russell 已提交
406
	/* Nothing should be pending. */
R
Rusty Russell 已提交
407
	BUG_ON(!list_empty(&vblk->reqs));
R
Rusty Russell 已提交
408 409 410 411

	/* Stop all the virtqueues. */
	vdev->config->reset(vdev);

412
	del_gendisk(vblk->disk);
R
Rusty Russell 已提交
413 414 415
	blk_cleanup_queue(vblk->disk->queue);
	put_disk(vblk->disk);
	mempool_destroy(vblk->pool);
416
	vdev->config->del_vqs(vdev);
R
Rusty Russell 已提交
417 418 419 420 421 422 423 424
	kfree(vblk);
}

static struct virtio_device_id id_table[] = {
	{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
	{ 0 },
};

425 426
static unsigned int features[] = {
	VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
427
	VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
428
	VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY
429 430
};

431 432 433 434 435 436
/*
 * virtio_blk causes spurious section mismatch warning by
 * simultaneously referring to a __devinit and a __devexit function.
 * Use __refdata to avoid this warning.
 */
static struct virtio_driver __refdata virtio_blk = {
437 438
	.feature_table = features,
	.feature_table_size = ARRAY_SIZE(features),
R
Rusty Russell 已提交
439 440 441 442 443 444 445 446 447
	.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)
{
448 449 450
	major = register_blkdev(0, "virtblk");
	if (major < 0)
		return major;
R
Rusty Russell 已提交
451 452 453 454 455
	return register_virtio_driver(&virtio_blk);
}

static void __exit fini(void)
{
456
	unregister_blkdev(major, "virtblk");
R
Rusty Russell 已提交
457 458 459 460 461 462 463 464
	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");