Block layer patches:
- file-posix: Don't waste a file descriptor for locking, don't lock the same bit multiple times - nvme: Fix double free and memory leak - Misc error handling fixes - Added NULL checks found by static analysis - Allow more block drivers to not be included in the qemu build -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJb6bK8AAoJEH8JsnLIjy/WyPoP/j8bNQseKzsKiclV942LitYl FX7px4xdAJEo9avuPCAfih7AiGxcf4A/cAunF8HsBXOHH7VJtaMqpAmkSb41G5qi eRKQNIWRb6J8VBJVloTGK4sNL92zShiehQFVhcsqdjn8d0xYi4d3QViLBLCnOdbs uaaW3T137lr5lyG9aFtfeVPnBTj9VFgZPsuikGtJT29r/V7MtUP4/r6gmNryixy9 8xznAn8wkIrDUq8nX6IkcPnVZFoUh2d7O8BLjFhpJNp+CudDz/N3WXv7sBn6p0yo Rhs+a+VQuDj/q8yxIDhyJ9KQmQbjSoKOv2pYitTsFuAi7KxtL0M6//y6OUu1A6s/ iUSLFBm1tkoXDQJx8XnDlLiITu1Y8e/gu4fADoFzxelwlXZBZVAcE03c/5jlxUAn sW1815JPop7NvaGKMTVGKCyD6TmkqDx06uHjD7VGebWlPa/qfzwl6SqY+L3GW5eL w0k/Qba849FkpQ5L7r1btCOFCS+FKDBUS1EpPzurL1MvPd3D0HwkGj6kM/xt7tnC wiqqOz7sX6zZutToYCQD9UmI2EgFsblbS8G2Ww8akbsPp5lyYjZJsaK8hQSU4nqL q0snTBI5DyL1ISjRjSnK7e0CZj785g67jsTryyz8IiUM70R3Q5WjVbOsxvcGrClC CE0lypMIKxDvcuRReMp/ =4Xo8 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - file-posix: Don't waste a file descriptor for locking, don't lock the same bit multiple times - nvme: Fix double free and memory leak - Misc error handling fixes - Added NULL checks found by static analysis - Allow more block drivers to not be included in the qemu build # gpg: Signature made Mon 12 Nov 2018 17:05:00 GMT # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: qcow2: Read outside array bounds in qcow2_pre_write_overlap_check() block: Fix potential Null pointer dereferences in vvfat.c qemu-img: assert block_job_get() does not return NULL in img_commit() block: Null pointer dereference in blk_root_get_parent_desc() job: Fix off-by-one assert checks for JobSTT and JobVerbTable block: Make more block drivers compile-time configurable tests: Add unit tests for image locking file-posix: Drop s->lock_fd file-posix: Skip effectiveless OFD lock operations nvme: free cmbuf in nvme_exit nvme: don't unref ctrl_mem when device unrealized blockdev: Consistently use snapshot_node_name in external_snapshot_prepare() blockdev: handle error on block latency histogram set error file-posix: Use error API properly Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6db87aae61
@ -1,10 +1,18 @@
|
|||||||
block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
block-obj-y += raw-format.o vmdk.o vpc.o
|
||||||
|
block-obj-$(CONFIG_QCOW1) += qcow.o
|
||||||
|
block-obj-$(CONFIG_VDI) += vdi.o
|
||||||
|
block-obj-$(CONFIG_CLOOP) += cloop.o
|
||||||
|
block-obj-$(CONFIG_BOCHS) += bochs.o
|
||||||
|
block-obj-$(CONFIG_VVFAT) += vvfat.o
|
||||||
|
block-obj-$(CONFIG_DMG) += dmg.o
|
||||||
|
|
||||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
|
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
|
||||||
block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
|
block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||||
block-obj-y += qed-check.o
|
block-obj-$(CONFIG_QED) += qed-check.o
|
||||||
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
||||||
block-obj-y += quorum.o
|
block-obj-y += quorum.o
|
||||||
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
|
block-obj-y += blkdebug.o blkverify.o blkreplay.o
|
||||||
|
block-obj-$(CONFIG_PARALLELS) += parallels.o
|
||||||
block-obj-y += blklogwrites.o
|
block-obj-y += blklogwrites.o
|
||||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||||
@ -14,7 +22,8 @@ block-obj-y += null.o mirror.o commit.o io.o create.o
|
|||||||
block-obj-y += throttle-groups.o
|
block-obj-y += throttle-groups.o
|
||||||
block-obj-$(CONFIG_LINUX) += nvme.o
|
block-obj-$(CONFIG_LINUX) += nvme.o
|
||||||
|
|
||||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
block-obj-y += nbd.o nbd-client.o
|
||||||
|
block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o
|
||||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||||
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
|
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
|
||||||
block-obj-$(CONFIG_LIBNFS) += nfs.o
|
block-obj-$(CONFIG_LIBNFS) += nfs.o
|
||||||
@ -45,7 +54,8 @@ gluster.o-libs := $(GLUSTERFS_LIBS)
|
|||||||
vxhs.o-libs := $(VXHS_LIBS)
|
vxhs.o-libs := $(VXHS_LIBS)
|
||||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||||
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
|
||||||
|
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
|
||||||
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
||||||
qcow.o-libs := -lz
|
qcow.o-libs := -lz
|
||||||
linux-aio.o-libs := -laio
|
linux-aio.o-libs := -laio
|
||||||
|
@ -918,7 +918,8 @@ char *blk_get_attached_dev_id(BlockBackend *blk)
|
|||||||
} else if (dev->id) {
|
} else if (dev->id) {
|
||||||
return g_strdup(dev->id);
|
return g_strdup(dev->id);
|
||||||
}
|
}
|
||||||
return object_get_canonical_path(OBJECT(dev));
|
|
||||||
|
return object_get_canonical_path(OBJECT(dev)) ?: g_strdup("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -142,7 +142,6 @@ do { \
|
|||||||
|
|
||||||
typedef struct BDRVRawState {
|
typedef struct BDRVRawState {
|
||||||
int fd;
|
int fd;
|
||||||
int lock_fd;
|
|
||||||
bool use_lock;
|
bool use_lock;
|
||||||
int type;
|
int type;
|
||||||
int open_flags;
|
int open_flags;
|
||||||
@ -152,6 +151,11 @@ typedef struct BDRVRawState {
|
|||||||
uint64_t perm;
|
uint64_t perm;
|
||||||
uint64_t shared_perm;
|
uint64_t shared_perm;
|
||||||
|
|
||||||
|
/* The perms bits whose corresponding bytes are already locked in
|
||||||
|
* s->fd. */
|
||||||
|
uint64_t locked_perm;
|
||||||
|
uint64_t locked_shared_perm;
|
||||||
|
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
bool is_xfs:1;
|
bool is_xfs:1;
|
||||||
#endif
|
#endif
|
||||||
@ -205,7 +209,7 @@ static int cdrom_reopen(BlockDriverState *bs);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__NetBSD__)
|
#if defined(__NetBSD__)
|
||||||
static int raw_normalize_devicepath(const char **filename)
|
static int raw_normalize_devicepath(const char **filename, Error **errp)
|
||||||
{
|
{
|
||||||
static char namebuf[PATH_MAX];
|
static char namebuf[PATH_MAX];
|
||||||
const char *dp, *fname;
|
const char *dp, *fname;
|
||||||
@ -214,8 +218,7 @@ static int raw_normalize_devicepath(const char **filename)
|
|||||||
fname = *filename;
|
fname = *filename;
|
||||||
dp = strrchr(fname, '/');
|
dp = strrchr(fname, '/');
|
||||||
if (lstat(fname, &sb) < 0) {
|
if (lstat(fname, &sb) < 0) {
|
||||||
fprintf(stderr, "%s: stat failed: %s\n",
|
error_setg_errno(errp, errno, "%s: stat failed", fname);
|
||||||
fname, strerror(errno));
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,14 +232,13 @@ static int raw_normalize_devicepath(const char **filename)
|
|||||||
snprintf(namebuf, PATH_MAX, "%.*s/r%s",
|
snprintf(namebuf, PATH_MAX, "%.*s/r%s",
|
||||||
(int)(dp - fname), fname, dp + 1);
|
(int)(dp - fname), fname, dp + 1);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s is a block device", fname);
|
|
||||||
*filename = namebuf;
|
*filename = namebuf;
|
||||||
fprintf(stderr, ", using %s\n", *filename);
|
warn_report("%s is a block device, using %s", fname, *filename);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int raw_normalize_devicepath(const char **filename)
|
static int raw_normalize_devicepath(const char **filename, Error **errp)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -461,9 +463,8 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
filename = qemu_opt_get(opts, "filename");
|
filename = qemu_opt_get(opts, "filename");
|
||||||
|
|
||||||
ret = raw_normalize_devicepath(&filename);
|
ret = raw_normalize_devicepath(&filename, errp);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not normalize device path");
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,10 +493,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
case ON_OFF_AUTO_ON:
|
case ON_OFF_AUTO_ON:
|
||||||
s->use_lock = true;
|
s->use_lock = true;
|
||||||
if (!qemu_has_ofd_lock()) {
|
if (!qemu_has_ofd_lock()) {
|
||||||
fprintf(stderr,
|
warn_report("File lock requested but OFD locking syscall is "
|
||||||
"File lock requested but OFD locking syscall is "
|
"unavailable, falling back to POSIX file locks");
|
||||||
"unavailable, falling back to POSIX file locks.\n"
|
error_printf("Due to the implementation, locks can be lost "
|
||||||
"Due to the implementation, locks can be lost "
|
|
||||||
"unexpectedly.\n");
|
"unexpectedly.\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -550,18 +550,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
}
|
}
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
|
|
||||||
s->lock_fd = -1;
|
|
||||||
if (s->use_lock) {
|
|
||||||
fd = qemu_open(filename, s->open_flags);
|
|
||||||
if (fd < 0) {
|
|
||||||
ret = -errno;
|
|
||||||
error_setg_errno(errp, errno, "Could not open '%s' for locking",
|
|
||||||
filename);
|
|
||||||
qemu_close(s->fd);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
s->lock_fd = fd;
|
|
||||||
}
|
|
||||||
s->perm = 0;
|
s->perm = 0;
|
||||||
s->shared_perm = BLK_PERM_ALL;
|
s->shared_perm = BLK_PERM_ALL;
|
||||||
|
|
||||||
@ -693,43 +681,72 @@ typedef enum {
|
|||||||
* file; if @unlock == true, also unlock the unneeded bytes.
|
* file; if @unlock == true, also unlock the unneeded bytes.
|
||||||
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
|
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
|
||||||
*/
|
*/
|
||||||
static int raw_apply_lock_bytes(int fd,
|
static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
|
||||||
uint64_t perm_lock_bits,
|
uint64_t perm_lock_bits,
|
||||||
uint64_t shared_perm_lock_bits,
|
uint64_t shared_perm_lock_bits,
|
||||||
bool unlock, Error **errp)
|
bool unlock, Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
uint64_t locked_perm, locked_shared_perm;
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
locked_perm = s->locked_perm;
|
||||||
|
locked_shared_perm = s->locked_shared_perm;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* We don't have the previous bits, just lock/unlock for each of the
|
||||||
|
* requested bits.
|
||||||
|
*/
|
||||||
|
if (unlock) {
|
||||||
|
locked_perm = BLK_PERM_ALL;
|
||||||
|
locked_shared_perm = BLK_PERM_ALL;
|
||||||
|
} else {
|
||||||
|
locked_perm = 0;
|
||||||
|
locked_shared_perm = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PERM_FOREACH(i) {
|
PERM_FOREACH(i) {
|
||||||
int off = RAW_LOCK_PERM_BASE + i;
|
int off = RAW_LOCK_PERM_BASE + i;
|
||||||
if (perm_lock_bits & (1ULL << i)) {
|
uint64_t bit = (1ULL << i);
|
||||||
|
if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
|
||||||
ret = qemu_lock_fd(fd, off, 1, false);
|
ret = qemu_lock_fd(fd, off, 1, false);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_setg(errp, "Failed to lock byte %d", off);
|
error_setg(errp, "Failed to lock byte %d", off);
|
||||||
return ret;
|
return ret;
|
||||||
|
} else if (s) {
|
||||||
|
s->locked_perm |= bit;
|
||||||
}
|
}
|
||||||
} else if (unlock) {
|
} else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
|
||||||
ret = qemu_unlock_fd(fd, off, 1);
|
ret = qemu_unlock_fd(fd, off, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_setg(errp, "Failed to unlock byte %d", off);
|
error_setg(errp, "Failed to unlock byte %d", off);
|
||||||
return ret;
|
return ret;
|
||||||
|
} else if (s) {
|
||||||
|
s->locked_perm &= ~bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PERM_FOREACH(i) {
|
PERM_FOREACH(i) {
|
||||||
int off = RAW_LOCK_SHARED_BASE + i;
|
int off = RAW_LOCK_SHARED_BASE + i;
|
||||||
if (shared_perm_lock_bits & (1ULL << i)) {
|
uint64_t bit = (1ULL << i);
|
||||||
|
if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
|
||||||
ret = qemu_lock_fd(fd, off, 1, false);
|
ret = qemu_lock_fd(fd, off, 1, false);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_setg(errp, "Failed to lock byte %d", off);
|
error_setg(errp, "Failed to lock byte %d", off);
|
||||||
return ret;
|
return ret;
|
||||||
|
} else if (s) {
|
||||||
|
s->locked_shared_perm |= bit;
|
||||||
}
|
}
|
||||||
} else if (unlock) {
|
} else if (unlock && (locked_shared_perm & bit) &&
|
||||||
|
!(shared_perm_lock_bits & bit)) {
|
||||||
ret = qemu_unlock_fd(fd, off, 1);
|
ret = qemu_unlock_fd(fd, off, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_setg(errp, "Failed to unlock byte %d", off);
|
error_setg(errp, "Failed to unlock byte %d", off);
|
||||||
return ret;
|
return ret;
|
||||||
|
} else if (s) {
|
||||||
|
s->locked_shared_perm &= ~bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,15 +810,13 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(s->lock_fd > 0);
|
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case RAW_PL_PREPARE:
|
case RAW_PL_PREPARE:
|
||||||
ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
|
ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm,
|
||||||
~s->shared_perm | ~new_shared,
|
~s->shared_perm | ~new_shared,
|
||||||
false, errp);
|
false, errp);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp);
|
ret = raw_check_lock_bytes(s->fd, new_perm, new_shared, errp);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -812,23 +827,23 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
|
|||||||
op = RAW_PL_ABORT;
|
op = RAW_PL_ABORT;
|
||||||
/* fall through to unlock bytes. */
|
/* fall through to unlock bytes. */
|
||||||
case RAW_PL_ABORT:
|
case RAW_PL_ABORT:
|
||||||
raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
|
raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm,
|
||||||
true, &local_err);
|
true, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
/* Theoretically the above call only unlocks bytes and it cannot
|
/* Theoretically the above call only unlocks bytes and it cannot
|
||||||
* fail. Something weird happened, report it.
|
* fail. Something weird happened, report it.
|
||||||
*/
|
*/
|
||||||
error_report_err(local_err);
|
warn_report_err(local_err);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RAW_PL_COMMIT:
|
case RAW_PL_COMMIT:
|
||||||
raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
|
raw_apply_lock_bytes(s, s->fd, new_perm, ~new_shared,
|
||||||
true, &local_err);
|
true, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
/* Theoretically the above call only unlocks bytes and it cannot
|
/* Theoretically the above call only unlocks bytes and it cannot
|
||||||
* fail. Something weird happened, report it.
|
* fail. Something weird happened, report it.
|
||||||
*/
|
*/
|
||||||
error_report_err(local_err);
|
warn_report_err(local_err);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -905,10 +920,8 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
|||||||
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
|
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
|
||||||
if (rs->fd == -1) {
|
if (rs->fd == -1) {
|
||||||
const char *normalized_filename = state->bs->filename;
|
const char *normalized_filename = state->bs->filename;
|
||||||
ret = raw_normalize_devicepath(&normalized_filename);
|
ret = raw_normalize_devicepath(&normalized_filename, errp);
|
||||||
if (ret < 0) {
|
if (ret >= 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not normalize device path");
|
|
||||||
} else {
|
|
||||||
assert(!(rs->open_flags & O_CREAT));
|
assert(!(rs->open_flags & O_CREAT));
|
||||||
rs->fd = qemu_open(normalized_filename, rs->open_flags);
|
rs->fd = qemu_open(normalized_filename, rs->open_flags);
|
||||||
if (rs->fd == -1) {
|
if (rs->fd == -1) {
|
||||||
@ -939,10 +952,18 @@ static void raw_reopen_commit(BDRVReopenState *state)
|
|||||||
{
|
{
|
||||||
BDRVRawReopenState *rs = state->opaque;
|
BDRVRawReopenState *rs = state->opaque;
|
||||||
BDRVRawState *s = state->bs->opaque;
|
BDRVRawState *s = state->bs->opaque;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
s->check_cache_dropped = rs->check_cache_dropped;
|
s->check_cache_dropped = rs->check_cache_dropped;
|
||||||
s->open_flags = rs->open_flags;
|
s->open_flags = rs->open_flags;
|
||||||
|
|
||||||
|
/* Copy locks to the new fd before closing the old one. */
|
||||||
|
raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
|
||||||
|
~s->locked_shared_perm, false, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
/* shouldn't fail in a sane host, but report it just in case. */
|
||||||
|
error_report_err(local_err);
|
||||||
|
}
|
||||||
qemu_close(s->fd);
|
qemu_close(s->fd);
|
||||||
s->fd = rs->fd;
|
s->fd = rs->fd;
|
||||||
|
|
||||||
@ -1788,7 +1809,7 @@ static int aio_worker(void *arg)
|
|||||||
ret = handle_aiocb_truncate(aiocb);
|
ret = handle_aiocb_truncate(aiocb);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
error_report("invalid aio request (0x%x)", aiocb->aio_type);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1935,10 +1956,6 @@ static void raw_close(BlockDriverState *bs)
|
|||||||
qemu_close(s->fd);
|
qemu_close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
}
|
}
|
||||||
if (s->lock_fd >= 0) {
|
|
||||||
qemu_close(s->lock_fd);
|
|
||||||
s->lock_fd = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2226,7 +2243,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
|
|||||||
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
|
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
|
||||||
|
|
||||||
/* Step one: Take locks */
|
/* Step one: Take locks */
|
||||||
result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
|
result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
@ -2270,13 +2287,13 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
|
raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
/* The above call should not fail, and if it does, that does
|
/* The above call should not fail, and if it does, that does
|
||||||
* not mean the whole creation operation has failed. So
|
* not mean the whole creation operation has failed. So
|
||||||
* report it the user for their convenience, but do not report
|
* report it the user for their convenience, but do not report
|
||||||
* it to the caller. */
|
* it to the caller. */
|
||||||
error_report_err(local_err);
|
warn_report_err(local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
out_close:
|
out_close:
|
||||||
@ -3141,9 +3158,8 @@ static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts
|
|||||||
|
|
||||||
(void)has_prefix;
|
(void)has_prefix;
|
||||||
|
|
||||||
ret = raw_normalize_devicepath(&filename);
|
ret = raw_normalize_devicepath(&filename, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not normalize device path");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2727,7 +2727,9 @@ static const char *metadata_ol_names[] = {
|
|||||||
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
|
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
|
||||||
[QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
|
[QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
|
||||||
[QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
|
[QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
|
||||||
|
[QCOW2_OL_BITMAP_DIRECTORY_BITNR] = "bitmap directory",
|
||||||
};
|
};
|
||||||
|
QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First performs a check for metadata overlaps (through
|
* First performs a check for metadata overlaps (through
|
||||||
|
@ -100,30 +100,26 @@ static inline void array_free(array_t* array)
|
|||||||
/* does not automatically grow */
|
/* does not automatically grow */
|
||||||
static inline void* array_get(array_t* array,unsigned int index) {
|
static inline void* array_get(array_t* array,unsigned int index) {
|
||||||
assert(index < array->next);
|
assert(index < array->next);
|
||||||
|
assert(array->pointer);
|
||||||
return array->pointer + index * array->item_size;
|
return array->pointer + index * array->item_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int array_ensure_allocated(array_t* array, int index)
|
static inline void array_ensure_allocated(array_t *array, int index)
|
||||||
{
|
{
|
||||||
if((index + 1) * array->item_size > array->size) {
|
if((index + 1) * array->item_size > array->size) {
|
||||||
int new_size = (index + 32) * array->item_size;
|
int new_size = (index + 32) * array->item_size;
|
||||||
array->pointer = g_realloc(array->pointer, new_size);
|
array->pointer = g_realloc(array->pointer, new_size);
|
||||||
if (!array->pointer)
|
assert(array->pointer);
|
||||||
return -1;
|
|
||||||
memset(array->pointer + array->size, 0, new_size - array->size);
|
memset(array->pointer + array->size, 0, new_size - array->size);
|
||||||
array->size = new_size;
|
array->size = new_size;
|
||||||
array->next = index + 1;
|
array->next = index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* array_get_next(array_t* array) {
|
static inline void* array_get_next(array_t* array) {
|
||||||
unsigned int next = array->next;
|
unsigned int next = array->next;
|
||||||
|
|
||||||
if (array_ensure_allocated(array, next) < 0)
|
array_ensure_allocated(array, next);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
array->next = next + 1;
|
array->next = next + 1;
|
||||||
return array_get(array, next);
|
return array_get(array, next);
|
||||||
}
|
}
|
||||||
@ -2422,16 +2418,13 @@ static int commit_direntries(BDRVVVFATState* s,
|
|||||||
direntry_t* direntry = array_get(&(s->directory), dir_index);
|
direntry_t* direntry = array_get(&(s->directory), dir_index);
|
||||||
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
|
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
|
||||||
mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
|
mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
|
||||||
|
|
||||||
int factor = 0x10 * s->sectors_per_cluster;
|
int factor = 0x10 * s->sectors_per_cluster;
|
||||||
int old_cluster_count, new_cluster_count;
|
int old_cluster_count, new_cluster_count;
|
||||||
int current_dir_index = mapping->info.dir.first_dir_index;
|
int current_dir_index;
|
||||||
int first_dir_index = current_dir_index;
|
int first_dir_index;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
|
|
||||||
DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
|
|
||||||
|
|
||||||
assert(direntry);
|
assert(direntry);
|
||||||
assert(mapping);
|
assert(mapping);
|
||||||
assert(mapping->begin == first_cluster);
|
assert(mapping->begin == first_cluster);
|
||||||
@ -2439,6 +2432,11 @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp
|
|||||||
assert(mapping->mode & MODE_DIRECTORY);
|
assert(mapping->mode & MODE_DIRECTORY);
|
||||||
assert(dir_index == 0 || is_directory(direntry));
|
assert(dir_index == 0 || is_directory(direntry));
|
||||||
|
|
||||||
|
DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
|
||||||
|
mapping->path, parent_mapping_index));
|
||||||
|
|
||||||
|
current_dir_index = mapping->info.dir.first_dir_index;
|
||||||
|
first_dir_index = current_dir_index;
|
||||||
mapping->info.dir.parent_mapping_index = parent_mapping_index;
|
mapping->info.dir.parent_mapping_index = parent_mapping_index;
|
||||||
|
|
||||||
if (first_cluster == 0) {
|
if (first_cluster == 0) {
|
||||||
@ -2488,6 +2486,9 @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp
|
|||||||
direntry = array_get(&(s->directory), first_dir_index + i);
|
direntry = array_get(&(s->directory), first_dir_index + i);
|
||||||
if (is_directory(direntry) && !is_dot(direntry)) {
|
if (is_directory(direntry) && !is_dot(direntry)) {
|
||||||
mapping = find_mapping_for_cluster(s, first_cluster);
|
mapping = find_mapping_for_cluster(s, first_cluster);
|
||||||
|
if (mapping == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
assert(mapping->mode & MODE_DIRECTORY);
|
assert(mapping->mode & MODE_DIRECTORY);
|
||||||
ret = commit_direntries(s, first_dir_index + i,
|
ret = commit_direntries(s, first_dir_index + i,
|
||||||
array_index(&(s->mapping), mapping));
|
array_index(&(s->mapping), mapping));
|
||||||
@ -2516,6 +2517,10 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
assert(offset < size);
|
assert(offset < size);
|
||||||
assert((offset % s->cluster_size) == 0);
|
assert((offset % s->cluster_size) == 0);
|
||||||
|
|
||||||
|
if (mapping == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = s->cluster_size; i < offset; i += s->cluster_size)
|
for (i = s->cluster_size; i < offset; i += s->cluster_size)
|
||||||
c = modified_fat_get(s, c);
|
c = modified_fat_get(s, c);
|
||||||
|
|
||||||
@ -2662,8 +2667,12 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
|
|||||||
if (commit->action == ACTION_RENAME) {
|
if (commit->action == ACTION_RENAME) {
|
||||||
mapping_t* mapping = find_mapping_for_cluster(s,
|
mapping_t* mapping = find_mapping_for_cluster(s,
|
||||||
commit->param.rename.cluster);
|
commit->param.rename.cluster);
|
||||||
char* old_path = mapping->path;
|
char *old_path;
|
||||||
|
|
||||||
|
if (mapping == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
old_path = mapping->path;
|
||||||
assert(commit->path);
|
assert(commit->path);
|
||||||
mapping->path = commit->path;
|
mapping->path = commit->path;
|
||||||
if (rename(old_path, mapping->path))
|
if (rename(old_path, mapping->path))
|
||||||
@ -2684,10 +2693,15 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
|
|||||||
direntry_t* d = direntry + i;
|
direntry_t* d = direntry + i;
|
||||||
|
|
||||||
if (is_file(d) || (is_directory(d) && !is_dot(d))) {
|
if (is_file(d) || (is_directory(d) && !is_dot(d))) {
|
||||||
|
int l;
|
||||||
|
char *new_path;
|
||||||
mapping_t* m = find_mapping_for_cluster(s,
|
mapping_t* m = find_mapping_for_cluster(s,
|
||||||
begin_of_direntry(d));
|
begin_of_direntry(d));
|
||||||
int l = strlen(m->path);
|
if (m == NULL) {
|
||||||
char* new_path = g_malloc(l + diff + 1);
|
return -1;
|
||||||
|
}
|
||||||
|
l = strlen(m->path);
|
||||||
|
new_path = g_malloc(l + diff + 1);
|
||||||
|
|
||||||
assert(!strncmp(m->path, mapping->path, l2));
|
assert(!strncmp(m->path, mapping->path, l2));
|
||||||
|
|
||||||
|
21
blockdev.c
21
blockdev.c
@ -1640,7 +1640,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
|||||||
}
|
}
|
||||||
|
|
||||||
options = qdict_new();
|
options = qdict_new();
|
||||||
if (s->has_snapshot_node_name) {
|
if (snapshot_node_name) {
|
||||||
qdict_put_str(options, "node-name", snapshot_node_name);
|
qdict_put_str(options, "node-name", snapshot_node_name);
|
||||||
}
|
}
|
||||||
qdict_put_str(options, "driver", format);
|
qdict_put_str(options, "driver", format);
|
||||||
@ -4413,6 +4413,7 @@ void qmp_x_block_latency_histogram_set(
|
|||||||
{
|
{
|
||||||
BlockBackend *blk = blk_by_name(device);
|
BlockBackend *blk = blk_by_name(device);
|
||||||
BlockAcctStats *stats;
|
BlockAcctStats *stats;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!blk) {
|
if (!blk) {
|
||||||
error_setg(errp, "Device '%s' not found", device);
|
error_setg(errp, "Device '%s' not found", device);
|
||||||
@ -4428,21 +4429,33 @@ void qmp_x_block_latency_histogram_set(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (has_boundaries || has_boundaries_read) {
|
if (has_boundaries || has_boundaries_read) {
|
||||||
block_latency_histogram_set(
|
ret = block_latency_histogram_set(
|
||||||
stats, BLOCK_ACCT_READ,
|
stats, BLOCK_ACCT_READ,
|
||||||
has_boundaries_read ? boundaries_read : boundaries);
|
has_boundaries_read ? boundaries_read : boundaries);
|
||||||
|
if (ret) {
|
||||||
|
error_setg(errp, "Device '%s' set read boundaries fail", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_boundaries || has_boundaries_write) {
|
if (has_boundaries || has_boundaries_write) {
|
||||||
block_latency_histogram_set(
|
ret = block_latency_histogram_set(
|
||||||
stats, BLOCK_ACCT_WRITE,
|
stats, BLOCK_ACCT_WRITE,
|
||||||
has_boundaries_write ? boundaries_write : boundaries);
|
has_boundaries_write ? boundaries_write : boundaries);
|
||||||
|
if (ret) {
|
||||||
|
error_setg(errp, "Device '%s' set write boundaries fail", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_boundaries || has_boundaries_flush) {
|
if (has_boundaries || has_boundaries_flush) {
|
||||||
block_latency_histogram_set(
|
ret = block_latency_histogram_set(
|
||||||
stats, BLOCK_ACCT_FLUSH,
|
stats, BLOCK_ACCT_FLUSH,
|
||||||
has_boundaries_flush ? boundaries_flush : boundaries);
|
has_boundaries_flush ? boundaries_flush : boundaries);
|
||||||
|
if (ret) {
|
||||||
|
error_setg(errp, "Device '%s' set flush boundaries fail", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
configure
vendored
91
configure
vendored
@ -470,6 +470,15 @@ tcmalloc="no"
|
|||||||
jemalloc="no"
|
jemalloc="no"
|
||||||
replication="yes"
|
replication="yes"
|
||||||
vxhs=""
|
vxhs=""
|
||||||
|
bochs="yes"
|
||||||
|
cloop="yes"
|
||||||
|
dmg="yes"
|
||||||
|
qcow1="yes"
|
||||||
|
vdi="yes"
|
||||||
|
vvfat="yes"
|
||||||
|
qed="yes"
|
||||||
|
parallels="yes"
|
||||||
|
sheepdog="yes"
|
||||||
libxml2=""
|
libxml2=""
|
||||||
docker="no"
|
docker="no"
|
||||||
debug_mutex="no"
|
debug_mutex="no"
|
||||||
@ -1416,6 +1425,42 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-vxhs) vxhs="yes"
|
--enable-vxhs) vxhs="yes"
|
||||||
;;
|
;;
|
||||||
|
--disable-bochs) bochs="no"
|
||||||
|
;;
|
||||||
|
--enable-bochs) bochs="yes"
|
||||||
|
;;
|
||||||
|
--disable-cloop) cloop="no"
|
||||||
|
;;
|
||||||
|
--enable-cloop) cloop="yes"
|
||||||
|
;;
|
||||||
|
--disable-dmg) dmg="no"
|
||||||
|
;;
|
||||||
|
--enable-dmg) dmg="yes"
|
||||||
|
;;
|
||||||
|
--disable-qcow1) qcow1="no"
|
||||||
|
;;
|
||||||
|
--enable-qcow1) qcow1="yes"
|
||||||
|
;;
|
||||||
|
--disable-vdi) vdi="no"
|
||||||
|
;;
|
||||||
|
--enable-vdi) vdi="yes"
|
||||||
|
;;
|
||||||
|
--disable-vvfat) vvfat="no"
|
||||||
|
;;
|
||||||
|
--enable-vvfat) vvfat="yes"
|
||||||
|
;;
|
||||||
|
--disable-qed) qed="no"
|
||||||
|
;;
|
||||||
|
--enable-qed) qed="yes"
|
||||||
|
;;
|
||||||
|
--disable-parallels) parallels="no"
|
||||||
|
;;
|
||||||
|
--enable-parallels) parallels="yes"
|
||||||
|
;;
|
||||||
|
--disable-sheepdog) sheepdog="no"
|
||||||
|
;;
|
||||||
|
--enable-sheepdog) sheepdog="yes"
|
||||||
|
;;
|
||||||
--disable-vhost-user) vhost_user="no"
|
--disable-vhost-user) vhost_user="no"
|
||||||
;;
|
;;
|
||||||
--enable-vhost-user)
|
--enable-vhost-user)
|
||||||
@ -1718,6 +1763,15 @@ disabled with --disable-FEATURE, default is enabled if available:
|
|||||||
qom-cast-debug cast debugging support
|
qom-cast-debug cast debugging support
|
||||||
tools build qemu-io, qemu-nbd and qemu-image tools
|
tools build qemu-io, qemu-nbd and qemu-image tools
|
||||||
vxhs Veritas HyperScale vDisk backend support
|
vxhs Veritas HyperScale vDisk backend support
|
||||||
|
bochs bochs image format support
|
||||||
|
cloop cloop image format support
|
||||||
|
dmg dmg image format support
|
||||||
|
qcow1 qcow v1 image format support
|
||||||
|
vdi vdi image format support
|
||||||
|
vvfat vvfat image format support
|
||||||
|
qed qed image format support
|
||||||
|
parallels parallels image format support
|
||||||
|
sheepdog sheepdog block driver support
|
||||||
crypto-afalg Linux AF_ALG crypto backend driver
|
crypto-afalg Linux AF_ALG crypto backend driver
|
||||||
vhost-user vhost-user support
|
vhost-user vhost-user support
|
||||||
capstone capstone disassembler support
|
capstone capstone disassembler support
|
||||||
@ -6043,6 +6097,15 @@ echo "jemalloc support $jemalloc"
|
|||||||
echo "avx2 optimization $avx2_opt"
|
echo "avx2 optimization $avx2_opt"
|
||||||
echo "replication support $replication"
|
echo "replication support $replication"
|
||||||
echo "VxHS block device $vxhs"
|
echo "VxHS block device $vxhs"
|
||||||
|
echo "bochs support $bochs"
|
||||||
|
echo "cloop support $cloop"
|
||||||
|
echo "dmg support $dmg"
|
||||||
|
echo "qcow v1 support $qcow1"
|
||||||
|
echo "vdi support $vdi"
|
||||||
|
echo "vvfat support $vvfat"
|
||||||
|
echo "qed support $qed"
|
||||||
|
echo "parallels support $parallels"
|
||||||
|
echo "sheepdog support $sheepdog"
|
||||||
echo "capstone $capstone"
|
echo "capstone $capstone"
|
||||||
echo "docker $docker"
|
echo "docker $docker"
|
||||||
echo "libpmem support $libpmem"
|
echo "libpmem support $libpmem"
|
||||||
@ -6799,6 +6862,34 @@ if test "$libpmem" = "yes" ; then
|
|||||||
echo "CONFIG_LIBPMEM=y" >> $config_host_mak
|
echo "CONFIG_LIBPMEM=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$bochs" = "yes" ; then
|
||||||
|
echo "CONFIG_BOCHS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$cloop" = "yes" ; then
|
||||||
|
echo "CONFIG_CLOOP=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$dmg" = "yes" ; then
|
||||||
|
echo "CONFIG_DMG=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$qcow1" = "yes" ; then
|
||||||
|
echo "CONFIG_QCOW1=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$vdi" = "yes" ; then
|
||||||
|
echo "CONFIG_VDI=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$vvfat" = "yes" ; then
|
||||||
|
echo "CONFIG_VVFAT=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$qed" = "yes" ; then
|
||||||
|
echo "CONFIG_QED=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$parallels" = "yes" ; then
|
||||||
|
echo "CONFIG_PARALLELS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$sheepdog" = "yes" ; then
|
||||||
|
echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$tcg_interpreter" = "yes"; then
|
if test "$tcg_interpreter" = "yes"; then
|
||||||
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
||||||
elif test "$ARCH" = "sparc64" ; then
|
elif test "$ARCH" = "sparc64" ; then
|
||||||
|
@ -1331,10 +1331,10 @@ static void nvme_exit(PCIDevice *pci_dev)
|
|||||||
g_free(n->namespaces);
|
g_free(n->namespaces);
|
||||||
g_free(n->cq);
|
g_free(n->cq);
|
||||||
g_free(n->sq);
|
g_free(n->sq);
|
||||||
if (n->cmbsz) {
|
|
||||||
memory_region_unref(&n->ctrl_mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (n->cmb_size_mb) {
|
||||||
|
g_free(n->cmbuf);
|
||||||
|
}
|
||||||
msix_uninit_exclusive_bar(pci_dev);
|
msix_uninit_exclusive_bar(pci_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
job.c
4
job.c
@ -159,7 +159,7 @@ bool job_is_internal(Job *job)
|
|||||||
static void job_state_transition(Job *job, JobStatus s1)
|
static void job_state_transition(Job *job, JobStatus s1)
|
||||||
{
|
{
|
||||||
JobStatus s0 = job->status;
|
JobStatus s0 = job->status;
|
||||||
assert(s1 >= 0 && s1 <= JOB_STATUS__MAX);
|
assert(s1 >= 0 && s1 < JOB_STATUS__MAX);
|
||||||
trace_job_state_transition(job, job->ret,
|
trace_job_state_transition(job, job->ret,
|
||||||
JobSTT[s0][s1] ? "allowed" : "disallowed",
|
JobSTT[s0][s1] ? "allowed" : "disallowed",
|
||||||
JobStatus_str(s0), JobStatus_str(s1));
|
JobStatus_str(s0), JobStatus_str(s1));
|
||||||
@ -174,7 +174,7 @@ static void job_state_transition(Job *job, JobStatus s1)
|
|||||||
int job_apply_verb(Job *job, JobVerb verb, Error **errp)
|
int job_apply_verb(Job *job, JobVerb verb, Error **errp)
|
||||||
{
|
{
|
||||||
JobStatus s0 = job->status;
|
JobStatus s0 = job->status;
|
||||||
assert(verb >= 0 && verb <= JOB_VERB__MAX);
|
assert(verb >= 0 && verb < JOB_VERB__MAX);
|
||||||
trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
|
trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
|
||||||
JobVerbTable[verb][s0] ? "allowed" : "prohibited");
|
JobVerbTable[verb][s0] ? "allowed" : "prohibited");
|
||||||
if (JobVerbTable[verb][s0]) {
|
if (JobVerbTable[verb][s0]) {
|
||||||
|
@ -1029,6 +1029,7 @@ static int img_commit(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
job = block_job_get("commit");
|
job = block_job_get("commit");
|
||||||
|
assert(job);
|
||||||
run_block_job(job, &local_err);
|
run_block_job(job, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
goto unref_backing;
|
goto unref_backing;
|
||||||
|
@ -70,6 +70,7 @@ check-unit-y += tests/test-bdrv-drain$(EXESUF)
|
|||||||
check-unit-y += tests/test-blockjob$(EXESUF)
|
check-unit-y += tests/test-blockjob$(EXESUF)
|
||||||
check-unit-y += tests/test-blockjob-txn$(EXESUF)
|
check-unit-y += tests/test-blockjob-txn$(EXESUF)
|
||||||
check-unit-y += tests/test-block-backend$(EXESUF)
|
check-unit-y += tests/test-block-backend$(EXESUF)
|
||||||
|
check-unit-y += tests/test-image-locking$(EXESUF)
|
||||||
check-unit-y += tests/test-x86-cpuid$(EXESUF)
|
check-unit-y += tests/test-x86-cpuid$(EXESUF)
|
||||||
# all code tested by test-x86-cpuid is inside topology.h
|
# all code tested by test-x86-cpuid is inside topology.h
|
||||||
ifeq ($(CONFIG_SOFTMMU),y)
|
ifeq ($(CONFIG_SOFTMMU),y)
|
||||||
@ -537,6 +538,7 @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te
|
|||||||
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
|
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
|
||||||
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
|
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
|
||||||
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
|
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
|
||||||
|
tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y)
|
||||||
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
|
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
|
||||||
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
|
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
|
||||||
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
|
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
|
||||||
|
157
tests/test-image-locking.c
Normal file
157
tests/test-image-locking.c
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Image locking tests
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Author: Fam Zheng <famz@redhat.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "block/block.h"
|
||||||
|
#include "sysemu/block-backend.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qapi/qmp/qdict.h"
|
||||||
|
|
||||||
|
static BlockBackend *open_image(const char *path,
|
||||||
|
uint64_t perm, uint64_t shared_perm,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
|
BlockBackend *blk;
|
||||||
|
QDict *options = qdict_new();
|
||||||
|
|
||||||
|
qdict_put_str(options, "driver", "raw");
|
||||||
|
blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err);
|
||||||
|
if (blk) {
|
||||||
|
g_assert_null(local_err);
|
||||||
|
if (blk_set_perm(blk, perm, shared_perm, errp)) {
|
||||||
|
blk_unref(blk);
|
||||||
|
blk = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
}
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_locked_bytes(int fd, uint64_t perm_locks,
|
||||||
|
uint64_t shared_perm_locks)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!perm_locks && !shared_perm_locks) {
|
||||||
|
g_assert(!qemu_lock_fd_test(fd, 0, 0, true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) {
|
||||||
|
uint64_t bit = (1ULL << i);
|
||||||
|
bool perm_expected = !!(bit & perm_locks);
|
||||||
|
bool shared_perm_expected = !!(bit & shared_perm_locks);
|
||||||
|
g_assert_cmpint(perm_expected, ==,
|
||||||
|
!!qemu_lock_fd_test(fd, 100 + i, 1, true));
|
||||||
|
g_assert_cmpint(shared_perm_expected, ==,
|
||||||
|
!!qemu_lock_fd_test(fd, 200 + i, 1, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_image_locking_basic(void)
|
||||||
|
{
|
||||||
|
BlockBackend *blk1, *blk2, *blk3;
|
||||||
|
char img_path[] = "/tmp/qtest.XXXXXX";
|
||||||
|
uint64_t perm, shared_perm;
|
||||||
|
|
||||||
|
int fd = mkstemp(img_path);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
|
||||||
|
shared_perm = BLK_PERM_ALL;
|
||||||
|
blk1 = open_image(img_path, perm, shared_perm, &error_abort);
|
||||||
|
g_assert(blk1);
|
||||||
|
|
||||||
|
check_locked_bytes(fd, perm, ~shared_perm);
|
||||||
|
|
||||||
|
/* compatible perm between blk1 and blk2 */
|
||||||
|
blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL);
|
||||||
|
g_assert(blk2);
|
||||||
|
check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm);
|
||||||
|
|
||||||
|
/* incompatible perm with already open blk1 and blk2 */
|
||||||
|
blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL);
|
||||||
|
g_assert_null(blk3);
|
||||||
|
|
||||||
|
blk_unref(blk2);
|
||||||
|
|
||||||
|
/* Check that extra bytes in blk2 are correctly unlocked */
|
||||||
|
check_locked_bytes(fd, perm, ~shared_perm);
|
||||||
|
|
||||||
|
blk_unref(blk1);
|
||||||
|
|
||||||
|
/* Image is unused, no lock there */
|
||||||
|
check_locked_bytes(fd, 0, 0);
|
||||||
|
blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort);
|
||||||
|
g_assert(blk3);
|
||||||
|
blk_unref(blk3);
|
||||||
|
close(fd);
|
||||||
|
unlink(img_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_set_perm_abort(void)
|
||||||
|
{
|
||||||
|
BlockBackend *blk1, *blk2;
|
||||||
|
char img_path[] = "/tmp/qtest.XXXXXX";
|
||||||
|
uint64_t perm, shared_perm;
|
||||||
|
int r;
|
||||||
|
int fd = mkstemp(img_path);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
|
||||||
|
shared_perm = BLK_PERM_ALL;
|
||||||
|
blk1 = open_image(img_path, perm, shared_perm, &error_abort);
|
||||||
|
g_assert(blk1);
|
||||||
|
|
||||||
|
blk2 = open_image(img_path, perm, shared_perm, &error_abort);
|
||||||
|
g_assert(blk2);
|
||||||
|
|
||||||
|
check_locked_bytes(fd, perm, ~shared_perm);
|
||||||
|
|
||||||
|
/* A failed blk_set_perm mustn't change perm status (locked bytes) */
|
||||||
|
r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED,
|
||||||
|
NULL);
|
||||||
|
g_assert_cmpint(r, !=, 0);
|
||||||
|
check_locked_bytes(fd, perm, ~shared_perm);
|
||||||
|
blk_unref(blk1);
|
||||||
|
blk_unref(blk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
bdrv_init();
|
||||||
|
qemu_init_main_loop(&error_abort);
|
||||||
|
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
|
if (qemu_has_ofd_lock()) {
|
||||||
|
g_test_add_func("/image-locking/basic", test_image_locking_basic);
|
||||||
|
g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user