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,10 +77,10 @@ | ||
| 77 | typedef struct BDRVRawState { | 77 | typedef struct BDRVRawState { |
| 78 | int fd; | 78 | int fd; |
| 79 | int type; | 79 | int type; |
| 80 | + int open_flags; | ||
| 80 | unsigned int lseek_err_cnt; | 81 | unsigned int lseek_err_cnt; |
| 81 | #if defined(__linux__) | 82 | #if defined(__linux__) |
| 82 | /* linux floppy specific */ | 83 | /* linux floppy specific */ |
| 83 | - int fd_open_flags; | ||
| 84 | int64_t fd_open_time; | 84 | int64_t fd_open_time; |
| 85 | int64_t fd_error_time; | 85 | int64_t fd_error_time; |
| 86 | int fd_got_error; | 86 | int fd_got_error; |
| @@ -111,6 +111,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) | @@ -111,6 +111,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) | ||
| 111 | open_flags |= O_DIRECT; | 111 | open_flags |= O_DIRECT; |
| 112 | #endif | 112 | #endif |
| 113 | 113 | ||
| 114 | + s->open_flags = open_flags; | ||
| 114 | s->type = FTYPE_FILE; | 115 | s->type = FTYPE_FILE; |
| 115 | 116 | ||
| 116 | fd = open(filename, open_flags, 0644); | 117 | fd = open(filename, open_flags, 0644); |
| @@ -141,7 +142,14 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) | @@ -141,7 +142,14 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) | ||
| 141 | #endif | 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 | uint8_t *buf, int count) | 153 | uint8_t *buf, int count) |
| 146 | { | 154 | { |
| 147 | BDRVRawState *s = bs->opaque; | 155 | BDRVRawState *s = bs->opaque; |
| @@ -194,7 +202,14 @@ label__raw_read__success: | @@ -194,7 +202,14 @@ label__raw_read__success: | ||
| 194 | return ret; | 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 | const uint8_t *buf, int count) | 213 | const uint8_t *buf, int count) |
| 199 | { | 214 | { |
| 200 | BDRVRawState *s = bs->opaque; | 215 | BDRVRawState *s = bs->opaque; |
| @@ -230,6 +245,67 @@ label__raw_write__success: | @@ -230,6 +245,67 @@ label__raw_write__success: | ||
| 230 | return ret; | 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 | /* Unix AIO using POSIX AIO */ | 310 | /* Unix AIO using POSIX AIO */ |
| 235 | 311 | ||
| @@ -402,10 +478,26 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, | @@ -402,10 +478,26 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, | ||
| 402 | BlockDriverCompletionFunc *cb, void *opaque) | 478 | BlockDriverCompletionFunc *cb, void *opaque) |
| 403 | { | 479 | { |
| 404 | RawAIOCB *acb; | 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 | acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); | 497 | acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); |
| 407 | if (!acb) | 498 | if (!acb) |
| 408 | return NULL; | 499 | return NULL; |
| 500 | + | ||
| 409 | if (aio_read(&acb->aiocb) < 0) { | 501 | if (aio_read(&acb->aiocb) < 0) { |
| 410 | qemu_aio_release(acb); | 502 | qemu_aio_release(acb); |
| 411 | return NULL; | 503 | return NULL; |
| @@ -418,6 +510,21 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, | @@ -418,6 +510,21 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, | ||
| 418 | BlockDriverCompletionFunc *cb, void *opaque) | 510 | BlockDriverCompletionFunc *cb, void *opaque) |
| 419 | { | 511 | { |
| 420 | RawAIOCB *acb; | 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 | acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); | 529 | acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); |
| 423 | if (!acb) | 530 | if (!acb) |
| @@ -679,7 +786,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) | @@ -679,7 +786,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) | ||
| 679 | s->type = FTYPE_CD; | 786 | s->type = FTYPE_CD; |
| 680 | } else if (strstart(filename, "/dev/fd", NULL)) { | 787 | } else if (strstart(filename, "/dev/fd", NULL)) { |
| 681 | s->type = FTYPE_FD; | 788 | s->type = FTYPE_FD; |
| 682 | - s->fd_open_flags = open_flags; | 789 | + s->open_flags = open_flags; |
| 683 | /* open will not fail even if no floppy is inserted */ | 790 | /* open will not fail even if no floppy is inserted */ |
| 684 | open_flags |= O_NONBLOCK; | 791 | open_flags |= O_NONBLOCK; |
| 685 | } else if (strstart(filename, "/dev/sg", NULL)) { | 792 | } else if (strstart(filename, "/dev/sg", NULL)) { |
| @@ -734,7 +841,7 @@ static int fd_open(BlockDriverState *bs) | @@ -734,7 +841,7 @@ static int fd_open(BlockDriverState *bs) | ||
| 734 | #endif | 841 | #endif |
| 735 | return -EIO; | 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 | if (s->fd < 0) { | 845 | if (s->fd < 0) { |
| 739 | s->fd_error_time = qemu_get_clock(rt_clock); | 846 | s->fd_error_time = qemu_get_clock(rt_clock); |
| 740 | s->fd_got_error = 1; | 847 | s->fd_got_error = 1; |
| @@ -831,7 +938,7 @@ static int raw_eject(BlockDriverState *bs, int eject_flag) | @@ -831,7 +938,7 @@ static int raw_eject(BlockDriverState *bs, int eject_flag) | ||
| 831 | close(s->fd); | 938 | close(s->fd); |
| 832 | s->fd = -1; | 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 | if (fd >= 0) { | 942 | if (fd >= 0) { |
| 836 | if (ioctl(fd, FDEJECT, 0) < 0) | 943 | if (ioctl(fd, FDEJECT, 0) < 0) |
| 837 | perror("FDEJECT"); | 944 | perror("FDEJECT"); |