Block layer patches for 2.4.0-rc1
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJVpSeXAAoJEH8JsnLIjy/WhyQP/3w/Nq1MnsT14Ak79LYsOd4C PpwgZF9Z3RZZoe+9bBO9RWzP1y/Pmxnui73A+1d+B4+moKswbvJW4lwx1aaP3Igq 9XzMA3/xwqdx5kGX7PDSZkdVZC513hI8rIxV9Ly+yE3h729dTHlrULfrgO8MWieQ zoWQAMk55tDmazuKKHXAHRphicWvg71+xOHCsJt/MMz/5u8ShHssoIqNXGj8G28m AZu2tzkBF4c6Y4b1aghsDpMnc269wD/4UNegpkTz66S9FpSix/f4GOtLGmwXJSrg zz4SDMNx7b/U/mZzV94LEd4GP2hEI2tzIKvkd3RHaeyVVlLqnxCHA4W0lpoTO4Ud QR8aWjFLIq4HqFrY3JC1EhpGMF0M3PAXMqtau1bCmLOr/+TZWazP0H/WJW65MCwM 5ertw87apRsIVPUhV22fKNUXary+GE7OHKEklUopFzUfgzzMq9uSTLbBAHX7j2jA FDl9NqbBc99FYe8KAwZwjaASavelodc7rnw6vxtWL1ERJPVqbuPpRZAlgGDAuoEN DWqnY+LQhPJNLNLeRTVvnWxAIIFBJRJUEF7Ekwabsz8CQ/8pq9XrX8KfStx3TUAm OHcw7XJqyirklmI987LuBADtE5SIK4Jbpg8m5UgS+hDqIRSt5WFrzS6Depu7JA/F WFfiNg3Y4Kkw236I8UHs =zRxM -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches for 2.4.0-rc1 # gpg: Signature made Tue Jul 14 16:15:35 2015 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: rbd: fix ceph settings precedence rbd: make qemu's cache setting override any ceph setting MAINTAINERS: update email address rbd: remove unused constants and fields block: Fix backing file child when modifying graph block: Reorder cleanups in bdrv_close() block: Introduce bdrv_unref_child() block: Introduce bdrv_open_child() block: Move bdrv_attach_child() calls up the call chain nvme: properly report volatile write caches nvme: implement the Flush command Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f3947986d9
@ -1169,7 +1169,7 @@ S: Supported
|
|||||||
F: block/vmdk.c
|
F: block/vmdk.c
|
||||||
|
|
||||||
RBD
|
RBD
|
||||||
M: Josh Durgin <josh.durgin@inktank.com>
|
M: Josh Durgin <jdurgin@redhat.com>
|
||||||
M: Jeff Cody <jcody@redhat.com>
|
M: Jeff Cody <jcody@redhat.com>
|
||||||
L: qemu-block@nongnu.org
|
L: qemu-block@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
|
164
block.c
164
block.c
@ -1102,12 +1102,46 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||||
|
BlockDriverState *child_bs,
|
||||||
|
const BdrvChildRole *child_role)
|
||||||
|
{
|
||||||
|
BdrvChild *child = g_new(BdrvChild, 1);
|
||||||
|
*child = (BdrvChild) {
|
||||||
|
.bs = child_bs,
|
||||||
|
.role = child_role,
|
||||||
|
};
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_detach_child(BdrvChild *child)
|
||||||
|
{
|
||||||
|
QLIST_REMOVE(child, next);
|
||||||
|
g_free(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
|
||||||
|
{
|
||||||
|
BlockDriverState *child_bs = child->bs;
|
||||||
|
|
||||||
|
if (child->bs->inherits_from == parent) {
|
||||||
|
child->bs->inherits_from = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_detach_child(child);
|
||||||
|
bdrv_unref(child_bs);
|
||||||
|
}
|
||||||
|
|
||||||
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
assert(bs->backing_blocker);
|
assert(bs->backing_blocker);
|
||||||
bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
|
bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
|
||||||
|
bdrv_detach_child(bs->backing_child);
|
||||||
} else if (backing_hd) {
|
} else if (backing_hd) {
|
||||||
error_setg(&bs->backing_blocker,
|
error_setg(&bs->backing_blocker,
|
||||||
"node is used as backing hd of '%s'",
|
"node is used as backing hd of '%s'",
|
||||||
@ -1118,8 +1152,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
|||||||
if (!backing_hd) {
|
if (!backing_hd) {
|
||||||
error_free(bs->backing_blocker);
|
error_free(bs->backing_blocker);
|
||||||
bs->backing_blocker = NULL;
|
bs->backing_blocker = NULL;
|
||||||
|
bs->backing_child = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
bs->backing_child = bdrv_attach_child(bs, backing_hd, &child_backing);
|
||||||
bs->open_flags &= ~BDRV_O_NO_BACKING;
|
bs->open_flags &= ~BDRV_O_NO_BACKING;
|
||||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
|
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
|
||||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
|
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
|
||||||
@ -1202,6 +1238,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
goto free_exit;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_set_backing_hd(bs, backing_hd);
|
bdrv_set_backing_hd(bs, backing_hd);
|
||||||
|
|
||||||
free_exit:
|
free_exit:
|
||||||
@ -1214,7 +1251,7 @@ free_exit:
|
|||||||
* device's options.
|
* device's options.
|
||||||
*
|
*
|
||||||
* If allow_none is true, no image will be opened if filename is false and no
|
* If allow_none is true, no image will be opened if filename is false and no
|
||||||
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
|
* BlockdevRef is given. NULL will be returned, but errp remains unset.
|
||||||
*
|
*
|
||||||
* bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
|
* bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
|
||||||
* That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
|
* That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
|
||||||
@ -1222,6 +1259,56 @@ free_exit:
|
|||||||
* BlockdevRef.
|
* BlockdevRef.
|
||||||
*
|
*
|
||||||
* The BlockdevRef will be removed from the options QDict.
|
* The BlockdevRef will be removed from the options QDict.
|
||||||
|
*/
|
||||||
|
BdrvChild *bdrv_open_child(const char *filename,
|
||||||
|
QDict *options, const char *bdref_key,
|
||||||
|
BlockDriverState* parent,
|
||||||
|
const BdrvChildRole *child_role,
|
||||||
|
bool allow_none, Error **errp)
|
||||||
|
{
|
||||||
|
BdrvChild *c = NULL;
|
||||||
|
BlockDriverState *bs;
|
||||||
|
QDict *image_options;
|
||||||
|
int ret;
|
||||||
|
char *bdref_key_dot;
|
||||||
|
const char *reference;
|
||||||
|
|
||||||
|
assert(child_role != NULL);
|
||||||
|
|
||||||
|
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
|
||||||
|
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
||||||
|
g_free(bdref_key_dot);
|
||||||
|
|
||||||
|
reference = qdict_get_try_str(options, bdref_key);
|
||||||
|
if (!filename && !reference && !qdict_size(image_options)) {
|
||||||
|
if (!allow_none) {
|
||||||
|
error_setg(errp, "A block device must be specified for \"%s\"",
|
||||||
|
bdref_key);
|
||||||
|
}
|
||||||
|
QDECREF(image_options);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = NULL;
|
||||||
|
ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0,
|
||||||
|
parent, child_role, NULL, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = bdrv_attach_child(parent, bs, child_role);
|
||||||
|
|
||||||
|
done:
|
||||||
|
qdict_del(options, bdref_key);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a version of bdrv_open_child() that returns 0/-EINVAL instead of
|
||||||
|
* a BdrvChild object.
|
||||||
|
*
|
||||||
|
* If allow_none is true, no image will be opened if filename is false and no
|
||||||
|
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
|
||||||
*
|
*
|
||||||
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
|
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
|
||||||
*/
|
*/
|
||||||
@ -1230,37 +1317,24 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
|||||||
BlockDriverState* parent, const BdrvChildRole *child_role,
|
BlockDriverState* parent, const BdrvChildRole *child_role,
|
||||||
bool allow_none, Error **errp)
|
bool allow_none, Error **errp)
|
||||||
{
|
{
|
||||||
QDict *image_options;
|
Error *local_err = NULL;
|
||||||
int ret;
|
BdrvChild *c;
|
||||||
char *bdref_key_dot;
|
|
||||||
const char *reference;
|
|
||||||
|
|
||||||
assert(pbs);
|
assert(pbs);
|
||||||
assert(*pbs == NULL);
|
assert(*pbs == NULL);
|
||||||
|
|
||||||
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
|
c = bdrv_open_child(filename, options, bdref_key, parent, child_role,
|
||||||
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
allow_none, &local_err);
|
||||||
g_free(bdref_key_dot);
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
reference = qdict_get_try_str(options, bdref_key);
|
return -EINVAL;
|
||||||
if (!filename && !reference && !qdict_size(image_options)) {
|
|
||||||
if (allow_none) {
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
error_setg(errp, "A block device must be specified for \"%s\"",
|
|
||||||
bdref_key);
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
QDECREF(image_options);
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
|
if (c != NULL) {
|
||||||
parent, child_role, NULL, errp);
|
*pbs = c->bs;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
return 0;
|
||||||
qdict_del(options, bdref_key);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||||
@ -1328,19 +1402,6 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_attach_child(BlockDriverState *parent_bs,
|
|
||||||
BlockDriverState *child_bs,
|
|
||||||
const BdrvChildRole *child_role)
|
|
||||||
{
|
|
||||||
BdrvChild *child = g_new(BdrvChild, 1);
|
|
||||||
*child = (BdrvChild) {
|
|
||||||
.bs = child_bs,
|
|
||||||
.role = child_role,
|
|
||||||
};
|
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||||
*
|
*
|
||||||
@ -1393,9 +1454,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
bdrv_ref(bs);
|
bdrv_ref(bs);
|
||||||
if (child_role) {
|
|
||||||
bdrv_attach_child(parent, bs, child_role);
|
|
||||||
}
|
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1540,10 +1598,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
|||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_role) {
|
|
||||||
bdrv_attach_child(parent, bs, child_role);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1849,20 +1903,23 @@ void bdrv_close(BlockDriverState *bs)
|
|||||||
if (bs->drv) {
|
if (bs->drv) {
|
||||||
BdrvChild *child, *next;
|
BdrvChild *child, *next;
|
||||||
|
|
||||||
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
bs->drv->bdrv_close(bs);
|
||||||
if (child->bs->inherits_from == bs) {
|
|
||||||
child->bs->inherits_from = NULL;
|
|
||||||
}
|
|
||||||
QLIST_REMOVE(child, next);
|
|
||||||
g_free(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
BlockDriverState *backing_hd = bs->backing_hd;
|
BlockDriverState *backing_hd = bs->backing_hd;
|
||||||
bdrv_set_backing_hd(bs, NULL);
|
bdrv_set_backing_hd(bs, NULL);
|
||||||
bdrv_unref(backing_hd);
|
bdrv_unref(backing_hd);
|
||||||
}
|
}
|
||||||
bs->drv->bdrv_close(bs);
|
|
||||||
|
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
||||||
|
/* TODO Remove bdrv_unref() from drivers' close function and use
|
||||||
|
* bdrv_unref_child() here */
|
||||||
|
if (child->bs->inherits_from == bs) {
|
||||||
|
child->bs->inherits_from = NULL;
|
||||||
|
}
|
||||||
|
bdrv_detach_child(child);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
@ -2116,7 +2173,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
|||||||
/* The contents of 'tmp' will become bs_top, as we are
|
/* The contents of 'tmp' will become bs_top, as we are
|
||||||
* swapping bs_new and bs_top contents. */
|
* swapping bs_new and bs_top contents. */
|
||||||
bdrv_set_backing_hd(bs_top, bs_new);
|
bdrv_set_backing_hd(bs_top, bs_new);
|
||||||
bdrv_attach_child(bs_top, bs_new, &child_backing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_delete(BlockDriverState *bs)
|
static void bdrv_delete(BlockDriverState *bs)
|
||||||
|
64
block/rbd.c
64
block/rbd.c
@ -74,25 +74,18 @@ typedef struct RBDAIOCB {
|
|||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
char *bounce;
|
char *bounce;
|
||||||
RBDAIOCmd cmd;
|
RBDAIOCmd cmd;
|
||||||
int64_t sector_num;
|
|
||||||
int error;
|
int error;
|
||||||
struct BDRVRBDState *s;
|
struct BDRVRBDState *s;
|
||||||
int status;
|
|
||||||
} RBDAIOCB;
|
} RBDAIOCB;
|
||||||
|
|
||||||
typedef struct RADOSCB {
|
typedef struct RADOSCB {
|
||||||
int rcbid;
|
|
||||||
RBDAIOCB *acb;
|
RBDAIOCB *acb;
|
||||||
struct BDRVRBDState *s;
|
struct BDRVRBDState *s;
|
||||||
int done;
|
|
||||||
int64_t size;
|
int64_t size;
|
||||||
char *buf;
|
char *buf;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
} RADOSCB;
|
} RADOSCB;
|
||||||
|
|
||||||
#define RBD_FD_READ 0
|
|
||||||
#define RBD_FD_WRITE 1
|
|
||||||
|
|
||||||
typedef struct BDRVRBDState {
|
typedef struct BDRVRBDState {
|
||||||
rados_t cluster;
|
rados_t cluster;
|
||||||
rados_ioctx_t io_ctx;
|
rados_ioctx_t io_ctx;
|
||||||
@ -235,7 +228,9 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
static int qemu_rbd_set_conf(rados_t cluster, const char *conf,
|
||||||
|
bool only_read_conf_file,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
char *p, *buf;
|
char *p, *buf;
|
||||||
char name[RBD_MAX_CONF_NAME_SIZE];
|
char name[RBD_MAX_CONF_NAME_SIZE];
|
||||||
@ -267,14 +262,18 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
|||||||
qemu_rbd_unescape(value);
|
qemu_rbd_unescape(value);
|
||||||
|
|
||||||
if (strcmp(name, "conf") == 0) {
|
if (strcmp(name, "conf") == 0) {
|
||||||
ret = rados_conf_read_file(cluster, value);
|
/* read the conf file alone, so it doesn't override more
|
||||||
if (ret < 0) {
|
specific settings for a particular device */
|
||||||
error_setg(errp, "error reading conf file %s", value);
|
if (only_read_conf_file) {
|
||||||
break;
|
ret = rados_conf_read_file(cluster, value);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "error reading conf file %s", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(name, "id") == 0) {
|
} else if (strcmp(name, "id") == 0) {
|
||||||
/* ignore, this is parsed by qemu_rbd_parse_clientname() */
|
/* ignore, this is parsed by qemu_rbd_parse_clientname() */
|
||||||
} else {
|
} else if (!only_read_conf_file) {
|
||||||
ret = rados_conf_set(cluster, name, value);
|
ret = rados_conf_set(cluster, name, value);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "invalid conf option %s", name);
|
error_setg(errp, "invalid conf option %s", name);
|
||||||
@ -337,10 +336,15 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
if (strstr(conf, "conf=") == NULL) {
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
/* try default location, but ignore failure */
|
/* try default location, but ignore failure */
|
||||||
rados_conf_read_file(cluster, NULL);
|
rados_conf_read_file(cluster, NULL);
|
||||||
|
} else if (conf[0] != '\0' &&
|
||||||
|
qemu_rbd_set_conf(cluster, conf, true, &local_err) < 0) {
|
||||||
|
rados_shutdown(cluster);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf[0] != '\0' &&
|
if (conf[0] != '\0' &&
|
||||||
qemu_rbd_set_conf(cluster, conf, &local_err) < 0) {
|
qemu_rbd_set_conf(cluster, conf, false, &local_err) < 0) {
|
||||||
rados_shutdown(cluster);
|
rados_shutdown(cluster);
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@ -405,7 +409,6 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
|||||||
}
|
}
|
||||||
qemu_vfree(acb->bounce);
|
qemu_vfree(acb->bounce);
|
||||||
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
||||||
acb->status = 0;
|
|
||||||
|
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
@ -468,6 +471,23 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->snap = g_strdup(snap_buf);
|
s->snap = g_strdup(snap_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
|
/* try default location, but ignore failure */
|
||||||
|
rados_conf_read_file(s->cluster, NULL);
|
||||||
|
} else if (conf[0] != '\0') {
|
||||||
|
r = qemu_rbd_set_conf(s->cluster, conf, true, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
goto failed_shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf[0] != '\0') {
|
||||||
|
r = qemu_rbd_set_conf(s->cluster, conf, false, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
goto failed_shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fallback to more conservative semantics if setting cache
|
* Fallback to more conservative semantics if setting cache
|
||||||
* options fails. Ignore errors from setting rbd_cache because the
|
* options fails. Ignore errors from setting rbd_cache because the
|
||||||
@ -481,18 +501,6 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
rados_conf_set(s->cluster, "rbd_cache", "true");
|
rados_conf_set(s->cluster, "rbd_cache", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(conf, "conf=") == NULL) {
|
|
||||||
/* try default location, but ignore failure */
|
|
||||||
rados_conf_read_file(s->cluster, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf[0] != '\0') {
|
|
||||||
r = qemu_rbd_set_conf(s->cluster, conf, errp);
|
|
||||||
if (r < 0) {
|
|
||||||
goto failed_shutdown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r = rados_connect(s->cluster);
|
r = rados_connect(s->cluster);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(errp, "error connecting");
|
error_setg(errp, "error connecting");
|
||||||
@ -621,7 +629,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
acb->error = 0;
|
acb->error = 0;
|
||||||
acb->s = s;
|
acb->s = s;
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
acb->status = -EINPROGRESS;
|
|
||||||
|
|
||||||
if (cmd == RBD_AIO_WRITE) {
|
if (cmd == RBD_AIO_WRITE) {
|
||||||
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
||||||
@ -633,7 +640,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
rcb = g_new(RADOSCB, 1);
|
rcb = g_new(RADOSCB, 1);
|
||||||
rcb->done = 0;
|
|
||||||
rcb->acb = acb;
|
rcb->acb = acb;
|
||||||
rcb->buf = buf;
|
rcb->buf = buf;
|
||||||
rcb->s = acb->s;
|
rcb->s = acb->s;
|
||||||
|
@ -207,11 +207,23 @@ static void nvme_rw_cb(void *opaque, int ret)
|
|||||||
} else {
|
} else {
|
||||||
req->status = NVME_INTERNAL_DEV_ERROR;
|
req->status = NVME_INTERNAL_DEV_ERROR;
|
||||||
}
|
}
|
||||||
|
if (req->has_sg) {
|
||||||
qemu_sglist_destroy(&req->qsg);
|
qemu_sglist_destroy(&req->qsg);
|
||||||
|
}
|
||||||
nvme_enqueue_req_completion(cq, req);
|
nvme_enqueue_req_completion(cq, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||||
|
NvmeRequest *req)
|
||||||
|
{
|
||||||
|
req->has_sg = false;
|
||||||
|
block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
|
||||||
|
BLOCK_ACCT_FLUSH);
|
||||||
|
req->aiocb = blk_aio_flush(n->conf.blk, nvme_rw_cb, req);
|
||||||
|
|
||||||
|
return NVME_NO_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||||
NvmeRequest *req)
|
NvmeRequest *req)
|
||||||
{
|
{
|
||||||
@ -235,6 +247,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
|||||||
}
|
}
|
||||||
assert((nlb << data_shift) == req->qsg.size);
|
assert((nlb << data_shift) == req->qsg.size);
|
||||||
|
|
||||||
|
req->has_sg = true;
|
||||||
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
|
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
|
||||||
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||||
req->aiocb = is_write ?
|
req->aiocb = is_write ?
|
||||||
@ -256,7 +269,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
|||||||
ns = &n->namespaces[nsid - 1];
|
ns = &n->namespaces[nsid - 1];
|
||||||
switch (cmd->opcode) {
|
switch (cmd->opcode) {
|
||||||
case NVME_CMD_FLUSH:
|
case NVME_CMD_FLUSH:
|
||||||
return NVME_SUCCESS;
|
return nvme_flush(n, ns, cmd, req);
|
||||||
case NVME_CMD_WRITE:
|
case NVME_CMD_WRITE:
|
||||||
case NVME_CMD_READ:
|
case NVME_CMD_READ:
|
||||||
return nvme_rw(n, ns, cmd, req);
|
return nvme_rw(n, ns, cmd, req);
|
||||||
@ -474,26 +487,32 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
|
|||||||
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||||
{
|
{
|
||||||
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
||||||
|
uint32_t result;
|
||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
|
||||||
req->cqe.result =
|
|
||||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
|
||||||
break;
|
|
||||||
case NVME_VOLATILE_WRITE_CACHE:
|
case NVME_VOLATILE_WRITE_CACHE:
|
||||||
req->cqe.result = cpu_to_le32(1);
|
result = blk_enable_write_cache(n->conf.blk);
|
||||||
|
break;
|
||||||
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
|
result = cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req->cqe.result = result;
|
||||||
return NVME_SUCCESS;
|
return NVME_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||||
{
|
{
|
||||||
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
||||||
|
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
|
||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
|
case NVME_VOLATILE_WRITE_CACHE:
|
||||||
|
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
|
||||||
|
break;
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
req->cqe.result =
|
req->cqe.result =
|
||||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
@ -818,6 +837,9 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
id->psd[0].mp = cpu_to_le16(0x9c4);
|
id->psd[0].mp = cpu_to_le16(0x9c4);
|
||||||
id->psd[0].enlat = cpu_to_le32(0x10);
|
id->psd[0].enlat = cpu_to_le32(0x10);
|
||||||
id->psd[0].exlat = cpu_to_le32(0x4);
|
id->psd[0].exlat = cpu_to_le32(0x4);
|
||||||
|
if (blk_enable_write_cache(n->conf.blk)) {
|
||||||
|
id->vwc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
n->bar.cap = 0;
|
n->bar.cap = 0;
|
||||||
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
|
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
|
||||||
|
@ -638,6 +638,7 @@ typedef struct NvmeRequest {
|
|||||||
struct NvmeSQueue *sq;
|
struct NvmeSQueue *sq;
|
||||||
BlockAIOCB *aiocb;
|
BlockAIOCB *aiocb;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
bool has_sg;
|
||||||
NvmeCqe cqe;
|
NvmeCqe cqe;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
QEMUSGList qsg;
|
QEMUSGList qsg;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
/* block.c */
|
/* block.c */
|
||||||
typedef struct BlockDriver BlockDriver;
|
typedef struct BlockDriver BlockDriver;
|
||||||
typedef struct BlockJob BlockJob;
|
typedef struct BlockJob BlockJob;
|
||||||
|
typedef struct BdrvChild BdrvChild;
|
||||||
typedef struct BdrvChildRole BdrvChildRole;
|
typedef struct BdrvChildRole BdrvChildRole;
|
||||||
|
|
||||||
typedef struct BlockDriverInfo {
|
typedef struct BlockDriverInfo {
|
||||||
@ -208,6 +209,11 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
|||||||
QDict *options, const char *bdref_key,
|
QDict *options, const char *bdref_key,
|
||||||
BlockDriverState* parent, const BdrvChildRole *child_role,
|
BlockDriverState* parent, const BdrvChildRole *child_role,
|
||||||
bool allow_none, Error **errp);
|
bool allow_none, Error **errp);
|
||||||
|
BdrvChild *bdrv_open_child(const char *filename,
|
||||||
|
QDict *options, const char *bdref_key,
|
||||||
|
BlockDriverState* parent,
|
||||||
|
const BdrvChildRole *child_role,
|
||||||
|
bool allow_none, Error **errp);
|
||||||
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
|
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
||||||
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
|
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
|
||||||
@ -507,6 +513,7 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
|
|||||||
|
|
||||||
void bdrv_ref(BlockDriverState *bs);
|
void bdrv_ref(BlockDriverState *bs);
|
||||||
void bdrv_unref(BlockDriverState *bs);
|
void bdrv_unref(BlockDriverState *bs);
|
||||||
|
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
|
||||||
|
|
||||||
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
|
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
|
||||||
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
|
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
|
||||||
|
@ -335,11 +335,11 @@ struct BdrvChildRole {
|
|||||||
extern const BdrvChildRole child_file;
|
extern const BdrvChildRole child_file;
|
||||||
extern const BdrvChildRole child_format;
|
extern const BdrvChildRole child_format;
|
||||||
|
|
||||||
typedef struct BdrvChild {
|
struct BdrvChild {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
const BdrvChildRole *role;
|
const BdrvChildRole *role;
|
||||||
QLIST_ENTRY(BdrvChild) next;
|
QLIST_ENTRY(BdrvChild) next;
|
||||||
} BdrvChild;
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: the function bdrv_append() copies and swaps contents of
|
* Note: the function bdrv_append() copies and swaps contents of
|
||||||
@ -379,6 +379,7 @@ struct BlockDriverState {
|
|||||||
char exact_filename[PATH_MAX];
|
char exact_filename[PATH_MAX];
|
||||||
|
|
||||||
BlockDriverState *backing_hd;
|
BlockDriverState *backing_hd;
|
||||||
|
BdrvChild *backing_child;
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
|
|
||||||
NotifierList close_notifiers;
|
NotifierList close_notifiers;
|
||||||
|
Loading…
Reference in New Issue
Block a user