#include "block_int.h"
#include <assert.h>
#ifdef CONFIG_AIO
-#include <aio.h>
+#include "posix-aio-compat.h"
#endif
#ifdef CONFIG_COCOA
#include <sys/dkio.h>
#endif
+#ifdef __DragonFly__
+#include <sys/ioctl.h>
+#include <sys/diskslice.h>
+#endif
+
//#define DEBUG_FLOPPY
//#define DEBUG_BLOCK
#if defined(DEBUG_BLOCK)
-#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
- { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
+#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (qemu_log_enabled()) \
+ { qemu_log(formatCstr, ##args); qemu_log_flush(); } } while (0)
#else
#define DEBUG_BLOCK_PRINT(formatCstr, args...)
#endif
reopen it to see if the disk has been changed */
#define FD_OPEN_TIMEOUT 1000
-/* posix-aio doesn't allow multiple outstanding requests to a single file
- * descriptor. we implement a pool of dup()'d file descriptors to work
- * around this */
-#define RAW_FD_POOL_SIZE 64
-
typedef struct BDRVRawState {
int fd;
int type;
unsigned int lseek_err_cnt;
- int fd_pool[RAW_FD_POOL_SIZE];
#if defined(__linux__)
/* linux floppy specific */
int fd_open_flags;
{
BDRVRawState *s = bs->opaque;
int fd, open_flags, ret;
- int i;
posix_aio_init();
return ret;
}
s->fd = fd;
- for (i = 0; i < RAW_FD_POOL_SIZE; i++)
- s->fd_pool[i] = -1;
s->aligned_buf = NULL;
if ((flags & BDRV_O_NOCACHE)) {
s->aligned_buf = qemu_memalign(512, ALIGNED_BUFFER_SIZE);
ret = fd_open(bs);
if (ret < 0)
- return ret;
+ return -errno;
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
++(s->lseek_err_cnt);
s->fd, bs->filename, offset, buf, count,
bs->total_sectors, errno, strerror(errno));
}
- return -1;
+ return -EIO;
}
s->lseek_err_cnt = 0;
label__raw_write__success:
- return ret;
+ return (ret < 0) ? -errno : ret;
}
return raw_pread_aligned(bs, offset, buf, count) + sum;
}
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ int ret;
+
+ ret = raw_pread(bs, sector_num * 512, buf, nb_sectors * 512);
+ if (ret == (nb_sectors * 512))
+ ret = 0;
+ return ret;
+}
+
/*
* offset and count are in bytes and possibly not aligned. For files opened
* with O_DIRECT, necessary alignments are ensured before calling
return raw_pwrite_aligned(bs, offset, buf, count) + sum;
}
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ int ret;
+ ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);
+ if (ret == (nb_sectors * 512))
+ ret = 0;
+ return ret;
+}
+
#ifdef CONFIG_AIO
/***********************************************************/
/* Unix AIO using POSIX AIO */
typedef struct RawAIOCB {
BlockDriverAIOCB common;
- int fd;
- struct aiocb aiocb;
+ struct qemu_paiocb aiocb;
struct RawAIOCB *next;
int ret;
} RawAIOCB;
RawAIOCB *first_aio;
} PosixAioState;
-static int raw_fd_pool_get(BDRVRawState *s)
-{
- int i;
-
- for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
- /* already in use */
- if (s->fd_pool[i] != -1)
- continue;
-
- /* try to dup file descriptor */
- s->fd_pool[i] = dup(s->fd);
- if (s->fd_pool[i] != -1)
- return s->fd_pool[i];
- }
-
- /* we couldn't dup the file descriptor so just use the main one */
- return s->fd;
-}
-
-static void raw_fd_pool_put(RawAIOCB *acb)
-{
- BDRVRawState *s = acb->common.bs->opaque;
- int i;
-
- for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
- if (s->fd_pool[i] == acb->fd) {
- close(s->fd_pool[i]);
- s->fd_pool[i] = -1;
- }
- }
-}
-
static void posix_aio_read(void *opaque)
{
PosixAioState *s = opaque;
acb = *pacb;
if (!acb)
goto the_end;
- ret = aio_error(&acb->aiocb);
+ ret = qemu_paio_error(&acb->aiocb);
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 */
if (ret == 0) {
- ret = aio_return(&acb->aiocb);
+ ret = qemu_paio_return(&acb->aiocb);
if (ret == acb->aiocb.aio_nbytes)
ret = 0;
else
*pacb = acb->next;
/* call the callback */
acb->common.cb(acb->common.opaque, ret);
- raw_fd_pool_put(acb);
qemu_aio_release(acb);
break;
} else {
struct sigaction act;
PosixAioState *s;
int fds[2];
+ struct qemu_paioinit ai;
if (posix_aio_state)
return 0;
s = qemu_malloc(sizeof(PosixAioState));
- if (s == NULL)
- return -ENOMEM;
sigfillset(&act.sa_mask);
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
-#if defined(__linux__)
- {
- struct aioinit ai;
+ memset(&ai, 0, sizeof(ai));
+ ai.aio_threads = 64;
+ ai.aio_num = 64;
+ qemu_paio_init(&ai);
- memset(&ai, 0, sizeof(ai));
-#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 4)
- ai.aio_threads = 64;
- ai.aio_num = 64;
-#else
- /* XXX: aio thread exit seems to hang on RedHat 9 and this init
- seems to fix the problem. */
- ai.aio_threads = 1;
- ai.aio_num = 1;
- ai.aio_idle_time = 365 * 100000;
-#endif
- aio_init(&ai);
- }
-#endif
posix_aio_state = s;
return 0;
acb = qemu_aio_get(bs, cb, opaque);
if (!acb)
return NULL;
- 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_fildes = s->fd;
+ acb->aiocb.ev_signo = SIGUSR2;
acb->aiocb.aio_buf = buf;
if (nb_sectors < 0)
acb->aiocb.aio_nbytes = -nb_sectors;
qemu_aio_release(acb);
}
+static void raw_aio_remove(RawAIOCB *acb)
+{
+ RawAIOCB **pacb;
+
+ /* remove the callback from the queue */
+ pacb = &posix_aio_state->first_aio;
+ for(;;) {
+ if (*pacb == NULL) {
+ fprintf(stderr, "raw_aio_remove: aio request not found!\n");
+ break;
+ } else if (*pacb == acb) {
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ break;
+ }
+ pacb = &(*pacb)->next;
+ }
+}
+
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
if (!acb)
return NULL;
- if (aio_read(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
+ if (qemu_paio_read(&acb->aiocb) < 0) {
+ raw_aio_remove(acb);
return NULL;
}
return &acb->common;
acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
if (!acb)
return NULL;
- if (aio_write(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
+ if (qemu_paio_write(&acb->aiocb) < 0) {
+ raw_aio_remove(acb);
return NULL;
}
return &acb->common;
{
int ret;
RawAIOCB *acb = (RawAIOCB *)blockacb;
- RawAIOCB **pacb;
- ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
- if (ret == AIO_NOTCANCELED) {
+ ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+ if (ret == QEMU_PAIO_NOTCANCELED) {
/* fail safe: if the aio could not be canceled, we wait for
it */
- while (aio_error(&acb->aiocb) == EINPROGRESS);
+ while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
}
- /* remove the callback from the queue */
- pacb = &posix_aio_state->first_aio;
- for(;;) {
- if (*pacb == NULL) {
- break;
- } else if (*pacb == acb) {
- *pacb = acb->next;
- raw_fd_pool_put(acb);
- qemu_aio_release(acb);
- break;
- }
- pacb = &acb->next;
- }
+ raw_aio_remove(acb);
}
-
#else /* CONFIG_AIO */
static int posix_aio_init(void)
{
}
#endif /* CONFIG_AIO */
-static void raw_close_fd_pool(BDRVRawState *s)
-{
- int i;
-
- for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
- if (s->fd_pool[i] != -1) {
- close(s->fd_pool[i]);
- s->fd_pool[i] = -1;
- }
- }
-}
static void raw_close(BlockDriverState *bs)
{
if (s->aligned_buf != NULL)
qemu_free(s->aligned_buf);
}
- raw_close_fd_pool(s);
}
static int raw_truncate(BlockDriverState *bs, int64_t offset)
BDRVRawState *s = bs->opaque;
int fd = s->fd;
int64_t size;
-#ifdef _BSD
+#ifdef HOST_BSD
struct stat sb;
#endif
#ifdef __sun__
if (ret < 0)
return ret;
-#ifdef _BSD
+#ifdef HOST_BSD
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#elif defined(DIOCGPART)
+ {
+ struct partinfo pi;
+ if (ioctl(fd, DIOCGPART, &pi) == 0)
+ size = pi.media_size;
+ else
+ size = 0;
+ }
+ if (size == 0)
#endif
#ifdef CONFIG_COCOA
size = LONG_LONG_MAX;
.bdrv_aio_cancel = raw_aio_cancel,
.aiocb_size = sizeof(RawAIOCB),
#endif
- .bdrv_pread = raw_pread,
- .bdrv_pwrite = raw_pwrite,
+
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
};
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
- int fd, open_flags, ret, i;
+ int fd, open_flags, ret;
posix_aio_init();
return ret;
}
s->fd = fd;
- for (i = 0; i < RAW_FD_POOL_SIZE; i++)
- s->fd_pool[i] = -1;
#if defined(__linux__)
/* close fd so that we can reopen it as needed */
if (s->type == FTYPE_FD) {
(qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
close(s->fd);
s->fd = -1;
- raw_close_fd_pool(s);
#ifdef DEBUG_FLOPPY
printf("Floppy closed\n");
#endif
if (s->fd >= 0) {
close(s->fd);
s->fd = -1;
- raw_close_fd_pool(s);
}
fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
if (fd >= 0) {
}
#endif /* !linux */
+static int raw_sg_send_command(BlockDriverState *bs, void *buf, int count)
+{
+ return raw_pwrite(bs, -1, buf, count);
+}
+
+static int raw_sg_recv_response(BlockDriverState *bs, void *buf, int count)
+{
+ return raw_pread(bs, -1, buf, count);
+}
+
+static BlockDriverAIOCB *raw_sg_aio_read(BlockDriverState *bs,
+ void *buf, int count,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ return raw_aio_read(bs, 0, buf, -(int64_t)count, cb, opaque);
+}
+
+static BlockDriverAIOCB *raw_sg_aio_write(BlockDriverState *bs,
+ void *buf, int count,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ return raw_aio_write(bs, 0, buf, -(int64_t)count, cb, opaque);
+}
+
BlockDriver bdrv_host_device = {
- "host_device",
- sizeof(BDRVRawState),
- NULL, /* no probe for protocols */
- hdev_open,
- NULL,
- NULL,
- raw_close,
- NULL,
- raw_flush,
+ .format_name = "host_device",
+ .instance_size = sizeof(BDRVRawState),
+ .bdrv_open = hdev_open,
+ .bdrv_close = raw_close,
+ .bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
- .bdrv_aio_read = raw_aio_read,
- .bdrv_aio_write = raw_aio_write,
- .bdrv_aio_cancel = raw_aio_cancel,
- .aiocb_size = sizeof(RawAIOCB),
+ .bdrv_aio_read = raw_aio_read,
+ .bdrv_aio_write = raw_aio_write,
+ .bdrv_aio_cancel = raw_aio_cancel,
+ .aiocb_size = sizeof(RawAIOCB),
#endif
- .bdrv_pread = raw_pread,
- .bdrv_pwrite = raw_pwrite,
- .bdrv_getlength = raw_getlength,
+
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
+ .bdrv_getlength = raw_getlength,
/* removable device support */
- .bdrv_is_inserted = raw_is_inserted,
- .bdrv_media_changed = raw_media_changed,
- .bdrv_eject = raw_eject,
- .bdrv_set_locked = raw_set_locked,
+ .bdrv_is_inserted = raw_is_inserted,
+ .bdrv_media_changed = raw_media_changed,
+ .bdrv_eject = raw_eject,
+ .bdrv_set_locked = raw_set_locked,
/* generic scsi device */
- .bdrv_ioctl = raw_ioctl,
+ .bdrv_ioctl = raw_ioctl,
+ .bdrv_sg_send_command = raw_sg_send_command,
+ .bdrv_sg_recv_response = raw_sg_recv_response,
+ .bdrv_sg_aio_read = raw_sg_aio_read,
+ .bdrv_sg_aio_write = raw_sg_aio_write,
};