Revision f141eafe posix-aio-compat.c
b/posix-aio-compat.c | ||
---|---|---|
20 | 20 |
#include <stdlib.h> |
21 | 21 |
#include <stdio.h> |
22 | 22 |
#include "osdep.h" |
23 |
#include "qemu-common.h" |
|
23 | 24 |
|
24 | 25 |
#include "posix-aio-compat.h" |
25 | 26 |
|
... | ... | |
76 | 77 |
if (ret) die2(ret, "pthread_create"); |
77 | 78 |
} |
78 | 79 |
|
79 |
static size_t handle_aiocb_readwrite(struct qemu_paiocb *aiocb) |
|
80 |
static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb) |
|
81 |
{ |
|
82 |
int ret; |
|
83 |
|
|
84 |
ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf); |
|
85 |
if (ret == -1) |
|
86 |
return -errno; |
|
87 |
return ret; |
|
88 |
} |
|
89 |
|
|
90 |
/* |
|
91 |
* Check if we need to copy the data in the aiocb into a new |
|
92 |
* properly aligned buffer. |
|
93 |
*/ |
|
94 |
static int aiocb_needs_copy(struct qemu_paiocb *aiocb) |
|
95 |
{ |
|
96 |
if (aiocb->aio_flags & QEMU_AIO_SECTOR_ALIGNED) { |
|
97 |
int i; |
|
98 |
|
|
99 |
for (i = 0; i < aiocb->aio_niov; i++) |
|
100 |
if ((uintptr_t) aiocb->aio_iov[i].iov_base % 512) |
|
101 |
return 1; |
|
102 |
} |
|
103 |
|
|
104 |
return 0; |
|
105 |
} |
|
106 |
|
|
107 |
static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf) |
|
80 | 108 |
{ |
81 | 109 |
size_t offset = 0; |
82 |
ssize_t len;
|
|
110 |
size_t len; |
|
83 | 111 |
|
84 | 112 |
while (offset < aiocb->aio_nbytes) { |
85 |
if (aiocb->aio_type == QEMU_PAIO_WRITE) |
|
86 |
len = pwrite(aiocb->aio_fildes, |
|
87 |
(const char *)aiocb->aio_buf + offset, |
|
113 |
if (aiocb->aio_type == QEMU_PAIO_WRITE) |
|
114 |
len = pwrite(aiocb->aio_fildes, |
|
115 |
(const char *)buf + offset, |
|
116 |
aiocb->aio_nbytes - offset, |
|
117 |
aiocb->aio_offset + offset); |
|
118 |
else |
|
119 |
len = pread(aiocb->aio_fildes, |
|
120 |
buf + offset, |
|
88 | 121 |
aiocb->aio_nbytes - offset, |
89 | 122 |
aiocb->aio_offset + offset); |
90 |
else |
|
91 |
len = pread(aiocb->aio_fildes, |
|
92 |
(char *)aiocb->aio_buf + offset, |
|
93 |
aiocb->aio_nbytes - offset, |
|
94 |
aiocb->aio_offset + offset); |
|
95 |
|
|
96 |
if (len == -1 && errno == EINTR) |
|
97 |
continue; |
|
98 |
else if (len == -1) { |
|
99 |
offset = -errno; |
|
100 |
break; |
|
101 |
} else if (len == 0) |
|
102 |
break; |
|
103 | 123 |
|
104 |
offset += len; |
|
124 |
if (len == -1 && errno == EINTR) |
|
125 |
continue; |
|
126 |
else if (len == -1) { |
|
127 |
offset = -errno; |
|
128 |
break; |
|
129 |
} else if (len == 0) |
|
130 |
break; |
|
131 |
|
|
132 |
offset += len; |
|
105 | 133 |
} |
106 | 134 |
|
107 | 135 |
return offset; |
108 | 136 |
} |
109 | 137 |
|
110 |
static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
|
|
138 |
static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
|
|
111 | 139 |
{ |
112 |
int ret; |
|
140 |
size_t nbytes; |
|
141 |
char *buf; |
|
142 |
|
|
143 |
if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) { |
|
144 |
/* |
|
145 |
* If there is just a single buffer, and it is properly aligned |
|
146 |
* we can just use plain pread/pwrite without any problems. |
|
147 |
*/ |
|
148 |
return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base); |
|
149 |
} |
|
113 | 150 |
|
114 |
ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_buf); |
|
115 |
if (ret == -1) |
|
116 |
return -errno; |
|
117 |
return ret; |
|
151 |
/* |
|
152 |
* Ok, we have to do it the hard way, copy all segments into |
|
153 |
* a single aligned buffer. |
|
154 |
*/ |
|
155 |
buf = qemu_memalign(512, aiocb->aio_nbytes); |
|
156 |
if (aiocb->aio_type == QEMU_PAIO_WRITE) { |
|
157 |
char *p = buf; |
|
158 |
int i; |
|
159 |
|
|
160 |
for (i = 0; i < aiocb->aio_niov; ++i) { |
|
161 |
memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len); |
|
162 |
p += aiocb->aio_iov[i].iov_len; |
|
163 |
} |
|
164 |
} |
|
165 |
|
|
166 |
nbytes = handle_aiocb_rw_linear(aiocb, buf); |
|
167 |
if (aiocb->aio_type != QEMU_PAIO_WRITE) { |
|
168 |
char *p = buf; |
|
169 |
size_t count = aiocb->aio_nbytes, copy; |
|
170 |
int i; |
|
171 |
|
|
172 |
for (i = 0; i < aiocb->aio_niov && count; ++i) { |
|
173 |
copy = count; |
|
174 |
if (copy > aiocb->aio_iov[i].iov_len) |
|
175 |
copy = aiocb->aio_iov[i].iov_len; |
|
176 |
memcpy(aiocb->aio_iov[i].iov_base, p, copy); |
|
177 |
p += copy; |
|
178 |
count -= copy; |
|
179 |
} |
|
180 |
} |
|
181 |
qemu_vfree(buf); |
|
182 |
|
|
183 |
return nbytes; |
|
118 | 184 |
} |
119 | 185 |
|
120 | 186 |
static void *aio_thread(void *unused) |
... | ... | |
157 | 223 |
switch (aiocb->aio_type) { |
158 | 224 |
case QEMU_PAIO_READ: |
159 | 225 |
case QEMU_PAIO_WRITE: |
160 |
ret = handle_aiocb_readwrite(aiocb);
|
|
226 |
ret = handle_aiocb_rw(aiocb);
|
|
161 | 227 |
break; |
162 | 228 |
case QEMU_PAIO_IOCTL: |
163 | 229 |
ret = handle_aiocb_ioctl(aiocb); |
Also available in: Unified diff