Blame view
drivers/block/virtio_blk.c
25.9 KB
09c434b8a treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
e467cde23 Block driver usin... |
2 3 |
//#define DEBUG #include <linux/spinlock.h> |
5a0e3ad6a include cleanup: ... |
4 |
#include <linux/slab.h> |
e467cde23 Block driver usin... |
5 6 |
#include <linux/blkdev.h> #include <linux/hdreg.h> |
0c8d44f23 block: Fix files ... |
7 |
#include <linux/module.h> |
4678d6f97 virtio_blk: fix c... |
8 |
#include <linux/mutex.h> |
ad71473d9 virtio_blk: use v... |
9 |
#include <linux/interrupt.h> |
e467cde23 Block driver usin... |
10 11 |
#include <linux/virtio.h> #include <linux/virtio_blk.h> |
3d1266c70 SG: audit of driv... |
12 |
#include <linux/scatterlist.h> |
7a7c924cf virtio_blk: allow... |
13 |
#include <linux/string_helpers.h> |
5087a50e6 virtio-blk: use i... |
14 |
#include <linux/idr.h> |
1cf7e9c68 virtio_blk: blk-m... |
15 |
#include <linux/blk-mq.h> |
ad71473d9 virtio_blk: use v... |
16 |
#include <linux/blk-mq-virtio.h> |
1cf7e9c68 virtio_blk: blk-m... |
17 |
#include <linux/numa.h> |
55a2415be virtio_blk: add a... |
18 |
#include <uapi/linux/virtio_ring.h> |
3d1266c70 SG: audit of driv... |
19 |
|
4f3bf19c6 virtio_blk: Dont ... |
20 |
#define PART_BITS 4 |
6a27b656f block: virtio-blk... |
21 |
#define VQ_NAME_LEN 16 |
1f23816b8 virtio_blk: add d... |
22 |
#define MAX_DISCARD_SEGMENTS 256u |
e467cde23 Block driver usin... |
23 |
|
5087a50e6 virtio-blk: use i... |
24 25 |
static int major; static DEFINE_IDA(vd_index_ida); |
2a647bfe1 virtio_blk: Add m... |
26 |
static struct workqueue_struct *virtblk_wq; |
4f3bf19c6 virtio_blk: Dont ... |
27 |
|
6a27b656f block: virtio-blk... |
28 29 30 31 32 |
struct virtio_blk_vq { struct virtqueue *vq; spinlock_t lock; char name[VQ_NAME_LEN]; } ____cacheline_aligned_in_smp; |
bb6ec5760 virtio_blk: codin... |
33 |
struct virtio_blk { |
90b5feb8c virtio-blk: handl... |
34 35 36 37 38 39 40 41 42 |
/* * This mutex must be held by anything that may run after * virtblk_remove() sets vblk->vdev to NULL. * * blk-mq, virtqueue processing, and sysfs attribute code paths are * shut down before vblk->vdev is set to NULL and therefore do not need * to hold this mutex. */ struct mutex vdev_mutex; |
e467cde23 Block driver usin... |
43 |
struct virtio_device *vdev; |
e467cde23 Block driver usin... |
44 45 46 |
/* The disk structure for the kernel. */ struct gendisk *disk; |
24d2f9030 blk-mq: split out... |
47 48 |
/* Block layer tags. */ struct blk_mq_tag_set tag_set; |
7a7c924cf virtio_blk: allow... |
49 50 |
/* Process context for config space updates */ struct work_struct config_work; |
90b5feb8c virtio-blk: handl... |
51 52 53 54 55 56 |
/* * Tracks references from block_device_operations open/release and * virtio_driver probe/remove so this object can be freed once no * longer in use. */ refcount_t refs; |
0864b79a1 virtio: block: dy... |
57 58 |
/* What host tells us, plus 2 for header & tailer. */ unsigned int sg_elems; |
5087a50e6 virtio-blk: use i... |
59 60 |
/* Ida index - used to track minor number allocations. */ int index; |
6a27b656f block: virtio-blk... |
61 62 63 64 |
/* num of vqs */ int num_vqs; struct virtio_blk_vq *vqs; |
e467cde23 Block driver usin... |
65 |
}; |
bb6ec5760 virtio_blk: codin... |
66 |
struct virtblk_req { |
97b50a654 virtio_blk: make ... |
67 |
struct virtio_blk_outhdr out_hdr; |
cb38fa23c virtio: de-struct... |
68 |
u8 status; |
a98755c55 virtio-blk: Add b... |
69 |
struct scatterlist sg[]; |
e467cde23 Block driver usin... |
70 |
}; |
2a842acab block: introduce ... |
71 |
static inline blk_status_t virtblk_result(struct virtblk_req *vbr) |
a98755c55 virtio-blk: Add b... |
72 73 74 |
{ switch (vbr->status) { case VIRTIO_BLK_S_OK: |
2a842acab block: introduce ... |
75 |
return BLK_STS_OK; |
a98755c55 virtio-blk: Add b... |
76 |
case VIRTIO_BLK_S_UNSUPP: |
2a842acab block: introduce ... |
77 |
return BLK_STS_NOTSUPP; |
a98755c55 virtio-blk: Add b... |
78 |
default: |
2a842acab block: introduce ... |
79 |
return BLK_STS_IOERR; |
a98755c55 virtio-blk: Add b... |
80 81 |
} } |
97b50a654 virtio_blk: make ... |
82 83 84 85 86 87 88 89 |
static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr, struct scatterlist *data_sg, bool have_data) { struct scatterlist hdr, status, *sgs[3]; unsigned int num_out = 0, num_in = 0; sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); sgs[num_out++] = &hdr; |
20af3cfd2 virtio-blk: use v... |
90 |
|
0a11cc36f virtio_blk: remov... |
91 |
if (have_data) { |
19c1c5a64 virtio_blk: v1.0 ... |
92 |
if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) |
20af3cfd2 virtio-blk: use v... |
93 |
sgs[num_out++] = data_sg; |
8f39db9d3 virtio-blk: use v... |
94 |
else |
20af3cfd2 virtio-blk: use v... |
95 96 |
sgs[num_out + num_in++] = data_sg; } |
8f39db9d3 virtio-blk: use v... |
97 98 99 100 |
sg_init_one(&status, &vbr->status, sizeof(vbr->status)); sgs[num_out + num_in++] = &status; return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
5ee21a52c virtio-blk: reorg... |
101 |
} |
1f23816b8 virtio_blk: add d... |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) { unsigned short segments = blk_rq_nr_discard_segments(req); unsigned short n = 0; struct virtio_blk_discard_write_zeroes *range; struct bio *bio; u32 flags = 0; if (unmap) flags |= VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP; range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC); if (!range) return -ENOMEM; |
af822aa68 block: virtio_blk... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
/* * Single max discard segment means multi-range discard isn't * supported, and block layer only runs contiguity merge like * normal RW request. So we can't reply on bio for retrieving * each range info. */ if (queue_max_discard_segments(req->q) == 1) { range[0].flags = cpu_to_le32(flags); range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req)); range[0].sector = cpu_to_le64(blk_rq_pos(req)); n = 1; } else { __rq_for_each_bio(bio, req) { u64 sector = bio->bi_iter.bi_sector; u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT; range[n].flags = cpu_to_le32(flags); range[n].num_sectors = cpu_to_le32(num_sectors); range[n].sector = cpu_to_le64(sector); n++; } |
1f23816b8 virtio_blk: add d... |
137 |
} |
af822aa68 block: virtio_blk... |
138 |
WARN_ON_ONCE(n != segments); |
1f23816b8 virtio_blk: add d... |
139 140 141 142 143 144 145 |
req->special_vec.bv_page = virt_to_page(range); req->special_vec.bv_offset = offset_in_page(range); req->special_vec.bv_len = sizeof(*range) * segments; req->rq_flags |= RQF_SPECIAL_PAYLOAD; return 0; } |
5124c2857 virtio_blk: use b... |
146 |
static inline void virtblk_request_done(struct request *req) |
a98755c55 virtio-blk: Add b... |
147 |
{ |
9d74e2573 blk-mq: do not in... |
148 |
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
a98755c55 virtio-blk: Add b... |
149 |
|
1f23816b8 virtio_blk: add d... |
150 151 152 153 |
if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { kfree(page_address(req->special_vec.bv_page) + req->special_vec.bv_offset); } |
d19633d53 virtio_blk: don't... |
154 |
blk_mq_end_request(req, virtblk_result(vbr)); |
a98755c55 virtio-blk: Add b... |
155 156 157 |
} static void virtblk_done(struct virtqueue *vq) |
e467cde23 Block driver usin... |
158 159 |
{ struct virtio_blk *vblk = vq->vdev->priv; |
1cf7e9c68 virtio_blk: blk-m... |
160 |
bool req_done = false; |
6a27b656f block: virtio-blk... |
161 |
int qid = vq->index; |
e467cde23 Block driver usin... |
162 |
struct virtblk_req *vbr; |
e467cde23 Block driver usin... |
163 |
unsigned long flags; |
a98755c55 virtio-blk: Add b... |
164 |
unsigned int len; |
e467cde23 Block driver usin... |
165 |
|
6a27b656f block: virtio-blk... |
166 |
spin_lock_irqsave(&vblk->vqs[qid].lock, flags); |
bb8111086 virtio-blk: Disab... |
167 168 |
do { virtqueue_disable_cb(vq); |
6a27b656f block: virtio-blk... |
169 |
while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { |
85dada09e virtio_blk: remov... |
170 |
struct request *req = blk_mq_rq_from_pdu(vbr); |
15f73f5b3 blk-mq: move fail... |
171 172 |
if (likely(!blk_should_fake_timeout(req->q))) blk_mq_complete_request(req); |
1cf7e9c68 virtio_blk: blk-m... |
173 |
req_done = true; |
33659ebba block: remove wra... |
174 |
} |
7f03b17d5 virtio_blk: verif... |
175 176 |
if (unlikely(virtqueue_is_broken(vq))) break; |
bb8111086 virtio-blk: Disab... |
177 |
} while (!virtqueue_enable_cb(vq)); |
1cf7e9c68 virtio_blk: blk-m... |
178 |
|
e467cde23 Block driver usin... |
179 |
/* In case queue is stopped waiting for more buffers. */ |
a98755c55 virtio-blk: Add b... |
180 |
if (req_done) |
1b4a32585 blk-mq: add async... |
181 |
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); |
6a27b656f block: virtio-blk... |
182 |
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); |
a98755c55 virtio-blk: Add b... |
183 |
} |
944e7c879 virtio_blk: imple... |
184 185 186 187 188 189 190 191 192 193 194 195 196 |
static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx) { struct virtio_blk *vblk = hctx->queue->queuedata; struct virtio_blk_vq *vq = &vblk->vqs[hctx->queue_num]; bool kick; spin_lock_irq(&vq->lock); kick = virtqueue_kick_prepare(vq->vq); spin_unlock_irq(&vq->lock); if (kick) virtqueue_notify(vq->vq); } |
fc17b6534 blk-mq: switch ->... |
197 |
static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, |
74c450521 blk-mq: add a 'li... |
198 |
const struct blk_mq_queue_data *bd) |
e467cde23 Block driver usin... |
199 |
{ |
1cf7e9c68 virtio_blk: blk-m... |
200 |
struct virtio_blk *vblk = hctx->queue->queuedata; |
74c450521 blk-mq: add a 'li... |
201 |
struct request *req = bd->rq; |
9d74e2573 blk-mq: do not in... |
202 |
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
1cf7e9c68 virtio_blk: blk-m... |
203 |
unsigned long flags; |
20af3cfd2 virtio-blk: use v... |
204 |
unsigned int num; |
6a27b656f block: virtio-blk... |
205 |
int qid = hctx->queue_num; |
5261b85e5 virtio_blk: don't... |
206 |
int err; |
e8edca6f7 block: virtio_blk... |
207 |
bool notify = false; |
1f23816b8 virtio_blk: add d... |
208 |
bool unmap = false; |
aebf526b5 block: fold cmd_t... |
209 |
u32 type; |
e467cde23 Block driver usin... |
210 |
|
aebf526b5 block: fold cmd_t... |
211 212 213 214 215 216 217 218 |
switch (req_op(req)) { case REQ_OP_READ: case REQ_OP_WRITE: type = 0; break; case REQ_OP_FLUSH: type = VIRTIO_BLK_T_FLUSH; break; |
1f23816b8 virtio_blk: add d... |
219 220 221 222 223 224 225 |
case REQ_OP_DISCARD: type = VIRTIO_BLK_T_DISCARD; break; case REQ_OP_WRITE_ZEROES: type = VIRTIO_BLK_T_WRITE_ZEROES; unmap = !(req->cmd_flags & REQ_NOUNMAP); break; |
aebf526b5 block: fold cmd_t... |
226 227 228 229 230 |
case REQ_OP_DRV_IN: type = VIRTIO_BLK_T_GET_ID; break; default: WARN_ON_ONCE(1); |
fc17b6534 blk-mq: switch ->... |
231 |
return BLK_STS_IOERR; |
e467cde23 Block driver usin... |
232 |
} |
187c49445 ANDROID: virtio_b... |
233 234 235 |
BUG_ON(type != VIRTIO_BLK_T_DISCARD && type != VIRTIO_BLK_T_WRITE_ZEROES && (req->nr_phys_segments + 2 > vblk->sg_elems)); |
aebf526b5 block: fold cmd_t... |
236 237 238 239 |
vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); vbr->out_hdr.sector = type ? 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req)); vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req)); |
e2490073c blk-mq: call blk_... |
240 |
blk_mq_start_request(req); |
1f23816b8 virtio_blk: add d... |
241 242 243 244 245 |
if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { err = virtblk_setup_discard_write_zeroes(req, unmap); if (err) return BLK_STS_RESOURCE; } |
85dada09e virtio_blk: remov... |
246 |
num = blk_rq_map_sg(hctx->queue, req, vbr->sg); |
1cde26f92 virtio_blk: SG_IO... |
247 |
if (num) { |
85dada09e virtio_blk: remov... |
248 |
if (rq_data_dir(req) == WRITE) |
19c1c5a64 virtio_blk: v1.0 ... |
249 |
vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT); |
20af3cfd2 virtio-blk: use v... |
250 |
else |
19c1c5a64 virtio_blk: v1.0 ... |
251 |
vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN); |
e467cde23 Block driver usin... |
252 |
} |
6a27b656f block: virtio-blk... |
253 |
spin_lock_irqsave(&vblk->vqs[qid].lock, flags); |
782e067db virtio-blk: remov... |
254 |
err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
5261b85e5 virtio_blk: don't... |
255 |
if (err) { |
6a27b656f block: virtio-blk... |
256 |
virtqueue_kick(vblk->vqs[qid].vq); |
f5f6b95c7 virtio-blk: fix h... |
257 258 259 260 261 |
/* Don't stop the queue if -ENOMEM: we may have failed to * bounce the buffer due to global resource outage. */ if (err == -ENOSPC) blk_mq_stop_hw_queue(hctx); |
6a27b656f block: virtio-blk... |
262 |
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); |
3d973b2e9 virtio-blk: impro... |
263 264 |
switch (err) { case -ENOSPC: |
86ff7c2a8 blk-mq: introduce... |
265 |
return BLK_STS_DEV_RESOURCE; |
3d973b2e9 virtio-blk: impro... |
266 267 268 269 270 |
case -ENOMEM: return BLK_STS_RESOURCE; default: return BLK_STS_IOERR; } |
a98755c55 virtio-blk: Add b... |
271 |
} |
74c450521 blk-mq: add a 'li... |
272 |
if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq)) |
e8edca6f7 block: virtio_blk... |
273 |
notify = true; |
6a27b656f block: virtio-blk... |
274 |
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); |
e8edca6f7 block: virtio_blk... |
275 276 |
if (notify) |
6a27b656f block: virtio-blk... |
277 |
virtqueue_notify(vblk->vqs[qid].vq); |
fc17b6534 blk-mq: switch ->... |
278 |
return BLK_STS_OK; |
a98755c55 virtio-blk: Add b... |
279 |
} |
4cb2ea28c Add virtio disk i... |
280 281 282 283 284 |
/* return id (s/n) string for *disk to *id_str */ static int virtblk_get_id(struct gendisk *disk, char *id_str) { struct virtio_blk *vblk = disk->private_data; |
f9596695b virtio_blk: use b... |
285 |
struct request_queue *q = vblk->disk->queue; |
4cb2ea28c Add virtio disk i... |
286 |
struct request *req; |
e4c4776de virtio-blk: fix r... |
287 |
int err; |
4cb2ea28c Add virtio disk i... |
288 |
|
ff005a066 block: sanitize b... |
289 |
req = blk_get_request(q, REQ_OP_DRV_IN, 0); |
f9596695b virtio_blk: use b... |
290 |
if (IS_ERR(req)) |
4cb2ea28c Add virtio disk i... |
291 |
return PTR_ERR(req); |
f9596695b virtio_blk: use b... |
292 293 294 295 |
err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); if (err) goto out; |
b7819b925 block: remove the... |
296 |
blk_execute_rq(vblk->disk->queue, vblk->disk, req, false); |
2a842acab block: introduce ... |
297 |
err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req))); |
f9596695b virtio_blk: use b... |
298 |
out: |
e4c4776de virtio-blk: fix r... |
299 |
blk_put_request(req); |
e4c4776de virtio-blk: fix r... |
300 |
return err; |
4cb2ea28c Add virtio disk i... |
301 |
} |
90b5feb8c virtio-blk: handl... |
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
static void virtblk_get(struct virtio_blk *vblk) { refcount_inc(&vblk->refs); } static void virtblk_put(struct virtio_blk *vblk) { if (refcount_dec_and_test(&vblk->refs)) { ida_simple_remove(&vd_index_ida, vblk->index); mutex_destroy(&vblk->vdev_mutex); kfree(vblk); } } static int virtblk_open(struct block_device *bd, fmode_t mode) { struct virtio_blk *vblk = bd->bd_disk->private_data; int ret = 0; mutex_lock(&vblk->vdev_mutex); if (vblk->vdev) virtblk_get(vblk); else ret = -ENXIO; mutex_unlock(&vblk->vdev_mutex); return ret; } static void virtblk_release(struct gendisk *disk, fmode_t mode) { struct virtio_blk *vblk = disk->private_data; virtblk_put(vblk); } |
135da0b03 virtio_blk: provi... |
338 339 340 |
/* We provide getgeo only to please some old bootloader/partitioning tools */ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { |
48e4043d4 virtio: add virti... |
341 |
struct virtio_blk *vblk = bd->bd_disk->private_data; |
90b5feb8c virtio-blk: handl... |
342 343 344 345 346 347 348 349 |
int ret = 0; mutex_lock(&vblk->vdev_mutex); if (!vblk->vdev) { ret = -ENXIO; goto out; } |
48e4043d4 virtio: add virti... |
350 351 |
/* see if the host passed in geometry config */ |
855e0c528 virtio: use size-... |
352 353 354 355 356 357 358 |
if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) { virtio_cread(vblk->vdev, struct virtio_blk_config, geometry.cylinders, &geo->cylinders); virtio_cread(vblk->vdev, struct virtio_blk_config, geometry.heads, &geo->heads); virtio_cread(vblk->vdev, struct virtio_blk_config, geometry.sectors, &geo->sectors); |
48e4043d4 virtio: add virti... |
359 360 361 362 363 364 |
} else { /* some standard values, similar to sd */ geo->heads = 1 << 6; geo->sectors = 1 << 5; geo->cylinders = get_capacity(bd->bd_disk) >> 11; } |
90b5feb8c virtio-blk: handl... |
365 366 367 |
out: mutex_unlock(&vblk->vdev_mutex); return ret; |
135da0b03 virtio_blk: provi... |
368 |
} |
83d5cde47 const: make block... |
369 |
static const struct block_device_operations virtblk_fops = { |
135da0b03 virtio_blk: provi... |
370 |
.owner = THIS_MODULE, |
90b5feb8c virtio-blk: handl... |
371 372 |
.open = virtblk_open, .release = virtblk_release, |
135da0b03 virtio_blk: provi... |
373 |
.getgeo = virtblk_getgeo, |
e467cde23 Block driver usin... |
374 |
}; |
d50ed907d virtio_blk: imple... |
375 376 377 378 |
static int index_to_minor(int index) { return index << PART_BITS; } |
5087a50e6 virtio-blk: use i... |
379 380 381 382 |
static int minor_to_index(int minor) { return minor >> PART_BITS; } |
e982c4d0a virtio-blk: moder... |
383 384 |
static ssize_t serial_show(struct device *dev, struct device_attribute *attr, char *buf) |
a5eb9e4ff virtio_blk: Add '... |
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
{ struct gendisk *disk = dev_to_disk(dev); int err; /* sysfs gives us a PAGE_SIZE buffer */ BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES); buf[VIRTIO_BLK_ID_BYTES] = '\0'; err = virtblk_get_id(disk, buf); if (!err) return strlen(buf); if (err == -EIO) /* Unsupported? Make it empty. */ return 0; return err; } |
393c525b5 virtio_blk: make ... |
402 |
|
e982c4d0a virtio-blk: moder... |
403 |
static DEVICE_ATTR_RO(serial); |
a5eb9e4ff virtio_blk: Add '... |
404 |
|
daf2a5016 virtio_blk: print... |
405 406 |
/* The queue's logical block size must be set before calling this */ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) |
7a7c924cf virtio_blk: allow... |
407 |
{ |
7a7c924cf virtio_blk: allow... |
408 409 410 |
struct virtio_device *vdev = vblk->vdev; struct request_queue *q = vblk->disk->queue; char cap_str_2[10], cap_str_10[10]; |
1046d3049 virtio_blk: fix i... |
411 |
unsigned long long nblocks; |
b9f28d863 sd, mmc, virtio_b... |
412 |
u64 capacity; |
7a7c924cf virtio_blk: allow... |
413 414 |
/* Host must always specify the capacity. */ |
855e0c528 virtio: use size-... |
415 |
virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity); |
7a7c924cf virtio_blk: allow... |
416 417 418 419 420 421 422 423 |
/* If capacity is too big, truncate with warning. */ if ((sector_t)capacity != capacity) { dev_warn(&vdev->dev, "Capacity %llu too large: truncating ", (unsigned long long)capacity); capacity = (sector_t)-1; } |
1046d3049 virtio_blk: fix i... |
424 425 426 |
nblocks = DIV_ROUND_UP_ULL(capacity, queue_logical_block_size(q) >> 9); string_get_size(nblocks, queue_logical_block_size(q), |
b9f28d863 sd, mmc, virtio_b... |
427 |
STRING_UNITS_2, cap_str_2, sizeof(cap_str_2)); |
1046d3049 virtio_blk: fix i... |
428 |
string_get_size(nblocks, queue_logical_block_size(q), |
b9f28d863 sd, mmc, virtio_b... |
429 |
STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); |
7a7c924cf virtio_blk: allow... |
430 431 |
dev_notice(&vdev->dev, |
daf2a5016 virtio_blk: print... |
432 433 434 435 |
"[%s] %s%llu %d-byte logical blocks (%s/%s) ", vblk->disk->disk_name, resize ? "new size: " : "", |
1046d3049 virtio_blk: fix i... |
436 437 438 439 |
nblocks, queue_logical_block_size(q), cap_str_10, cap_str_2); |
7a7c924cf virtio_blk: allow... |
440 |
|
662155e28 virtio_blk.c: Con... |
441 |
set_capacity_revalidate_and_notify(vblk->disk, capacity, true); |
daf2a5016 virtio_blk: print... |
442 443 444 445 446 447 |
} static void virtblk_config_changed_work(struct work_struct *work) { struct virtio_blk *vblk = container_of(work, struct virtio_blk, config_work); |
daf2a5016 virtio_blk: print... |
448 449 |
virtblk_update_capacity(vblk, true); |
7a7c924cf virtio_blk: allow... |
450 451 452 453 454 455 456 457 |
} static void virtblk_config_changed(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; queue_work(virtblk_wq, &vblk->config_work); } |
6abd6e5a4 virtio: blk: Move... |
458 459 |
static int init_vq(struct virtio_blk *vblk) { |
2ff98449e virtio_blk: Delet... |
460 |
int err; |
6a27b656f block: virtio-blk... |
461 462 463 464 465 466 |
int i; vq_callback_t **callbacks; const char **names; struct virtqueue **vqs; unsigned short num_vqs; struct virtio_device *vdev = vblk->vdev; |
ad71473d9 virtio_blk: use v... |
467 |
struct irq_affinity desc = { 0, }; |
6a27b656f block: virtio-blk... |
468 469 470 471 472 473 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ, struct virtio_blk_config, num_queues, &num_vqs); if (err) num_vqs = 1; |
bf348f9b7 virtio-blk: limit... |
474 |
num_vqs = min_t(unsigned int, nr_cpu_ids, num_vqs); |
668866b6e virtio_blk: Use k... |
475 |
vblk->vqs = kmalloc_array(num_vqs, sizeof(*vblk->vqs), GFP_KERNEL); |
347a52939 virtio_blk: Fix a... |
476 477 |
if (!vblk->vqs) return -ENOMEM; |
6a27b656f block: virtio-blk... |
478 |
|
668866b6e virtio_blk: Use k... |
479 480 481 |
names = kmalloc_array(num_vqs, sizeof(*names), GFP_KERNEL); callbacks = kmalloc_array(num_vqs, sizeof(*callbacks), GFP_KERNEL); vqs = kmalloc_array(num_vqs, sizeof(*vqs), GFP_KERNEL); |
347a52939 virtio_blk: Fix a... |
482 483 484 485 |
if (!names || !callbacks || !vqs) { err = -ENOMEM; goto out; } |
6abd6e5a4 virtio: blk: Move... |
486 |
|
6a27b656f block: virtio-blk... |
487 488 489 490 491 492 493 |
for (i = 0; i < num_vqs; i++) { callbacks[i] = virtblk_done; snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%d", i); names[i] = vblk->vqs[i].name; } /* Discover virtqueues and write information to configuration. */ |
9b2bbdb22 virtio: wrap find... |
494 |
err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc); |
6a27b656f block: virtio-blk... |
495 |
if (err) |
347a52939 virtio_blk: Fix a... |
496 |
goto out; |
6abd6e5a4 virtio: blk: Move... |
497 |
|
6a27b656f block: virtio-blk... |
498 499 500 501 502 |
for (i = 0; i < num_vqs; i++) { spin_lock_init(&vblk->vqs[i].lock); vblk->vqs[i].vq = vqs[i]; } vblk->num_vqs = num_vqs; |
347a52939 virtio_blk: Fix a... |
503 |
out: |
6a27b656f block: virtio-blk... |
504 |
kfree(vqs); |
6a27b656f block: virtio-blk... |
505 |
kfree(callbacks); |
6a27b656f block: virtio-blk... |
506 |
kfree(names); |
6a27b656f block: virtio-blk... |
507 508 |
if (err) kfree(vblk->vqs); |
6abd6e5a4 virtio: blk: Move... |
509 510 |
return err; } |
c0aa3e091 virtio_blk: helpe... |
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
/* * Legacy naming scheme used for virtio devices. We are stuck with it for * virtio blk but don't ever use it for any new driver. */ static int virtblk_name_format(char *prefix, int index, char *buf, int buflen) { const int base = 'z' - 'a' + 1; char *begin = buf + strlen(prefix); char *end = buf + buflen; char *p; int unit; p = end - 1; *p = '\0'; unit = base; do { if (p == begin) return -EINVAL; *--p = 'a' + (index % unit); index = (index / unit) - 1; } while (index >= 0); memmove(begin, p, end - p); memcpy(buf, prefix, strlen(prefix)); return 0; } |
cd5d50386 virtio-blk: allow... |
538 539 540 541 |
static int virtblk_get_cache_mode(struct virtio_device *vdev) { u8 writeback; int err; |
855e0c528 virtio: use size-... |
542 543 544 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE, struct virtio_blk_config, wce, &writeback); |
592002f55 virtio_blk: VIRTI... |
545 546 547 548 549 |
/* * If WCE is not configurable and flush is not available, * assume no writeback cache is in use. */ |
cd5d50386 virtio-blk: allow... |
550 |
if (err) |
592002f55 virtio_blk: VIRTI... |
551 |
writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH); |
cd5d50386 virtio-blk: allow... |
552 553 554 555 556 557 558 559 |
return writeback; } static void virtblk_update_cache_mode(struct virtio_device *vdev) { u8 writeback = virtblk_get_cache_mode(vdev); struct virtio_blk *vblk = vdev->priv; |
ad9126ac7 virtio_blk: switc... |
560 |
blk_queue_write_cache(vblk->disk->queue, writeback, false); |
659e56ba8 block: add a new ... |
561 |
revalidate_disk_size(vblk->disk, true); |
cd5d50386 virtio-blk: allow... |
562 563 564 565 566 567 568 |
} static const char *const virtblk_cache_types[] = { "write through", "write back" }; static ssize_t |
e982c4d0a virtio-blk: moder... |
569 570 |
cache_type_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
cd5d50386 virtio-blk: allow... |
571 572 573 574 575 |
{ struct gendisk *disk = dev_to_disk(dev); struct virtio_blk *vblk = disk->private_data; struct virtio_device *vdev = vblk->vdev; int i; |
cd5d50386 virtio-blk: allow... |
576 577 |
BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE)); |
f53d5aa05 virtio_blk: Use s... |
578 |
i = sysfs_match_string(virtblk_cache_types, buf); |
cd5d50386 virtio-blk: allow... |
579 |
if (i < 0) |
f53d5aa05 virtio_blk: Use s... |
580 |
return i; |
cd5d50386 virtio-blk: allow... |
581 |
|
855e0c528 virtio: use size-... |
582 |
virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i); |
cd5d50386 virtio-blk: allow... |
583 584 585 586 587 |
virtblk_update_cache_mode(vdev); return count; } static ssize_t |
e982c4d0a virtio-blk: moder... |
588 |
cache_type_show(struct device *dev, struct device_attribute *attr, char *buf) |
cd5d50386 virtio-blk: allow... |
589 590 591 592 593 594 595 596 597 |
{ struct gendisk *disk = dev_to_disk(dev); struct virtio_blk *vblk = disk->private_data; u8 writeback = virtblk_get_cache_mode(vblk->vdev); BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types)); return snprintf(buf, 40, "%s ", virtblk_cache_types[writeback]); } |
e982c4d0a virtio-blk: moder... |
598 599 600 601 602 603 604 605 606 607 608 |
static DEVICE_ATTR_RW(cache_type); static struct attribute *virtblk_attrs[] = { &dev_attr_serial.attr, &dev_attr_cache_type.attr, NULL, }; static umode_t virtblk_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { |
4ce790632 virtio-blk: Use k... |
609 |
struct device *dev = kobj_to_dev(kobj); |
e982c4d0a virtio-blk: moder... |
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
struct gendisk *disk = dev_to_disk(dev); struct virtio_blk *vblk = disk->private_data; struct virtio_device *vdev = vblk->vdev; if (a == &dev_attr_cache_type.attr && !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) return S_IRUGO; return a->mode; } static const struct attribute_group virtblk_attr_group = { .attrs = virtblk_attrs, .is_visible = virtblk_attrs_are_visible, }; static const struct attribute_group *virtblk_attr_groups[] = { &virtblk_attr_group, NULL, }; |
cd5d50386 virtio-blk: allow... |
630 |
|
d6296d39e blk-mq: update ->... |
631 632 |
static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, unsigned int numa_node) |
e9b267d91 blk-mq: add ->ini... |
633 |
{ |
d6296d39e blk-mq: update ->... |
634 |
struct virtio_blk *vblk = set->driver_data; |
e9b267d91 blk-mq: add ->ini... |
635 636 637 638 639 |
struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); sg_init_table(vbr->sg, vblk->sg_elems); return 0; } |
ad71473d9 virtio_blk: use v... |
640 641 642 |
static int virtblk_map_queues(struct blk_mq_tag_set *set) { struct virtio_blk *vblk = set->driver_data; |
9bc00750f virtio_blk: repla... |
643 644 |
return blk_mq_virtio_map_queues(&set->map[HCTX_TYPE_DEFAULT], vblk->vdev, 0); |
ad71473d9 virtio_blk: use v... |
645 |
} |
f363b089b blk-mq: constify ... |
646 |
static const struct blk_mq_ops virtio_mq_ops = { |
1cf7e9c68 virtio_blk: blk-m... |
647 |
.queue_rq = virtio_queue_rq, |
944e7c879 virtio_blk: imple... |
648 |
.commit_rqs = virtio_commit_rqs, |
5124c2857 virtio_blk: use b... |
649 |
.complete = virtblk_request_done, |
24d2f9030 blk-mq: split out... |
650 |
.init_request = virtblk_init_request, |
ad71473d9 virtio_blk: use v... |
651 |
.map_queues = virtblk_map_queues, |
1cf7e9c68 virtio_blk: blk-m... |
652 |
}; |
24d2f9030 blk-mq: split out... |
653 654 |
static unsigned int virtblk_queue_depth; module_param_named(queue_depth, virtblk_queue_depth, uint, 0444); |
1cf7e9c68 virtio_blk: blk-m... |
655 |
|
8d85fce77 Drivers: block: r... |
656 |
static int virtblk_probe(struct virtio_device *vdev) |
e467cde23 Block driver usin... |
657 658 |
{ struct virtio_blk *vblk; |
69740c8ba virtio_blk: add b... |
659 |
struct request_queue *q; |
5087a50e6 virtio-blk: use i... |
660 |
int err, index; |
a98755c55 virtio-blk: Add b... |
661 |
|
fd1068e18 virtio-blk: Consi... |
662 |
u32 v, blk_size, max_size, sg_elems, opt_io_size; |
69740c8ba virtio_blk: add b... |
663 664 |
u16 min_io_size; u8 physical_block_exp, alignment_offset; |
e467cde23 Block driver usin... |
665 |
|
a4379fd84 virtio/blk: verif... |
666 667 668 669 670 671 |
if (!vdev->config->get) { dev_err(&vdev->dev, "%s failure: config access disabled ", __func__); return -EINVAL; } |
5087a50e6 virtio-blk: use i... |
672 673 674 675 676 |
err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS), GFP_KERNEL); if (err < 0) goto out; index = err; |
4f3bf19c6 virtio_blk: Dont ... |
677 |
|
0864b79a1 virtio: block: dy... |
678 |
/* We need to know how many segments before we allocate. */ |
855e0c528 virtio: use size-... |
679 680 681 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX, struct virtio_blk_config, seg_max, &sg_elems); |
a5b365a65 virtio-blk: fix m... |
682 683 684 |
/* We need at least one SG element, whatever they say. */ if (err || !sg_elems) |
0864b79a1 virtio: block: dy... |
685 686 687 688 |
sg_elems = 1; /* We need an extra sg elements at head and tail. */ sg_elems += 2; |
1cf7e9c68 virtio_blk: blk-m... |
689 |
vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); |
e467cde23 Block driver usin... |
690 691 |
if (!vblk) { err = -ENOMEM; |
5087a50e6 virtio-blk: use i... |
692 |
goto out_free_index; |
e467cde23 Block driver usin... |
693 |
} |
90b5feb8c virtio-blk: handl... |
694 695 696 |
/* This reference is dropped in virtblk_remove(). */ refcount_set(&vblk->refs, 1); mutex_init(&vblk->vdev_mutex); |
e467cde23 Block driver usin... |
697 |
vblk->vdev = vdev; |
0864b79a1 virtio: block: dy... |
698 |
vblk->sg_elems = sg_elems; |
a98755c55 virtio-blk: Add b... |
699 |
|
7a7c924cf virtio_blk: allow... |
700 |
INIT_WORK(&vblk->config_work, virtblk_config_changed_work); |
e467cde23 Block driver usin... |
701 |
|
6abd6e5a4 virtio: blk: Move... |
702 703 |
err = init_vq(vblk); if (err) |
e467cde23 Block driver usin... |
704 |
goto out_free_vblk; |
e467cde23 Block driver usin... |
705 |
|
e467cde23 Block driver usin... |
706 |
/* FIXME: How many partitions? How long is a piece of string? */ |
4f3bf19c6 virtio_blk: Dont ... |
707 |
vblk->disk = alloc_disk(1 << PART_BITS); |
e467cde23 Block driver usin... |
708 709 |
if (!vblk->disk) { err = -ENOMEM; |
1cf7e9c68 virtio_blk: blk-m... |
710 |
goto out_free_vq; |
e467cde23 Block driver usin... |
711 |
} |
fc4324b45 virtio-blk: base ... |
712 |
/* Default queue sizing is to fill the ring. */ |
24d2f9030 blk-mq: split out... |
713 |
if (!virtblk_queue_depth) { |
6a27b656f block: virtio-blk... |
714 |
virtblk_queue_depth = vblk->vqs[0].vq->num_free; |
fc4324b45 virtio-blk: base ... |
715 716 |
/* ... but without indirect descs, we use 2 descs per req */ if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) |
24d2f9030 blk-mq: split out... |
717 |
virtblk_queue_depth /= 2; |
fc4324b45 virtio-blk: base ... |
718 |
} |
24d2f9030 blk-mq: split out... |
719 720 721 |
memset(&vblk->tag_set, 0, sizeof(vblk->tag_set)); vblk->tag_set.ops = &virtio_mq_ops; |
24d2f9030 blk-mq: split out... |
722 723 724 725 |
vblk->tag_set.queue_depth = virtblk_queue_depth; vblk->tag_set.numa_node = NUMA_NO_NODE; vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; vblk->tag_set.cmd_size = |
1cf7e9c68 virtio_blk: blk-m... |
726 727 |
sizeof(struct virtblk_req) + sizeof(struct scatterlist) * sg_elems; |
24d2f9030 blk-mq: split out... |
728 |
vblk->tag_set.driver_data = vblk; |
6a27b656f block: virtio-blk... |
729 |
vblk->tag_set.nr_hw_queues = vblk->num_vqs; |
1cf7e9c68 virtio_blk: blk-m... |
730 |
|
24d2f9030 blk-mq: split out... |
731 732 733 |
err = blk_mq_alloc_tag_set(&vblk->tag_set); if (err) goto out_put_disk; |
6bf6b0aa3 virtio_blk: fix p... |
734 |
q = blk_mq_init_queue(&vblk->tag_set); |
35b489d32 block: fix checki... |
735 |
if (IS_ERR(q)) { |
e467cde23 Block driver usin... |
736 |
err = -ENOMEM; |
24d2f9030 blk-mq: split out... |
737 |
goto out_free_tags; |
e467cde23 Block driver usin... |
738 |
} |
6bf6b0aa3 virtio_blk: fix p... |
739 |
vblk->disk->queue = q; |
e467cde23 Block driver usin... |
740 |
|
69740c8ba virtio_blk: add b... |
741 |
q->queuedata = vblk; |
7d116b626 virtio_blk: set q... |
742 |
|
c0aa3e091 virtio_blk: helpe... |
743 |
virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN); |
d50ed907d virtio_blk: imple... |
744 |
|
e467cde23 Block driver usin... |
745 |
vblk->disk->major = major; |
d50ed907d virtio_blk: imple... |
746 |
vblk->disk->first_minor = index_to_minor(index); |
e467cde23 Block driver usin... |
747 748 |
vblk->disk->private_data = vblk; vblk->disk->fops = &virtblk_fops; |
5fa3142da virtio-blk: Allow... |
749 |
vblk->disk->flags |= GENHD_FL_EXT_DEVT; |
5087a50e6 virtio-blk: use i... |
750 |
vblk->index = index; |
4f3bf19c6 virtio_blk: Dont ... |
751 |
|
02c42b7a6 virtio_blk: drop ... |
752 |
/* configure queue flush support */ |
cd5d50386 virtio-blk: allow... |
753 |
virtblk_update_cache_mode(vdev); |
e467cde23 Block driver usin... |
754 |
|
3ef536095 virtio_blk: allow... |
755 756 757 |
/* 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); |
0864b79a1 virtio: block: dy... |
758 |
/* We can handle whatever the host told us to handle. */ |
ee714f2dd block: Finalize c... |
759 |
blk_queue_max_segments(q, vblk->sg_elems-2); |
0864b79a1 virtio: block: dy... |
760 |
|
4b7f7e204 virtio: set max_s... |
761 |
/* No real sector limit. */ |
ee714f2dd block: Finalize c... |
762 |
blk_queue_max_hw_sectors(q, -1U); |
4b7f7e204 virtio: set max_s... |
763 |
|
fd1068e18 virtio-blk: Consi... |
764 |
max_size = virtio_max_dma_size(vdev); |
a586d4f60 virtio: simplify ... |
765 766 |
/* Host can optionally specify maximum segment size and number of * segments. */ |
855e0c528 virtio: use size-... |
767 768 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX, struct virtio_blk_config, size_max, &v); |
e467cde23 Block driver usin... |
769 |
if (!err) |
fd1068e18 virtio-blk: Consi... |
770 771 772 |
max_size = min(max_size, v); blk_queue_max_segment_size(q, max_size); |
e467cde23 Block driver usin... |
773 |
|
066f4d82a virtio_blk: check... |
774 |
/* Host can optionally specify the block size of the device */ |
855e0c528 virtio: use size-... |
775 776 777 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, struct virtio_blk_config, blk_size, &blk_size); |
066f4d82a virtio_blk: check... |
778 |
if (!err) |
69740c8ba virtio_blk: add b... |
779 780 781 782 783 |
blk_queue_logical_block_size(q, blk_size); else blk_size = queue_logical_block_size(q); /* Use topology information if available */ |
855e0c528 virtio: use size-... |
784 785 786 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, struct virtio_blk_config, physical_block_exp, &physical_block_exp); |
69740c8ba virtio_blk: add b... |
787 788 789 |
if (!err && physical_block_exp) blk_queue_physical_block_size(q, blk_size * (1 << physical_block_exp)); |
855e0c528 virtio: use size-... |
790 791 792 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, struct virtio_blk_config, alignment_offset, &alignment_offset); |
69740c8ba virtio_blk: add b... |
793 794 |
if (!err && alignment_offset) blk_queue_alignment_offset(q, blk_size * alignment_offset); |
855e0c528 virtio: use size-... |
795 796 797 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, struct virtio_blk_config, min_io_size, &min_io_size); |
69740c8ba virtio_blk: add b... |
798 799 |
if (!err && min_io_size) blk_queue_io_min(q, blk_size * min_io_size); |
855e0c528 virtio: use size-... |
800 801 802 |
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, struct virtio_blk_config, opt_io_size, &opt_io_size); |
69740c8ba virtio_blk: add b... |
803 804 |
if (!err && opt_io_size) blk_queue_io_opt(q, blk_size * opt_io_size); |
1f23816b8 virtio_blk: add d... |
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 |
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { q->limits.discard_granularity = blk_size; virtio_cread(vdev, struct virtio_blk_config, discard_sector_alignment, &v); q->limits.discard_alignment = v ? v << SECTOR_SHIFT : 0; virtio_cread(vdev, struct virtio_blk_config, max_discard_sectors, &v); blk_queue_max_discard_sectors(q, v ? v : UINT_MAX); virtio_cread(vdev, struct virtio_blk_config, max_discard_seg, &v); blk_queue_max_discard_segments(q, min_not_zero(v, MAX_DISCARD_SEGMENTS)); blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); } if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) { virtio_cread(vdev, struct virtio_blk_config, max_write_zeroes_sectors, &v); blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX); } |
daf2a5016 virtio_blk: print... |
830 |
virtblk_update_capacity(vblk, false); |
7a11370e5 virtio_blk: enabl... |
831 |
virtio_device_ready(vdev); |
e982c4d0a virtio-blk: moder... |
832 |
device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); |
e467cde23 Block driver usin... |
833 |
return 0; |
24d2f9030 blk-mq: split out... |
834 835 |
out_free_tags: blk_mq_free_tag_set(&vblk->tag_set); |
e467cde23 Block driver usin... |
836 837 |
out_put_disk: put_disk(vblk->disk); |
e467cde23 Block driver usin... |
838 |
out_free_vq: |
d2a7ddda9 virtio: find_vqs/... |
839 |
vdev->config->del_vqs(vdev); |
e7eea44ee virtio-blk: free ... |
840 |
kfree(vblk->vqs); |
e467cde23 Block driver usin... |
841 842 |
out_free_vblk: kfree(vblk); |
5087a50e6 virtio-blk: use i... |
843 844 |
out_free_index: ida_simple_remove(&vd_index_ida, index); |
e467cde23 Block driver usin... |
845 846 847 |
out: return err; } |
8d85fce77 Drivers: block: r... |
848 |
static void virtblk_remove(struct virtio_device *vdev) |
e467cde23 Block driver usin... |
849 850 |
{ struct virtio_blk *vblk = vdev->priv; |
e467cde23 Block driver usin... |
851 |
|
cc74f7193 virtio_blk: drop ... |
852 853 |
/* Make sure no work handler is accessing the device. */ flush_work(&vblk->config_work); |
7a7c924cf virtio_blk: allow... |
854 |
|
02e2b1249 virtio-blk: Call ... |
855 |
del_gendisk(vblk->disk); |
483001c76 virtio-blk: Reset... |
856 |
blk_cleanup_queue(vblk->disk->queue); |
02e2b1249 virtio-blk: Call ... |
857 |
|
24d2f9030 blk-mq: split out... |
858 |
blk_mq_free_tag_set(&vblk->tag_set); |
90b5feb8c virtio-blk: handl... |
859 |
mutex_lock(&vblk->vdev_mutex); |
6e5aa7efb virtio: reset fun... |
860 861 |
/* Stop all the virtqueues. */ vdev->config->reset(vdev); |
90b5feb8c virtio-blk: handl... |
862 863 |
/* Virtqueues are stopped, nothing can use vblk->vdev anymore. */ vblk->vdev = NULL; |
e467cde23 Block driver usin... |
864 |
put_disk(vblk->disk); |
d2a7ddda9 virtio: find_vqs/... |
865 |
vdev->config->del_vqs(vdev); |
6a27b656f block: virtio-blk... |
866 |
kfree(vblk->vqs); |
f4953fe6c virtio-blk: Don't... |
867 |
|
90b5feb8c virtio-blk: handl... |
868 869 870 |
mutex_unlock(&vblk->vdev_mutex); virtblk_put(vblk); |
e467cde23 Block driver usin... |
871 |
} |
891070003 virtio: pm: use C... |
872 |
#ifdef CONFIG_PM_SLEEP |
f8fb5bc23 virtio: blk: Add ... |
873 874 875 876 877 878 |
static int virtblk_freeze(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; /* Ensure we don't receive any more interrupts */ vdev->config->reset(vdev); |
cc74f7193 virtio_blk: drop ... |
879 |
/* Make sure no work handler is accessing the device. */ |
f8fb5bc23 virtio: blk: Add ... |
880 |
flush_work(&vblk->config_work); |
9b3e99058 virtio_blk: quies... |
881 |
blk_mq_quiesce_queue(vblk->disk->queue); |
f8fb5bc23 virtio: blk: Add ... |
882 883 884 885 886 887 888 889 890 |
vdev->config->del_vqs(vdev); return 0; } static int virtblk_restore(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; int ret; |
f8fb5bc23 virtio: blk: Add ... |
891 |
ret = init_vq(vdev->priv); |
6d62c37f1 virtio_blk: enabl... |
892 893 894 895 |
if (ret) return ret; virtio_device_ready(vdev); |
1cf7e9c68 virtio_blk: blk-m... |
896 |
|
9b3e99058 virtio_blk: quies... |
897 |
blk_mq_unquiesce_queue(vblk->disk->queue); |
6d62c37f1 virtio_blk: enabl... |
898 |
return 0; |
f8fb5bc23 virtio: blk: Add ... |
899 900 |
} #endif |
47483e252 block: make virti... |
901 |
static const struct virtio_device_id id_table[] = { |
e467cde23 Block driver usin... |
902 903 904 |
{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID }, { 0 }, }; |
19c1c5a64 virtio_blk: v1.0 ... |
905 |
static unsigned int features_legacy[] = { |
02c42b7a6 virtio_blk: drop ... |
906 |
VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, |
97b50a654 virtio_blk: make ... |
907 |
VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
592002f55 virtio_blk: VIRTI... |
908 |
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
1f23816b8 virtio_blk: add d... |
909 |
VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
19c1c5a64 virtio_blk: v1.0 ... |
910 911 912 913 914 |
} ; static unsigned int features[] = { VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
592002f55 virtio_blk: VIRTI... |
915 |
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
1f23816b8 virtio_blk: add d... |
916 |
VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
c45a6816c virtio: explicit ... |
917 |
}; |
8d85fce77 Drivers: block: r... |
918 |
static struct virtio_driver virtio_blk = { |
19c1c5a64 virtio_blk: v1.0 ... |
919 920 921 922 923 924 925 926 927 928 |
.feature_table = features, .feature_table_size = ARRAY_SIZE(features), .feature_table_legacy = features_legacy, .feature_table_size_legacy = ARRAY_SIZE(features_legacy), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, .probe = virtblk_probe, .remove = virtblk_remove, .config_changed = virtblk_config_changed, |
891070003 virtio: pm: use C... |
929 |
#ifdef CONFIG_PM_SLEEP |
19c1c5a64 virtio_blk: v1.0 ... |
930 931 |
.freeze = virtblk_freeze, .restore = virtblk_restore, |
f8fb5bc23 virtio: blk: Add ... |
932 |
#endif |
e467cde23 Block driver usin... |
933 934 935 936 |
}; static int __init init(void) { |
7a7c924cf virtio_blk: allow... |
937 938 939 940 941 |
int error; virtblk_wq = alloc_workqueue("virtio-blk", 0, 0); if (!virtblk_wq) return -ENOMEM; |
4f3bf19c6 virtio_blk: Dont ... |
942 |
major = register_blkdev(0, "virtblk"); |
7a7c924cf virtio_blk: allow... |
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 |
if (major < 0) { error = major; goto out_destroy_workqueue; } error = register_virtio_driver(&virtio_blk); if (error) goto out_unregister_blkdev; return 0; out_unregister_blkdev: unregister_blkdev(major, "virtblk"); out_destroy_workqueue: destroy_workqueue(virtblk_wq); return error; |
e467cde23 Block driver usin... |
958 959 960 961 962 |
} static void __exit fini(void) { unregister_virtio_driver(&virtio_blk); |
38f37b578 virtio_blk: fix r... |
963 |
unregister_blkdev(major, "virtblk"); |
7a7c924cf virtio_blk: allow... |
964 |
destroy_workqueue(virtblk_wq); |
e467cde23 Block driver usin... |
965 966 967 968 969 970 971 |
} module_init(init); module_exit(fini); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio block driver"); MODULE_LICENSE("GPL"); |