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"); | ... | ... |