version 1.1.1.1, 2018/04/24 16:47:26
|
version 1.1.1.2, 2018/04/24 16:50:44
|
Line 22
|
Line 22
|
* THE SOFTWARE. |
* THE SOFTWARE. |
*/ |
*/ |
#include "qemu-common.h" |
#include "qemu-common.h" |
#ifndef QEMU_IMG |
|
#include "qemu-timer.h" |
#include "qemu-timer.h" |
#include "exec-all.h" |
#include "qemu-char.h" |
#endif |
|
#include "block_int.h" |
#include "block_int.h" |
#include <assert.h> |
#include <assert.h> |
#include <aio.h> |
#ifdef CONFIG_AIO |
|
#include "posix-aio-compat.h" |
|
#endif |
|
|
#ifdef CONFIG_COCOA |
#ifdef CONFIG_COCOA |
#include <paths.h> |
#include <paths.h> |
Line 53
|
Line 53
|
#include <linux/fd.h> |
#include <linux/fd.h> |
#endif |
#endif |
#ifdef __FreeBSD__ |
#ifdef __FreeBSD__ |
|
#include <signal.h> |
#include <sys/disk.h> |
#include <sys/disk.h> |
#endif |
#endif |
|
|
|
#ifdef __OpenBSD__ |
|
#include <sys/ioctl.h> |
|
#include <sys/disklabel.h> |
|
#include <sys/dkio.h> |
|
#endif |
|
|
//#define DEBUG_FLOPPY |
//#define DEBUG_FLOPPY |
|
|
//#define DEBUG_BLOCK |
//#define DEBUG_BLOCK |
#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) |
#if defined(DEBUG_BLOCK) |
#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ |
#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (qemu_log_enabled()) \ |
{ fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) |
{ qemu_log(formatCstr, ##args); qemu_log_flush(); } } while (0) |
#else |
#else |
#define DEBUG_BLOCK_PRINT(formatCstr, args...) |
#define DEBUG_BLOCK_PRINT(formatCstr, args...) |
#endif |
#endif |
|
|
|
/* OS X does not have O_DSYNC */ |
|
#ifndef O_DSYNC |
|
#define O_DSYNC O_SYNC |
|
#endif |
|
|
|
/* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */ |
|
#ifndef O_DIRECT |
|
#define O_DIRECT O_DSYNC |
|
#endif |
|
|
#define FTYPE_FILE 0 |
#define FTYPE_FILE 0 |
#define FTYPE_CD 1 |
#define FTYPE_CD 1 |
#define FTYPE_FD 2 |
#define FTYPE_FD 2 |
|
|
|
#define ALIGNED_BUFFER_SIZE (32 * 512) |
|
|
/* if the FD is not accessed during that time (in ms), we try to |
/* if the FD is not accessed during that time (in ms), we try to |
reopen it to see if the disk has been changed */ |
reopen it to see if the disk has been changed */ |
#define FD_OPEN_TIMEOUT 1000 |
#define FD_OPEN_TIMEOUT 1000 |
Line 86 typedef struct BDRVRawState {
|
Line 105 typedef struct BDRVRawState {
|
int fd_got_error; |
int fd_got_error; |
int fd_media_changed; |
int fd_media_changed; |
#endif |
#endif |
|
uint8_t* aligned_buf; |
} BDRVRawState; |
} BDRVRawState; |
|
|
|
static int posix_aio_init(void); |
|
|
static int fd_open(BlockDriverState *bs); |
static int fd_open(BlockDriverState *bs); |
|
|
static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
Line 95 static int raw_open(BlockDriverState *bs
|
Line 117 static int raw_open(BlockDriverState *bs
|
BDRVRawState *s = bs->opaque; |
BDRVRawState *s = bs->opaque; |
int fd, open_flags, ret; |
int fd, open_flags, ret; |
|
|
|
posix_aio_init(); |
|
|
s->lseek_err_cnt = 0; |
s->lseek_err_cnt = 0; |
|
|
open_flags = O_BINARY; |
open_flags = O_BINARY; |
Line 106 static int raw_open(BlockDriverState *bs
|
Line 130 static int raw_open(BlockDriverState *bs
|
} |
} |
if (flags & BDRV_O_CREAT) |
if (flags & BDRV_O_CREAT) |
open_flags |= O_CREAT | O_TRUNC; |
open_flags |= O_CREAT | O_TRUNC; |
#ifdef O_DIRECT |
|
if (flags & BDRV_O_DIRECT) |
/* Use O_DSYNC for write-through caching, no flags for write-back caching, |
|
* and O_DIRECT for no caching. */ |
|
if ((flags & BDRV_O_NOCACHE)) |
open_flags |= O_DIRECT; |
open_flags |= O_DIRECT; |
#endif |
else if (!(flags & BDRV_O_CACHE_WB)) |
|
open_flags |= O_DSYNC; |
|
|
s->type = FTYPE_FILE; |
s->type = FTYPE_FILE; |
|
|
Line 121 static int raw_open(BlockDriverState *bs
|
Line 148 static int raw_open(BlockDriverState *bs
|
return ret; |
return ret; |
} |
} |
s->fd = fd; |
s->fd = fd; |
|
s->aligned_buf = NULL; |
|
if ((flags & BDRV_O_NOCACHE)) { |
|
s->aligned_buf = qemu_memalign(512, ALIGNED_BUFFER_SIZE); |
|
if (s->aligned_buf == NULL) { |
|
ret = -errno; |
|
close(fd); |
|
return ret; |
|
} |
|
} |
return 0; |
return 0; |
} |
} |
|
|
Line 141 static int raw_open(BlockDriverState *bs
|
Line 177 static int raw_open(BlockDriverState *bs
|
#endif |
#endif |
*/ |
*/ |
|
|
static int raw_pread(BlockDriverState *bs, int64_t offset, |
/* |
|
* offset and count are in bytes, but must be multiples of 512 for files |
|
* opened with O_DIRECT. buf must be aligned to 512 bytes then. |
|
* |
|
* This function may be called without alignment if the caller ensures |
|
* that O_DIRECT is not in effect. |
|
*/ |
|
static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, |
uint8_t *buf, int count) |
uint8_t *buf, int count) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BDRVRawState *s = bs->opaque; |
Line 194 label__raw_read__success:
|
Line 237 label__raw_read__success:
|
return ret; |
return ret; |
} |
} |
|
|
static int raw_pwrite(BlockDriverState *bs, int64_t offset, |
/* |
|
* offset and count are in bytes, but must be multiples of 512 for files |
|
* opened with O_DIRECT. buf must be aligned to 512 bytes then. |
|
* |
|
* This function may be called without alignment if the caller ensures |
|
* that O_DIRECT is not in effect. |
|
*/ |
|
static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, |
const uint8_t *buf, int count) |
const uint8_t *buf, int count) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BDRVRawState *s = bs->opaque; |
Line 202 static int raw_pwrite(BlockDriverState *
|
Line 252 static int raw_pwrite(BlockDriverState *
|
|
|
ret = fd_open(bs); |
ret = fd_open(bs); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return -errno; |
|
|
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { |
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { |
++(s->lseek_err_cnt); |
++(s->lseek_err_cnt); |
Line 212 static int raw_pwrite(BlockDriverState *
|
Line 262 static int raw_pwrite(BlockDriverState *
|
s->fd, bs->filename, offset, buf, count, |
s->fd, bs->filename, offset, buf, count, |
bs->total_sectors, errno, strerror(errno)); |
bs->total_sectors, errno, strerror(errno)); |
} |
} |
return -1; |
return -EIO; |
} |
} |
s->lseek_err_cnt = 0; |
s->lseek_err_cnt = 0; |
|
|
Line 227 static int raw_pwrite(BlockDriverState *
|
Line 277 static int raw_pwrite(BlockDriverState *
|
|
|
label__raw_write__success: |
label__raw_write__success: |
|
|
return ret; |
return (ret < 0) ? -errno : ret; |
} |
} |
|
|
/***********************************************************/ |
|
/* Unix AIO using POSIX AIO */ |
|
|
|
typedef struct RawAIOCB { |
/* |
BlockDriverAIOCB common; |
* offset and count are in bytes and possibly not aligned. For files opened |
struct aiocb aiocb; |
* with O_DIRECT, necessary alignments are ensured before calling |
struct RawAIOCB *next; |
* raw_pread_aligned to do the actual read. |
} RawAIOCB; |
*/ |
|
static int raw_pread(BlockDriverState *bs, int64_t offset, |
|
uint8_t *buf, int count) |
|
{ |
|
BDRVRawState *s = bs->opaque; |
|
int size, ret, shift, sum; |
|
|
static int aio_sig_num = SIGUSR2; |
sum = 0; |
static RawAIOCB *first_aio; /* AIO issued */ |
|
static int aio_initialized = 0; |
|
|
|
static void aio_signal_handler(int signum) |
if (s->aligned_buf != NULL) { |
{ |
|
#ifndef QEMU_IMG |
if (offset & 0x1ff) { |
CPUState *env = cpu_single_env; |
/* align offset on a 512 bytes boundary */ |
if (env) { |
|
/* stop the currently executing cpu because a timer occured */ |
shift = offset & 0x1ff; |
cpu_interrupt(env, CPU_INTERRUPT_EXIT); |
size = (shift + count + 0x1ff) & ~0x1ff; |
#ifdef USE_KQEMU |
if (size > ALIGNED_BUFFER_SIZE) |
if (env->kqemu_enabled) { |
size = ALIGNED_BUFFER_SIZE; |
kqemu_cpu_interrupt(env); |
ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size); |
|
if (ret < 0) |
|
return ret; |
|
|
|
size = 512 - shift; |
|
if (size > count) |
|
size = count; |
|
memcpy(buf, s->aligned_buf + shift, size); |
|
|
|
buf += size; |
|
offset += size; |
|
count -= size; |
|
sum += size; |
|
|
|
if (count == 0) |
|
return sum; |
|
} |
|
if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { |
|
|
|
/* read on aligned buffer */ |
|
|
|
while (count) { |
|
|
|
size = (count + 0x1ff) & ~0x1ff; |
|
if (size > ALIGNED_BUFFER_SIZE) |
|
size = ALIGNED_BUFFER_SIZE; |
|
|
|
ret = raw_pread_aligned(bs, offset, s->aligned_buf, size); |
|
if (ret < 0) |
|
return ret; |
|
|
|
size = ret; |
|
if (size > count) |
|
size = count; |
|
|
|
memcpy(buf, s->aligned_buf, size); |
|
|
|
buf += size; |
|
offset += size; |
|
count -= size; |
|
sum += size; |
|
} |
|
|
|
return sum; |
} |
} |
#endif |
|
} |
} |
#endif |
|
|
return raw_pread_aligned(bs, offset, buf, count) + sum; |
} |
} |
|
|
void qemu_aio_init(void) |
/* |
|
* offset and count are in bytes and possibly not aligned. For files opened |
|
* with O_DIRECT, necessary alignments are ensured before calling |
|
* raw_pwrite_aligned to do the actual write. |
|
*/ |
|
static int raw_pwrite(BlockDriverState *bs, int64_t offset, |
|
const uint8_t *buf, int count) |
{ |
{ |
struct sigaction act; |
BDRVRawState *s = bs->opaque; |
|
int size, ret, shift, sum; |
|
|
aio_initialized = 1; |
sum = 0; |
|
|
sigfillset(&act.sa_mask); |
if (s->aligned_buf != NULL) { |
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ |
|
act.sa_handler = aio_signal_handler; |
|
sigaction(aio_sig_num, &act, NULL); |
|
|
|
#if defined(__GLIBC__) && defined(__linux__) |
if (offset & 0x1ff) { |
{ |
/* align offset on a 512 bytes boundary */ |
/* XXX: aio thread exit seems to hang on RedHat 9 and this init |
shift = offset & 0x1ff; |
seems to fix the problem. */ |
ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, 512); |
struct aioinit ai; |
if (ret < 0) |
memset(&ai, 0, sizeof(ai)); |
return ret; |
ai.aio_threads = 1; |
|
ai.aio_num = 1; |
size = 512 - shift; |
ai.aio_idle_time = 365 * 100000; |
if (size > count) |
aio_init(&ai); |
size = count; |
|
memcpy(s->aligned_buf + shift, buf, size); |
|
|
|
ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, 512); |
|
if (ret < 0) |
|
return ret; |
|
|
|
buf += size; |
|
offset += size; |
|
count -= size; |
|
sum += size; |
|
|
|
if (count == 0) |
|
return sum; |
|
} |
|
if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { |
|
|
|
while ((size = (count & ~0x1ff)) != 0) { |
|
|
|
if (size > ALIGNED_BUFFER_SIZE) |
|
size = ALIGNED_BUFFER_SIZE; |
|
|
|
memcpy(s->aligned_buf, buf, size); |
|
|
|
ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size); |
|
if (ret < 0) |
|
return ret; |
|
|
|
buf += ret; |
|
offset += ret; |
|
count -= ret; |
|
sum += ret; |
|
} |
|
/* here, count < 512 because (count & ~0x1ff) == 0 */ |
|
if (count) { |
|
ret = raw_pread_aligned(bs, offset, s->aligned_buf, 512); |
|
if (ret < 0) |
|
return ret; |
|
memcpy(s->aligned_buf, buf, count); |
|
|
|
ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, 512); |
|
if (ret < 0) |
|
return ret; |
|
if (count < ret) |
|
ret = count; |
|
|
|
sum += ret; |
|
} |
|
return sum; |
|
} |
} |
} |
#endif |
return raw_pwrite_aligned(bs, offset, buf, count) + sum; |
} |
} |
|
|
void qemu_aio_poll(void) |
#ifdef CONFIG_AIO |
|
/***********************************************************/ |
|
/* Unix AIO using POSIX AIO */ |
|
|
|
typedef struct RawAIOCB { |
|
BlockDriverAIOCB common; |
|
struct qemu_paiocb aiocb; |
|
struct RawAIOCB *next; |
|
int ret; |
|
} RawAIOCB; |
|
|
|
typedef struct PosixAioState |
{ |
{ |
|
int rfd, wfd; |
|
RawAIOCB *first_aio; |
|
} PosixAioState; |
|
|
|
static void posix_aio_read(void *opaque) |
|
{ |
|
PosixAioState *s = opaque; |
RawAIOCB *acb, **pacb; |
RawAIOCB *acb, **pacb; |
int ret; |
int ret; |
|
ssize_t len; |
|
|
|
/* read all bytes from signal pipe */ |
|
for (;;) { |
|
char bytes[16]; |
|
|
|
len = read(s->rfd, bytes, sizeof(bytes)); |
|
if (len == -1 && errno == EINTR) |
|
continue; /* try again */ |
|
if (len == sizeof(bytes)) |
|
continue; /* more to read */ |
|
break; |
|
} |
|
|
for(;;) { |
for(;;) { |
pacb = &first_aio; |
pacb = &s->first_aio; |
for(;;) { |
for(;;) { |
acb = *pacb; |
acb = *pacb; |
if (!acb) |
if (!acb) |
goto the_end; |
goto the_end; |
ret = aio_error(&acb->aiocb); |
ret = qemu_paio_error(&acb->aiocb); |
if (ret == ECANCELED) { |
if (ret == ECANCELED) { |
/* remove the request */ |
/* remove the request */ |
*pacb = acb->next; |
*pacb = acb->next; |
Line 303 void qemu_aio_poll(void)
|
Line 481 void qemu_aio_poll(void)
|
} else if (ret != EINPROGRESS) { |
} else if (ret != EINPROGRESS) { |
/* end of aio */ |
/* end of aio */ |
if (ret == 0) { |
if (ret == 0) { |
ret = aio_return(&acb->aiocb); |
ret = qemu_paio_return(&acb->aiocb); |
if (ret == acb->aiocb.aio_nbytes) |
if (ret == acb->aiocb.aio_nbytes) |
ret = 0; |
ret = 0; |
else |
else |
Line 325 void qemu_aio_poll(void)
|
Line 503 void qemu_aio_poll(void)
|
the_end: ; |
the_end: ; |
} |
} |
|
|
/* Wait for all IO requests to complete. */ |
static int posix_aio_flush(void *opaque) |
void qemu_aio_flush(void) |
|
{ |
{ |
qemu_aio_wait_start(); |
PosixAioState *s = opaque; |
qemu_aio_poll(); |
return !!s->first_aio; |
while (first_aio) { |
|
qemu_aio_wait(); |
|
} |
|
qemu_aio_wait_end(); |
|
} |
} |
|
|
/* wait until at least one AIO was handled */ |
static PosixAioState *posix_aio_state; |
static sigset_t wait_oset; |
|
|
|
void qemu_aio_wait_start(void) |
static void aio_signal_handler(int signum) |
{ |
{ |
sigset_t set; |
if (posix_aio_state) { |
|
char byte = 0; |
|
|
if (!aio_initialized) |
write(posix_aio_state->wfd, &byte, sizeof(byte)); |
qemu_aio_init(); |
} |
sigemptyset(&set); |
|
sigaddset(&set, aio_sig_num); |
qemu_service_io(); |
sigprocmask(SIG_BLOCK, &set, &wait_oset); |
|
} |
} |
|
|
void qemu_aio_wait(void) |
static int posix_aio_init(void) |
{ |
{ |
sigset_t set; |
struct sigaction act; |
int nb_sigs; |
PosixAioState *s; |
|
int fds[2]; |
|
struct qemu_paioinit ai; |
|
|
|
if (posix_aio_state) |
|
return 0; |
|
|
#ifndef QEMU_IMG |
s = qemu_malloc(sizeof(PosixAioState)); |
if (qemu_bh_poll()) |
|
return; |
|
#endif |
|
sigemptyset(&set); |
|
sigaddset(&set, aio_sig_num); |
|
sigwait(&set, &nb_sigs); |
|
qemu_aio_poll(); |
|
} |
|
|
|
void qemu_aio_wait_end(void) |
sigfillset(&act.sa_mask); |
{ |
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ |
sigprocmask(SIG_SETMASK, &wait_oset, NULL); |
act.sa_handler = aio_signal_handler; |
|
sigaction(SIGUSR2, &act, NULL); |
|
|
|
s->first_aio = NULL; |
|
if (pipe(fds) == -1) { |
|
fprintf(stderr, "failed to create pipe\n"); |
|
return -errno; |
|
} |
|
|
|
s->rfd = fds[0]; |
|
s->wfd = fds[1]; |
|
|
|
fcntl(s->rfd, F_SETFL, O_NONBLOCK); |
|
fcntl(s->wfd, F_SETFL, O_NONBLOCK); |
|
|
|
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s); |
|
|
|
memset(&ai, 0, sizeof(ai)); |
|
ai.aio_threads = 64; |
|
ai.aio_num = 64; |
|
qemu_paio_init(&ai); |
|
|
|
posix_aio_state = s; |
|
|
|
return 0; |
} |
} |
|
|
static RawAIOCB *raw_aio_setup(BlockDriverState *bs, |
static RawAIOCB *raw_aio_setup(BlockDriverState *bs, |
Line 384 static RawAIOCB *raw_aio_setup(BlockDriv
|
Line 577 static RawAIOCB *raw_aio_setup(BlockDriv
|
if (!acb) |
if (!acb) |
return NULL; |
return NULL; |
acb->aiocb.aio_fildes = s->fd; |
acb->aiocb.aio_fildes = s->fd; |
acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num; |
acb->aiocb.ev_signo = SIGUSR2; |
acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; |
|
acb->aiocb.aio_buf = buf; |
acb->aiocb.aio_buf = buf; |
if (nb_sectors < 0) |
if (nb_sectors < 0) |
acb->aiocb.aio_nbytes = -nb_sectors; |
acb->aiocb.aio_nbytes = -nb_sectors; |
else |
else |
acb->aiocb.aio_nbytes = nb_sectors * 512; |
acb->aiocb.aio_nbytes = nb_sectors * 512; |
acb->aiocb.aio_offset = sector_num * 512; |
acb->aiocb.aio_offset = sector_num * 512; |
acb->next = first_aio; |
acb->next = posix_aio_state->first_aio; |
first_aio = acb; |
posix_aio_state->first_aio = acb; |
return acb; |
return acb; |
} |
} |
|
|
|
static void raw_aio_em_cb(void* opaque) |
|
{ |
|
RawAIOCB *acb = opaque; |
|
acb->common.cb(acb->common.opaque, acb->ret); |
|
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, |
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, |
int64_t sector_num, uint8_t *buf, int nb_sectors, |
int64_t sector_num, uint8_t *buf, int nb_sectors, |
BlockDriverCompletionFunc *cb, void *opaque) |
BlockDriverCompletionFunc *cb, void *opaque) |
{ |
{ |
RawAIOCB *acb; |
RawAIOCB *acb; |
|
|
|
/* |
|
* If O_DIRECT is used and the buffer is not aligned fall back |
|
* to synchronous IO. |
|
*/ |
|
BDRVRawState *s = bs->opaque; |
|
|
|
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) { |
|
QEMUBH *bh; |
|
acb = qemu_aio_get(bs, cb, opaque); |
|
acb->ret = raw_pread(bs, 512 * sector_num, buf, 512 * nb_sectors); |
|
bh = qemu_bh_new(raw_aio_em_cb, acb); |
|
qemu_bh_schedule(bh); |
|
return &acb->common; |
|
} |
|
|
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); |
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); |
if (!acb) |
if (!acb) |
return NULL; |
return NULL; |
if (aio_read(&acb->aiocb) < 0) { |
if (qemu_paio_read(&acb->aiocb) < 0) { |
qemu_aio_release(acb); |
raw_aio_remove(acb); |
return NULL; |
return NULL; |
} |
} |
return &acb->common; |
return &acb->common; |
Line 419 static BlockDriverAIOCB *raw_aio_write(B
|
Line 652 static BlockDriverAIOCB *raw_aio_write(B
|
{ |
{ |
RawAIOCB *acb; |
RawAIOCB *acb; |
|
|
|
/* |
|
* If O_DIRECT is used and the buffer is not aligned fall back |
|
* to synchronous IO. |
|
*/ |
|
BDRVRawState *s = bs->opaque; |
|
|
|
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) { |
|
QEMUBH *bh; |
|
acb = qemu_aio_get(bs, cb, opaque); |
|
acb->ret = raw_pwrite(bs, 512 * sector_num, buf, 512 * nb_sectors); |
|
bh = qemu_bh_new(raw_aio_em_cb, acb); |
|
qemu_bh_schedule(bh); |
|
return &acb->common; |
|
} |
|
|
acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); |
acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); |
if (!acb) |
if (!acb) |
return NULL; |
return NULL; |
if (aio_write(&acb->aiocb) < 0) { |
if (qemu_paio_write(&acb->aiocb) < 0) { |
qemu_aio_release(acb); |
raw_aio_remove(acb); |
return NULL; |
return NULL; |
} |
} |
return &acb->common; |
return &acb->common; |
Line 433 static void raw_aio_cancel(BlockDriverAI
|
Line 681 static void raw_aio_cancel(BlockDriverAI
|
{ |
{ |
int ret; |
int ret; |
RawAIOCB *acb = (RawAIOCB *)blockacb; |
RawAIOCB *acb = (RawAIOCB *)blockacb; |
RawAIOCB **pacb; |
|
|
|
ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); |
ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); |
if (ret == AIO_NOTCANCELED) { |
if (ret == QEMU_PAIO_NOTCANCELED) { |
/* fail safe: if the aio could not be canceled, we wait for |
/* fail safe: if the aio could not be canceled, we wait for |
it */ |
it */ |
while (aio_error(&acb->aiocb) == EINPROGRESS); |
while (qemu_paio_error(&acb->aiocb) == EINPROGRESS); |
} |
} |
|
|
/* remove the callback from the queue */ |
raw_aio_remove(acb); |
pacb = &first_aio; |
} |
for(;;) { |
#else /* CONFIG_AIO */ |
if (*pacb == NULL) { |
static int posix_aio_init(void) |
break; |
{ |
} else if (*pacb == acb) { |
return 0; |
*pacb = acb->next; |
|
qemu_aio_release(acb); |
|
break; |
|
} |
|
pacb = &acb->next; |
|
} |
|
} |
} |
|
#endif /* CONFIG_AIO */ |
|
|
|
|
static void raw_close(BlockDriverState *bs) |
static void raw_close(BlockDriverState *bs) |
{ |
{ |
Line 462 static void raw_close(BlockDriverState *
|
Line 705 static void raw_close(BlockDriverState *
|
if (s->fd >= 0) { |
if (s->fd >= 0) { |
close(s->fd); |
close(s->fd); |
s->fd = -1; |
s->fd = -1; |
|
if (s->aligned_buf != NULL) |
|
qemu_free(s->aligned_buf); |
} |
} |
} |
} |
|
|
Line 475 static int raw_truncate(BlockDriverState
|
Line 720 static int raw_truncate(BlockDriverState
|
return 0; |
return 0; |
} |
} |
|
|
|
#ifdef __OpenBSD__ |
|
static int64_t raw_getlength(BlockDriverState *bs) |
|
{ |
|
BDRVRawState *s = bs->opaque; |
|
int fd = s->fd; |
|
struct stat st; |
|
|
|
if (fstat(fd, &st)) |
|
return -1; |
|
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { |
|
struct disklabel dl; |
|
|
|
if (ioctl(fd, DIOCGDINFO, &dl)) |
|
return -1; |
|
return (uint64_t)dl.d_secsize * |
|
dl.d_partitions[DISKPART(st.st_rdev)].p_size; |
|
} else |
|
return st.st_size; |
|
} |
|
#else /* !__OpenBSD__ */ |
static int64_t raw_getlength(BlockDriverState *bs) |
static int64_t raw_getlength(BlockDriverState *bs) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BDRVRawState *s = bs->opaque; |
Line 521 static int64_t raw_getlength(BlockDrive
|
Line 786 static int64_t raw_getlength(BlockDrive
|
} |
} |
return size; |
return size; |
} |
} |
|
#endif |
|
|
static int raw_create(const char *filename, int64_t total_size, |
static int raw_create(const char *filename, int64_t total_size, |
const char *backing_file, int flags) |
const char *backing_file, int flags) |
Line 556 BlockDriver bdrv_raw = {
|
Line 822 BlockDriver bdrv_raw = {
|
raw_create, |
raw_create, |
raw_flush, |
raw_flush, |
|
|
|
#ifdef CONFIG_AIO |
.bdrv_aio_read = raw_aio_read, |
.bdrv_aio_read = raw_aio_read, |
.bdrv_aio_write = raw_aio_write, |
.bdrv_aio_write = raw_aio_write, |
.bdrv_aio_cancel = raw_aio_cancel, |
.bdrv_aio_cancel = raw_aio_cancel, |
.aiocb_size = sizeof(RawAIOCB), |
.aiocb_size = sizeof(RawAIOCB), |
.protocol_name = "file", |
#endif |
|
|
.bdrv_pread = raw_pread, |
.bdrv_pread = raw_pread, |
.bdrv_pwrite = raw_pwrite, |
.bdrv_pwrite = raw_pwrite, |
.bdrv_truncate = raw_truncate, |
.bdrv_truncate = raw_truncate, |
Line 633 static int hdev_open(BlockDriverState *b
|
Line 901 static int hdev_open(BlockDriverState *b
|
BDRVRawState *s = bs->opaque; |
BDRVRawState *s = bs->opaque; |
int fd, open_flags, ret; |
int fd, open_flags, ret; |
|
|
|
posix_aio_init(); |
|
|
#ifdef CONFIG_COCOA |
#ifdef CONFIG_COCOA |
if (strstart(filename, "/dev/cdrom", NULL)) { |
if (strstart(filename, "/dev/cdrom", NULL)) { |
kern_return_t kernResult; |
kern_return_t kernResult; |
Line 666 static int hdev_open(BlockDriverState *b
|
Line 936 static int hdev_open(BlockDriverState *b
|
open_flags |= O_RDONLY; |
open_flags |= O_RDONLY; |
bs->read_only = 1; |
bs->read_only = 1; |
} |
} |
#ifdef O_DIRECT |
/* Use O_DSYNC for write-through caching, no flags for write-back caching, |
if (flags & BDRV_O_DIRECT) |
* and O_DIRECT for no caching. */ |
|
if ((flags & BDRV_O_NOCACHE)) |
open_flags |= O_DIRECT; |
open_flags |= O_DIRECT; |
#endif |
else if (!(flags & BDRV_O_CACHE_WB)) |
|
open_flags |= O_DSYNC; |
|
|
s->type = FTYPE_FILE; |
s->type = FTYPE_FILE; |
#if defined(__linux__) |
#if defined(__linux__) |
Line 705 static int hdev_open(BlockDriverState *b
|
Line 977 static int hdev_open(BlockDriverState *b
|
return 0; |
return 0; |
} |
} |
|
|
#if defined(__linux__) && !defined(QEMU_IMG) |
#if defined(__linux__) |
|
|
/* Note: we do not have a reliable method to detect if the floppy is |
/* 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 |
present. The current method is to try to open the floppy at every |
I/O and to keep it opened during a few hundreds of ms. */ |
I/O and to keep it opened during a few hundreds of ms. */ |
Line 755 static int fd_open(BlockDriverState *bs)
|
Line 1026 static int fd_open(BlockDriverState *bs)
|
s->fd_got_error = 0; |
s->fd_got_error = 0; |
return 0; |
return 0; |
} |
} |
#else |
|
static int fd_open(BlockDriverState *bs) |
|
{ |
|
return 0; |
|
} |
|
#endif |
|
|
|
#if defined(__linux__) |
|
|
|
static int raw_is_inserted(BlockDriverState *bs) |
static int raw_is_inserted(BlockDriverState *bs) |
{ |
{ |
Line 871 static int raw_ioctl(BlockDriverState *b
|
Line 1134 static int raw_ioctl(BlockDriverState *b
|
} |
} |
#else |
#else |
|
|
|
static int fd_open(BlockDriverState *bs) |
|
{ |
|
return 0; |
|
} |
|
|
static int raw_is_inserted(BlockDriverState *bs) |
static int raw_is_inserted(BlockDriverState *bs) |
{ |
{ |
return 1; |
return 1; |
Line 908 BlockDriver bdrv_host_device = {
|
Line 1176 BlockDriver bdrv_host_device = {
|
NULL, |
NULL, |
raw_flush, |
raw_flush, |
|
|
|
#ifdef CONFIG_AIO |
.bdrv_aio_read = raw_aio_read, |
.bdrv_aio_read = raw_aio_read, |
.bdrv_aio_write = raw_aio_write, |
.bdrv_aio_write = raw_aio_write, |
.bdrv_aio_cancel = raw_aio_cancel, |
.bdrv_aio_cancel = raw_aio_cancel, |
.aiocb_size = sizeof(RawAIOCB), |
.aiocb_size = sizeof(RawAIOCB), |
|
#endif |
|
|
.bdrv_pread = raw_pread, |
.bdrv_pread = raw_pread, |
.bdrv_pwrite = raw_pwrite, |
.bdrv_pwrite = raw_pwrite, |
.bdrv_getlength = raw_getlength, |
.bdrv_getlength = raw_getlength, |