root / block / win32-aio.c @ f53f81e0
History | View | Annotate | Download (5.7 kB)
1 | a2736526 | Paolo Bonzini | /*
|
---|---|---|---|
2 | a2736526 | Paolo Bonzini | * Block driver for RAW files (win32)
|
3 | a2736526 | Paolo Bonzini | *
|
4 | a2736526 | Paolo Bonzini | * Copyright (c) 2006 Fabrice Bellard
|
5 | a2736526 | Paolo Bonzini | *
|
6 | a2736526 | Paolo Bonzini | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | a2736526 | Paolo Bonzini | * of this software and associated documentation files (the "Software"), to deal
|
8 | a2736526 | Paolo Bonzini | * in the Software without restriction, including without limitation the rights
|
9 | a2736526 | Paolo Bonzini | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | a2736526 | Paolo Bonzini | * copies of the Software, and to permit persons to whom the Software is
|
11 | a2736526 | Paolo Bonzini | * furnished to do so, subject to the following conditions:
|
12 | a2736526 | Paolo Bonzini | *
|
13 | a2736526 | Paolo Bonzini | * The above copyright notice and this permission notice shall be included in
|
14 | a2736526 | Paolo Bonzini | * all copies or substantial portions of the Software.
|
15 | a2736526 | Paolo Bonzini | *
|
16 | a2736526 | Paolo Bonzini | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | a2736526 | Paolo Bonzini | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | a2736526 | Paolo Bonzini | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | a2736526 | Paolo Bonzini | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | a2736526 | Paolo Bonzini | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | a2736526 | Paolo Bonzini | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | a2736526 | Paolo Bonzini | * THE SOFTWARE.
|
23 | a2736526 | Paolo Bonzini | */
|
24 | a2736526 | Paolo Bonzini | #include "qemu-common.h" |
25 | 1de7afc9 | Paolo Bonzini | #include "qemu/timer.h" |
26 | 737e150e | Paolo Bonzini | #include "block/block_int.h" |
27 | 1de7afc9 | Paolo Bonzini | #include "qemu/module.h" |
28 | 737e150e | Paolo Bonzini | #include "block/aio.h" |
29 | a2736526 | Paolo Bonzini | #include "raw-aio.h" |
30 | 1de7afc9 | Paolo Bonzini | #include "qemu/event_notifier.h" |
31 | 3249dbe6 | Michael Tokarev | #include "qemu/iov.h" |
32 | a2736526 | Paolo Bonzini | #include <windows.h> |
33 | a2736526 | Paolo Bonzini | #include <winioctl.h> |
34 | a2736526 | Paolo Bonzini | |
35 | a2736526 | Paolo Bonzini | #define FTYPE_FILE 0 |
36 | a2736526 | Paolo Bonzini | #define FTYPE_CD 1 |
37 | a2736526 | Paolo Bonzini | #define FTYPE_HARDDISK 2 |
38 | a2736526 | Paolo Bonzini | |
39 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOState {
|
40 | a2736526 | Paolo Bonzini | HANDLE hIOCP; |
41 | a2736526 | Paolo Bonzini | EventNotifier e; |
42 | a2736526 | Paolo Bonzini | int count;
|
43 | a2736526 | Paolo Bonzini | }; |
44 | a2736526 | Paolo Bonzini | |
45 | a2736526 | Paolo Bonzini | typedef struct QEMUWin32AIOCB { |
46 | a2736526 | Paolo Bonzini | BlockDriverAIOCB common; |
47 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOState *ctx;
|
48 | a2736526 | Paolo Bonzini | int nbytes;
|
49 | a2736526 | Paolo Bonzini | OVERLAPPED ov; |
50 | a2736526 | Paolo Bonzini | QEMUIOVector *qiov; |
51 | a2736526 | Paolo Bonzini | void *buf;
|
52 | a2736526 | Paolo Bonzini | bool is_read;
|
53 | a2736526 | Paolo Bonzini | bool is_linear;
|
54 | a2736526 | Paolo Bonzini | } QEMUWin32AIOCB; |
55 | a2736526 | Paolo Bonzini | |
56 | a2736526 | Paolo Bonzini | /*
|
57 | a2736526 | Paolo Bonzini | * Completes an AIO request (calls the callback and frees the ACB).
|
58 | a2736526 | Paolo Bonzini | */
|
59 | a2736526 | Paolo Bonzini | static void win32_aio_process_completion(QEMUWin32AIOState *s, |
60 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb, DWORD count) |
61 | a2736526 | Paolo Bonzini | { |
62 | a2736526 | Paolo Bonzini | int ret;
|
63 | a2736526 | Paolo Bonzini | s->count--; |
64 | a2736526 | Paolo Bonzini | |
65 | a2736526 | Paolo Bonzini | if (waiocb->ov.Internal != 0) { |
66 | a2736526 | Paolo Bonzini | ret = -EIO; |
67 | a2736526 | Paolo Bonzini | } else {
|
68 | a2736526 | Paolo Bonzini | ret = 0;
|
69 | a2736526 | Paolo Bonzini | if (count < waiocb->nbytes) {
|
70 | a2736526 | Paolo Bonzini | /* Short reads mean EOF, pad with zeros. */
|
71 | a2736526 | Paolo Bonzini | if (waiocb->is_read) {
|
72 | a2736526 | Paolo Bonzini | qemu_iovec_memset(waiocb->qiov, count, 0,
|
73 | a2736526 | Paolo Bonzini | waiocb->qiov->size - count); |
74 | a2736526 | Paolo Bonzini | } else {
|
75 | a2736526 | Paolo Bonzini | ret = -EINVAL; |
76 | a2736526 | Paolo Bonzini | } |
77 | a2736526 | Paolo Bonzini | } |
78 | a2736526 | Paolo Bonzini | } |
79 | a2736526 | Paolo Bonzini | |
80 | a2736526 | Paolo Bonzini | if (!waiocb->is_linear) {
|
81 | a2736526 | Paolo Bonzini | if (ret == 0 && waiocb->is_read) { |
82 | a2736526 | Paolo Bonzini | QEMUIOVector *qiov = waiocb->qiov; |
83 | 3249dbe6 | Michael Tokarev | iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
|
84 | a2736526 | Paolo Bonzini | } |
85 | e8bccad5 | Kevin Wolf | qemu_vfree(waiocb->buf); |
86 | a2736526 | Paolo Bonzini | } |
87 | a2736526 | Paolo Bonzini | |
88 | a2736526 | Paolo Bonzini | |
89 | a2736526 | Paolo Bonzini | waiocb->common.cb(waiocb->common.opaque, ret); |
90 | a2736526 | Paolo Bonzini | qemu_aio_release(waiocb); |
91 | a2736526 | Paolo Bonzini | } |
92 | a2736526 | Paolo Bonzini | |
93 | a2736526 | Paolo Bonzini | static void win32_aio_completion_cb(EventNotifier *e) |
94 | a2736526 | Paolo Bonzini | { |
95 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e); |
96 | a2736526 | Paolo Bonzini | DWORD count; |
97 | a2736526 | Paolo Bonzini | ULONG_PTR key; |
98 | a2736526 | Paolo Bonzini | OVERLAPPED *ov; |
99 | a2736526 | Paolo Bonzini | |
100 | a2736526 | Paolo Bonzini | event_notifier_test_and_clear(&s->e); |
101 | a2736526 | Paolo Bonzini | while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) { |
102 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov); |
103 | a2736526 | Paolo Bonzini | |
104 | a2736526 | Paolo Bonzini | win32_aio_process_completion(s, waiocb, count); |
105 | a2736526 | Paolo Bonzini | } |
106 | a2736526 | Paolo Bonzini | } |
107 | a2736526 | Paolo Bonzini | |
108 | a2736526 | Paolo Bonzini | static void win32_aio_cancel(BlockDriverAIOCB *blockacb) |
109 | a2736526 | Paolo Bonzini | { |
110 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb; |
111 | a2736526 | Paolo Bonzini | |
112 | a2736526 | Paolo Bonzini | /*
|
113 | a2736526 | Paolo Bonzini | * CancelIoEx is only supported in Vista and newer. For now, just
|
114 | a2736526 | Paolo Bonzini | * wait for completion.
|
115 | a2736526 | Paolo Bonzini | */
|
116 | a2736526 | Paolo Bonzini | while (!HasOverlappedIoCompleted(&waiocb->ov)) {
|
117 | a2736526 | Paolo Bonzini | qemu_aio_wait(); |
118 | a2736526 | Paolo Bonzini | } |
119 | a2736526 | Paolo Bonzini | } |
120 | a2736526 | Paolo Bonzini | |
121 | d7331bed | Stefan Hajnoczi | static const AIOCBInfo win32_aiocb_info = { |
122 | a2736526 | Paolo Bonzini | .aiocb_size = sizeof(QEMUWin32AIOCB),
|
123 | a2736526 | Paolo Bonzini | .cancel = win32_aio_cancel, |
124 | a2736526 | Paolo Bonzini | }; |
125 | a2736526 | Paolo Bonzini | |
126 | a2736526 | Paolo Bonzini | BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, |
127 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *aio, HANDLE hfile, |
128 | a2736526 | Paolo Bonzini | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
129 | a2736526 | Paolo Bonzini | BlockDriverCompletionFunc *cb, void *opaque, int type) |
130 | a2736526 | Paolo Bonzini | { |
131 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOCB *waiocb;
|
132 | a2736526 | Paolo Bonzini | uint64_t offset = sector_num * 512;
|
133 | a2736526 | Paolo Bonzini | DWORD rc; |
134 | a2736526 | Paolo Bonzini | |
135 | d7331bed | Stefan Hajnoczi | waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque); |
136 | a2736526 | Paolo Bonzini | waiocb->nbytes = nb_sectors * 512;
|
137 | a2736526 | Paolo Bonzini | waiocb->qiov = qiov; |
138 | a2736526 | Paolo Bonzini | waiocb->is_read = (type == QEMU_AIO_READ); |
139 | a2736526 | Paolo Bonzini | |
140 | a2736526 | Paolo Bonzini | if (qiov->niov > 1) { |
141 | a2736526 | Paolo Bonzini | waiocb->buf = qemu_blockalign(bs, qiov->size); |
142 | a2736526 | Paolo Bonzini | if (type & QEMU_AIO_WRITE) {
|
143 | 3249dbe6 | Michael Tokarev | iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
|
144 | a2736526 | Paolo Bonzini | } |
145 | a2736526 | Paolo Bonzini | waiocb->is_linear = false;
|
146 | a2736526 | Paolo Bonzini | } else {
|
147 | a2736526 | Paolo Bonzini | waiocb->buf = qiov->iov[0].iov_base;
|
148 | a2736526 | Paolo Bonzini | waiocb->is_linear = true;
|
149 | a2736526 | Paolo Bonzini | } |
150 | a2736526 | Paolo Bonzini | |
151 | cee40d2d | Stefan Weil | memset(&waiocb->ov, 0, sizeof(waiocb->ov)); |
152 | cee40d2d | Stefan Weil | waiocb->ov.Offset = (DWORD)offset; |
153 | cee40d2d | Stefan Weil | waiocb->ov.OffsetHigh = (DWORD)(offset >> 32);
|
154 | cee40d2d | Stefan Weil | waiocb->ov.hEvent = event_notifier_get_handle(&aio->e); |
155 | cee40d2d | Stefan Weil | |
156 | a2736526 | Paolo Bonzini | aio->count++; |
157 | a2736526 | Paolo Bonzini | |
158 | a2736526 | Paolo Bonzini | if (type & QEMU_AIO_READ) {
|
159 | a2736526 | Paolo Bonzini | rc = ReadFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
160 | a2736526 | Paolo Bonzini | } else {
|
161 | a2736526 | Paolo Bonzini | rc = WriteFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
162 | a2736526 | Paolo Bonzini | } |
163 | a2736526 | Paolo Bonzini | if(rc == 0 && GetLastError() != ERROR_IO_PENDING) { |
164 | a2736526 | Paolo Bonzini | goto out_dec_count;
|
165 | a2736526 | Paolo Bonzini | } |
166 | a2736526 | Paolo Bonzini | return &waiocb->common;
|
167 | a2736526 | Paolo Bonzini | |
168 | a2736526 | Paolo Bonzini | out_dec_count:
|
169 | a2736526 | Paolo Bonzini | aio->count--; |
170 | a2736526 | Paolo Bonzini | qemu_aio_release(waiocb); |
171 | a2736526 | Paolo Bonzini | return NULL; |
172 | a2736526 | Paolo Bonzini | } |
173 | a2736526 | Paolo Bonzini | |
174 | a2736526 | Paolo Bonzini | int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
175 | a2736526 | Paolo Bonzini | { |
176 | a2736526 | Paolo Bonzini | if (CreateIoCompletionPort(hfile, aio->hIOCP, (ULONG_PTR) 0, 0) == NULL) { |
177 | a2736526 | Paolo Bonzini | return -EINVAL;
|
178 | a2736526 | Paolo Bonzini | } else {
|
179 | a2736526 | Paolo Bonzini | return 0; |
180 | a2736526 | Paolo Bonzini | } |
181 | a2736526 | Paolo Bonzini | } |
182 | a2736526 | Paolo Bonzini | |
183 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *win32_aio_init(void)
|
184 | a2736526 | Paolo Bonzini | { |
185 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *s; |
186 | a2736526 | Paolo Bonzini | |
187 | a2736526 | Paolo Bonzini | s = g_malloc0(sizeof(*s));
|
188 | a2736526 | Paolo Bonzini | if (event_notifier_init(&s->e, false) < 0) { |
189 | a2736526 | Paolo Bonzini | goto out_free_state;
|
190 | a2736526 | Paolo Bonzini | } |
191 | a2736526 | Paolo Bonzini | |
192 | a2736526 | Paolo Bonzini | s->hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); |
193 | a2736526 | Paolo Bonzini | if (s->hIOCP == NULL) { |
194 | a2736526 | Paolo Bonzini | goto out_close_efd;
|
195 | a2736526 | Paolo Bonzini | } |
196 | a2736526 | Paolo Bonzini | |
197 | b10577df | Stefan Hajnoczi | qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb); |
198 | a2736526 | Paolo Bonzini | |
199 | a2736526 | Paolo Bonzini | return s;
|
200 | a2736526 | Paolo Bonzini | |
201 | a2736526 | Paolo Bonzini | out_close_efd:
|
202 | a2736526 | Paolo Bonzini | event_notifier_cleanup(&s->e); |
203 | a2736526 | Paolo Bonzini | out_free_state:
|
204 | a2736526 | Paolo Bonzini | g_free(s); |
205 | a2736526 | Paolo Bonzini | return NULL; |
206 | a2736526 | Paolo Bonzini | } |