| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | //#define DEBUG |
|---|
| 2 | 3 | #include <linux/spinlock.h> |
|---|
| 3 | 4 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 10 | 11 | #include <linux/virtio_blk.h> |
|---|
| 11 | 12 | #include <linux/scatterlist.h> |
|---|
| 12 | 13 | #include <linux/string_helpers.h> |
|---|
| 13 | | -#include <scsi/scsi_cmnd.h> |
|---|
| 14 | 14 | #include <linux/idr.h> |
|---|
| 15 | 15 | #include <linux/blk-mq.h> |
|---|
| 16 | 16 | #include <linux/blk-mq-virtio.h> |
|---|
| 17 | 17 | #include <linux/numa.h> |
|---|
| 18 | +#include <uapi/linux/virtio_ring.h> |
|---|
| 18 | 19 | |
|---|
| 19 | 20 | #define PART_BITS 4 |
|---|
| 20 | 21 | #define VQ_NAME_LEN 16 |
|---|
| 22 | +#define MAX_DISCARD_SEGMENTS 256u |
|---|
| 21 | 23 | |
|---|
| 22 | 24 | static int major; |
|---|
| 23 | 25 | static DEFINE_IDA(vd_index_ida); |
|---|
| .. | .. |
|---|
| 70 | 72 | }; |
|---|
| 71 | 73 | |
|---|
| 72 | 74 | struct virtblk_req { |
|---|
| 73 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 74 | | - struct scsi_request sreq; /* for SCSI passthrough, must be first */ |
|---|
| 75 | | - u8 sense[SCSI_SENSE_BUFFERSIZE]; |
|---|
| 76 | | - struct virtio_scsi_inhdr in_hdr; |
|---|
| 77 | | -#endif |
|---|
| 78 | 75 | struct virtio_blk_outhdr out_hdr; |
|---|
| 79 | 76 | u8 status; |
|---|
| 80 | 77 | struct scatterlist sg[]; |
|---|
| .. | .. |
|---|
| 91 | 88 | return BLK_STS_IOERR; |
|---|
| 92 | 89 | } |
|---|
| 93 | 90 | } |
|---|
| 94 | | - |
|---|
| 95 | | -/* |
|---|
| 96 | | - * If this is a packet command we need a couple of additional headers. Behind |
|---|
| 97 | | - * the normal outhdr we put a segment with the scsi command block, and before |
|---|
| 98 | | - * the normal inhdr we put the sense data and the inhdr with additional status |
|---|
| 99 | | - * information. |
|---|
| 100 | | - */ |
|---|
| 101 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 102 | | -static int virtblk_add_req_scsi(struct virtqueue *vq, struct virtblk_req *vbr, |
|---|
| 103 | | - struct scatterlist *data_sg, bool have_data) |
|---|
| 104 | | -{ |
|---|
| 105 | | - struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6]; |
|---|
| 106 | | - unsigned int num_out = 0, num_in = 0; |
|---|
| 107 | | - |
|---|
| 108 | | - sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); |
|---|
| 109 | | - sgs[num_out++] = &hdr; |
|---|
| 110 | | - sg_init_one(&cmd, vbr->sreq.cmd, vbr->sreq.cmd_len); |
|---|
| 111 | | - sgs[num_out++] = &cmd; |
|---|
| 112 | | - |
|---|
| 113 | | - if (have_data) { |
|---|
| 114 | | - if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) |
|---|
| 115 | | - sgs[num_out++] = data_sg; |
|---|
| 116 | | - else |
|---|
| 117 | | - sgs[num_out + num_in++] = data_sg; |
|---|
| 118 | | - } |
|---|
| 119 | | - |
|---|
| 120 | | - sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE); |
|---|
| 121 | | - sgs[num_out + num_in++] = &sense; |
|---|
| 122 | | - sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr)); |
|---|
| 123 | | - sgs[num_out + num_in++] = &inhdr; |
|---|
| 124 | | - sg_init_one(&status, &vbr->status, sizeof(vbr->status)); |
|---|
| 125 | | - sgs[num_out + num_in++] = &status; |
|---|
| 126 | | - |
|---|
| 127 | | - return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
|---|
| 128 | | -} |
|---|
| 129 | | - |
|---|
| 130 | | -static inline void virtblk_scsi_request_done(struct request *req) |
|---|
| 131 | | -{ |
|---|
| 132 | | - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
|---|
| 133 | | - struct virtio_blk *vblk = req->q->queuedata; |
|---|
| 134 | | - struct scsi_request *sreq = &vbr->sreq; |
|---|
| 135 | | - |
|---|
| 136 | | - sreq->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual); |
|---|
| 137 | | - sreq->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len); |
|---|
| 138 | | - sreq->result = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors); |
|---|
| 139 | | -} |
|---|
| 140 | | - |
|---|
| 141 | | -static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, |
|---|
| 142 | | - unsigned int cmd, unsigned long data) |
|---|
| 143 | | -{ |
|---|
| 144 | | - struct gendisk *disk = bdev->bd_disk; |
|---|
| 145 | | - struct virtio_blk *vblk = disk->private_data; |
|---|
| 146 | | - |
|---|
| 147 | | - /* |
|---|
| 148 | | - * Only allow the generic SCSI ioctls if the host can support it. |
|---|
| 149 | | - */ |
|---|
| 150 | | - if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) |
|---|
| 151 | | - return -ENOTTY; |
|---|
| 152 | | - |
|---|
| 153 | | - return scsi_cmd_blk_ioctl(bdev, mode, cmd, |
|---|
| 154 | | - (void __user *)data); |
|---|
| 155 | | -} |
|---|
| 156 | | -#else |
|---|
| 157 | | -static inline int virtblk_add_req_scsi(struct virtqueue *vq, |
|---|
| 158 | | - struct virtblk_req *vbr, struct scatterlist *data_sg, |
|---|
| 159 | | - bool have_data) |
|---|
| 160 | | -{ |
|---|
| 161 | | - return -EIO; |
|---|
| 162 | | -} |
|---|
| 163 | | -static inline void virtblk_scsi_request_done(struct request *req) |
|---|
| 164 | | -{ |
|---|
| 165 | | -} |
|---|
| 166 | | -#define virtblk_ioctl NULL |
|---|
| 167 | | -#endif /* CONFIG_VIRTIO_BLK_SCSI */ |
|---|
| 168 | 91 | |
|---|
| 169 | 92 | static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr, |
|---|
| 170 | 93 | struct scatterlist *data_sg, bool have_data) |
|---|
| .. | .. |
|---|
| 188 | 111 | return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
|---|
| 189 | 112 | } |
|---|
| 190 | 113 | |
|---|
| 114 | +static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) |
|---|
| 115 | +{ |
|---|
| 116 | + unsigned short segments = blk_rq_nr_discard_segments(req); |
|---|
| 117 | + unsigned short n = 0; |
|---|
| 118 | + struct virtio_blk_discard_write_zeroes *range; |
|---|
| 119 | + struct bio *bio; |
|---|
| 120 | + u32 flags = 0; |
|---|
| 121 | + |
|---|
| 122 | + if (unmap) |
|---|
| 123 | + flags |= VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP; |
|---|
| 124 | + |
|---|
| 125 | + range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC); |
|---|
| 126 | + if (!range) |
|---|
| 127 | + return -ENOMEM; |
|---|
| 128 | + |
|---|
| 129 | + /* |
|---|
| 130 | + * Single max discard segment means multi-range discard isn't |
|---|
| 131 | + * supported, and block layer only runs contiguity merge like |
|---|
| 132 | + * normal RW request. So we can't reply on bio for retrieving |
|---|
| 133 | + * each range info. |
|---|
| 134 | + */ |
|---|
| 135 | + if (queue_max_discard_segments(req->q) == 1) { |
|---|
| 136 | + range[0].flags = cpu_to_le32(flags); |
|---|
| 137 | + range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req)); |
|---|
| 138 | + range[0].sector = cpu_to_le64(blk_rq_pos(req)); |
|---|
| 139 | + n = 1; |
|---|
| 140 | + } else { |
|---|
| 141 | + __rq_for_each_bio(bio, req) { |
|---|
| 142 | + u64 sector = bio->bi_iter.bi_sector; |
|---|
| 143 | + u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT; |
|---|
| 144 | + |
|---|
| 145 | + range[n].flags = cpu_to_le32(flags); |
|---|
| 146 | + range[n].num_sectors = cpu_to_le32(num_sectors); |
|---|
| 147 | + range[n].sector = cpu_to_le64(sector); |
|---|
| 148 | + n++; |
|---|
| 149 | + } |
|---|
| 150 | + } |
|---|
| 151 | + |
|---|
| 152 | + WARN_ON_ONCE(n != segments); |
|---|
| 153 | + |
|---|
| 154 | + req->special_vec.bv_page = virt_to_page(range); |
|---|
| 155 | + req->special_vec.bv_offset = offset_in_page(range); |
|---|
| 156 | + req->special_vec.bv_len = sizeof(*range) * segments; |
|---|
| 157 | + req->rq_flags |= RQF_SPECIAL_PAYLOAD; |
|---|
| 158 | + |
|---|
| 159 | + return 0; |
|---|
| 160 | +} |
|---|
| 161 | + |
|---|
| 191 | 162 | static inline void virtblk_request_done(struct request *req) |
|---|
| 192 | 163 | { |
|---|
| 193 | 164 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
|---|
| 194 | 165 | |
|---|
| 195 | | - switch (req_op(req)) { |
|---|
| 196 | | - case REQ_OP_SCSI_IN: |
|---|
| 197 | | - case REQ_OP_SCSI_OUT: |
|---|
| 198 | | - virtblk_scsi_request_done(req); |
|---|
| 199 | | - break; |
|---|
| 166 | + if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { |
|---|
| 167 | + kfree(page_address(req->special_vec.bv_page) + |
|---|
| 168 | + req->special_vec.bv_offset); |
|---|
| 200 | 169 | } |
|---|
| 201 | 170 | |
|---|
| 202 | 171 | blk_mq_end_request(req, virtblk_result(vbr)); |
|---|
| .. | .. |
|---|
| 217 | 186 | while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { |
|---|
| 218 | 187 | struct request *req = blk_mq_rq_from_pdu(vbr); |
|---|
| 219 | 188 | |
|---|
| 220 | | - blk_mq_complete_request(req); |
|---|
| 189 | + if (likely(!blk_should_fake_timeout(req->q))) |
|---|
| 190 | + blk_mq_complete_request(req); |
|---|
| 221 | 191 | req_done = true; |
|---|
| 222 | 192 | } |
|---|
| 223 | 193 | if (unlikely(virtqueue_is_broken(vq))) |
|---|
| .. | .. |
|---|
| 228 | 198 | if (req_done) |
|---|
| 229 | 199 | blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); |
|---|
| 230 | 200 | spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); |
|---|
| 201 | +} |
|---|
| 202 | + |
|---|
| 203 | +static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx) |
|---|
| 204 | +{ |
|---|
| 205 | + struct virtio_blk *vblk = hctx->queue->queuedata; |
|---|
| 206 | + struct virtio_blk_vq *vq = &vblk->vqs[hctx->queue_num]; |
|---|
| 207 | + bool kick; |
|---|
| 208 | + |
|---|
| 209 | + spin_lock_irq(&vq->lock); |
|---|
| 210 | + kick = virtqueue_kick_prepare(vq->vq); |
|---|
| 211 | + spin_unlock_irq(&vq->lock); |
|---|
| 212 | + |
|---|
| 213 | + if (kick) |
|---|
| 214 | + virtqueue_notify(vq->vq); |
|---|
| 231 | 215 | } |
|---|
| 232 | 216 | |
|---|
| 233 | 217 | static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, |
|---|
| .. | .. |
|---|
| 241 | 225 | int qid = hctx->queue_num; |
|---|
| 242 | 226 | int err; |
|---|
| 243 | 227 | bool notify = false; |
|---|
| 228 | + bool unmap = false; |
|---|
| 244 | 229 | u32 type; |
|---|
| 245 | | - |
|---|
| 246 | | - BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); |
|---|
| 247 | 230 | |
|---|
| 248 | 231 | switch (req_op(req)) { |
|---|
| 249 | 232 | case REQ_OP_READ: |
|---|
| .. | .. |
|---|
| 253 | 236 | case REQ_OP_FLUSH: |
|---|
| 254 | 237 | type = VIRTIO_BLK_T_FLUSH; |
|---|
| 255 | 238 | break; |
|---|
| 256 | | - case REQ_OP_SCSI_IN: |
|---|
| 257 | | - case REQ_OP_SCSI_OUT: |
|---|
| 258 | | - type = VIRTIO_BLK_T_SCSI_CMD; |
|---|
| 239 | + case REQ_OP_DISCARD: |
|---|
| 240 | + type = VIRTIO_BLK_T_DISCARD; |
|---|
| 241 | + break; |
|---|
| 242 | + case REQ_OP_WRITE_ZEROES: |
|---|
| 243 | + type = VIRTIO_BLK_T_WRITE_ZEROES; |
|---|
| 244 | + unmap = !(req->cmd_flags & REQ_NOUNMAP); |
|---|
| 259 | 245 | break; |
|---|
| 260 | 246 | case REQ_OP_DRV_IN: |
|---|
| 261 | 247 | type = VIRTIO_BLK_T_GET_ID; |
|---|
| .. | .. |
|---|
| 265 | 251 | return BLK_STS_IOERR; |
|---|
| 266 | 252 | } |
|---|
| 267 | 253 | |
|---|
| 254 | + BUG_ON(type != VIRTIO_BLK_T_DISCARD && |
|---|
| 255 | + type != VIRTIO_BLK_T_WRITE_ZEROES && |
|---|
| 256 | + (req->nr_phys_segments + 2 > vblk->sg_elems)); |
|---|
| 257 | + |
|---|
| 268 | 258 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); |
|---|
| 269 | 259 | vbr->out_hdr.sector = type ? |
|---|
| 270 | 260 | 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req)); |
|---|
| 271 | 261 | vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req)); |
|---|
| 272 | 262 | |
|---|
| 273 | 263 | blk_mq_start_request(req); |
|---|
| 264 | + |
|---|
| 265 | + if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { |
|---|
| 266 | + err = virtblk_setup_discard_write_zeroes(req, unmap); |
|---|
| 267 | + if (err) |
|---|
| 268 | + return BLK_STS_RESOURCE; |
|---|
| 269 | + } |
|---|
| 274 | 270 | |
|---|
| 275 | 271 | num = blk_rq_map_sg(hctx->queue, req, vbr->sg); |
|---|
| 276 | 272 | if (num) { |
|---|
| .. | .. |
|---|
| 281 | 277 | } |
|---|
| 282 | 278 | |
|---|
| 283 | 279 | spin_lock_irqsave(&vblk->vqs[qid].lock, flags); |
|---|
| 284 | | - if (blk_rq_is_scsi(req)) |
|---|
| 285 | | - err = virtblk_add_req_scsi(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
|---|
| 286 | | - else |
|---|
| 287 | | - err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
|---|
| 280 | + err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
|---|
| 288 | 281 | if (err) { |
|---|
| 289 | 282 | virtqueue_kick(vblk->vqs[qid].vq); |
|---|
| 290 | 283 | /* Don't stop the queue if -ENOMEM: we may have failed to |
|---|
| .. | .. |
|---|
| 406 | 399 | } |
|---|
| 407 | 400 | |
|---|
| 408 | 401 | static const struct block_device_operations virtblk_fops = { |
|---|
| 409 | | - .ioctl = virtblk_ioctl, |
|---|
| 410 | 402 | .owner = THIS_MODULE, |
|---|
| 411 | 403 | .open = virtblk_open, |
|---|
| 412 | 404 | .release = virtblk_release, |
|---|
| .. | .. |
|---|
| 423 | 415 | return minor >> PART_BITS; |
|---|
| 424 | 416 | } |
|---|
| 425 | 417 | |
|---|
| 426 | | -static ssize_t virtblk_serial_show(struct device *dev, |
|---|
| 427 | | - struct device_attribute *attr, char *buf) |
|---|
| 418 | +static ssize_t serial_show(struct device *dev, |
|---|
| 419 | + struct device_attribute *attr, char *buf) |
|---|
| 428 | 420 | { |
|---|
| 429 | 421 | struct gendisk *disk = dev_to_disk(dev); |
|---|
| 430 | 422 | int err; |
|---|
| .. | .. |
|---|
| 443 | 435 | return err; |
|---|
| 444 | 436 | } |
|---|
| 445 | 437 | |
|---|
| 446 | | -static DEVICE_ATTR(serial, 0444, virtblk_serial_show, NULL); |
|---|
| 438 | +static DEVICE_ATTR_RO(serial); |
|---|
| 447 | 439 | |
|---|
| 448 | 440 | /* The queue's logical block size must be set before calling this */ |
|---|
| 449 | 441 | static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) |
|---|
| .. | .. |
|---|
| 480 | 472 | cap_str_10, |
|---|
| 481 | 473 | cap_str_2); |
|---|
| 482 | 474 | |
|---|
| 483 | | - set_capacity(vblk->disk, capacity); |
|---|
| 475 | + set_capacity_revalidate_and_notify(vblk->disk, capacity, true); |
|---|
| 484 | 476 | } |
|---|
| 485 | 477 | |
|---|
| 486 | 478 | static void virtblk_config_changed_work(struct work_struct *work) |
|---|
| 487 | 479 | { |
|---|
| 488 | 480 | struct virtio_blk *vblk = |
|---|
| 489 | 481 | container_of(work, struct virtio_blk, config_work); |
|---|
| 490 | | - char *envp[] = { "RESIZE=1", NULL }; |
|---|
| 491 | 482 | |
|---|
| 492 | 483 | virtblk_update_capacity(vblk, true); |
|---|
| 493 | | - revalidate_disk(vblk->disk); |
|---|
| 494 | | - kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp); |
|---|
| 495 | 484 | } |
|---|
| 496 | 485 | |
|---|
| 497 | 486 | static void virtblk_config_changed(struct virtio_device *vdev) |
|---|
| .. | .. |
|---|
| 611 | 600 | struct virtio_blk *vblk = vdev->priv; |
|---|
| 612 | 601 | |
|---|
| 613 | 602 | blk_queue_write_cache(vblk->disk->queue, writeback, false); |
|---|
| 614 | | - revalidate_disk(vblk->disk); |
|---|
| 603 | + revalidate_disk_size(vblk->disk, true); |
|---|
| 615 | 604 | } |
|---|
| 616 | 605 | |
|---|
| 617 | 606 | static const char *const virtblk_cache_types[] = { |
|---|
| .. | .. |
|---|
| 619 | 608 | }; |
|---|
| 620 | 609 | |
|---|
| 621 | 610 | static ssize_t |
|---|
| 622 | | -virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, |
|---|
| 623 | | - const char *buf, size_t count) |
|---|
| 611 | +cache_type_store(struct device *dev, struct device_attribute *attr, |
|---|
| 612 | + const char *buf, size_t count) |
|---|
| 624 | 613 | { |
|---|
| 625 | 614 | struct gendisk *disk = dev_to_disk(dev); |
|---|
| 626 | 615 | struct virtio_blk *vblk = disk->private_data; |
|---|
| .. | .. |
|---|
| 638 | 627 | } |
|---|
| 639 | 628 | |
|---|
| 640 | 629 | static ssize_t |
|---|
| 641 | | -virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, |
|---|
| 642 | | - char *buf) |
|---|
| 630 | +cache_type_show(struct device *dev, struct device_attribute *attr, char *buf) |
|---|
| 643 | 631 | { |
|---|
| 644 | 632 | struct gendisk *disk = dev_to_disk(dev); |
|---|
| 645 | 633 | struct virtio_blk *vblk = disk->private_data; |
|---|
| .. | .. |
|---|
| 649 | 637 | return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]); |
|---|
| 650 | 638 | } |
|---|
| 651 | 639 | |
|---|
| 652 | | -static const struct device_attribute dev_attr_cache_type_ro = |
|---|
| 653 | | - __ATTR(cache_type, 0444, |
|---|
| 654 | | - virtblk_cache_type_show, NULL); |
|---|
| 655 | | -static const struct device_attribute dev_attr_cache_type_rw = |
|---|
| 656 | | - __ATTR(cache_type, 0644, |
|---|
| 657 | | - virtblk_cache_type_show, virtblk_cache_type_store); |
|---|
| 640 | +static DEVICE_ATTR_RW(cache_type); |
|---|
| 641 | + |
|---|
| 642 | +static struct attribute *virtblk_attrs[] = { |
|---|
| 643 | + &dev_attr_serial.attr, |
|---|
| 644 | + &dev_attr_cache_type.attr, |
|---|
| 645 | + NULL, |
|---|
| 646 | +}; |
|---|
| 647 | + |
|---|
| 648 | +static umode_t virtblk_attrs_are_visible(struct kobject *kobj, |
|---|
| 649 | + struct attribute *a, int n) |
|---|
| 650 | +{ |
|---|
| 651 | + struct device *dev = kobj_to_dev(kobj); |
|---|
| 652 | + struct gendisk *disk = dev_to_disk(dev); |
|---|
| 653 | + struct virtio_blk *vblk = disk->private_data; |
|---|
| 654 | + struct virtio_device *vdev = vblk->vdev; |
|---|
| 655 | + |
|---|
| 656 | + if (a == &dev_attr_cache_type.attr && |
|---|
| 657 | + !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) |
|---|
| 658 | + return S_IRUGO; |
|---|
| 659 | + |
|---|
| 660 | + return a->mode; |
|---|
| 661 | +} |
|---|
| 662 | + |
|---|
| 663 | +static const struct attribute_group virtblk_attr_group = { |
|---|
| 664 | + .attrs = virtblk_attrs, |
|---|
| 665 | + .is_visible = virtblk_attrs_are_visible, |
|---|
| 666 | +}; |
|---|
| 667 | + |
|---|
| 668 | +static const struct attribute_group *virtblk_attr_groups[] = { |
|---|
| 669 | + &virtblk_attr_group, |
|---|
| 670 | + NULL, |
|---|
| 671 | +}; |
|---|
| 658 | 672 | |
|---|
| 659 | 673 | static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, |
|---|
| 660 | 674 | unsigned int hctx_idx, unsigned int numa_node) |
|---|
| .. | .. |
|---|
| 662 | 676 | struct virtio_blk *vblk = set->driver_data; |
|---|
| 663 | 677 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); |
|---|
| 664 | 678 | |
|---|
| 665 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 666 | | - vbr->sreq.sense = vbr->sense; |
|---|
| 667 | | -#endif |
|---|
| 668 | 679 | sg_init_table(vbr->sg, vblk->sg_elems); |
|---|
| 669 | 680 | return 0; |
|---|
| 670 | 681 | } |
|---|
| .. | .. |
|---|
| 673 | 684 | { |
|---|
| 674 | 685 | struct virtio_blk *vblk = set->driver_data; |
|---|
| 675 | 686 | |
|---|
| 676 | | - return blk_mq_virtio_map_queues(set, vblk->vdev, 0); |
|---|
| 687 | + return blk_mq_virtio_map_queues(&set->map[HCTX_TYPE_DEFAULT], |
|---|
| 688 | + vblk->vdev, 0); |
|---|
| 677 | 689 | } |
|---|
| 678 | | - |
|---|
| 679 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 680 | | -static void virtblk_initialize_rq(struct request *req) |
|---|
| 681 | | -{ |
|---|
| 682 | | - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
|---|
| 683 | | - |
|---|
| 684 | | - scsi_req_init(&vbr->sreq); |
|---|
| 685 | | -} |
|---|
| 686 | | -#endif |
|---|
| 687 | 690 | |
|---|
| 688 | 691 | static const struct blk_mq_ops virtio_mq_ops = { |
|---|
| 689 | 692 | .queue_rq = virtio_queue_rq, |
|---|
| 693 | + .commit_rqs = virtio_commit_rqs, |
|---|
| 690 | 694 | .complete = virtblk_request_done, |
|---|
| 691 | 695 | .init_request = virtblk_init_request, |
|---|
| 692 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 693 | | - .initialize_rq_fn = virtblk_initialize_rq, |
|---|
| 694 | | -#endif |
|---|
| 695 | 696 | .map_queues = virtblk_map_queues, |
|---|
| 696 | 697 | }; |
|---|
| 697 | 698 | |
|---|
| .. | .. |
|---|
| 704 | 705 | struct request_queue *q; |
|---|
| 705 | 706 | int err, index; |
|---|
| 706 | 707 | |
|---|
| 707 | | - u32 v, blk_size, sg_elems, opt_io_size; |
|---|
| 708 | + u32 v, blk_size, max_size, sg_elems, opt_io_size; |
|---|
| 708 | 709 | u16 min_io_size; |
|---|
| 709 | 710 | u8 physical_block_exp, alignment_offset; |
|---|
| 710 | 711 | |
|---|
| .. | .. |
|---|
| 811 | 812 | /* No real sector limit. */ |
|---|
| 812 | 813 | blk_queue_max_hw_sectors(q, -1U); |
|---|
| 813 | 814 | |
|---|
| 815 | + max_size = virtio_max_dma_size(vdev); |
|---|
| 816 | + |
|---|
| 814 | 817 | /* Host can optionally specify maximum segment size and number of |
|---|
| 815 | 818 | * segments. */ |
|---|
| 816 | 819 | err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX, |
|---|
| 817 | 820 | struct virtio_blk_config, size_max, &v); |
|---|
| 818 | 821 | if (!err) |
|---|
| 819 | | - blk_queue_max_segment_size(q, v); |
|---|
| 820 | | - else |
|---|
| 821 | | - blk_queue_max_segment_size(q, -1U); |
|---|
| 822 | + max_size = min(max_size, v); |
|---|
| 823 | + |
|---|
| 824 | + blk_queue_max_segment_size(q, max_size); |
|---|
| 822 | 825 | |
|---|
| 823 | 826 | /* Host can optionally specify the block size of the device */ |
|---|
| 824 | 827 | err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, |
|---|
| 825 | 828 | struct virtio_blk_config, blk_size, |
|---|
| 826 | 829 | &blk_size); |
|---|
| 827 | | - if (!err) |
|---|
| 830 | + if (!err) { |
|---|
| 831 | + err = blk_validate_block_size(blk_size); |
|---|
| 832 | + if (err) { |
|---|
| 833 | + dev_err(&vdev->dev, |
|---|
| 834 | + "virtio_blk: invalid block size: 0x%x\n", |
|---|
| 835 | + blk_size); |
|---|
| 836 | + goto out_cleanup_disk; |
|---|
| 837 | + } |
|---|
| 838 | + |
|---|
| 828 | 839 | blk_queue_logical_block_size(q, blk_size); |
|---|
| 829 | | - else |
|---|
| 840 | + } else |
|---|
| 830 | 841 | blk_size = queue_logical_block_size(q); |
|---|
| 831 | 842 | |
|---|
| 832 | 843 | /* Use topology information if available */ |
|---|
| .. | .. |
|---|
| 855 | 866 | if (!err && opt_io_size) |
|---|
| 856 | 867 | blk_queue_io_opt(q, blk_size * opt_io_size); |
|---|
| 857 | 868 | |
|---|
| 869 | + if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { |
|---|
| 870 | + virtio_cread(vdev, struct virtio_blk_config, |
|---|
| 871 | + discard_sector_alignment, &v); |
|---|
| 872 | + if (v) |
|---|
| 873 | + q->limits.discard_granularity = v << SECTOR_SHIFT; |
|---|
| 874 | + else |
|---|
| 875 | + q->limits.discard_granularity = blk_size; |
|---|
| 876 | + |
|---|
| 877 | + virtio_cread(vdev, struct virtio_blk_config, |
|---|
| 878 | + max_discard_sectors, &v); |
|---|
| 879 | + blk_queue_max_discard_sectors(q, v ? v : UINT_MAX); |
|---|
| 880 | + |
|---|
| 881 | + virtio_cread(vdev, struct virtio_blk_config, max_discard_seg, |
|---|
| 882 | + &v); |
|---|
| 883 | + |
|---|
| 884 | + /* |
|---|
| 885 | + * max_discard_seg == 0 is out of spec but we always |
|---|
| 886 | + * handled it. |
|---|
| 887 | + */ |
|---|
| 888 | + if (!v) |
|---|
| 889 | + v = sg_elems - 2; |
|---|
| 890 | + blk_queue_max_discard_segments(q, |
|---|
| 891 | + min(v, MAX_DISCARD_SEGMENTS)); |
|---|
| 892 | + |
|---|
| 893 | + blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); |
|---|
| 894 | + } |
|---|
| 895 | + |
|---|
| 896 | + if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) { |
|---|
| 897 | + virtio_cread(vdev, struct virtio_blk_config, |
|---|
| 898 | + max_write_zeroes_sectors, &v); |
|---|
| 899 | + blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX); |
|---|
| 900 | + } |
|---|
| 901 | + |
|---|
| 858 | 902 | virtblk_update_capacity(vblk, false); |
|---|
| 859 | 903 | virtio_device_ready(vdev); |
|---|
| 860 | 904 | |
|---|
| 861 | | - device_add_disk(&vdev->dev, vblk->disk); |
|---|
| 862 | | - err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial); |
|---|
| 863 | | - if (err) |
|---|
| 864 | | - goto out_del_disk; |
|---|
| 865 | | - |
|---|
| 866 | | - if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) |
|---|
| 867 | | - err = device_create_file(disk_to_dev(vblk->disk), |
|---|
| 868 | | - &dev_attr_cache_type_rw); |
|---|
| 869 | | - else |
|---|
| 870 | | - err = device_create_file(disk_to_dev(vblk->disk), |
|---|
| 871 | | - &dev_attr_cache_type_ro); |
|---|
| 872 | | - if (err) |
|---|
| 873 | | - goto out_del_disk; |
|---|
| 905 | + device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); |
|---|
| 874 | 906 | return 0; |
|---|
| 875 | 907 | |
|---|
| 876 | | -out_del_disk: |
|---|
| 877 | | - del_gendisk(vblk->disk); |
|---|
| 908 | +out_cleanup_disk: |
|---|
| 878 | 909 | blk_cleanup_queue(vblk->disk->queue); |
|---|
| 879 | 910 | out_free_tags: |
|---|
| 880 | 911 | blk_mq_free_tag_set(&vblk->tag_set); |
|---|
| .. | .. |
|---|
| 963 | 994 | static unsigned int features_legacy[] = { |
|---|
| 964 | 995 | VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, |
|---|
| 965 | 996 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
|---|
| 966 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
|---|
| 967 | | - VIRTIO_BLK_F_SCSI, |
|---|
| 968 | | -#endif |
|---|
| 969 | 997 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
|---|
| 970 | | - VIRTIO_BLK_F_MQ, |
|---|
| 998 | + VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
|---|
| 971 | 999 | } |
|---|
| 972 | 1000 | ; |
|---|
| 973 | 1001 | static unsigned int features[] = { |
|---|
| 974 | 1002 | VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, |
|---|
| 975 | 1003 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
|---|
| 976 | 1004 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
|---|
| 977 | | - VIRTIO_BLK_F_MQ, |
|---|
| 1005 | + VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
|---|
| 978 | 1006 | }; |
|---|
| 979 | 1007 | |
|---|
| 980 | 1008 | static struct virtio_driver virtio_blk = { |
|---|