mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-07 05:47:40 +00:00
Merge remote-tracking branch 'kwolf/for-anthony' into staging
This commit is contained in:
commit
c8af89af96
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
typedef struct BDRVNBDState {
|
typedef struct BDRVNBDState {
|
||||||
int sock;
|
int sock;
|
||||||
|
uint32_t nbdflags;
|
||||||
off_t size;
|
off_t size;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
char *export_name; /* An NBD server may export several devices */
|
char *export_name; /* An NBD server may export several devices */
|
||||||
@ -111,7 +112,6 @@ static int nbd_establish_connection(BlockDriverState *bs)
|
|||||||
int ret;
|
int ret;
|
||||||
off_t size;
|
off_t size;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
uint32_t nbdflags;
|
|
||||||
|
|
||||||
if (s->host_spec[0] == '/') {
|
if (s->host_spec[0] == '/') {
|
||||||
sock = unix_socket_outgoing(s->host_spec);
|
sock = unix_socket_outgoing(s->host_spec);
|
||||||
@ -126,7 +126,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NBD handshake */
|
/* NBD handshake */
|
||||||
ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
|
ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
|
||||||
&blocksize);
|
&blocksize);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
logout("Failed to negotiate with the NBD server\n");
|
logout("Failed to negotiate with the NBD server\n");
|
||||||
|
@ -839,7 +839,14 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
|
|||||||
static int raw_flush(BlockDriverState *bs)
|
static int raw_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
return qemu_fdatasync(s->fd);
|
int ret;
|
||||||
|
|
||||||
|
ret = qemu_fdatasync(s->fd);
|
||||||
|
if (ret < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
|
83
block/rbd.c
83
block/rbd.c
@ -13,35 +13,33 @@
|
|||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu-error.h"
|
#include "qemu-error.h"
|
||||||
|
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
#include <rbd/librbd.h>
|
#include <rbd/librbd.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When specifying the image filename use:
|
* When specifying the image filename use:
|
||||||
*
|
*
|
||||||
* rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
|
* rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
|
||||||
*
|
*
|
||||||
* poolname must be the name of an existing rados pool
|
* poolname must be the name of an existing rados pool.
|
||||||
*
|
*
|
||||||
* devicename is the basename for all objects used to
|
* devicename is the name of the rbd image.
|
||||||
* emulate the raw device.
|
|
||||||
*
|
*
|
||||||
* Each option given is used to configure rados, and may be
|
* Each option given is used to configure rados, and may be any valid
|
||||||
* any Ceph option, or "conf". The "conf" option specifies
|
* Ceph option, "id", or "conf".
|
||||||
* a Ceph configuration file to read.
|
|
||||||
*
|
*
|
||||||
* Metadata information (image size, ...) is stored in an
|
* The "id" option indicates what user we should authenticate as to
|
||||||
* object with the name "devicename.rbd".
|
* the Ceph cluster. If it is excluded we will use the Ceph default
|
||||||
|
* (normally 'admin').
|
||||||
*
|
*
|
||||||
* The raw device is split into 4MB sized objects by default.
|
* The "conf" option specifies a Ceph configuration file to read. If
|
||||||
* The sequencenumber is encoded in a 12 byte long hex-string,
|
* it is not specified, we will read from the default Ceph locations
|
||||||
* and is attached to the devicename, separated by a dot.
|
* (e.g., /etc/ceph/ceph.conf). To avoid reading _any_ configuration
|
||||||
* e.g. "devicename.1234567890ab"
|
* file, specify conf=/dev/null.
|
||||||
*
|
*
|
||||||
|
* Configuration values containing :, @, or = can be escaped with a
|
||||||
|
* leading "\".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
|
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
|
||||||
@ -104,8 +102,15 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
|
|||||||
*p = NULL;
|
*p = NULL;
|
||||||
|
|
||||||
if (delim != '\0') {
|
if (delim != '\0') {
|
||||||
end = strchr(src, delim);
|
for (end = src; *end; ++end) {
|
||||||
if (end) {
|
if (*end == delim) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*end == '\\' && end[1] != '\0') {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*end == delim) {
|
||||||
*p = end + 1;
|
*p = end + 1;
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
}
|
}
|
||||||
@ -124,6 +129,19 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qemu_rbd_unescape(char *src)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for (p = src; *src; ++src, ++p) {
|
||||||
|
if (*src == '\\' && src[1] != '\0') {
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
*p = *src;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
static int qemu_rbd_parsename(const char *filename,
|
static int qemu_rbd_parsename(const char *filename,
|
||||||
char *pool, int pool_len,
|
char *pool, int pool_len,
|
||||||
char *snap, int snap_len,
|
char *snap, int snap_len,
|
||||||
@ -148,6 +166,7 @@ static int qemu_rbd_parsename(const char *filename,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
qemu_rbd_unescape(pool);
|
||||||
|
|
||||||
if (strchr(p, '@')) {
|
if (strchr(p, '@')) {
|
||||||
ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
|
ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
|
||||||
@ -155,9 +174,11 @@ static int qemu_rbd_parsename(const char *filename,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
|
ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
|
||||||
|
qemu_rbd_unescape(snap);
|
||||||
} else {
|
} else {
|
||||||
ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
|
ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
|
||||||
}
|
}
|
||||||
|
qemu_rbd_unescape(name);
|
||||||
if (ret < 0 || !p) {
|
if (ret < 0 || !p) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -213,6 +234,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
qemu_rbd_unescape(name);
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
error_report("conf option %s has no value", name);
|
error_report("conf option %s has no value", name);
|
||||||
@ -225,6 +247,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
qemu_rbd_unescape(value);
|
||||||
|
|
||||||
if (strcmp(name, "conf") == 0) {
|
if (strcmp(name, "conf") == 0) {
|
||||||
ret = rados_conf_read_file(cluster, value);
|
ret = rados_conf_read_file(cluster, value);
|
||||||
@ -298,11 +321,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(conf, "conf=") == NULL) {
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
if (rados_conf_read_file(cluster, NULL) < 0) {
|
/* try default location, but ignore failure */
|
||||||
error_report("error reading config file");
|
rados_conf_read_file(cluster, NULL);
|
||||||
rados_shutdown(cluster);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf[0] != '\0' &&
|
if (conf[0] != '\0' &&
|
||||||
@ -441,11 +461,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(conf, "conf=") == NULL) {
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
r = rados_conf_read_file(s->cluster, NULL);
|
/* try default location, but ignore failure */
|
||||||
if (r < 0) {
|
rados_conf_read_file(s->cluster, NULL);
|
||||||
error_report("error reading config file");
|
|
||||||
goto failed_shutdown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf[0] != '\0') {
|
if (conf[0] != '\0') {
|
||||||
@ -688,6 +705,17 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
|||||||
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
|
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qemu_rbd_flush(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
|
||||||
|
/* rbd_flush added in 0.1.1 */
|
||||||
|
BDRVRBDState *s = bs->opaque;
|
||||||
|
return rbd_flush(s->image);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
{
|
{
|
||||||
BDRVRBDState *s = bs->opaque;
|
BDRVRBDState *s = bs->opaque;
|
||||||
@ -823,6 +851,7 @@ static BlockDriver bdrv_rbd = {
|
|||||||
.bdrv_file_open = qemu_rbd_open,
|
.bdrv_file_open = qemu_rbd_open,
|
||||||
.bdrv_close = qemu_rbd_close,
|
.bdrv_close = qemu_rbd_close,
|
||||||
.bdrv_create = qemu_rbd_create,
|
.bdrv_create = qemu_rbd_create,
|
||||||
|
.bdrv_flush = qemu_rbd_flush,
|
||||||
.bdrv_get_info = qemu_rbd_getinfo,
|
.bdrv_get_info = qemu_rbd_getinfo,
|
||||||
.create_options = qemu_rbd_create_options,
|
.create_options = qemu_rbd_create_options,
|
||||||
.bdrv_getlength = qemu_rbd_getlength,
|
.bdrv_getlength = qemu_rbd_getlength,
|
||||||
|
14
block/vmdk.c
14
block/vmdk.c
@ -179,11 +179,16 @@ static void vmdk_free_extents(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
VmdkExtent *e;
|
||||||
|
|
||||||
for (i = 0; i < s->num_extents; i++) {
|
for (i = 0; i < s->num_extents; i++) {
|
||||||
g_free(s->extents[i].l1_table);
|
e = &s->extents[i];
|
||||||
g_free(s->extents[i].l2_cache);
|
g_free(e->l1_table);
|
||||||
g_free(s->extents[i].l1_backup_table);
|
g_free(e->l2_cache);
|
||||||
|
g_free(e->l1_backup_table);
|
||||||
|
if (e->file != bs->file) {
|
||||||
|
bdrv_delete(e->file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_free(s->extents);
|
g_free(s->extents);
|
||||||
}
|
}
|
||||||
@ -619,12 +624,13 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
|||||||
s->desc_offset = 0;
|
s->desc_offset = 0;
|
||||||
ret = vmdk_parse_extents(buf, bs, bs->file->filename);
|
ret = vmdk_parse_extents(buf, bs, bs->file->filename);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
vmdk_free_extents(bs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to open parent images, if exist */
|
/* try to open parent images, if exist */
|
||||||
if (vmdk_parent_open(bs)) {
|
if (vmdk_parent_open(bs)) {
|
||||||
g_free(s->extents);
|
vmdk_free_extents(bs);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->parent_cid = vmdk_read_cid(bs, 1);
|
s->parent_cid = vmdk_read_cid(bs, 1);
|
||||||
|
5
cpus.c
5
cpus.c
@ -380,11 +380,6 @@ static int qemu_signal_init(void)
|
|||||||
int sigfd;
|
int sigfd;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
|
||||||
/* SIGUSR2 used by posix-aio-compat.c */
|
|
||||||
sigemptyset(&set);
|
|
||||||
sigaddset(&set, SIGUSR2);
|
|
||||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIG_IPI must be blocked in the main thread and must not be caught
|
* SIG_IPI must be blocked in the main thread and must not be caught
|
||||||
* by sigwait() in the signal thread. Otherwise, the cpu thread will
|
* by sigwait() in the signal thread. Otherwise, the cpu thread will
|
||||||
|
@ -42,7 +42,8 @@ typedef struct {
|
|||||||
BlockDriverAIOCB *acb;
|
BlockDriverAIOCB *acb;
|
||||||
QEMUSGList *sg;
|
QEMUSGList *sg;
|
||||||
uint64_t sector_num;
|
uint64_t sector_num;
|
||||||
int is_write;
|
bool to_dev;
|
||||||
|
bool in_cancel;
|
||||||
int sg_cur_index;
|
int sg_cur_index;
|
||||||
target_phys_addr_t sg_cur_byte;
|
target_phys_addr_t sg_cur_byte;
|
||||||
QEMUIOVector iov;
|
QEMUIOVector iov;
|
||||||
@ -58,7 +59,7 @@ static void reschedule_dma(void *opaque)
|
|||||||
|
|
||||||
qemu_bh_delete(dbs->bh);
|
qemu_bh_delete(dbs->bh);
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
dma_bdrv_cb(opaque, 0);
|
dma_bdrv_cb(dbs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void continue_after_map_failure(void *opaque)
|
static void continue_after_map_failure(void *opaque)
|
||||||
@ -75,9 +76,29 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
|
|||||||
|
|
||||||
for (i = 0; i < dbs->iov.niov; ++i) {
|
for (i = 0; i < dbs->iov.niov; ++i) {
|
||||||
cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
|
cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
|
||||||
dbs->iov.iov[i].iov_len, !dbs->is_write,
|
dbs->iov.iov[i].iov_len, !dbs->to_dev,
|
||||||
dbs->iov.iov[i].iov_len);
|
dbs->iov.iov[i].iov_len);
|
||||||
}
|
}
|
||||||
|
qemu_iovec_reset(&dbs->iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_complete(DMAAIOCB *dbs, int ret)
|
||||||
|
{
|
||||||
|
dma_bdrv_unmap(dbs);
|
||||||
|
if (dbs->common.cb) {
|
||||||
|
dbs->common.cb(dbs->common.opaque, ret);
|
||||||
|
}
|
||||||
|
qemu_iovec_destroy(&dbs->iov);
|
||||||
|
if (dbs->bh) {
|
||||||
|
qemu_bh_delete(dbs->bh);
|
||||||
|
dbs->bh = NULL;
|
||||||
|
}
|
||||||
|
if (!dbs->in_cancel) {
|
||||||
|
/* Requests may complete while dma_aio_cancel is in progress. In
|
||||||
|
* this case, the AIOCB should not be released because it is still
|
||||||
|
* referenced by dma_aio_cancel. */
|
||||||
|
qemu_aio_release(dbs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_bdrv_cb(void *opaque, int ret)
|
static void dma_bdrv_cb(void *opaque, int ret)
|
||||||
@ -89,19 +110,16 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
|||||||
dbs->acb = NULL;
|
dbs->acb = NULL;
|
||||||
dbs->sector_num += dbs->iov.size / 512;
|
dbs->sector_num += dbs->iov.size / 512;
|
||||||
dma_bdrv_unmap(dbs);
|
dma_bdrv_unmap(dbs);
|
||||||
qemu_iovec_reset(&dbs->iov);
|
|
||||||
|
|
||||||
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
|
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
|
||||||
dbs->common.cb(dbs->common.opaque, ret);
|
dma_complete(dbs, ret);
|
||||||
qemu_iovec_destroy(&dbs->iov);
|
|
||||||
qemu_aio_release(dbs);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
||||||
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
||||||
cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
|
cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
|
||||||
mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
|
mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->to_dev);
|
||||||
if (!mem)
|
if (!mem)
|
||||||
break;
|
break;
|
||||||
qemu_iovec_add(&dbs->iov, mem, cur_len);
|
qemu_iovec_add(&dbs->iov, mem, cur_len);
|
||||||
@ -120,9 +138,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
|||||||
dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
|
dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
|
||||||
dbs->iov.size / 512, dma_bdrv_cb, dbs);
|
dbs->iov.size / 512, dma_bdrv_cb, dbs);
|
||||||
if (!dbs->acb) {
|
if (!dbs->acb) {
|
||||||
dma_bdrv_unmap(dbs);
|
dma_complete(dbs, -EIO);
|
||||||
qemu_iovec_destroy(&dbs->iov);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +147,14 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
|
|||||||
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
|
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
|
||||||
|
|
||||||
if (dbs->acb) {
|
if (dbs->acb) {
|
||||||
bdrv_aio_cancel(dbs->acb);
|
BlockDriverAIOCB *acb = dbs->acb;
|
||||||
|
dbs->acb = NULL;
|
||||||
|
dbs->in_cancel = true;
|
||||||
|
bdrv_aio_cancel(acb);
|
||||||
|
dbs->in_cancel = false;
|
||||||
}
|
}
|
||||||
|
dbs->common.cb = NULL;
|
||||||
|
dma_complete(dbs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AIOPool dma_aio_pool = {
|
static AIOPool dma_aio_pool = {
|
||||||
@ -143,7 +165,7 @@ static AIOPool dma_aio_pool = {
|
|||||||
BlockDriverAIOCB *dma_bdrv_io(
|
BlockDriverAIOCB *dma_bdrv_io(
|
||||||
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
|
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
|
||||||
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
||||||
void *opaque, int is_write)
|
void *opaque, bool to_dev)
|
||||||
{
|
{
|
||||||
DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
|
DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
|
||||||
|
|
||||||
@ -153,15 +175,11 @@ BlockDriverAIOCB *dma_bdrv_io(
|
|||||||
dbs->sector_num = sector_num;
|
dbs->sector_num = sector_num;
|
||||||
dbs->sg_cur_index = 0;
|
dbs->sg_cur_index = 0;
|
||||||
dbs->sg_cur_byte = 0;
|
dbs->sg_cur_byte = 0;
|
||||||
dbs->is_write = is_write;
|
dbs->to_dev = to_dev;
|
||||||
dbs->io_func = io_func;
|
dbs->io_func = io_func;
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||||
dma_bdrv_cb(dbs, 0);
|
dma_bdrv_cb(dbs, 0);
|
||||||
if (!dbs->acb) {
|
|
||||||
qemu_aio_release(dbs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &dbs->common;
|
return &dbs->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,12 +188,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
|
|||||||
QEMUSGList *sg, uint64_t sector,
|
QEMUSGList *sg, uint64_t sector,
|
||||||
void (*cb)(void *opaque, int ret), void *opaque)
|
void (*cb)(void *opaque, int ret), void *opaque)
|
||||||
{
|
{
|
||||||
return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0);
|
return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
|
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
|
||||||
QEMUSGList *sg, uint64_t sector,
|
QEMUSGList *sg, uint64_t sector,
|
||||||
void (*cb)(void *opaque, int ret), void *opaque)
|
void (*cb)(void *opaque, int ret), void *opaque)
|
||||||
{
|
{
|
||||||
return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1);
|
return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true);
|
||||||
}
|
}
|
||||||
|
10
dma.h
10
dma.h
@ -15,10 +15,13 @@
|
|||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct ScatterGatherEntry ScatterGatherEntry;
|
||||||
|
|
||||||
|
#if defined(TARGET_PHYS_ADDR_BITS)
|
||||||
|
struct ScatterGatherEntry {
|
||||||
target_phys_addr_t base;
|
target_phys_addr_t base;
|
||||||
target_phys_addr_t len;
|
target_phys_addr_t len;
|
||||||
} ScatterGatherEntry;
|
};
|
||||||
|
|
||||||
struct QEMUSGList {
|
struct QEMUSGList {
|
||||||
ScatterGatherEntry *sg;
|
ScatterGatherEntry *sg;
|
||||||
@ -31,6 +34,7 @@ void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
|
|||||||
void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
|
void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
|
||||||
target_phys_addr_t len);
|
target_phys_addr_t len);
|
||||||
void qemu_sglist_destroy(QEMUSGList *qsg);
|
void qemu_sglist_destroy(QEMUSGList *qsg);
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
|
typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
|
||||||
QEMUIOVector *iov, int nb_sectors,
|
QEMUIOVector *iov, int nb_sectors,
|
||||||
@ -39,7 +43,7 @@ typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
|
|||||||
BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
|
BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
|
||||||
QEMUSGList *sg, uint64_t sector_num,
|
QEMUSGList *sg, uint64_t sector_num,
|
||||||
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
||||||
void *opaque, int is_write);
|
void *opaque, bool to_dev);
|
||||||
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
|
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
|
||||||
QEMUSGList *sg, uint64_t sector,
|
QEMUSGList *sg, uint64_t sector,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
BlockDriverCompletionFunc *cb, void *opaque);
|
||||||
|
@ -499,10 +499,7 @@ static void ahci_reset_port(AHCIState *s, int port)
|
|||||||
ide_bus_reset(&d->port);
|
ide_bus_reset(&d->port);
|
||||||
ide_state->ncq_queues = AHCI_MAX_CMDS;
|
ide_state->ncq_queues = AHCI_MAX_CMDS;
|
||||||
|
|
||||||
pr->irq_stat = 0;
|
|
||||||
pr->irq_mask = 0;
|
|
||||||
pr->scr_stat = 0;
|
pr->scr_stat = 0;
|
||||||
pr->scr_ctl = 0;
|
|
||||||
pr->scr_err = 0;
|
pr->scr_err = 0;
|
||||||
pr->scr_act = 0;
|
pr->scr_act = 0;
|
||||||
d->busy_slot = -1;
|
d->busy_slot = -1;
|
||||||
@ -1159,12 +1156,17 @@ void ahci_uninit(AHCIState *s)
|
|||||||
void ahci_reset(void *opaque)
|
void ahci_reset(void *opaque)
|
||||||
{
|
{
|
||||||
struct AHCIPCIState *d = opaque;
|
struct AHCIPCIState *d = opaque;
|
||||||
|
AHCIPortRegs *pr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
d->ahci.control_regs.irqstatus = 0;
|
d->ahci.control_regs.irqstatus = 0;
|
||||||
d->ahci.control_regs.ghc = 0;
|
d->ahci.control_regs.ghc = 0;
|
||||||
|
|
||||||
for (i = 0; i < d->ahci.ports; i++) {
|
for (i = 0; i < d->ahci.ports; i++) {
|
||||||
|
pr = &d->ahci.dev[i].port_regs;
|
||||||
|
pr->irq_stat = 0;
|
||||||
|
pr->irq_mask = 0;
|
||||||
|
pr->scr_ctl = 0;
|
||||||
ahci_reset_port(&d->ahci, i);
|
ahci_reset_port(&d->ahci, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,7 @@ handle_rw_error:
|
|||||||
break;
|
break;
|
||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
|
s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
|
||||||
ide_issue_trim, ide_dma_cb, s, 1);
|
ide_issue_trim, ide_dma_cb, s, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||||||
break;
|
break;
|
||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
|
m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
|
||||||
ide_issue_trim, pmac_ide_transfer_cb, s, 1);
|
ide_issue_trim, pmac_ide_transfer_cb, s, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,15 +542,15 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
cmd->xfer = buf[8] | (buf[7] << 8);
|
cmd->xfer = lduw_be_p(&buf[7]);
|
||||||
cmd->len = 10;
|
cmd->len = 10;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
cmd->xfer = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
|
cmd->xfer = ldl_be_p(&buf[10]);
|
||||||
cmd->len = 16;
|
cmd->len = 16;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
|
cmd->xfer = ldl_be_p(&buf[6]);
|
||||||
cmd->len = 12;
|
cmd->len = 12;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -710,23 +710,15 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
|||||||
|
|
||||||
switch (buf[0] >> 5) {
|
switch (buf[0] >> 5) {
|
||||||
case 0:
|
case 0:
|
||||||
lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
|
lba = ldl_be_p(&buf[0]) & 0x1fffff;
|
||||||
(((uint64_t) buf[1] & 0x1f) << 16);
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
|
case 5:
|
||||||
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
|
lba = ldl_be_p(&buf[2]);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
|
lba = ldq_be_p(&buf[2]);
|
||||||
((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
|
|
||||||
((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
|
|
||||||
((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
|
|
||||||
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lba = -1;
|
lba = -1;
|
||||||
|
@ -55,6 +55,7 @@ typedef struct SCSIDiskReq {
|
|||||||
/* Both sector and sector_count are in terms of qemu 512 byte blocks. */
|
/* Both sector and sector_count are in terms of qemu 512 byte blocks. */
|
||||||
uint64_t sector;
|
uint64_t sector;
|
||||||
uint32_t sector_count;
|
uint32_t sector_count;
|
||||||
|
uint32_t buflen;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
@ -78,13 +79,15 @@ struct SCSIDiskState
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
|
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
|
||||||
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
|
static int scsi_disk_emulate_command(SCSIDiskReq *r);
|
||||||
|
|
||||||
static void scsi_free_request(SCSIRequest *req)
|
static void scsi_free_request(SCSIRequest *req)
|
||||||
{
|
{
|
||||||
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||||
|
|
||||||
|
if (r->iov.iov_base) {
|
||||||
qemu_vfree(r->iov.iov_base);
|
qemu_vfree(r->iov.iov_base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for command completion with sense. */
|
/* Helper function for command completion with sense. */
|
||||||
@ -108,6 +111,19 @@ static void scsi_cancel_io(SCSIRequest *req)
|
|||||||
r->req.aiocb = NULL;
|
r->req.aiocb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t scsi_init_iovec(SCSIDiskReq *r)
|
||||||
|
{
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
|
|
||||||
|
if (!r->iov.iov_base) {
|
||||||
|
r->buflen = SCSI_DMA_BUF_SIZE;
|
||||||
|
r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
|
||||||
|
}
|
||||||
|
r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
|
||||||
|
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
||||||
|
return r->qiov.size / 512;
|
||||||
|
}
|
||||||
|
|
||||||
static void scsi_read_complete(void * opaque, int ret)
|
static void scsi_read_complete(void * opaque, int ret)
|
||||||
{
|
{
|
||||||
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
||||||
@ -125,12 +141,12 @@ static void scsi_read_complete(void * opaque, int ret)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
|
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
|
||||||
|
|
||||||
n = r->iov.iov_len / 512;
|
n = r->qiov.size / 512;
|
||||||
r->sector += n;
|
r->sector += n;
|
||||||
r->sector_count -= n;
|
r->sector_count -= n;
|
||||||
scsi_req_data(&r->req, r->iov.iov_len);
|
scsi_req_data(&r->req, r->qiov.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scsi_flush_complete(void * opaque, int ret)
|
static void scsi_flush_complete(void * opaque, int ret)
|
||||||
@ -181,16 +197,10 @@ static void scsi_read_data(SCSIRequest *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = r->sector_count;
|
|
||||||
if (n > SCSI_DMA_BUF_SIZE / 512)
|
|
||||||
n = SCSI_DMA_BUF_SIZE / 512;
|
|
||||||
|
|
||||||
if (s->tray_open) {
|
if (s->tray_open) {
|
||||||
scsi_read_complete(r, -ENOMEDIUM);
|
scsi_read_complete(r, -ENOMEDIUM);
|
||||||
}
|
}
|
||||||
r->iov.iov_len = n * 512;
|
n = scsi_init_iovec(r);
|
||||||
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
|
||||||
|
|
||||||
bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
||||||
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
|
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
|
||||||
scsi_read_complete, r);
|
scsi_read_complete, r);
|
||||||
@ -239,7 +249,6 @@ static void scsi_write_complete(void * opaque, int ret)
|
|||||||
{
|
{
|
||||||
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
uint32_t len;
|
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
|
||||||
if (r->req.aiocb != NULL) {
|
if (r->req.aiocb != NULL) {
|
||||||
@ -253,19 +262,15 @@ static void scsi_write_complete(void * opaque, int ret)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = r->iov.iov_len / 512;
|
n = r->qiov.size / 512;
|
||||||
r->sector += n;
|
r->sector += n;
|
||||||
r->sector_count -= n;
|
r->sector_count -= n;
|
||||||
if (r->sector_count == 0) {
|
if (r->sector_count == 0) {
|
||||||
scsi_req_complete(&r->req, GOOD);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
} else {
|
} else {
|
||||||
len = r->sector_count * 512;
|
scsi_init_iovec(r);
|
||||||
if (len > SCSI_DMA_BUF_SIZE) {
|
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
|
||||||
len = SCSI_DMA_BUF_SIZE;
|
scsi_req_data(&r->req, r->qiov.size);
|
||||||
}
|
|
||||||
r->iov.iov_len = len;
|
|
||||||
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
|
|
||||||
scsi_req_data(&r->req, len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,13 +289,11 @@ static void scsi_write_data(SCSIRequest *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = r->iov.iov_len / 512;
|
n = r->qiov.size / 512;
|
||||||
if (n) {
|
if (n) {
|
||||||
if (s->tray_open) {
|
if (s->tray_open) {
|
||||||
scsi_write_complete(r, -ENOMEDIUM);
|
scsi_write_complete(r, -ENOMEDIUM);
|
||||||
}
|
}
|
||||||
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
|
||||||
|
|
||||||
bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
|
bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
|
||||||
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
|
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
|
||||||
scsi_write_complete, r);
|
scsi_write_complete, r);
|
||||||
@ -298,7 +301,7 @@ static void scsi_write_data(SCSIRequest *req)
|
|||||||
scsi_write_complete(r, -ENOMEM);
|
scsi_write_complete(r, -ENOMEM);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Invoke completion routine to fetch data from host. */
|
/* Called for the first time. Ask the driver to send us more data. */
|
||||||
scsi_write_complete(r, 0);
|
scsi_write_complete(r, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +332,7 @@ static void scsi_dma_restart_bh(void *opaque)
|
|||||||
scsi_write_data(&r->req);
|
scsi_write_data(&r->req);
|
||||||
break;
|
break;
|
||||||
case SCSI_REQ_STATUS_RETRY_FLUSH:
|
case SCSI_REQ_STATUS_RETRY_FLUSH:
|
||||||
ret = scsi_disk_emulate_command(r, r->iov.iov_base);
|
ret = scsi_disk_emulate_command(r);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
scsi_req_complete(&r->req, GOOD);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
}
|
}
|
||||||
@ -844,13 +847,31 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
|
static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
||||||
{
|
{
|
||||||
SCSIRequest *req = &r->req;
|
SCSIRequest *req = &r->req;
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
|
uint8_t *outbuf;
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
|
|
||||||
|
if (!r->iov.iov_base) {
|
||||||
|
/*
|
||||||
|
* FIXME: we shouldn't return anything bigger than 4k, but the code
|
||||||
|
* requires the buffer to be as big as req->cmd.xfer in several
|
||||||
|
* places. So, do not allow CDBs with a very large ALLOCATION
|
||||||
|
* LENGTH. The real fix would be to modify scsi_read_data and
|
||||||
|
* dma_buf_read, so that they return data beyond the buflen
|
||||||
|
* as all zeros.
|
||||||
|
*/
|
||||||
|
if (req->cmd.xfer > 65536) {
|
||||||
|
goto illegal_request;
|
||||||
|
}
|
||||||
|
r->buflen = MAX(4096, req->cmd.xfer);
|
||||||
|
r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
outbuf = r->iov.iov_base;
|
||||||
switch (req->cmd.buf[0]) {
|
switch (req->cmd.buf[0]) {
|
||||||
case TEST_UNIT_READY:
|
case TEST_UNIT_READY:
|
||||||
if (s->tray_open || !bdrv_is_inserted(s->bs))
|
if (s->tray_open || !bdrv_is_inserted(s->bs))
|
||||||
@ -1001,11 +1022,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
int32_t len;
|
int32_t len;
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
uint8_t *outbuf;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
command = buf[0];
|
command = buf[0];
|
||||||
outbuf = (uint8_t *)r->iov.iov_base;
|
|
||||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
|
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
|
||||||
|
|
||||||
#ifdef DEBUG_SCSI
|
#ifdef DEBUG_SCSI
|
||||||
@ -1034,7 +1053,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
case GET_CONFIGURATION:
|
case GET_CONFIGURATION:
|
||||||
case SERVICE_ACTION_IN_16:
|
case SERVICE_ACTION_IN_16:
|
||||||
case VERIFY_10:
|
case VERIFY_10:
|
||||||
rc = scsi_disk_emulate_command(r, outbuf);
|
rc = scsi_disk_emulate_command(r);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1285,11 +1304,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
|
|||||||
{
|
{
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
||||||
SCSIRequest *req;
|
SCSIRequest *req;
|
||||||
SCSIDiskReq *r;
|
|
||||||
|
|
||||||
req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
|
req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
|
||||||
r = DO_UPCAST(SCSIDiskReq, req, req);
|
|
||||||
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,12 +244,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
|
|||||||
static void scsi_req_fixup(SCSIRequest *req)
|
static void scsi_req_fixup(SCSIRequest *req)
|
||||||
{
|
{
|
||||||
switch(req->cmd.buf[0]) {
|
switch(req->cmd.buf[0]) {
|
||||||
case WRITE_10:
|
|
||||||
req->cmd.buf[1] &= ~0x08; /* disable FUA */
|
|
||||||
break;
|
|
||||||
case READ_10:
|
|
||||||
req->cmd.buf[1] &= ~0x08; /* disable FUA */
|
|
||||||
break;
|
|
||||||
case REWIND:
|
case REWIND:
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
if (req->dev->type == TYPE_TAPE) {
|
if (req->dev->type == TYPE_TAPE) {
|
||||||
|
11
linux-aio.c
11
linux-aio.c
@ -68,15 +68,6 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
|||||||
qemu_aio_release(laiocb);
|
qemu_aio_release(laiocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* All requests are directly processed when they complete, so there's nothing
|
|
||||||
* left to do during qemu_aio_wait().
|
|
||||||
*/
|
|
||||||
static int qemu_laio_process_requests(void *opaque)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_laio_completion_cb(void *opaque)
|
static void qemu_laio_completion_cb(void *opaque)
|
||||||
{
|
{
|
||||||
struct qemu_laio_state *s = opaque;
|
struct qemu_laio_state *s = opaque;
|
||||||
@ -215,7 +206,7 @@ void *laio_init(void)
|
|||||||
goto out_close_efd;
|
goto out_close_efd;
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
|
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
|
||||||
qemu_laio_flush_cb, qemu_laio_process_requests, s);
|
qemu_laio_flush_cb, NULL, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
|
42
nbd.c
42
nbd.c
@ -30,6 +30,10 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "qemu_socket.h"
|
#include "qemu_socket.h"
|
||||||
|
|
||||||
//#define DEBUG_NBD
|
//#define DEBUG_NBD
|
||||||
@ -63,6 +67,8 @@
|
|||||||
#define NBD_PRINT_DEBUG _IO(0xab, 6)
|
#define NBD_PRINT_DEBUG _IO(0xab, 6)
|
||||||
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
|
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
|
||||||
#define NBD_DISCONNECT _IO(0xab, 8)
|
#define NBD_DISCONNECT _IO(0xab, 8)
|
||||||
|
#define NBD_SET_TIMEOUT _IO(0xab, 9)
|
||||||
|
#define NBD_SET_FLAGS _IO(0xab, 10)
|
||||||
|
|
||||||
#define NBD_OPT_EXPORT_NAME (1 << 0)
|
#define NBD_OPT_EXPORT_NAME (1 << 0)
|
||||||
|
|
||||||
@ -172,7 +178,7 @@ int unix_socket_outgoing(const char *path)
|
|||||||
Request (type == 2)
|
Request (type == 2)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int nbd_negotiate(int csock, off_t size)
|
int nbd_negotiate(int csock, off_t size, uint32_t flags)
|
||||||
{
|
{
|
||||||
char buf[8 + 8 + 8 + 128];
|
char buf[8 + 8 + 8 + 128];
|
||||||
|
|
||||||
@ -180,14 +186,16 @@ int nbd_negotiate(int csock, off_t size)
|
|||||||
[ 0 .. 7] passwd ("NBDMAGIC")
|
[ 0 .. 7] passwd ("NBDMAGIC")
|
||||||
[ 8 .. 15] magic (0x00420281861253)
|
[ 8 .. 15] magic (0x00420281861253)
|
||||||
[16 .. 23] size
|
[16 .. 23] size
|
||||||
[24 .. 151] reserved (0)
|
[24 .. 27] flags
|
||||||
|
[28 .. 151] reserved (0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TRACE("Beginning negotiation.");
|
TRACE("Beginning negotiation.");
|
||||||
memcpy(buf, "NBDMAGIC", 8);
|
memcpy(buf, "NBDMAGIC", 8);
|
||||||
cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
|
cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
|
||||||
cpu_to_be64w((uint64_t*)(buf + 16), size);
|
cpu_to_be64w((uint64_t*)(buf + 16), size);
|
||||||
memset(buf + 24, 0, 128);
|
cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS);
|
||||||
|
memset(buf + 28, 0, 124);
|
||||||
|
|
||||||
if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
|
if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
LOG("write failed");
|
LOG("write failed");
|
||||||
@ -337,8 +345,8 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifdef __linux__
|
||||||
int nbd_init(int fd, int csock, off_t size, size_t blocksize)
|
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
|
||||||
{
|
{
|
||||||
TRACE("Setting block size to %lu", (unsigned long)blocksize);
|
TRACE("Setting block size to %lu", (unsigned long)blocksize);
|
||||||
|
|
||||||
@ -358,6 +366,26 @@ int nbd_init(int fd, int csock, off_t size, size_t blocksize)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & NBD_FLAG_READ_ONLY) {
|
||||||
|
int read_only = 1;
|
||||||
|
TRACE("Setting readonly attribute");
|
||||||
|
|
||||||
|
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
|
||||||
|
int serrno = errno;
|
||||||
|
LOG("Failed setting read-only attribute");
|
||||||
|
errno = serrno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
|
||||||
|
&& errno != ENOTTY) {
|
||||||
|
int serrno = errno;
|
||||||
|
LOG("Failed setting flags");
|
||||||
|
errno = serrno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("Clearing NBD socket");
|
TRACE("Clearing NBD socket");
|
||||||
|
|
||||||
if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
|
if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
|
||||||
@ -548,7 +576,7 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
||||||
off_t *offset, bool readonly, uint8_t *data, int data_size)
|
off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size)
|
||||||
{
|
{
|
||||||
struct nbd_request request;
|
struct nbd_request request;
|
||||||
struct nbd_reply reply;
|
struct nbd_reply reply;
|
||||||
@ -632,7 +660,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readonly) {
|
if (nbdflags & NBD_FLAG_READ_ONLY) {
|
||||||
TRACE("Server is read-only, return error");
|
TRACE("Server is read-only, return error");
|
||||||
reply.error = 1;
|
reply.error = 1;
|
||||||
} else {
|
} else {
|
||||||
|
20
nbd.h
20
nbd.h
@ -37,10 +37,22 @@ struct nbd_reply {
|
|||||||
uint64_t handle;
|
uint64_t handle;
|
||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
|
|
||||||
|
#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */
|
||||||
|
#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */
|
||||||
|
#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */
|
||||||
|
#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */
|
||||||
|
#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */
|
||||||
|
#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
|
||||||
|
|
||||||
|
#define NBD_CMD_MASK_COMMAND 0x0000ffff
|
||||||
|
#define NBD_CMD_FLAG_FUA (1 << 16)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NBD_CMD_READ = 0,
|
NBD_CMD_READ = 0,
|
||||||
NBD_CMD_WRITE = 1,
|
NBD_CMD_WRITE = 1,
|
||||||
NBD_CMD_DISC = 2
|
NBD_CMD_DISC = 2,
|
||||||
|
NBD_CMD_FLUSH = 3,
|
||||||
|
NBD_CMD_TRIM = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NBD_DEFAULT_PORT 10809
|
#define NBD_DEFAULT_PORT 10809
|
||||||
@ -53,14 +65,14 @@ int tcp_socket_incoming_spec(const char *address_and_port);
|
|||||||
int unix_socket_outgoing(const char *path);
|
int unix_socket_outgoing(const char *path);
|
||||||
int unix_socket_incoming(const char *path);
|
int unix_socket_incoming(const char *path);
|
||||||
|
|
||||||
int nbd_negotiate(int csock, off_t size);
|
int nbd_negotiate(int csock, off_t size, uint32_t flags);
|
||||||
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||||
off_t *size, size_t *blocksize);
|
off_t *size, size_t *blocksize);
|
||||||
int nbd_init(int fd, int csock, off_t size, size_t blocksize);
|
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
||||||
int nbd_send_request(int csock, struct nbd_request *request);
|
int nbd_send_request(int csock, struct nbd_request *request);
|
||||||
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
||||||
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
||||||
off_t *offset, bool readonly, uint8_t *data, int data_size);
|
off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size);
|
||||||
int nbd_client(int fd);
|
int nbd_client(int fd);
|
||||||
int nbd_disconnect(int fd);
|
int nbd_disconnect(int fd);
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ struct qemu_paiocb {
|
|||||||
int aio_niov;
|
int aio_niov;
|
||||||
size_t aio_nbytes;
|
size_t aio_nbytes;
|
||||||
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
|
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
|
||||||
int ev_signo;
|
|
||||||
off_t aio_offset;
|
off_t aio_offset;
|
||||||
|
|
||||||
QTAILQ_ENTRY(qemu_paiocb) node;
|
QTAILQ_ENTRY(qemu_paiocb) node;
|
||||||
@ -181,7 +180,6 @@ qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
|
|||||||
|
|
||||||
static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
|
static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -189,12 +187,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
|
|||||||
len = qemu_pwritev(aiocb->aio_fildes,
|
len = qemu_pwritev(aiocb->aio_fildes,
|
||||||
aiocb->aio_iov,
|
aiocb->aio_iov,
|
||||||
aiocb->aio_niov,
|
aiocb->aio_niov,
|
||||||
aiocb->aio_offset + offset);
|
aiocb->aio_offset);
|
||||||
else
|
else
|
||||||
len = qemu_preadv(aiocb->aio_fildes,
|
len = qemu_preadv(aiocb->aio_fildes,
|
||||||
aiocb->aio_iov,
|
aiocb->aio_iov,
|
||||||
aiocb->aio_niov,
|
aiocb->aio_niov,
|
||||||
aiocb->aio_offset + offset);
|
aiocb->aio_offset);
|
||||||
} while (len == -1 && errno == EINTR);
|
} while (len == -1 && errno == EINTR);
|
||||||
|
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
@ -309,12 +307,10 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
|
|||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void posix_aio_notify_event(void);
|
||||||
|
|
||||||
static void *aio_thread(void *unused)
|
static void *aio_thread(void *unused)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
pid = getpid();
|
|
||||||
|
|
||||||
mutex_lock(&lock);
|
mutex_lock(&lock);
|
||||||
pending_threads--;
|
pending_threads--;
|
||||||
mutex_unlock(&lock);
|
mutex_unlock(&lock);
|
||||||
@ -381,7 +377,7 @@ static void *aio_thread(void *unused)
|
|||||||
aiocb->ret = ret;
|
aiocb->ret = ret;
|
||||||
mutex_unlock(&lock);
|
mutex_unlock(&lock);
|
||||||
|
|
||||||
if (kill(pid, aiocb->ev_signo)) die("kill failed");
|
posix_aio_notify_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_threads--;
|
cur_threads--;
|
||||||
@ -548,18 +544,14 @@ static int posix_aio_flush(void *opaque)
|
|||||||
|
|
||||||
static PosixAioState *posix_aio_state;
|
static PosixAioState *posix_aio_state;
|
||||||
|
|
||||||
static void aio_signal_handler(int signum)
|
static void posix_aio_notify_event(void)
|
||||||
{
|
{
|
||||||
if (posix_aio_state) {
|
|
||||||
char byte = 0;
|
char byte = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
|
ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
|
||||||
if (ret < 0 && errno != EAGAIN)
|
if (ret < 0 && errno != EAGAIN)
|
||||||
die("write()");
|
die("write()");
|
||||||
}
|
|
||||||
|
|
||||||
qemu_service_io();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paio_remove(struct qemu_paiocb *acb)
|
static void paio_remove(struct qemu_paiocb *acb)
|
||||||
@ -623,7 +615,6 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
acb->aio_type = type;
|
acb->aio_type = type;
|
||||||
acb->aio_fildes = fd;
|
acb->aio_fildes = fd;
|
||||||
acb->ev_signo = SIGUSR2;
|
|
||||||
|
|
||||||
if (qiov) {
|
if (qiov) {
|
||||||
acb->aio_iov = qiov->iov;
|
acb->aio_iov = qiov->iov;
|
||||||
@ -651,7 +642,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
acb->aio_type = QEMU_AIO_IOCTL;
|
acb->aio_type = QEMU_AIO_IOCTL;
|
||||||
acb->aio_fildes = fd;
|
acb->aio_fildes = fd;
|
||||||
acb->ev_signo = SIGUSR2;
|
|
||||||
acb->aio_offset = 0;
|
acb->aio_offset = 0;
|
||||||
acb->aio_ioctl_buf = buf;
|
acb->aio_ioctl_buf = buf;
|
||||||
acb->aio_ioctl_cmd = req;
|
acb->aio_ioctl_cmd = req;
|
||||||
@ -665,7 +655,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
|
|||||||
|
|
||||||
int paio_init(void)
|
int paio_init(void)
|
||||||
{
|
{
|
||||||
struct sigaction act;
|
|
||||||
PosixAioState *s;
|
PosixAioState *s;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
int ret;
|
int ret;
|
||||||
@ -675,11 +664,6 @@ int paio_init(void)
|
|||||||
|
|
||||||
s = g_malloc(sizeof(PosixAioState));
|
s = g_malloc(sizeof(PosixAioState));
|
||||||
|
|
||||||
sigfillset(&act.sa_mask);
|
|
||||||
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
|
|
||||||
act.sa_handler = aio_signal_handler;
|
|
||||||
sigaction(SIGUSR2, &act, NULL);
|
|
||||||
|
|
||||||
s->first_aio = NULL;
|
s->first_aio = NULL;
|
||||||
if (qemu_pipe(fds) == -1) {
|
if (qemu_pipe(fds) == -1) {
|
||||||
fprintf(stderr, "failed to create pipe\n");
|
fprintf(stderr, "failed to create pipe\n");
|
||||||
|
11
qemu-nbd.c
11
qemu-nbd.c
@ -185,7 +185,7 @@ int main(int argc, char **argv)
|
|||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
off_t dev_offset = 0;
|
off_t dev_offset = 0;
|
||||||
off_t offset = 0;
|
off_t offset = 0;
|
||||||
bool readonly = false;
|
uint32_t nbdflags = 0;
|
||||||
bool disconnect = false;
|
bool disconnect = false;
|
||||||
const char *bindto = "0.0.0.0";
|
const char *bindto = "0.0.0.0";
|
||||||
int port = NBD_DEFAULT_PORT;
|
int port = NBD_DEFAULT_PORT;
|
||||||
@ -230,7 +230,6 @@ int main(int argc, char **argv)
|
|||||||
int nb_fds = 0;
|
int nb_fds = 0;
|
||||||
int max_fd;
|
int max_fd;
|
||||||
int persistent = 0;
|
int persistent = 0;
|
||||||
uint32_t nbdflags;
|
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
@ -263,7 +262,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
readonly = true;
|
nbdflags |= NBD_FLAG_READ_ONLY;
|
||||||
flags &= ~BDRV_O_RDWR;
|
flags &= ~BDRV_O_RDWR;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
@ -404,7 +403,7 @@ int main(int argc, char **argv)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nbd_init(fd, sock, size, blocksize);
|
ret = nbd_init(fd, sock, nbdflags, size, blocksize);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
@ -463,7 +462,7 @@ int main(int argc, char **argv)
|
|||||||
for (i = 1; i < nb_fds && ret; i++) {
|
for (i = 1; i < nb_fds && ret; i++) {
|
||||||
if (FD_ISSET(sharing_fds[i], &fds)) {
|
if (FD_ISSET(sharing_fds[i], &fds)) {
|
||||||
if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
|
if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
|
||||||
&offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
|
&offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
|
||||||
close(sharing_fds[i]);
|
close(sharing_fds[i]);
|
||||||
nb_fds--;
|
nb_fds--;
|
||||||
sharing_fds[i] = sharing_fds[nb_fds];
|
sharing_fds[i] = sharing_fds[nb_fds];
|
||||||
@ -479,7 +478,7 @@ int main(int argc, char **argv)
|
|||||||
(struct sockaddr *)&addr,
|
(struct sockaddr *)&addr,
|
||||||
&addr_len);
|
&addr_len);
|
||||||
if (sharing_fds[nb_fds] != -1 &&
|
if (sharing_fds[nb_fds] != -1 &&
|
||||||
nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {
|
nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
|
||||||
if (sharing_fds[nb_fds] > max_fd)
|
if (sharing_fds[nb_fds] > max_fd)
|
||||||
max_fd = sharing_fds[nb_fds];
|
max_fd = sharing_fds[nb_fds];
|
||||||
nb_fds++;
|
nb_fds++;
|
||||||
|
Loading…
Reference in New Issue
Block a user