Commit adcbebaa40933e15d18fa629fa8528e5c8388695
1 parent
dd53ded3
Align file accesses with cache=off (Kevin Wolf, Laurent Vivier)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4367 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
113 additions
and
6 deletions
block-raw-posix.c
... | ... | @@ -77,10 +77,10 @@ |
77 | 77 | typedef struct BDRVRawState { |
78 | 78 | int fd; |
79 | 79 | int type; |
80 | + int open_flags; | |
80 | 81 | unsigned int lseek_err_cnt; |
81 | 82 | #if defined(__linux__) |
82 | 83 | /* linux floppy specific */ |
83 | - int fd_open_flags; | |
84 | 84 | int64_t fd_open_time; |
85 | 85 | int64_t fd_error_time; |
86 | 86 | int fd_got_error; |
... | ... | @@ -111,6 +111,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
111 | 111 | open_flags |= O_DIRECT; |
112 | 112 | #endif |
113 | 113 | |
114 | + s->open_flags = open_flags; | |
114 | 115 | s->type = FTYPE_FILE; |
115 | 116 | |
116 | 117 | fd = open(filename, open_flags, 0644); |
... | ... | @@ -141,7 +142,14 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
141 | 142 | #endif |
142 | 143 | */ |
143 | 144 | |
144 | -static int raw_pread(BlockDriverState *bs, int64_t offset, | |
145 | +/* | |
146 | + * offset and count are in bytes, but must be multiples of 512 for files | |
147 | + * opened with O_DIRECT. buf must be aligned to 512 bytes then. | |
148 | + * | |
149 | + * This function may be called without alignment if the caller ensures | |
150 | + * that O_DIRECT is not in effect. | |
151 | + */ | |
152 | +static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, | |
145 | 153 | uint8_t *buf, int count) |
146 | 154 | { |
147 | 155 | BDRVRawState *s = bs->opaque; |
... | ... | @@ -194,7 +202,14 @@ label__raw_read__success: |
194 | 202 | return ret; |
195 | 203 | } |
196 | 204 | |
197 | -static int raw_pwrite(BlockDriverState *bs, int64_t offset, | |
205 | +/* | |
206 | + * offset and count are in bytes, but must be multiples of 512 for files | |
207 | + * opened with O_DIRECT. buf must be aligned to 512 bytes then. | |
208 | + * | |
209 | + * This function may be called without alignment if the caller ensures | |
210 | + * that O_DIRECT is not in effect. | |
211 | + */ | |
212 | +static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, | |
198 | 213 | const uint8_t *buf, int count) |
199 | 214 | { |
200 | 215 | BDRVRawState *s = bs->opaque; |
... | ... | @@ -230,6 +245,67 @@ label__raw_write__success: |
230 | 245 | return ret; |
231 | 246 | } |
232 | 247 | |
248 | + | |
249 | +#ifdef O_DIRECT | |
250 | +/* | |
251 | + * offset and count are in bytes and possibly not aligned. For files opened | |
252 | + * with O_DIRECT, necessary alignments are ensured before calling | |
253 | + * raw_pread_aligned to do the actual read. | |
254 | + */ | |
255 | +static int raw_pread(BlockDriverState *bs, int64_t offset, | |
256 | + uint8_t *buf, int count) | |
257 | +{ | |
258 | + BDRVRawState *s = bs->opaque; | |
259 | + | |
260 | + if (unlikely((s->open_flags & O_DIRECT) && | |
261 | + (offset % 512 || count % 512 || (uintptr_t) buf % 512))) { | |
262 | + | |
263 | + int ret; | |
264 | + | |
265 | + // Temporarily disable O_DIRECT for unaligned access | |
266 | + fcntl(s->fd, F_SETFL, s->open_flags & ~O_DIRECT); | |
267 | + ret = raw_pread_aligned(bs, offset, buf, count); | |
268 | + fcntl(s->fd, F_SETFL, s->open_flags); | |
269 | + | |
270 | + return ret; | |
271 | + | |
272 | + } else { | |
273 | + return raw_pread_aligned(bs, offset, buf, count); | |
274 | + } | |
275 | +} | |
276 | + | |
277 | +/* | |
278 | + * offset and count are in bytes and possibly not aligned. For files opened | |
279 | + * with O_DIRECT, necessary alignments are ensured before calling | |
280 | + * raw_pwrite_aligned to do the actual write. | |
281 | + */ | |
282 | +static int raw_pwrite(BlockDriverState *bs, int64_t offset, | |
283 | + const uint8_t *buf, int count) | |
284 | +{ | |
285 | + BDRVRawState *s = bs->opaque; | |
286 | + | |
287 | + if (unlikely((s->open_flags & O_DIRECT) && | |
288 | + (offset % 512 || count % 512 || (uintptr_t) buf % 512))) { | |
289 | + | |
290 | + int ret; | |
291 | + | |
292 | + // Temporarily disable O_DIRECT for unaligned access | |
293 | + fcntl(s->fd, F_SETFL, s->open_flags & ~O_DIRECT); | |
294 | + ret = raw_pwrite_aligned(bs, offset, buf, count); | |
295 | + fcntl(s->fd, F_SETFL, s->open_flags); | |
296 | + | |
297 | + return ret; | |
298 | + } else { | |
299 | + return raw_pwrite_aligned(bs, offset, buf, count); | |
300 | + } | |
301 | +} | |
302 | + | |
303 | +#else | |
304 | +#define raw_pread raw_pread_aligned | |
305 | +#define raw_pwrite raw_pwrite_aligned | |
306 | +#endif | |
307 | + | |
308 | + | |
233 | 309 | /***********************************************************/ |
234 | 310 | /* Unix AIO using POSIX AIO */ |
235 | 311 | |
... | ... | @@ -402,10 +478,26 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, |
402 | 478 | BlockDriverCompletionFunc *cb, void *opaque) |
403 | 479 | { |
404 | 480 | RawAIOCB *acb; |
481 | + BDRVRawState *s = bs->opaque; | |
482 | + | |
483 | + /* | |
484 | + * If O_DIRECT is used and the buffer is not aligned fall back | |
485 | + * to synchronous IO. | |
486 | + */ | |
487 | + if (unlikely((s->open_flags & O_DIRECT) && ((uintptr_t) buf % 512))) { | |
488 | + int ret; | |
489 | + | |
490 | + acb = qemu_aio_get(bs, cb, opaque); | |
491 | + ret = raw_pread(bs, 512 * sector_num, buf, 512 * nb_sectors); | |
492 | + acb->common.cb(acb->common.opaque, ret); | |
493 | + qemu_aio_release(acb); | |
494 | + return &acb->common; | |
495 | + } | |
405 | 496 | |
406 | 497 | acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); |
407 | 498 | if (!acb) |
408 | 499 | return NULL; |
500 | + | |
409 | 501 | if (aio_read(&acb->aiocb) < 0) { |
410 | 502 | qemu_aio_release(acb); |
411 | 503 | return NULL; |
... | ... | @@ -418,6 +510,21 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, |
418 | 510 | BlockDriverCompletionFunc *cb, void *opaque) |
419 | 511 | { |
420 | 512 | RawAIOCB *acb; |
513 | + BDRVRawState *s = bs->opaque; | |
514 | + | |
515 | + /* | |
516 | + * If O_DIRECT is used and the buffer is not aligned fall back | |
517 | + * to synchronous IO. | |
518 | + */ | |
519 | + if (unlikely((s->open_flags & O_DIRECT) && ((uintptr_t) buf % 512))) { | |
520 | + int ret; | |
521 | + | |
522 | + acb = qemu_aio_get(bs, cb, opaque); | |
523 | + ret = raw_pwrite(bs, 512 * sector_num, buf, 512 * nb_sectors); | |
524 | + acb->common.cb(acb->common.opaque, ret); | |
525 | + qemu_aio_release(acb); | |
526 | + return &acb->common; | |
527 | + } | |
421 | 528 | |
422 | 529 | acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); |
423 | 530 | if (!acb) |
... | ... | @@ -679,7 +786,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) |
679 | 786 | s->type = FTYPE_CD; |
680 | 787 | } else if (strstart(filename, "/dev/fd", NULL)) { |
681 | 788 | s->type = FTYPE_FD; |
682 | - s->fd_open_flags = open_flags; | |
789 | + s->open_flags = open_flags; | |
683 | 790 | /* open will not fail even if no floppy is inserted */ |
684 | 791 | open_flags |= O_NONBLOCK; |
685 | 792 | } else if (strstart(filename, "/dev/sg", NULL)) { |
... | ... | @@ -734,7 +841,7 @@ static int fd_open(BlockDriverState *bs) |
734 | 841 | #endif |
735 | 842 | return -EIO; |
736 | 843 | } |
737 | - s->fd = open(bs->filename, s->fd_open_flags); | |
844 | + s->fd = open(bs->filename, s->open_flags); | |
738 | 845 | if (s->fd < 0) { |
739 | 846 | s->fd_error_time = qemu_get_clock(rt_clock); |
740 | 847 | s->fd_got_error = 1; |
... | ... | @@ -831,7 +938,7 @@ static int raw_eject(BlockDriverState *bs, int eject_flag) |
831 | 938 | close(s->fd); |
832 | 939 | s->fd = -1; |
833 | 940 | } |
834 | - fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); | |
941 | + fd = open(bs->filename, s->open_flags | O_NONBLOCK); | |
835 | 942 | if (fd >= 0) { |
836 | 943 | if (ioctl(fd, FDEJECT, 0) < 0) |
837 | 944 | perror("FDEJECT"); | ... | ... |