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