Revision 9ef91a67 block/raw-posix.c
b/block/raw-posix.c | ||
---|---|---|
27 | 27 |
#include "qemu-log.h" |
28 | 28 |
#include "block_int.h" |
29 | 29 |
#include "module.h" |
30 |
#include "posix-aio-compat.h"
|
|
30 |
#include "block/raw-posix-aio.h"
|
|
31 | 31 |
|
32 | 32 |
#ifdef CONFIG_COCOA |
33 | 33 |
#include <paths.h> |
... | ... | |
107 | 107 |
int type; |
108 | 108 |
unsigned int lseek_err_cnt; |
109 | 109 |
int open_flags; |
110 |
void *aio_ctx; |
|
110 | 111 |
#if defined(__linux__) |
111 | 112 |
/* linux floppy specific */ |
112 | 113 |
int64_t fd_open_time; |
... | ... | |
117 | 118 |
uint8_t* aligned_buf; |
118 | 119 |
} BDRVRawState; |
119 | 120 |
|
120 |
static int posix_aio_init(void); |
|
121 |
|
|
122 | 121 |
static int fd_open(BlockDriverState *bs); |
123 | 122 |
static int64_t raw_getlength(BlockDriverState *bs); |
124 | 123 |
|
... | ... | |
132 | 131 |
BDRVRawState *s = bs->opaque; |
133 | 132 |
int fd, ret; |
134 | 133 |
|
135 |
posix_aio_init(); |
|
136 |
|
|
137 | 134 |
s->lseek_err_cnt = 0; |
138 | 135 |
|
139 | 136 |
s->open_flags = open_flags | O_BINARY; |
... | ... | |
165 | 162 |
if ((bdrv_flags & BDRV_O_NOCACHE)) { |
166 | 163 |
s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE); |
167 | 164 |
if (s->aligned_buf == NULL) { |
168 |
ret = -errno; |
|
169 |
close(fd); |
|
170 |
return ret; |
|
165 |
goto out_close; |
|
171 | 166 |
} |
172 | 167 |
} |
168 |
|
|
169 |
s->aio_ctx = paio_init(); |
|
170 |
if (!s->aio_ctx) { |
|
171 |
goto out_free_buf; |
|
172 |
} |
|
173 |
|
|
173 | 174 |
return 0; |
175 |
|
|
176 |
out_free_buf: |
|
177 |
qemu_vfree(s->aligned_buf); |
|
178 |
out_close: |
|
179 |
close(fd); |
|
180 |
return -errno; |
|
174 | 181 |
} |
175 | 182 |
|
176 | 183 |
static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
... | ... | |
487 | 494 |
return ret; |
488 | 495 |
} |
489 | 496 |
|
490 |
/***********************************************************/ |
|
491 |
/* Unix AIO using POSIX AIO */ |
|
492 |
|
|
493 |
typedef struct RawAIOCB { |
|
494 |
BlockDriverAIOCB common; |
|
495 |
struct qemu_paiocb aiocb; |
|
496 |
struct RawAIOCB *next; |
|
497 |
int ret; |
|
498 |
} RawAIOCB; |
|
499 |
|
|
500 |
typedef struct PosixAioState |
|
501 |
{ |
|
502 |
int rfd, wfd; |
|
503 |
RawAIOCB *first_aio; |
|
504 |
} PosixAioState; |
|
505 |
|
|
506 |
static void posix_aio_read(void *opaque) |
|
507 |
{ |
|
508 |
PosixAioState *s = opaque; |
|
509 |
RawAIOCB *acb, **pacb; |
|
510 |
int ret; |
|
511 |
ssize_t len; |
|
512 |
|
|
513 |
/* read all bytes from signal pipe */ |
|
514 |
for (;;) { |
|
515 |
char bytes[16]; |
|
516 |
|
|
517 |
len = read(s->rfd, bytes, sizeof(bytes)); |
|
518 |
if (len == -1 && errno == EINTR) |
|
519 |
continue; /* try again */ |
|
520 |
if (len == sizeof(bytes)) |
|
521 |
continue; /* more to read */ |
|
522 |
break; |
|
523 |
} |
|
524 |
|
|
525 |
for(;;) { |
|
526 |
pacb = &s->first_aio; |
|
527 |
for(;;) { |
|
528 |
acb = *pacb; |
|
529 |
if (!acb) |
|
530 |
goto the_end; |
|
531 |
ret = qemu_paio_error(&acb->aiocb); |
|
532 |
if (ret == ECANCELED) { |
|
533 |
/* remove the request */ |
|
534 |
*pacb = acb->next; |
|
535 |
qemu_aio_release(acb); |
|
536 |
} else if (ret != EINPROGRESS) { |
|
537 |
/* end of aio */ |
|
538 |
if (ret == 0) { |
|
539 |
ret = qemu_paio_return(&acb->aiocb); |
|
540 |
if (ret == acb->aiocb.aio_nbytes) |
|
541 |
ret = 0; |
|
542 |
else |
|
543 |
ret = -EINVAL; |
|
544 |
} else { |
|
545 |
ret = -ret; |
|
546 |
} |
|
547 |
/* remove the request */ |
|
548 |
*pacb = acb->next; |
|
549 |
/* call the callback */ |
|
550 |
acb->common.cb(acb->common.opaque, ret); |
|
551 |
qemu_aio_release(acb); |
|
552 |
break; |
|
553 |
} else { |
|
554 |
pacb = &acb->next; |
|
555 |
} |
|
556 |
} |
|
557 |
} |
|
558 |
the_end: ; |
|
559 |
} |
|
560 |
|
|
561 |
static int posix_aio_flush(void *opaque) |
|
562 |
{ |
|
563 |
PosixAioState *s = opaque; |
|
564 |
return !!s->first_aio; |
|
565 |
} |
|
566 |
|
|
567 |
static PosixAioState *posix_aio_state; |
|
568 |
|
|
569 |
static void aio_signal_handler(int signum) |
|
570 |
{ |
|
571 |
if (posix_aio_state) { |
|
572 |
char byte = 0; |
|
573 |
|
|
574 |
write(posix_aio_state->wfd, &byte, sizeof(byte)); |
|
575 |
} |
|
576 |
|
|
577 |
qemu_service_io(); |
|
578 |
} |
|
579 |
|
|
580 |
static int posix_aio_init(void) |
|
497 |
/* |
|
498 |
* Check if all memory in this vector is sector aligned. |
|
499 |
*/ |
|
500 |
static int qiov_is_aligned(QEMUIOVector *qiov) |
|
581 | 501 |
{ |
582 |
struct sigaction act; |
|
583 |
PosixAioState *s; |
|
584 |
int fds[2]; |
|
585 |
struct qemu_paioinit ai; |
|
586 |
|
|
587 |
if (posix_aio_state) |
|
588 |
return 0; |
|
589 |
|
|
590 |
s = qemu_malloc(sizeof(PosixAioState)); |
|
591 |
|
|
592 |
sigfillset(&act.sa_mask); |
|
593 |
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ |
|
594 |
act.sa_handler = aio_signal_handler; |
|
595 |
sigaction(SIGUSR2, &act, NULL); |
|
596 |
|
|
597 |
s->first_aio = NULL; |
|
598 |
if (pipe(fds) == -1) { |
|
599 |
fprintf(stderr, "failed to create pipe\n"); |
|
600 |
return -errno; |
|
601 |
} |
|
602 |
|
|
603 |
s->rfd = fds[0]; |
|
604 |
s->wfd = fds[1]; |
|
605 |
|
|
606 |
fcntl(s->rfd, F_SETFL, O_NONBLOCK); |
|
607 |
fcntl(s->wfd, F_SETFL, O_NONBLOCK); |
|
608 |
|
|
609 |
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s); |
|
610 |
|
|
611 |
memset(&ai, 0, sizeof(ai)); |
|
612 |
ai.aio_threads = 64; |
|
613 |
ai.aio_num = 64; |
|
614 |
qemu_paio_init(&ai); |
|
615 |
|
|
616 |
posix_aio_state = s; |
|
617 |
|
|
618 |
return 0; |
|
619 |
} |
|
502 |
int i; |
|
620 | 503 |
|
621 |
static void raw_aio_remove(RawAIOCB *acb) |
|
622 |
{ |
|
623 |
RawAIOCB **pacb; |
|
624 |
|
|
625 |
/* remove the callback from the queue */ |
|
626 |
pacb = &posix_aio_state->first_aio; |
|
627 |
for(;;) { |
|
628 |
if (*pacb == NULL) { |
|
629 |
fprintf(stderr, "raw_aio_remove: aio request not found!\n"); |
|
630 |
break; |
|
631 |
} else if (*pacb == acb) { |
|
632 |
*pacb = acb->next; |
|
633 |
qemu_aio_release(acb); |
|
634 |
break; |
|
504 |
for (i = 0; i < qiov->niov; i++) { |
|
505 |
if ((uintptr_t) qiov->iov[i].iov_base % 512) { |
|
506 |
return 0; |
|
635 | 507 |
} |
636 |
pacb = &(*pacb)->next; |
|
637 | 508 |
} |
638 |
} |
|
639 |
|
|
640 |
static void raw_aio_cancel(BlockDriverAIOCB *blockacb) |
|
641 |
{ |
|
642 |
int ret; |
|
643 |
RawAIOCB *acb = (RawAIOCB *)blockacb; |
|
644 | 509 |
|
645 |
ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); |
|
646 |
if (ret == QEMU_PAIO_NOTCANCELED) { |
|
647 |
/* fail safe: if the aio could not be canceled, we wait for |
|
648 |
it */ |
|
649 |
while (qemu_paio_error(&acb->aiocb) == EINPROGRESS); |
|
650 |
} |
|
651 |
|
|
652 |
raw_aio_remove(acb); |
|
510 |
return 1; |
|
653 | 511 |
} |
654 | 512 |
|
655 |
static AIOPool raw_aio_pool = { |
|
656 |
.aiocb_size = sizeof(RawAIOCB), |
|
657 |
.cancel = raw_aio_cancel, |
|
658 |
}; |
|
659 |
|
|
660 |
static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num, |
|
661 |
QEMUIOVector *qiov, int nb_sectors, |
|
662 |
BlockDriverCompletionFunc *cb, void *opaque) |
|
513 |
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs, |
|
514 |
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, |
|
515 |
BlockDriverCompletionFunc *cb, void *opaque, int type) |
|
663 | 516 |
{ |
664 | 517 |
BDRVRawState *s = bs->opaque; |
665 |
RawAIOCB *acb; |
|
666 | 518 |
|
667 | 519 |
if (fd_open(bs) < 0) |
668 | 520 |
return NULL; |
669 | 521 |
|
670 |
acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque); |
|
671 |
if (!acb) |
|
672 |
return NULL; |
|
673 |
acb->aiocb.aio_fildes = s->fd; |
|
674 |
acb->aiocb.ev_signo = SIGUSR2; |
|
675 |
acb->aiocb.aio_iov = qiov->iov; |
|
676 |
acb->aiocb.aio_niov = qiov->niov; |
|
677 |
acb->aiocb.aio_nbytes = nb_sectors * 512; |
|
678 |
acb->aiocb.aio_offset = sector_num * 512; |
|
679 |
acb->aiocb.aio_flags = 0; |
|
680 |
|
|
681 | 522 |
/* |
682 | 523 |
* If O_DIRECT is used the buffer needs to be aligned on a sector |
683 |
* boundary. Tell the low level code to ensure that in case it's
|
|
684 |
* not done yet.
|
|
524 |
* boundary. Check if this is the case or telll the low-level
|
|
525 |
* driver that it needs to copy the buffer.
|
|
685 | 526 |
*/ |
686 |
if (s->aligned_buf) |
|
687 |
acb->aiocb.aio_flags |= QEMU_AIO_SECTOR_ALIGNED; |
|
527 |
if (s->aligned_buf && !qiov_is_aligned(qiov)) { |
|
528 |
type |= QEMU_AIO_MISALIGNED; |
|
529 |
} |
|
688 | 530 |
|
689 |
acb->next = posix_aio_state->first_aio; |
|
690 |
posix_aio_state->first_aio = acb; |
|
691 |
return acb; |
|
531 |
return paio_submit(bs, s->aio_ctx, s->fd, sector_num, qiov, nb_sectors, |
|
532 |
cb, opaque, type); |
|
692 | 533 |
} |
693 | 534 |
|
694 | 535 |
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs, |
695 | 536 |
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, |
696 | 537 |
BlockDriverCompletionFunc *cb, void *opaque) |
697 | 538 |
{ |
698 |
RawAIOCB *acb; |
|
699 |
|
|
700 |
acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque); |
|
701 |
if (!acb) |
|
702 |
return NULL; |
|
703 |
if (qemu_paio_read(&acb->aiocb) < 0) { |
|
704 |
raw_aio_remove(acb); |
|
705 |
return NULL; |
|
706 |
} |
|
707 |
return &acb->common; |
|
539 |
return raw_aio_submit(bs, sector_num, qiov, nb_sectors, |
|
540 |
cb, opaque, QEMU_AIO_READ); |
|
708 | 541 |
} |
709 | 542 |
|
710 | 543 |
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs, |
711 | 544 |
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, |
712 | 545 |
BlockDriverCompletionFunc *cb, void *opaque) |
713 | 546 |
{ |
714 |
RawAIOCB *acb; |
|
715 |
|
|
716 |
acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque); |
|
717 |
if (!acb) |
|
718 |
return NULL; |
|
719 |
if (qemu_paio_write(&acb->aiocb) < 0) { |
|
720 |
raw_aio_remove(acb); |
|
721 |
return NULL; |
|
722 |
} |
|
723 |
return &acb->common; |
|
547 |
return raw_aio_submit(bs, sector_num, qiov, nb_sectors, |
|
548 |
cb, opaque, QEMU_AIO_WRITE); |
|
724 | 549 |
} |
725 | 550 |
|
726 | 551 |
static void raw_close(BlockDriverState *bs) |
... | ... | |
1085 | 910 |
BlockDriverCompletionFunc *cb, void *opaque) |
1086 | 911 |
{ |
1087 | 912 |
BDRVRawState *s = bs->opaque; |
1088 |
RawAIOCB *acb; |
|
1089 | 913 |
|
1090 | 914 |
if (fd_open(bs) < 0) |
1091 | 915 |
return NULL; |
1092 |
|
|
1093 |
acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque); |
|
1094 |
if (!acb) |
|
1095 |
return NULL; |
|
1096 |
acb->aiocb.aio_fildes = s->fd; |
|
1097 |
acb->aiocb.ev_signo = SIGUSR2; |
|
1098 |
acb->aiocb.aio_offset = 0; |
|
1099 |
acb->aiocb.aio_flags = 0; |
|
1100 |
|
|
1101 |
acb->next = posix_aio_state->first_aio; |
|
1102 |
posix_aio_state->first_aio = acb; |
|
1103 |
|
|
1104 |
acb->aiocb.aio_ioctl_buf = buf; |
|
1105 |
acb->aiocb.aio_ioctl_cmd = req; |
|
1106 |
if (qemu_paio_ioctl(&acb->aiocb) < 0) { |
|
1107 |
raw_aio_remove(acb); |
|
1108 |
return NULL; |
|
1109 |
} |
|
1110 |
|
|
1111 |
return &acb->common; |
|
916 |
return paio_ioctl(bs, s->fd, req, buf, cb, opaque); |
|
1112 | 917 |
} |
1113 | 918 |
|
1114 | 919 |
#elif defined(__FreeBSD__) |
... | ... | |
1189 | 994 |
BDRVRawState *s = bs->opaque; |
1190 | 995 |
int ret; |
1191 | 996 |
|
1192 |
posix_aio_init(); |
|
1193 |
|
|
1194 | 997 |
s->type = FTYPE_FD; |
1195 | 998 |
|
1196 | 999 |
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */ |
Also available in: Unified diff