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