root / hw / xen_disk.c @ ab034c26
History | View | Annotate | Download (24.3 kB)
1 | 62d23efa | aliguori | /*
|
---|---|---|---|
2 | 62d23efa | aliguori | * xen paravirt block device backend
|
3 | 62d23efa | aliguori | *
|
4 | 62d23efa | aliguori | * (c) Gerd Hoffmann <kraxel@redhat.com>
|
5 | 62d23efa | aliguori | *
|
6 | 62d23efa | aliguori | * This program is free software; you can redistribute it and/or modify
|
7 | 62d23efa | aliguori | * it under the terms of the GNU General Public License as published by
|
8 | 62d23efa | aliguori | * the Free Software Foundation; under version 2 of the License.
|
9 | 62d23efa | aliguori | *
|
10 | 62d23efa | aliguori | * This program is distributed in the hope that it will be useful,
|
11 | 62d23efa | aliguori | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 | 62d23efa | aliguori | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13 | 62d23efa | aliguori | * GNU General Public License for more details.
|
14 | 62d23efa | aliguori | *
|
15 | 62d23efa | aliguori | * You should have received a copy of the GNU General Public License along
|
16 | 8167ee88 | Blue Swirl | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
17 | 6b620ca3 | Paolo Bonzini | *
|
18 | 6b620ca3 | Paolo Bonzini | * Contributions after 2012-01-13 are licensed under the terms of the
|
19 | 6b620ca3 | Paolo Bonzini | * GNU GPL, version 2 or (at your option) any later version.
|
20 | 62d23efa | aliguori | */
|
21 | 62d23efa | aliguori | |
22 | 62d23efa | aliguori | #include <stdio.h> |
23 | 62d23efa | aliguori | #include <stdlib.h> |
24 | 62d23efa | aliguori | #include <stdarg.h> |
25 | 62d23efa | aliguori | #include <string.h> |
26 | 62d23efa | aliguori | #include <unistd.h> |
27 | 62d23efa | aliguori | #include <signal.h> |
28 | 62d23efa | aliguori | #include <inttypes.h> |
29 | 62d23efa | aliguori | #include <time.h> |
30 | 62d23efa | aliguori | #include <fcntl.h> |
31 | 62d23efa | aliguori | #include <errno.h> |
32 | 62d23efa | aliguori | #include <sys/ioctl.h> |
33 | 62d23efa | aliguori | #include <sys/types.h> |
34 | 62d23efa | aliguori | #include <sys/stat.h> |
35 | 62d23efa | aliguori | #include <sys/mman.h> |
36 | 62d23efa | aliguori | #include <sys/uio.h> |
37 | 62d23efa | aliguori | |
38 | 62d23efa | aliguori | #include <xs.h> |
39 | 62d23efa | aliguori | #include <xenctrl.h> |
40 | 62d23efa | aliguori | #include <xen/io/xenbus.h> |
41 | 62d23efa | aliguori | |
42 | 62d23efa | aliguori | #include "hw.h" |
43 | 62d23efa | aliguori | #include "block_int.h" |
44 | 62d23efa | aliguori | #include "qemu-char.h" |
45 | 62d23efa | aliguori | #include "xen_blkif.h" |
46 | 62d23efa | aliguori | #include "xen_backend.h" |
47 | 2446333c | Blue Swirl | #include "blockdev.h" |
48 | 62d23efa | aliguori | |
49 | 62d23efa | aliguori | /* ------------------------------------------------------------- */
|
50 | 62d23efa | aliguori | |
51 | 62d23efa | aliguori | static int batch_maps = 0; |
52 | 62d23efa | aliguori | |
53 | 62d23efa | aliguori | static int max_requests = 32; |
54 | 62d23efa | aliguori | |
55 | 62d23efa | aliguori | /* ------------------------------------------------------------- */
|
56 | 62d23efa | aliguori | |
57 | 62d23efa | aliguori | #define BLOCK_SIZE 512 |
58 | 62d23efa | aliguori | #define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) |
59 | 62d23efa | aliguori | |
60 | 62d23efa | aliguori | struct ioreq {
|
61 | 62d23efa | aliguori | blkif_request_t req; |
62 | 62d23efa | aliguori | int16_t status; |
63 | 62d23efa | aliguori | |
64 | 62d23efa | aliguori | /* parsed request */
|
65 | 62d23efa | aliguori | off_t start; |
66 | 62d23efa | aliguori | QEMUIOVector v; |
67 | 62d23efa | aliguori | int presync;
|
68 | 62d23efa | aliguori | int postsync;
|
69 | c6961b7d | Stefano Stabellini | uint8_t mapped; |
70 | 62d23efa | aliguori | |
71 | 62d23efa | aliguori | /* grant mapping */
|
72 | 62d23efa | aliguori | uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST]; |
73 | 62d23efa | aliguori | uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; |
74 | 62d23efa | aliguori | int prot;
|
75 | 62d23efa | aliguori | void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
76 | 62d23efa | aliguori | void *pages;
|
77 | 62d23efa | aliguori | |
78 | 62d23efa | aliguori | /* aio status */
|
79 | 62d23efa | aliguori | int aio_inflight;
|
80 | 62d23efa | aliguori | int aio_errors;
|
81 | 62d23efa | aliguori | |
82 | 62d23efa | aliguori | struct XenBlkDev *blkdev;
|
83 | 72cf2d4f | Blue Swirl | QLIST_ENTRY(ioreq) list; |
84 | a597e79c | Christoph Hellwig | BlockAcctCookie acct; |
85 | 62d23efa | aliguori | }; |
86 | 62d23efa | aliguori | |
87 | 62d23efa | aliguori | struct XenBlkDev {
|
88 | 62d23efa | aliguori | struct XenDevice xendev; /* must be first */ |
89 | 62d23efa | aliguori | char *params;
|
90 | 62d23efa | aliguori | char *mode;
|
91 | 62d23efa | aliguori | char *type;
|
92 | 62d23efa | aliguori | char *dev;
|
93 | 62d23efa | aliguori | char *devtype;
|
94 | 62d23efa | aliguori | const char *fileproto; |
95 | 62d23efa | aliguori | const char *filename; |
96 | 62d23efa | aliguori | int ring_ref;
|
97 | 62d23efa | aliguori | void *sring;
|
98 | 62d23efa | aliguori | int64_t file_blk; |
99 | 62d23efa | aliguori | int64_t file_size; |
100 | 62d23efa | aliguori | int protocol;
|
101 | 62d23efa | aliguori | blkif_back_rings_t rings; |
102 | 62d23efa | aliguori | int more_work;
|
103 | 62d23efa | aliguori | int cnt_map;
|
104 | 62d23efa | aliguori | |
105 | 62d23efa | aliguori | /* request lists */
|
106 | 72cf2d4f | Blue Swirl | QLIST_HEAD(inflight_head, ioreq) inflight; |
107 | 72cf2d4f | Blue Swirl | QLIST_HEAD(finished_head, ioreq) finished; |
108 | 72cf2d4f | Blue Swirl | QLIST_HEAD(freelist_head, ioreq) freelist; |
109 | 62d23efa | aliguori | int requests_total;
|
110 | 62d23efa | aliguori | int requests_inflight;
|
111 | 62d23efa | aliguori | int requests_finished;
|
112 | 62d23efa | aliguori | |
113 | 62d23efa | aliguori | /* qemu block driver */
|
114 | 751c6a17 | Gerd Hoffmann | DriveInfo *dinfo; |
115 | 62d23efa | aliguori | BlockDriverState *bs; |
116 | 62d23efa | aliguori | QEMUBH *bh; |
117 | 62d23efa | aliguori | }; |
118 | 62d23efa | aliguori | |
119 | 62d23efa | aliguori | /* ------------------------------------------------------------- */
|
120 | 62d23efa | aliguori | |
121 | 62d23efa | aliguori | static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) |
122 | 62d23efa | aliguori | { |
123 | 62d23efa | aliguori | struct ioreq *ioreq = NULL; |
124 | 62d23efa | aliguori | |
125 | 72cf2d4f | Blue Swirl | if (QLIST_EMPTY(&blkdev->freelist)) {
|
126 | 209cd7ab | Anthony PERARD | if (blkdev->requests_total >= max_requests) {
|
127 | 209cd7ab | Anthony PERARD | goto out;
|
128 | 209cd7ab | Anthony PERARD | } |
129 | 209cd7ab | Anthony PERARD | /* allocate new struct */
|
130 | 7267c094 | Anthony Liguori | ioreq = g_malloc0(sizeof(*ioreq));
|
131 | 209cd7ab | Anthony PERARD | ioreq->blkdev = blkdev; |
132 | 209cd7ab | Anthony PERARD | blkdev->requests_total++; |
133 | 62d23efa | aliguori | qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST); |
134 | 62d23efa | aliguori | } else {
|
135 | 209cd7ab | Anthony PERARD | /* get one from freelist */
|
136 | 209cd7ab | Anthony PERARD | ioreq = QLIST_FIRST(&blkdev->freelist); |
137 | 209cd7ab | Anthony PERARD | QLIST_REMOVE(ioreq, list); |
138 | 62d23efa | aliguori | qemu_iovec_reset(&ioreq->v); |
139 | 62d23efa | aliguori | } |
140 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); |
141 | 62d23efa | aliguori | blkdev->requests_inflight++; |
142 | 62d23efa | aliguori | |
143 | 62d23efa | aliguori | out:
|
144 | 62d23efa | aliguori | return ioreq;
|
145 | 62d23efa | aliguori | } |
146 | 62d23efa | aliguori | |
147 | 62d23efa | aliguori | static void ioreq_finish(struct ioreq *ioreq) |
148 | 62d23efa | aliguori | { |
149 | 62d23efa | aliguori | struct XenBlkDev *blkdev = ioreq->blkdev;
|
150 | 62d23efa | aliguori | |
151 | 72cf2d4f | Blue Swirl | QLIST_REMOVE(ioreq, list); |
152 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list); |
153 | 62d23efa | aliguori | blkdev->requests_inflight--; |
154 | 62d23efa | aliguori | blkdev->requests_finished++; |
155 | 62d23efa | aliguori | } |
156 | 62d23efa | aliguori | |
157 | ed547766 | Jan Beulich | static void ioreq_release(struct ioreq *ioreq, bool finish) |
158 | 62d23efa | aliguori | { |
159 | 62d23efa | aliguori | struct XenBlkDev *blkdev = ioreq->blkdev;
|
160 | 62d23efa | aliguori | |
161 | 72cf2d4f | Blue Swirl | QLIST_REMOVE(ioreq, list); |
162 | 62d23efa | aliguori | memset(ioreq, 0, sizeof(*ioreq)); |
163 | 62d23efa | aliguori | ioreq->blkdev = blkdev; |
164 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); |
165 | ed547766 | Jan Beulich | if (finish) {
|
166 | ed547766 | Jan Beulich | blkdev->requests_finished--; |
167 | ed547766 | Jan Beulich | } else {
|
168 | ed547766 | Jan Beulich | blkdev->requests_inflight--; |
169 | ed547766 | Jan Beulich | } |
170 | 62d23efa | aliguori | } |
171 | 62d23efa | aliguori | |
172 | 62d23efa | aliguori | /*
|
173 | 62d23efa | aliguori | * translate request into iovec + start offset
|
174 | 62d23efa | aliguori | * do sanity checks along the way
|
175 | 62d23efa | aliguori | */
|
176 | 62d23efa | aliguori | static int ioreq_parse(struct ioreq *ioreq) |
177 | 62d23efa | aliguori | { |
178 | 62d23efa | aliguori | struct XenBlkDev *blkdev = ioreq->blkdev;
|
179 | 62d23efa | aliguori | uintptr_t mem; |
180 | 62d23efa | aliguori | size_t len; |
181 | 62d23efa | aliguori | int i;
|
182 | 62d23efa | aliguori | |
183 | 62d23efa | aliguori | xen_be_printf(&blkdev->xendev, 3,
|
184 | 209cd7ab | Anthony PERARD | "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n", |
185 | 209cd7ab | Anthony PERARD | ioreq->req.operation, ioreq->req.nr_segments, |
186 | 209cd7ab | Anthony PERARD | ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number); |
187 | 62d23efa | aliguori | switch (ioreq->req.operation) {
|
188 | 62d23efa | aliguori | case BLKIF_OP_READ:
|
189 | 209cd7ab | Anthony PERARD | ioreq->prot = PROT_WRITE; /* to memory */
|
190 | 209cd7ab | Anthony PERARD | break;
|
191 | 62d23efa | aliguori | case BLKIF_OP_WRITE_BARRIER:
|
192 | 5cbdebe3 | Stefano Stabellini | if (!ioreq->req.nr_segments) {
|
193 | 5cbdebe3 | Stefano Stabellini | ioreq->presync = 1;
|
194 | 5cbdebe3 | Stefano Stabellini | return 0; |
195 | 5cbdebe3 | Stefano Stabellini | } |
196 | ba1dffed | Stefano Stabellini | ioreq->presync = ioreq->postsync = 1;
|
197 | 209cd7ab | Anthony PERARD | /* fall through */
|
198 | 62d23efa | aliguori | case BLKIF_OP_WRITE:
|
199 | 209cd7ab | Anthony PERARD | ioreq->prot = PROT_READ; /* from memory */
|
200 | 209cd7ab | Anthony PERARD | break;
|
201 | 62d23efa | aliguori | default:
|
202 | 209cd7ab | Anthony PERARD | xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n", |
203 | 209cd7ab | Anthony PERARD | ioreq->req.operation); |
204 | 209cd7ab | Anthony PERARD | goto err;
|
205 | 62d23efa | aliguori | }; |
206 | 62d23efa | aliguori | |
207 | 908c7b9f | Gerd Hoffmann | if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { |
208 | 908c7b9f | Gerd Hoffmann | xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n"); |
209 | 908c7b9f | Gerd Hoffmann | goto err;
|
210 | 908c7b9f | Gerd Hoffmann | } |
211 | 908c7b9f | Gerd Hoffmann | |
212 | 62d23efa | aliguori | ioreq->start = ioreq->req.sector_number * blkdev->file_blk; |
213 | 62d23efa | aliguori | for (i = 0; i < ioreq->req.nr_segments; i++) { |
214 | 209cd7ab | Anthony PERARD | if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
|
215 | 209cd7ab | Anthony PERARD | xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n"); |
216 | 209cd7ab | Anthony PERARD | goto err;
|
217 | 209cd7ab | Anthony PERARD | } |
218 | 209cd7ab | Anthony PERARD | if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
|
219 | 209cd7ab | Anthony PERARD | xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n"); |
220 | 209cd7ab | Anthony PERARD | goto err;
|
221 | 209cd7ab | Anthony PERARD | } |
222 | 209cd7ab | Anthony PERARD | if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
|
223 | 209cd7ab | Anthony PERARD | xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n"); |
224 | 209cd7ab | Anthony PERARD | goto err;
|
225 | 209cd7ab | Anthony PERARD | } |
226 | 209cd7ab | Anthony PERARD | |
227 | 209cd7ab | Anthony PERARD | ioreq->domids[i] = blkdev->xendev.dom; |
228 | 209cd7ab | Anthony PERARD | ioreq->refs[i] = ioreq->req.seg[i].gref; |
229 | 209cd7ab | Anthony PERARD | |
230 | 209cd7ab | Anthony PERARD | mem = ioreq->req.seg[i].first_sect * blkdev->file_blk; |
231 | 209cd7ab | Anthony PERARD | len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
|
232 | 62d23efa | aliguori | qemu_iovec_add(&ioreq->v, (void*)mem, len);
|
233 | 62d23efa | aliguori | } |
234 | 62d23efa | aliguori | if (ioreq->start + ioreq->v.size > blkdev->file_size) {
|
235 | 209cd7ab | Anthony PERARD | xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n"); |
236 | 209cd7ab | Anthony PERARD | goto err;
|
237 | 62d23efa | aliguori | } |
238 | 62d23efa | aliguori | return 0; |
239 | 62d23efa | aliguori | |
240 | 62d23efa | aliguori | err:
|
241 | 62d23efa | aliguori | ioreq->status = BLKIF_RSP_ERROR; |
242 | 62d23efa | aliguori | return -1; |
243 | 62d23efa | aliguori | } |
244 | 62d23efa | aliguori | |
245 | 62d23efa | aliguori | static void ioreq_unmap(struct ioreq *ioreq) |
246 | 62d23efa | aliguori | { |
247 | d5b93ddf | Anthony PERARD | XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; |
248 | 62d23efa | aliguori | int i;
|
249 | 62d23efa | aliguori | |
250 | c6961b7d | Stefano Stabellini | if (ioreq->v.niov == 0 || ioreq->mapped == 0) { |
251 | 62d23efa | aliguori | return;
|
252 | 209cd7ab | Anthony PERARD | } |
253 | 62d23efa | aliguori | if (batch_maps) {
|
254 | 209cd7ab | Anthony PERARD | if (!ioreq->pages) {
|
255 | 209cd7ab | Anthony PERARD | return;
|
256 | 209cd7ab | Anthony PERARD | } |
257 | 209cd7ab | Anthony PERARD | if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) { |
258 | 209cd7ab | Anthony PERARD | xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", |
259 | 209cd7ab | Anthony PERARD | strerror(errno)); |
260 | 209cd7ab | Anthony PERARD | } |
261 | 209cd7ab | Anthony PERARD | ioreq->blkdev->cnt_map -= ioreq->v.niov; |
262 | 209cd7ab | Anthony PERARD | ioreq->pages = NULL;
|
263 | 62d23efa | aliguori | } else {
|
264 | 209cd7ab | Anthony PERARD | for (i = 0; i < ioreq->v.niov; i++) { |
265 | 209cd7ab | Anthony PERARD | if (!ioreq->page[i]) {
|
266 | 209cd7ab | Anthony PERARD | continue;
|
267 | 209cd7ab | Anthony PERARD | } |
268 | 209cd7ab | Anthony PERARD | if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) { |
269 | 209cd7ab | Anthony PERARD | xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", |
270 | 209cd7ab | Anthony PERARD | strerror(errno)); |
271 | 209cd7ab | Anthony PERARD | } |
272 | 209cd7ab | Anthony PERARD | ioreq->blkdev->cnt_map--; |
273 | 209cd7ab | Anthony PERARD | ioreq->page[i] = NULL;
|
274 | 209cd7ab | Anthony PERARD | } |
275 | 62d23efa | aliguori | } |
276 | c6961b7d | Stefano Stabellini | ioreq->mapped = 0;
|
277 | 62d23efa | aliguori | } |
278 | 62d23efa | aliguori | |
279 | 62d23efa | aliguori | static int ioreq_map(struct ioreq *ioreq) |
280 | 62d23efa | aliguori | { |
281 | d5b93ddf | Anthony PERARD | XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; |
282 | 62d23efa | aliguori | int i;
|
283 | 62d23efa | aliguori | |
284 | c6961b7d | Stefano Stabellini | if (ioreq->v.niov == 0 || ioreq->mapped == 1) { |
285 | 62d23efa | aliguori | return 0; |
286 | 209cd7ab | Anthony PERARD | } |
287 | 62d23efa | aliguori | if (batch_maps) {
|
288 | 209cd7ab | Anthony PERARD | ioreq->pages = xc_gnttab_map_grant_refs |
289 | 209cd7ab | Anthony PERARD | (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot); |
290 | 209cd7ab | Anthony PERARD | if (ioreq->pages == NULL) { |
291 | 209cd7ab | Anthony PERARD | xen_be_printf(&ioreq->blkdev->xendev, 0,
|
292 | 209cd7ab | Anthony PERARD | "can't map %d grant refs (%s, %d maps)\n",
|
293 | 209cd7ab | Anthony PERARD | ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map); |
294 | 209cd7ab | Anthony PERARD | return -1; |
295 | 209cd7ab | Anthony PERARD | } |
296 | 209cd7ab | Anthony PERARD | for (i = 0; i < ioreq->v.niov; i++) { |
297 | 209cd7ab | Anthony PERARD | ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE + |
298 | 209cd7ab | Anthony PERARD | (uintptr_t)ioreq->v.iov[i].iov_base; |
299 | 209cd7ab | Anthony PERARD | } |
300 | 209cd7ab | Anthony PERARD | ioreq->blkdev->cnt_map += ioreq->v.niov; |
301 | 62d23efa | aliguori | } else {
|
302 | 209cd7ab | Anthony PERARD | for (i = 0; i < ioreq->v.niov; i++) { |
303 | 209cd7ab | Anthony PERARD | ioreq->page[i] = xc_gnttab_map_grant_ref |
304 | 209cd7ab | Anthony PERARD | (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot); |
305 | 209cd7ab | Anthony PERARD | if (ioreq->page[i] == NULL) { |
306 | 209cd7ab | Anthony PERARD | xen_be_printf(&ioreq->blkdev->xendev, 0,
|
307 | 209cd7ab | Anthony PERARD | "can't map grant ref %d (%s, %d maps)\n",
|
308 | 209cd7ab | Anthony PERARD | ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map); |
309 | 209cd7ab | Anthony PERARD | ioreq_unmap(ioreq); |
310 | 209cd7ab | Anthony PERARD | return -1; |
311 | 209cd7ab | Anthony PERARD | } |
312 | 209cd7ab | Anthony PERARD | ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base; |
313 | 209cd7ab | Anthony PERARD | ioreq->blkdev->cnt_map++; |
314 | 209cd7ab | Anthony PERARD | } |
315 | 62d23efa | aliguori | } |
316 | c6961b7d | Stefano Stabellini | ioreq->mapped = 1;
|
317 | 62d23efa | aliguori | return 0; |
318 | 62d23efa | aliguori | } |
319 | 62d23efa | aliguori | |
320 | c6961b7d | Stefano Stabellini | static int ioreq_runio_qemu_aio(struct ioreq *ioreq); |
321 | c6961b7d | Stefano Stabellini | |
322 | 62d23efa | aliguori | static void qemu_aio_complete(void *opaque, int ret) |
323 | 62d23efa | aliguori | { |
324 | 62d23efa | aliguori | struct ioreq *ioreq = opaque;
|
325 | 62d23efa | aliguori | |
326 | 62d23efa | aliguori | if (ret != 0) { |
327 | 62d23efa | aliguori | xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n", |
328 | 62d23efa | aliguori | ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); |
329 | 62d23efa | aliguori | ioreq->aio_errors++; |
330 | 62d23efa | aliguori | } |
331 | 62d23efa | aliguori | |
332 | 62d23efa | aliguori | ioreq->aio_inflight--; |
333 | c6961b7d | Stefano Stabellini | if (ioreq->presync) {
|
334 | c6961b7d | Stefano Stabellini | ioreq->presync = 0;
|
335 | c6961b7d | Stefano Stabellini | ioreq_runio_qemu_aio(ioreq); |
336 | c6961b7d | Stefano Stabellini | return;
|
337 | c6961b7d | Stefano Stabellini | } |
338 | 209cd7ab | Anthony PERARD | if (ioreq->aio_inflight > 0) { |
339 | 62d23efa | aliguori | return;
|
340 | 209cd7ab | Anthony PERARD | } |
341 | d56de074 | Stefano Stabellini | if (ioreq->postsync) {
|
342 | c6961b7d | Stefano Stabellini | ioreq->postsync = 0;
|
343 | c6961b7d | Stefano Stabellini | ioreq->aio_inflight++; |
344 | c6961b7d | Stefano Stabellini | bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq); |
345 | c6961b7d | Stefano Stabellini | return;
|
346 | d56de074 | Stefano Stabellini | } |
347 | 62d23efa | aliguori | |
348 | 62d23efa | aliguori | ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; |
349 | 62d23efa | aliguori | ioreq_unmap(ioreq); |
350 | 62d23efa | aliguori | ioreq_finish(ioreq); |
351 | a597e79c | Christoph Hellwig | bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct); |
352 | 62d23efa | aliguori | qemu_bh_schedule(ioreq->blkdev->bh); |
353 | 62d23efa | aliguori | } |
354 | 62d23efa | aliguori | |
355 | 62d23efa | aliguori | static int ioreq_runio_qemu_aio(struct ioreq *ioreq) |
356 | 62d23efa | aliguori | { |
357 | 62d23efa | aliguori | struct XenBlkDev *blkdev = ioreq->blkdev;
|
358 | 62d23efa | aliguori | |
359 | 209cd7ab | Anthony PERARD | if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) { |
360 | 209cd7ab | Anthony PERARD | goto err_no_map;
|
361 | 209cd7ab | Anthony PERARD | } |
362 | 62d23efa | aliguori | |
363 | 62d23efa | aliguori | ioreq->aio_inflight++; |
364 | 209cd7ab | Anthony PERARD | if (ioreq->presync) {
|
365 | c6961b7d | Stefano Stabellini | bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq); |
366 | c6961b7d | Stefano Stabellini | return 0; |
367 | 209cd7ab | Anthony PERARD | } |
368 | 62d23efa | aliguori | |
369 | 62d23efa | aliguori | switch (ioreq->req.operation) {
|
370 | 62d23efa | aliguori | case BLKIF_OP_READ:
|
371 | a597e79c | Christoph Hellwig | bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_READ); |
372 | 62d23efa | aliguori | ioreq->aio_inflight++; |
373 | 62d23efa | aliguori | bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE, |
374 | 62d23efa | aliguori | &ioreq->v, ioreq->v.size / BLOCK_SIZE, |
375 | 62d23efa | aliguori | qemu_aio_complete, ioreq); |
376 | 209cd7ab | Anthony PERARD | break;
|
377 | 62d23efa | aliguori | case BLKIF_OP_WRITE:
|
378 | 62d23efa | aliguori | case BLKIF_OP_WRITE_BARRIER:
|
379 | 209cd7ab | Anthony PERARD | if (!ioreq->req.nr_segments) {
|
380 | 5cbdebe3 | Stefano Stabellini | break;
|
381 | 209cd7ab | Anthony PERARD | } |
382 | a597e79c | Christoph Hellwig | |
383 | a597e79c | Christoph Hellwig | bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_WRITE); |
384 | 209bef3e | Feiran Zheng | ioreq->aio_inflight++; |
385 | 62d23efa | aliguori | bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE, |
386 | 62d23efa | aliguori | &ioreq->v, ioreq->v.size / BLOCK_SIZE, |
387 | 62d23efa | aliguori | qemu_aio_complete, ioreq); |
388 | 209cd7ab | Anthony PERARD | break;
|
389 | 62d23efa | aliguori | default:
|
390 | 209cd7ab | Anthony PERARD | /* unknown operation (shouldn't happen -- parse catches this) */
|
391 | 209cd7ab | Anthony PERARD | goto err;
|
392 | 62d23efa | aliguori | } |
393 | 62d23efa | aliguori | |
394 | 62d23efa | aliguori | qemu_aio_complete(ioreq, 0);
|
395 | 62d23efa | aliguori | |
396 | 62d23efa | aliguori | return 0; |
397 | 62d23efa | aliguori | |
398 | 62d23efa | aliguori | err:
|
399 | f6ec953c | Feiran Zheng | ioreq_unmap(ioreq); |
400 | f6ec953c | Feiran Zheng | err_no_map:
|
401 | f6ec953c | Feiran Zheng | ioreq_finish(ioreq); |
402 | 62d23efa | aliguori | ioreq->status = BLKIF_RSP_ERROR; |
403 | 62d23efa | aliguori | return -1; |
404 | 62d23efa | aliguori | } |
405 | 62d23efa | aliguori | |
406 | 62d23efa | aliguori | static int blk_send_response_one(struct ioreq *ioreq) |
407 | 62d23efa | aliguori | { |
408 | 62d23efa | aliguori | struct XenBlkDev *blkdev = ioreq->blkdev;
|
409 | 62d23efa | aliguori | int send_notify = 0; |
410 | 62d23efa | aliguori | int have_requests = 0; |
411 | 62d23efa | aliguori | blkif_response_t resp; |
412 | 62d23efa | aliguori | void *dst;
|
413 | 62d23efa | aliguori | |
414 | 62d23efa | aliguori | resp.id = ioreq->req.id; |
415 | 62d23efa | aliguori | resp.operation = ioreq->req.operation; |
416 | 62d23efa | aliguori | resp.status = ioreq->status; |
417 | 62d23efa | aliguori | |
418 | 62d23efa | aliguori | /* Place on the response ring for the relevant domain. */
|
419 | 62d23efa | aliguori | switch (blkdev->protocol) {
|
420 | 62d23efa | aliguori | case BLKIF_PROTOCOL_NATIVE:
|
421 | 209cd7ab | Anthony PERARD | dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt); |
422 | 209cd7ab | Anthony PERARD | break;
|
423 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_32:
|
424 | 6fcfeff9 | Blue Swirl | dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part, |
425 | 6fcfeff9 | Blue Swirl | blkdev->rings.x86_32_part.rsp_prod_pvt); |
426 | 209cd7ab | Anthony PERARD | break;
|
427 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_64:
|
428 | 6fcfeff9 | Blue Swirl | dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part, |
429 | 6fcfeff9 | Blue Swirl | blkdev->rings.x86_64_part.rsp_prod_pvt); |
430 | 209cd7ab | Anthony PERARD | break;
|
431 | 62d23efa | aliguori | default:
|
432 | 209cd7ab | Anthony PERARD | dst = NULL;
|
433 | 62d23efa | aliguori | } |
434 | 62d23efa | aliguori | memcpy(dst, &resp, sizeof(resp));
|
435 | 62d23efa | aliguori | blkdev->rings.common.rsp_prod_pvt++; |
436 | 62d23efa | aliguori | |
437 | 62d23efa | aliguori | RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify); |
438 | 62d23efa | aliguori | if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
|
439 | 209cd7ab | Anthony PERARD | /*
|
440 | 209cd7ab | Anthony PERARD | * Tail check for pending requests. Allows frontend to avoid
|
441 | 209cd7ab | Anthony PERARD | * notifications if requests are already in flight (lower
|
442 | 209cd7ab | Anthony PERARD | * overheads and promotes batching).
|
443 | 209cd7ab | Anthony PERARD | */
|
444 | 209cd7ab | Anthony PERARD | RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests); |
445 | 62d23efa | aliguori | } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) { |
446 | 209cd7ab | Anthony PERARD | have_requests = 1;
|
447 | 62d23efa | aliguori | } |
448 | 62d23efa | aliguori | |
449 | 209cd7ab | Anthony PERARD | if (have_requests) {
|
450 | 209cd7ab | Anthony PERARD | blkdev->more_work++; |
451 | 209cd7ab | Anthony PERARD | } |
452 | 62d23efa | aliguori | return send_notify;
|
453 | 62d23efa | aliguori | } |
454 | 62d23efa | aliguori | |
455 | 62d23efa | aliguori | /* walk finished list, send outstanding responses, free requests */
|
456 | 62d23efa | aliguori | static void blk_send_response_all(struct XenBlkDev *blkdev) |
457 | 62d23efa | aliguori | { |
458 | 62d23efa | aliguori | struct ioreq *ioreq;
|
459 | 62d23efa | aliguori | int send_notify = 0; |
460 | 62d23efa | aliguori | |
461 | 72cf2d4f | Blue Swirl | while (!QLIST_EMPTY(&blkdev->finished)) {
|
462 | 72cf2d4f | Blue Swirl | ioreq = QLIST_FIRST(&blkdev->finished); |
463 | 209cd7ab | Anthony PERARD | send_notify += blk_send_response_one(ioreq); |
464 | ed547766 | Jan Beulich | ioreq_release(ioreq, true);
|
465 | 209cd7ab | Anthony PERARD | } |
466 | 209cd7ab | Anthony PERARD | if (send_notify) {
|
467 | 209cd7ab | Anthony PERARD | xen_be_send_notify(&blkdev->xendev); |
468 | 62d23efa | aliguori | } |
469 | 62d23efa | aliguori | } |
470 | 62d23efa | aliguori | |
471 | 62d23efa | aliguori | static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc) |
472 | 62d23efa | aliguori | { |
473 | 62d23efa | aliguori | switch (blkdev->protocol) {
|
474 | 62d23efa | aliguori | case BLKIF_PROTOCOL_NATIVE:
|
475 | 209cd7ab | Anthony PERARD | memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc), |
476 | 209cd7ab | Anthony PERARD | sizeof(ioreq->req));
|
477 | 209cd7ab | Anthony PERARD | break;
|
478 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_32:
|
479 | 6fcfeff9 | Blue Swirl | blkif_get_x86_32_req(&ioreq->req, |
480 | 6fcfeff9 | Blue Swirl | RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc)); |
481 | 209cd7ab | Anthony PERARD | break;
|
482 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_64:
|
483 | 6fcfeff9 | Blue Swirl | blkif_get_x86_64_req(&ioreq->req, |
484 | 6fcfeff9 | Blue Swirl | RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc)); |
485 | 209cd7ab | Anthony PERARD | break;
|
486 | 62d23efa | aliguori | } |
487 | 62d23efa | aliguori | return 0; |
488 | 62d23efa | aliguori | } |
489 | 62d23efa | aliguori | |
490 | 62d23efa | aliguori | static void blk_handle_requests(struct XenBlkDev *blkdev) |
491 | 62d23efa | aliguori | { |
492 | 62d23efa | aliguori | RING_IDX rc, rp; |
493 | 62d23efa | aliguori | struct ioreq *ioreq;
|
494 | 62d23efa | aliguori | |
495 | 62d23efa | aliguori | blkdev->more_work = 0;
|
496 | 62d23efa | aliguori | |
497 | 62d23efa | aliguori | rc = blkdev->rings.common.req_cons; |
498 | 62d23efa | aliguori | rp = blkdev->rings.common.sring->req_prod; |
499 | 62d23efa | aliguori | xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
|
500 | 62d23efa | aliguori | |
501 | 4e5b184d | Paolo Bonzini | blk_send_response_all(blkdev); |
502 | fc1f79f7 | blueswir1 | while (rc != rp) {
|
503 | 62d23efa | aliguori | /* pull request from ring */
|
504 | 209cd7ab | Anthony PERARD | if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
|
505 | 62d23efa | aliguori | break;
|
506 | 209cd7ab | Anthony PERARD | } |
507 | 62d23efa | aliguori | ioreq = ioreq_start(blkdev); |
508 | 62d23efa | aliguori | if (ioreq == NULL) { |
509 | 62d23efa | aliguori | blkdev->more_work++; |
510 | 62d23efa | aliguori | break;
|
511 | 62d23efa | aliguori | } |
512 | 62d23efa | aliguori | blk_get_request(blkdev, ioreq, rc); |
513 | 62d23efa | aliguori | blkdev->rings.common.req_cons = ++rc; |
514 | 62d23efa | aliguori | |
515 | 62d23efa | aliguori | /* parse them */
|
516 | 62d23efa | aliguori | if (ioreq_parse(ioreq) != 0) { |
517 | 209cd7ab | Anthony PERARD | if (blk_send_response_one(ioreq)) {
|
518 | 62d23efa | aliguori | xen_be_send_notify(&blkdev->xendev); |
519 | 209cd7ab | Anthony PERARD | } |
520 | ed547766 | Jan Beulich | ioreq_release(ioreq, false);
|
521 | 62d23efa | aliguori | continue;
|
522 | 62d23efa | aliguori | } |
523 | 62d23efa | aliguori | |
524 | 4e5b184d | Paolo Bonzini | ioreq_runio_qemu_aio(ioreq); |
525 | 209cd7ab | Anthony PERARD | } |
526 | 62d23efa | aliguori | |
527 | 209cd7ab | Anthony PERARD | if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
|
528 | 62d23efa | aliguori | qemu_bh_schedule(blkdev->bh); |
529 | 209cd7ab | Anthony PERARD | } |
530 | 62d23efa | aliguori | } |
531 | 62d23efa | aliguori | |
532 | 62d23efa | aliguori | /* ------------------------------------------------------------- */
|
533 | 62d23efa | aliguori | |
534 | 62d23efa | aliguori | static void blk_bh(void *opaque) |
535 | 62d23efa | aliguori | { |
536 | 62d23efa | aliguori | struct XenBlkDev *blkdev = opaque;
|
537 | 62d23efa | aliguori | blk_handle_requests(blkdev); |
538 | 62d23efa | aliguori | } |
539 | 62d23efa | aliguori | |
540 | 64c27e5b | Jan Beulich | /*
|
541 | 64c27e5b | Jan Beulich | * We need to account for the grant allocations requiring contiguous
|
542 | 64c27e5b | Jan Beulich | * chunks; the worst case number would be
|
543 | 64c27e5b | Jan Beulich | * max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
|
544 | 64c27e5b | Jan Beulich | * but in order to keep things simple just use
|
545 | 64c27e5b | Jan Beulich | * 2 * max_req * max_seg.
|
546 | 64c27e5b | Jan Beulich | */
|
547 | 64c27e5b | Jan Beulich | #define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg)) |
548 | 64c27e5b | Jan Beulich | |
549 | 62d23efa | aliguori | static void blk_alloc(struct XenDevice *xendev) |
550 | 62d23efa | aliguori | { |
551 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
552 | 62d23efa | aliguori | |
553 | 72cf2d4f | Blue Swirl | QLIST_INIT(&blkdev->inflight); |
554 | 72cf2d4f | Blue Swirl | QLIST_INIT(&blkdev->finished); |
555 | 72cf2d4f | Blue Swirl | QLIST_INIT(&blkdev->freelist); |
556 | 62d23efa | aliguori | blkdev->bh = qemu_bh_new(blk_bh, blkdev); |
557 | 209cd7ab | Anthony PERARD | if (xen_mode != XEN_EMULATE) {
|
558 | 62d23efa | aliguori | batch_maps = 1;
|
559 | 209cd7ab | Anthony PERARD | } |
560 | 64c27e5b | Jan Beulich | if (xc_gnttab_set_max_grants(xendev->gnttabdev,
|
561 | 64c27e5b | Jan Beulich | MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
|
562 | 64c27e5b | Jan Beulich | xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n", |
563 | 64c27e5b | Jan Beulich | strerror(errno)); |
564 | 64c27e5b | Jan Beulich | } |
565 | 62d23efa | aliguori | } |
566 | 62d23efa | aliguori | |
567 | 62d23efa | aliguori | static int blk_init(struct XenDevice *xendev) |
568 | 62d23efa | aliguori | { |
569 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
570 | 5cce43bb | Kevin Wolf | int index, qflags, info = 0; |
571 | 62d23efa | aliguori | |
572 | 62d23efa | aliguori | /* read xenstore entries */
|
573 | 62d23efa | aliguori | if (blkdev->params == NULL) { |
574 | 5ea3c2b4 | Stefano Stabellini | char *h = NULL; |
575 | 209cd7ab | Anthony PERARD | blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
|
576 | 5ea3c2b4 | Stefano Stabellini | if (blkdev->params != NULL) { |
577 | 5ea3c2b4 | Stefano Stabellini | h = strchr(blkdev->params, ':');
|
578 | 5ea3c2b4 | Stefano Stabellini | } |
579 | 209cd7ab | Anthony PERARD | if (h != NULL) { |
580 | 209cd7ab | Anthony PERARD | blkdev->fileproto = blkdev->params; |
581 | 209cd7ab | Anthony PERARD | blkdev->filename = h+1;
|
582 | 209cd7ab | Anthony PERARD | *h = 0;
|
583 | 209cd7ab | Anthony PERARD | } else {
|
584 | 209cd7ab | Anthony PERARD | blkdev->fileproto = "<unset>";
|
585 | 209cd7ab | Anthony PERARD | blkdev->filename = blkdev->params; |
586 | 209cd7ab | Anthony PERARD | } |
587 | 209cd7ab | Anthony PERARD | } |
588 | 7cef3f4f | Stefano Stabellini | if (!strcmp("aio", blkdev->fileproto)) { |
589 | 7cef3f4f | Stefano Stabellini | blkdev->fileproto = "raw";
|
590 | 7cef3f4f | Stefano Stabellini | } |
591 | 209cd7ab | Anthony PERARD | if (blkdev->mode == NULL) { |
592 | 209cd7ab | Anthony PERARD | blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
|
593 | 209cd7ab | Anthony PERARD | } |
594 | 209cd7ab | Anthony PERARD | if (blkdev->type == NULL) { |
595 | 209cd7ab | Anthony PERARD | blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
|
596 | 209cd7ab | Anthony PERARD | } |
597 | 209cd7ab | Anthony PERARD | if (blkdev->dev == NULL) { |
598 | 209cd7ab | Anthony PERARD | blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
|
599 | 209cd7ab | Anthony PERARD | } |
600 | 209cd7ab | Anthony PERARD | if (blkdev->devtype == NULL) { |
601 | 209cd7ab | Anthony PERARD | blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
|
602 | 209cd7ab | Anthony PERARD | } |
603 | 62d23efa | aliguori | |
604 | 62d23efa | aliguori | /* do we have all we need? */
|
605 | 62d23efa | aliguori | if (blkdev->params == NULL || |
606 | 209cd7ab | Anthony PERARD | blkdev->mode == NULL ||
|
607 | 209cd7ab | Anthony PERARD | blkdev->type == NULL ||
|
608 | 209cd7ab | Anthony PERARD | blkdev->dev == NULL) {
|
609 | 5ea3c2b4 | Stefano Stabellini | goto out_error;
|
610 | 209cd7ab | Anthony PERARD | } |
611 | 62d23efa | aliguori | |
612 | 62d23efa | aliguori | /* read-only ? */
|
613 | 82091410 | Stefano Stabellini | qflags = BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO; |
614 | 62d23efa | aliguori | if (strcmp(blkdev->mode, "w") == 0) { |
615 | 82091410 | Stefano Stabellini | qflags |= BDRV_O_RDWR; |
616 | 62d23efa | aliguori | } else {
|
617 | 209cd7ab | Anthony PERARD | info |= VDISK_READONLY; |
618 | 62d23efa | aliguori | } |
619 | 62d23efa | aliguori | |
620 | 62d23efa | aliguori | /* cdrom ? */
|
621 | 209cd7ab | Anthony PERARD | if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) { |
622 | 209cd7ab | Anthony PERARD | info |= VDISK_CDROM; |
623 | 209cd7ab | Anthony PERARD | } |
624 | 62d23efa | aliguori | |
625 | 62d23efa | aliguori | /* init qemu block driver */
|
626 | 751c6a17 | Gerd Hoffmann | index = (blkdev->xendev.dev - 202 * 256) / 16; |
627 | 751c6a17 | Gerd Hoffmann | blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
628 | 751c6a17 | Gerd Hoffmann | if (!blkdev->dinfo) {
|
629 | 62d23efa | aliguori | /* setup via xenbus -> create new block driver instance */
|
630 | 62d23efa | aliguori | xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); |
631 | ad717139 | Kevin Wolf | blkdev->bs = bdrv_new(blkdev->dev); |
632 | 5ea3c2b4 | Stefano Stabellini | if (blkdev->bs) {
|
633 | 5ea3c2b4 | Stefano Stabellini | if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
|
634 | 5ea3c2b4 | Stefano Stabellini | bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
|
635 | 5ea3c2b4 | Stefano Stabellini | bdrv_delete(blkdev->bs); |
636 | 5ea3c2b4 | Stefano Stabellini | blkdev->bs = NULL;
|
637 | 5ea3c2b4 | Stefano Stabellini | } |
638 | 5ea3c2b4 | Stefano Stabellini | } |
639 | 5ea3c2b4 | Stefano Stabellini | if (!blkdev->bs) {
|
640 | 5ea3c2b4 | Stefano Stabellini | goto out_error;
|
641 | ad717139 | Kevin Wolf | } |
642 | 62d23efa | aliguori | } else {
|
643 | 62d23efa | aliguori | /* setup via qemu cmdline -> already setup for us */
|
644 | 62d23efa | aliguori | xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n"); |
645 | 209cd7ab | Anthony PERARD | blkdev->bs = blkdev->dinfo->bdrv; |
646 | 62d23efa | aliguori | } |
647 | fa879d62 | Markus Armbruster | bdrv_attach_dev_nofail(blkdev->bs, blkdev); |
648 | 62d23efa | aliguori | blkdev->file_blk = BLOCK_SIZE; |
649 | 62d23efa | aliguori | blkdev->file_size = bdrv_getlength(blkdev->bs); |
650 | 62d23efa | aliguori | if (blkdev->file_size < 0) { |
651 | 62d23efa | aliguori | xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n", |
652 | 62d23efa | aliguori | (int)blkdev->file_size, strerror(-blkdev->file_size),
|
653 | 62d23efa | aliguori | blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
|
654 | 209cd7ab | Anthony PERARD | blkdev->file_size = 0;
|
655 | 62d23efa | aliguori | } |
656 | 62d23efa | aliguori | |
657 | 62d23efa | aliguori | xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," |
658 | 209cd7ab | Anthony PERARD | " size %" PRId64 " (%" PRId64 " MB)\n", |
659 | 209cd7ab | Anthony PERARD | blkdev->type, blkdev->fileproto, blkdev->filename, |
660 | 209cd7ab | Anthony PERARD | blkdev->file_size, blkdev->file_size >> 20);
|
661 | 62d23efa | aliguori | |
662 | 62d23efa | aliguori | /* fill info */
|
663 | 5cce43bb | Kevin Wolf | xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1); |
664 | 62d23efa | aliguori | xenstore_write_be_int(&blkdev->xendev, "info", info);
|
665 | 62d23efa | aliguori | xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
|
666 | 62d23efa | aliguori | xenstore_write_be_int(&blkdev->xendev, "sectors",
|
667 | 209cd7ab | Anthony PERARD | blkdev->file_size / blkdev->file_blk); |
668 | 62d23efa | aliguori | return 0; |
669 | 5ea3c2b4 | Stefano Stabellini | |
670 | 5ea3c2b4 | Stefano Stabellini | out_error:
|
671 | 7267c094 | Anthony Liguori | g_free(blkdev->params); |
672 | 5ea3c2b4 | Stefano Stabellini | blkdev->params = NULL;
|
673 | 7267c094 | Anthony Liguori | g_free(blkdev->mode); |
674 | 5ea3c2b4 | Stefano Stabellini | blkdev->mode = NULL;
|
675 | 7267c094 | Anthony Liguori | g_free(blkdev->type); |
676 | 5ea3c2b4 | Stefano Stabellini | blkdev->type = NULL;
|
677 | 7267c094 | Anthony Liguori | g_free(blkdev->dev); |
678 | 5ea3c2b4 | Stefano Stabellini | blkdev->dev = NULL;
|
679 | 7267c094 | Anthony Liguori | g_free(blkdev->devtype); |
680 | 5ea3c2b4 | Stefano Stabellini | blkdev->devtype = NULL;
|
681 | 5ea3c2b4 | Stefano Stabellini | return -1; |
682 | 62d23efa | aliguori | } |
683 | 62d23efa | aliguori | |
684 | 62d23efa | aliguori | static int blk_connect(struct XenDevice *xendev) |
685 | 62d23efa | aliguori | { |
686 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
687 | 62d23efa | aliguori | |
688 | 209cd7ab | Anthony PERARD | if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) { |
689 | 209cd7ab | Anthony PERARD | return -1; |
690 | 209cd7ab | Anthony PERARD | } |
691 | 62d23efa | aliguori | if (xenstore_read_fe_int(&blkdev->xendev, "event-channel", |
692 | 209cd7ab | Anthony PERARD | &blkdev->xendev.remote_port) == -1) {
|
693 | 209cd7ab | Anthony PERARD | return -1; |
694 | 209cd7ab | Anthony PERARD | } |
695 | 62d23efa | aliguori | |
696 | 62d23efa | aliguori | blkdev->protocol = BLKIF_PROTOCOL_NATIVE; |
697 | 62d23efa | aliguori | if (blkdev->xendev.protocol) {
|
698 | 209cd7ab | Anthony PERARD | if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { |
699 | 62d23efa | aliguori | blkdev->protocol = BLKIF_PROTOCOL_X86_32; |
700 | 209cd7ab | Anthony PERARD | } |
701 | 209cd7ab | Anthony PERARD | if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { |
702 | 62d23efa | aliguori | blkdev->protocol = BLKIF_PROTOCOL_X86_64; |
703 | 209cd7ab | Anthony PERARD | } |
704 | 62d23efa | aliguori | } |
705 | 62d23efa | aliguori | |
706 | 62d23efa | aliguori | blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev, |
707 | 209cd7ab | Anthony PERARD | blkdev->xendev.dom, |
708 | 209cd7ab | Anthony PERARD | blkdev->ring_ref, |
709 | 209cd7ab | Anthony PERARD | PROT_READ | PROT_WRITE); |
710 | 209cd7ab | Anthony PERARD | if (!blkdev->sring) {
|
711 | 209cd7ab | Anthony PERARD | return -1; |
712 | 209cd7ab | Anthony PERARD | } |
713 | 62d23efa | aliguori | blkdev->cnt_map++; |
714 | 62d23efa | aliguori | |
715 | 62d23efa | aliguori | switch (blkdev->protocol) {
|
716 | 62d23efa | aliguori | case BLKIF_PROTOCOL_NATIVE:
|
717 | 62d23efa | aliguori | { |
718 | 209cd7ab | Anthony PERARD | blkif_sring_t *sring_native = blkdev->sring; |
719 | 209cd7ab | Anthony PERARD | BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE); |
720 | 209cd7ab | Anthony PERARD | break;
|
721 | 62d23efa | aliguori | } |
722 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_32:
|
723 | 62d23efa | aliguori | { |
724 | 209cd7ab | Anthony PERARD | blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; |
725 | 6fcfeff9 | Blue Swirl | |
726 | 6fcfeff9 | Blue Swirl | BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE); |
727 | 209cd7ab | Anthony PERARD | break;
|
728 | 62d23efa | aliguori | } |
729 | 62d23efa | aliguori | case BLKIF_PROTOCOL_X86_64:
|
730 | 62d23efa | aliguori | { |
731 | 209cd7ab | Anthony PERARD | blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; |
732 | 6fcfeff9 | Blue Swirl | |
733 | 6fcfeff9 | Blue Swirl | BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE); |
734 | 209cd7ab | Anthony PERARD | break;
|
735 | 62d23efa | aliguori | } |
736 | 62d23efa | aliguori | } |
737 | 62d23efa | aliguori | |
738 | 62d23efa | aliguori | xen_be_bind_evtchn(&blkdev->xendev); |
739 | 62d23efa | aliguori | |
740 | 62d23efa | aliguori | xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, " |
741 | 209cd7ab | Anthony PERARD | "remote port %d, local port %d\n",
|
742 | 209cd7ab | Anthony PERARD | blkdev->xendev.protocol, blkdev->ring_ref, |
743 | 209cd7ab | Anthony PERARD | blkdev->xendev.remote_port, blkdev->xendev.local_port); |
744 | 62d23efa | aliguori | return 0; |
745 | 62d23efa | aliguori | } |
746 | 62d23efa | aliguori | |
747 | 62d23efa | aliguori | static void blk_disconnect(struct XenDevice *xendev) |
748 | 62d23efa | aliguori | { |
749 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
750 | 62d23efa | aliguori | |
751 | 62d23efa | aliguori | if (blkdev->bs) {
|
752 | 751c6a17 | Gerd Hoffmann | if (!blkdev->dinfo) {
|
753 | 62d23efa | aliguori | /* close/delete only if we created it ourself */
|
754 | 62d23efa | aliguori | bdrv_close(blkdev->bs); |
755 | 7429f2e1 | Stefano Stabellini | bdrv_detach_dev(blkdev->bs, blkdev); |
756 | 62d23efa | aliguori | bdrv_delete(blkdev->bs); |
757 | 62d23efa | aliguori | } |
758 | 209cd7ab | Anthony PERARD | blkdev->bs = NULL;
|
759 | 62d23efa | aliguori | } |
760 | 62d23efa | aliguori | xen_be_unbind_evtchn(&blkdev->xendev); |
761 | 62d23efa | aliguori | |
762 | 62d23efa | aliguori | if (blkdev->sring) {
|
763 | 209cd7ab | Anthony PERARD | xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
|
764 | 209cd7ab | Anthony PERARD | blkdev->cnt_map--; |
765 | 209cd7ab | Anthony PERARD | blkdev->sring = NULL;
|
766 | 62d23efa | aliguori | } |
767 | 62d23efa | aliguori | } |
768 | 62d23efa | aliguori | |
769 | 62d23efa | aliguori | static int blk_free(struct XenDevice *xendev) |
770 | 62d23efa | aliguori | { |
771 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
772 | 62d23efa | aliguori | struct ioreq *ioreq;
|
773 | 62d23efa | aliguori | |
774 | 77ba8fef | Stefano Stabellini | if (blkdev->bs || blkdev->sring) {
|
775 | 77ba8fef | Stefano Stabellini | blk_disconnect(xendev); |
776 | 77ba8fef | Stefano Stabellini | } |
777 | 77ba8fef | Stefano Stabellini | |
778 | 72cf2d4f | Blue Swirl | while (!QLIST_EMPTY(&blkdev->freelist)) {
|
779 | 209cd7ab | Anthony PERARD | ioreq = QLIST_FIRST(&blkdev->freelist); |
780 | 72cf2d4f | Blue Swirl | QLIST_REMOVE(ioreq, list); |
781 | 62d23efa | aliguori | qemu_iovec_destroy(&ioreq->v); |
782 | 7267c094 | Anthony Liguori | g_free(ioreq); |
783 | 62d23efa | aliguori | } |
784 | 62d23efa | aliguori | |
785 | 7267c094 | Anthony Liguori | g_free(blkdev->params); |
786 | 7267c094 | Anthony Liguori | g_free(blkdev->mode); |
787 | 7267c094 | Anthony Liguori | g_free(blkdev->type); |
788 | 7267c094 | Anthony Liguori | g_free(blkdev->dev); |
789 | 7267c094 | Anthony Liguori | g_free(blkdev->devtype); |
790 | 62d23efa | aliguori | qemu_bh_delete(blkdev->bh); |
791 | 62d23efa | aliguori | return 0; |
792 | 62d23efa | aliguori | } |
793 | 62d23efa | aliguori | |
794 | 62d23efa | aliguori | static void blk_event(struct XenDevice *xendev) |
795 | 62d23efa | aliguori | { |
796 | 62d23efa | aliguori | struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); |
797 | 62d23efa | aliguori | |
798 | 62d23efa | aliguori | qemu_bh_schedule(blkdev->bh); |
799 | 62d23efa | aliguori | } |
800 | 62d23efa | aliguori | |
801 | 62d23efa | aliguori | struct XenDevOps xen_blkdev_ops = {
|
802 | 62d23efa | aliguori | .size = sizeof(struct XenBlkDev), |
803 | 62d23efa | aliguori | .flags = DEVOPS_FLAG_NEED_GNTDEV, |
804 | 62d23efa | aliguori | .alloc = blk_alloc, |
805 | 62d23efa | aliguori | .init = blk_init, |
806 | 384087b2 | John Haxby | .initialise = blk_connect, |
807 | 62d23efa | aliguori | .disconnect = blk_disconnect, |
808 | 62d23efa | aliguori | .event = blk_event, |
809 | 62d23efa | aliguori | .free = blk_free, |
810 | 62d23efa | aliguori | }; |