Index: block-raw-posix.c =================================================================== --- block-raw-posix.c (revision 5304) +++ block-raw-posix.c (working copy) @@ -84,10 +84,20 @@ reopen it to see if the disk has been changed */ #define FD_OPEN_TIMEOUT 1000 +#define RAW_FD_POOL_SIZE 4 + +typedef struct RawFdPoolEntry +{ + int fd; + int inuse; +} RawFdPoolEntry; + typedef struct BDRVRawState { int fd; int type; unsigned int lseek_err_cnt; + int fd0_inuse; + RawFdPoolEntry fd_pool[RAW_FD_POOL_SIZE]; #if defined(__linux__) /* linux floppy specific */ int fd_open_flags; @@ -109,6 +119,7 @@ { BDRVRawState *s = bs->opaque; int fd, open_flags, ret; + int i; posix_aio_init(); @@ -138,6 +149,11 @@ return ret; } s->fd = fd; + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + s->fd_pool[i].fd = -1; + s->fd_pool[i].inuse = 0; + } + s->fd0_inuse = 0; #if defined(O_DIRECT) s->aligned_buf = NULL; if (flags & BDRV_O_DIRECT) { @@ -436,6 +452,7 @@ typedef struct RawAIOCB { BlockDriverAIOCB common; + int fd; struct aiocb aiocb; struct RawAIOCB *next; int ret; @@ -447,6 +464,52 @@ RawAIOCB *first_aio; } PosixAioState; +static int raw_fd_pool_get(BDRVRawState *s) +{ + if (s->fd0_inuse) { + int i; + + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i].fd == -1) { + s->fd_pool[i].fd = dup(s->fd); + if (s->fd_pool[i].fd == -1) + continue; + s->fd_pool[i].inuse = 0; + } + + if (!s->fd_pool[i].inuse) { + s->fd_pool[i].inuse++; + return s->fd_pool[i].fd; + } + } + } + s->fd0_inuse++; + + return s->fd; +} + +static void raw_fd_pool_put(RawAIOCB *acb) +{ + BDRVRawState *s = acb->common.bs->opaque; + int fd = acb->fd; + int i; + + if (s->fd == fd) { + s->fd0_inuse--; + return; + } + + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i].fd == fd) { + s->fd_pool[i].inuse--; + if (s->fd_pool[i].inuse == 0) { + close(s->fd_pool[i].fd); + s->fd_pool[i].fd = -1; + } + } + } +} + static void posix_aio_read(void *opaque) { PosixAioState *s = opaque; @@ -487,6 +550,7 @@ if (ret == ECANCELED) { /* remove the request */ *pacb = acb->next; + raw_fd_pool_put(acb); qemu_aio_release(acb); } else if (ret != EINPROGRESS) { /* end of aio */ @@ -503,6 +567,7 @@ *pacb = acb->next; /* call the callback */ acb->common.cb(acb->common.opaque, ret); + raw_fd_pool_put(acb); qemu_aio_release(acb); break; } else { @@ -575,7 +640,8 @@ acb = qemu_aio_get(bs, cb, opaque); if (!acb) return NULL; - acb->aiocb.aio_fildes = s->fd; + acb->fd = raw_fd_pool_get(s); + acb->aiocb.aio_fildes = acb->fd; acb->aiocb.aio_sigevent.sigev_signo = SIGUSR2; acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; acb->aiocb.aio_buf = buf; @@ -682,6 +748,7 @@ break; } else if (*pacb == acb) { *pacb = acb->next; + raw_fd_pool_put(acb); qemu_aio_release(acb); break; } @@ -698,6 +765,7 @@ static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; + int i; if (s->fd >= 0) { close(s->fd); s->fd = -1; @@ -706,6 +774,10 @@ qemu_free(s->aligned_buf); #endif } + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i].fd != -1) + close(s->fd_pool[i].fd); + } } static int raw_truncate(BlockDriverState *bs, int64_t offset) @@ -973,6 +1045,18 @@ } #if defined(__linux__) +static void raw_invalidate_fd_pool(BDRVRawState *s) +{ + int i; + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i].fd != -1) { + close(s->fd_pool[i].fd); + s->fd_pool[i].fd = -1; + s->fd_pool[i].inuse = 0; + } + } + s->fd0_inuse = 0; +} /* Note: we do not have a reliable method to detect if the floppy is present. The current method is to try to open the floppy at every @@ -989,6 +1073,7 @@ (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) { close(s->fd); s->fd = -1; + raw_invalidate_fd_pool(s); #ifdef DEBUG_FLOPPY printf("Floppy closed\n"); #endif @@ -1089,6 +1174,7 @@ if (s->fd >= 0) { close(s->fd); s->fd = -1; + raw_invalidate_fd_pool(s); } fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); if (fd >= 0) {