root / block / win32-aio.c @ dc7588c1
History | View | Annotate | Download (5.9 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 | a2736526 | Paolo Bonzini | #include "qemu-common.h" |
29 | 737e150e | Paolo Bonzini | #include "block/aio.h" |
30 | a2736526 | Paolo Bonzini | #include "raw-aio.h" |
31 | 1de7afc9 | Paolo Bonzini | #include "qemu/event_notifier.h" |
32 | 3249dbe6 | Michael Tokarev | #include "qemu/iov.h" |
33 | a2736526 | Paolo Bonzini | #include <windows.h> |
34 | a2736526 | Paolo Bonzini | #include <winioctl.h> |
35 | a2736526 | Paolo Bonzini | |
36 | a2736526 | Paolo Bonzini | #define FTYPE_FILE 0 |
37 | a2736526 | Paolo Bonzini | #define FTYPE_CD 1 |
38 | a2736526 | Paolo Bonzini | #define FTYPE_HARDDISK 2 |
39 | a2736526 | Paolo Bonzini | |
40 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOState {
|
41 | a2736526 | Paolo Bonzini | HANDLE hIOCP; |
42 | a2736526 | Paolo Bonzini | EventNotifier e; |
43 | a2736526 | Paolo Bonzini | int count;
|
44 | a2736526 | Paolo Bonzini | }; |
45 | a2736526 | Paolo Bonzini | |
46 | a2736526 | Paolo Bonzini | typedef struct QEMUWin32AIOCB { |
47 | a2736526 | Paolo Bonzini | BlockDriverAIOCB common; |
48 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOState *ctx;
|
49 | a2736526 | Paolo Bonzini | int nbytes;
|
50 | a2736526 | Paolo Bonzini | OVERLAPPED ov; |
51 | a2736526 | Paolo Bonzini | QEMUIOVector *qiov; |
52 | a2736526 | Paolo Bonzini | void *buf;
|
53 | a2736526 | Paolo Bonzini | bool is_read;
|
54 | a2736526 | Paolo Bonzini | bool is_linear;
|
55 | a2736526 | Paolo Bonzini | } QEMUWin32AIOCB; |
56 | a2736526 | Paolo Bonzini | |
57 | a2736526 | Paolo Bonzini | /*
|
58 | a2736526 | Paolo Bonzini | * Completes an AIO request (calls the callback and frees the ACB).
|
59 | a2736526 | Paolo Bonzini | */
|
60 | a2736526 | Paolo Bonzini | static void win32_aio_process_completion(QEMUWin32AIOState *s, |
61 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb, DWORD count) |
62 | a2736526 | Paolo Bonzini | { |
63 | a2736526 | Paolo Bonzini | int ret;
|
64 | a2736526 | Paolo Bonzini | s->count--; |
65 | a2736526 | Paolo Bonzini | |
66 | a2736526 | Paolo Bonzini | if (waiocb->ov.Internal != 0) { |
67 | a2736526 | Paolo Bonzini | ret = -EIO; |
68 | a2736526 | Paolo Bonzini | } else {
|
69 | a2736526 | Paolo Bonzini | ret = 0;
|
70 | a2736526 | Paolo Bonzini | if (count < waiocb->nbytes) {
|
71 | a2736526 | Paolo Bonzini | /* Short reads mean EOF, pad with zeros. */
|
72 | a2736526 | Paolo Bonzini | if (waiocb->is_read) {
|
73 | a2736526 | Paolo Bonzini | qemu_iovec_memset(waiocb->qiov, count, 0,
|
74 | a2736526 | Paolo Bonzini | waiocb->qiov->size - count); |
75 | a2736526 | Paolo Bonzini | } else {
|
76 | a2736526 | Paolo Bonzini | ret = -EINVAL; |
77 | a2736526 | Paolo Bonzini | } |
78 | a2736526 | Paolo Bonzini | } |
79 | a2736526 | Paolo Bonzini | } |
80 | a2736526 | Paolo Bonzini | |
81 | a2736526 | Paolo Bonzini | if (!waiocb->is_linear) {
|
82 | a2736526 | Paolo Bonzini | if (ret == 0 && waiocb->is_read) { |
83 | a2736526 | Paolo Bonzini | QEMUIOVector *qiov = waiocb->qiov; |
84 | 3249dbe6 | Michael Tokarev | iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
|
85 | a2736526 | Paolo Bonzini | } |
86 | e8bccad5 | Kevin Wolf | qemu_vfree(waiocb->buf); |
87 | a2736526 | Paolo Bonzini | } |
88 | a2736526 | Paolo Bonzini | |
89 | a2736526 | Paolo Bonzini | |
90 | a2736526 | Paolo Bonzini | waiocb->common.cb(waiocb->common.opaque, ret); |
91 | a2736526 | Paolo Bonzini | qemu_aio_release(waiocb); |
92 | a2736526 | Paolo Bonzini | } |
93 | a2736526 | Paolo Bonzini | |
94 | a2736526 | Paolo Bonzini | static void win32_aio_completion_cb(EventNotifier *e) |
95 | a2736526 | Paolo Bonzini | { |
96 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e); |
97 | a2736526 | Paolo Bonzini | DWORD count; |
98 | a2736526 | Paolo Bonzini | ULONG_PTR key; |
99 | a2736526 | Paolo Bonzini | OVERLAPPED *ov; |
100 | a2736526 | Paolo Bonzini | |
101 | a2736526 | Paolo Bonzini | event_notifier_test_and_clear(&s->e); |
102 | a2736526 | Paolo Bonzini | while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) { |
103 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov); |
104 | a2736526 | Paolo Bonzini | |
105 | a2736526 | Paolo Bonzini | win32_aio_process_completion(s, waiocb, count); |
106 | a2736526 | Paolo Bonzini | } |
107 | a2736526 | Paolo Bonzini | } |
108 | a2736526 | Paolo Bonzini | |
109 | a2736526 | Paolo Bonzini | static int win32_aio_flush_cb(EventNotifier *e) |
110 | a2736526 | Paolo Bonzini | { |
111 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e); |
112 | a2736526 | Paolo Bonzini | |
113 | a2736526 | Paolo Bonzini | return (s->count > 0) ? 1 : 0; |
114 | a2736526 | Paolo Bonzini | } |
115 | a2736526 | Paolo Bonzini | |
116 | a2736526 | Paolo Bonzini | static void win32_aio_cancel(BlockDriverAIOCB *blockacb) |
117 | a2736526 | Paolo Bonzini | { |
118 | a2736526 | Paolo Bonzini | QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb; |
119 | a2736526 | Paolo Bonzini | |
120 | a2736526 | Paolo Bonzini | /*
|
121 | a2736526 | Paolo Bonzini | * CancelIoEx is only supported in Vista and newer. For now, just
|
122 | a2736526 | Paolo Bonzini | * wait for completion.
|
123 | a2736526 | Paolo Bonzini | */
|
124 | a2736526 | Paolo Bonzini | while (!HasOverlappedIoCompleted(&waiocb->ov)) {
|
125 | a2736526 | Paolo Bonzini | qemu_aio_wait(); |
126 | a2736526 | Paolo Bonzini | } |
127 | a2736526 | Paolo Bonzini | } |
128 | a2736526 | Paolo Bonzini | |
129 | d7331bed | Stefan Hajnoczi | static const AIOCBInfo win32_aiocb_info = { |
130 | a2736526 | Paolo Bonzini | .aiocb_size = sizeof(QEMUWin32AIOCB),
|
131 | a2736526 | Paolo Bonzini | .cancel = win32_aio_cancel, |
132 | a2736526 | Paolo Bonzini | }; |
133 | a2736526 | Paolo Bonzini | |
134 | a2736526 | Paolo Bonzini | BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, |
135 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *aio, HANDLE hfile, |
136 | a2736526 | Paolo Bonzini | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
137 | a2736526 | Paolo Bonzini | BlockDriverCompletionFunc *cb, void *opaque, int type) |
138 | a2736526 | Paolo Bonzini | { |
139 | a2736526 | Paolo Bonzini | struct QEMUWin32AIOCB *waiocb;
|
140 | a2736526 | Paolo Bonzini | uint64_t offset = sector_num * 512;
|
141 | a2736526 | Paolo Bonzini | DWORD rc; |
142 | a2736526 | Paolo Bonzini | |
143 | d7331bed | Stefan Hajnoczi | waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque); |
144 | a2736526 | Paolo Bonzini | waiocb->nbytes = nb_sectors * 512;
|
145 | a2736526 | Paolo Bonzini | waiocb->qiov = qiov; |
146 | a2736526 | Paolo Bonzini | waiocb->is_read = (type == QEMU_AIO_READ); |
147 | a2736526 | Paolo Bonzini | |
148 | a2736526 | Paolo Bonzini | if (qiov->niov > 1) { |
149 | a2736526 | Paolo Bonzini | waiocb->buf = qemu_blockalign(bs, qiov->size); |
150 | a2736526 | Paolo Bonzini | if (type & QEMU_AIO_WRITE) {
|
151 | 3249dbe6 | Michael Tokarev | iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
|
152 | a2736526 | Paolo Bonzini | } |
153 | a2736526 | Paolo Bonzini | waiocb->is_linear = false;
|
154 | a2736526 | Paolo Bonzini | } else {
|
155 | a2736526 | Paolo Bonzini | waiocb->buf = qiov->iov[0].iov_base;
|
156 | a2736526 | Paolo Bonzini | waiocb->is_linear = true;
|
157 | a2736526 | Paolo Bonzini | } |
158 | a2736526 | Paolo Bonzini | |
159 | cee40d2d | Stefan Weil | memset(&waiocb->ov, 0, sizeof(waiocb->ov)); |
160 | cee40d2d | Stefan Weil | waiocb->ov.Offset = (DWORD)offset; |
161 | cee40d2d | Stefan Weil | waiocb->ov.OffsetHigh = (DWORD)(offset >> 32);
|
162 | cee40d2d | Stefan Weil | waiocb->ov.hEvent = event_notifier_get_handle(&aio->e); |
163 | cee40d2d | Stefan Weil | |
164 | a2736526 | Paolo Bonzini | aio->count++; |
165 | a2736526 | Paolo Bonzini | |
166 | a2736526 | Paolo Bonzini | if (type & QEMU_AIO_READ) {
|
167 | a2736526 | Paolo Bonzini | rc = ReadFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
168 | a2736526 | Paolo Bonzini | } else {
|
169 | a2736526 | Paolo Bonzini | rc = WriteFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
170 | a2736526 | Paolo Bonzini | } |
171 | a2736526 | Paolo Bonzini | if(rc == 0 && GetLastError() != ERROR_IO_PENDING) { |
172 | a2736526 | Paolo Bonzini | goto out_dec_count;
|
173 | a2736526 | Paolo Bonzini | } |
174 | a2736526 | Paolo Bonzini | return &waiocb->common;
|
175 | a2736526 | Paolo Bonzini | |
176 | a2736526 | Paolo Bonzini | out_dec_count:
|
177 | a2736526 | Paolo Bonzini | aio->count--; |
178 | a2736526 | Paolo Bonzini | qemu_aio_release(waiocb); |
179 | a2736526 | Paolo Bonzini | return NULL; |
180 | a2736526 | Paolo Bonzini | } |
181 | a2736526 | Paolo Bonzini | |
182 | a2736526 | Paolo Bonzini | int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
183 | a2736526 | Paolo Bonzini | { |
184 | a2736526 | Paolo Bonzini | if (CreateIoCompletionPort(hfile, aio->hIOCP, (ULONG_PTR) 0, 0) == NULL) { |
185 | a2736526 | Paolo Bonzini | return -EINVAL;
|
186 | a2736526 | Paolo Bonzini | } else {
|
187 | a2736526 | Paolo Bonzini | return 0; |
188 | a2736526 | Paolo Bonzini | } |
189 | a2736526 | Paolo Bonzini | } |
190 | a2736526 | Paolo Bonzini | |
191 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *win32_aio_init(void)
|
192 | a2736526 | Paolo Bonzini | { |
193 | a2736526 | Paolo Bonzini | QEMUWin32AIOState *s; |
194 | a2736526 | Paolo Bonzini | |
195 | a2736526 | Paolo Bonzini | s = g_malloc0(sizeof(*s));
|
196 | a2736526 | Paolo Bonzini | if (event_notifier_init(&s->e, false) < 0) { |
197 | a2736526 | Paolo Bonzini | goto out_free_state;
|
198 | a2736526 | Paolo Bonzini | } |
199 | a2736526 | Paolo Bonzini | |
200 | a2736526 | Paolo Bonzini | s->hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); |
201 | a2736526 | Paolo Bonzini | if (s->hIOCP == NULL) { |
202 | a2736526 | Paolo Bonzini | goto out_close_efd;
|
203 | a2736526 | Paolo Bonzini | } |
204 | a2736526 | Paolo Bonzini | |
205 | a2736526 | Paolo Bonzini | qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb, |
206 | a2736526 | Paolo Bonzini | win32_aio_flush_cb); |
207 | a2736526 | Paolo Bonzini | |
208 | a2736526 | Paolo Bonzini | return s;
|
209 | a2736526 | Paolo Bonzini | |
210 | a2736526 | Paolo Bonzini | out_close_efd:
|
211 | a2736526 | Paolo Bonzini | event_notifier_cleanup(&s->e); |
212 | a2736526 | Paolo Bonzini | out_free_state:
|
213 | a2736526 | Paolo Bonzini | g_free(s); |
214 | a2736526 | Paolo Bonzini | return NULL; |
215 | a2736526 | Paolo Bonzini | } |