Merge remote-tracking branch 'remotes/kraxel/tags/ui-20200904-pull-request' into staging
ui: memleak fixes.
gtk: refresh interval fix.
spice: add mouse buttons.
# gpg: Signature made Fri 04 Sep 2020 08:00:55 BST
# gpg: using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138
* remotes/kraxel/tags/ui-20200904-pull-request:
ui/gtk: Update refresh interval after widget is realized
ui: Add more mouse buttons to SPICE
vnc-auth-sasl: Plug memleak in vnc_socket_ip_addr_string
ui/gtk-gl-area: Plug memleak in gd_gl_area_create_context()
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 2d48281..6489abb 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -2009,6 +2009,80 @@
}
}
+static void __attribute__((noinline))
+store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
+ uintptr_t retaddr, size_t size, uintptr_t mmu_idx,
+ bool big_endian)
+{
+ const size_t tlb_off = offsetof(CPUTLBEntry, addr_write);
+ uintptr_t index, index2;
+ CPUTLBEntry *entry, *entry2;
+ target_ulong page2, tlb_addr, tlb_addr2;
+ TCGMemOpIdx oi;
+ size_t size2;
+ int i;
+
+ /*
+ * Ensure the second page is in the TLB. Note that the first page
+ * is already guaranteed to be filled, and that the second page
+ * cannot evict the first.
+ */
+ page2 = (addr + size) & TARGET_PAGE_MASK;
+ size2 = (addr + size) & ~TARGET_PAGE_MASK;
+ index2 = tlb_index(env, mmu_idx, page2);
+ entry2 = tlb_entry(env, mmu_idx, page2);
+
+ tlb_addr2 = tlb_addr_write(entry2);
+ if (!tlb_hit_page(tlb_addr2, page2)) {
+ if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) {
+ tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE,
+ mmu_idx, retaddr);
+ index2 = tlb_index(env, mmu_idx, page2);
+ entry2 = tlb_entry(env, mmu_idx, page2);
+ }
+ tlb_addr2 = tlb_addr_write(entry2);
+ }
+
+ index = tlb_index(env, mmu_idx, addr);
+ entry = tlb_entry(env, mmu_idx, addr);
+ tlb_addr = tlb_addr_write(entry);
+
+ /*
+ * Handle watchpoints. Since this may trap, all checks
+ * must happen before any store.
+ */
+ if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
+ cpu_check_watchpoint(env_cpu(env), addr, size - size2,
+ env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
+ BP_MEM_WRITE, retaddr);
+ }
+ if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) {
+ cpu_check_watchpoint(env_cpu(env), page2, size2,
+ env_tlb(env)->d[mmu_idx].iotlb[index2].attrs,
+ BP_MEM_WRITE, retaddr);
+ }
+
+ /*
+ * XXX: not efficient, but simple.
+ * This loop must go in the forward direction to avoid issues
+ * with self-modifying code in Windows 64-bit.
+ */
+ oi = make_memop_idx(MO_UB, mmu_idx);
+ if (big_endian) {
+ for (i = 0; i < size; ++i) {
+ /* Big-endian extract. */
+ uint8_t val8 = val >> (((size - 1) * 8) - (i * 8));
+ helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
+ }
+ } else {
+ for (i = 0; i < size; ++i) {
+ /* Little-endian extract. */
+ uint8_t val8 = val >> (i * 8);
+ helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
+ }
+ }
+}
+
static inline void QEMU_ALWAYS_INLINE
store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
TCGMemOpIdx oi, uintptr_t retaddr, MemOp op)
@@ -2097,64 +2171,9 @@
if (size > 1
&& unlikely((addr & ~TARGET_PAGE_MASK) + size - 1
>= TARGET_PAGE_SIZE)) {
- int i;
- uintptr_t index2;
- CPUTLBEntry *entry2;
- target_ulong page2, tlb_addr2;
- size_t size2;
-
do_unaligned_access:
- /*
- * Ensure the second page is in the TLB. Note that the first page
- * is already guaranteed to be filled, and that the second page
- * cannot evict the first.
- */
- page2 = (addr + size) & TARGET_PAGE_MASK;
- size2 = (addr + size) & ~TARGET_PAGE_MASK;
- index2 = tlb_index(env, mmu_idx, page2);
- entry2 = tlb_entry(env, mmu_idx, page2);
- tlb_addr2 = tlb_addr_write(entry2);
- if (!tlb_hit_page(tlb_addr2, page2)) {
- if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) {
- tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE,
- mmu_idx, retaddr);
- index2 = tlb_index(env, mmu_idx, page2);
- entry2 = tlb_entry(env, mmu_idx, page2);
- }
- tlb_addr2 = tlb_addr_write(entry2);
- }
-
- /*
- * Handle watchpoints. Since this may trap, all checks
- * must happen before any store.
- */
- if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
- cpu_check_watchpoint(env_cpu(env), addr, size - size2,
- env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
- BP_MEM_WRITE, retaddr);
- }
- if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) {
- cpu_check_watchpoint(env_cpu(env), page2, size2,
- env_tlb(env)->d[mmu_idx].iotlb[index2].attrs,
- BP_MEM_WRITE, retaddr);
- }
-
- /*
- * XXX: not efficient, but simple.
- * This loop must go in the forward direction to avoid issues
- * with self-modifying code in Windows 64-bit.
- */
- for (i = 0; i < size; ++i) {
- uint8_t val8;
- if (memop_big_endian(op)) {
- /* Big-endian extract. */
- val8 = val >> (((size - 1) * 8) - (i * 8));
- } else {
- /* Little-endian extract. */
- val8 = val >> (i * 8);
- }
- helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
- }
+ store_helper_unaligned(env, addr, val, retaddr, size,
+ mmu_idx, memop_big_endian(op));
return;
}
@@ -2162,8 +2181,9 @@
store_memop(haddr, val, op);
}
-void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
- TCGMemOpIdx oi, uintptr_t retaddr)
+void __attribute__((noinline))
+helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
+ TCGMemOpIdx oi, uintptr_t retaddr)
{
store_helper(env, addr, val, oi, retaddr, MO_UB);
}
diff --git a/block/nbd.c b/block/nbd.c
index 7bb881f..9daf003 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -38,6 +38,7 @@
#include "qapi/qapi-visit-sockets.h"
#include "qapi/qmp/qstring.h"
+#include "qapi/clone-visitor.h"
#include "block/qdict.h"
#include "block/nbd.h"
@@ -62,6 +63,47 @@
NBD_CLIENT_QUIT
} NBDClientState;
+typedef enum NBDConnectThreadState {
+ /* No thread, no pending results */
+ CONNECT_THREAD_NONE,
+
+ /* Thread is running, no results for now */
+ CONNECT_THREAD_RUNNING,
+
+ /*
+ * Thread is running, but requestor exited. Thread should close
+ * the new socket and free the connect state on exit.
+ */
+ CONNECT_THREAD_RUNNING_DETACHED,
+
+ /* Thread finished, results are stored in a state */
+ CONNECT_THREAD_FAIL,
+ CONNECT_THREAD_SUCCESS
+} NBDConnectThreadState;
+
+typedef struct NBDConnectThread {
+ /* Initialization constants */
+ SocketAddress *saddr; /* address to connect to */
+ /*
+ * Bottom half to schedule on completion. Scheduled only if bh_ctx is not
+ * NULL
+ */
+ QEMUBHFunc *bh_func;
+ void *bh_opaque;
+
+ /*
+ * Result of last attempt. Valid in FAIL and SUCCESS states.
+ * If you want to steal error, don't forget to set pointer to NULL.
+ */
+ QIOChannelSocket *sioc;
+ Error *err;
+
+ /* state and bh_ctx are protected by mutex */
+ QemuMutex mutex;
+ NBDConnectThreadState state; /* current state of the thread */
+ AioContext *bh_ctx; /* where to schedule bh (NULL means don't schedule) */
+} NBDConnectThread;
+
typedef struct BDRVNBDState {
QIOChannelSocket *sioc; /* The master data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
@@ -91,10 +133,17 @@
QCryptoTLSCreds *tlscreds;
const char *hostname;
char *x_dirty_bitmap;
+
+ bool wait_connect;
+ NBDConnectThread *connect_thread;
} BDRVNBDState;
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
Error **errp);
+static QIOChannelSocket *nbd_co_establish_connection(BlockDriverState *bs,
+ Error **errp);
+static void nbd_co_establish_connection_cancel(BlockDriverState *bs,
+ bool detach);
static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc,
Error **errp);
@@ -191,6 +240,8 @@
if (s->connection_co_sleep_ns_state) {
qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
}
+
+ nbd_co_establish_connection_cancel(bs, false);
}
static void coroutine_fn nbd_client_co_drain_end(BlockDriverState *bs)
@@ -223,6 +274,7 @@
if (s->connection_co_sleep_ns_state) {
qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
}
+ nbd_co_establish_connection_cancel(bs, true);
}
if (qemu_in_coroutine()) {
s->teardown_co = qemu_coroutine_self();
@@ -246,6 +298,216 @@
return s->state == NBD_CLIENT_CONNECTING_WAIT;
}
+static void connect_bh(void *opaque)
+{
+ BDRVNBDState *state = opaque;
+
+ assert(state->wait_connect);
+ state->wait_connect = false;
+ aio_co_wake(state->connection_co);
+}
+
+static void nbd_init_connect_thread(BDRVNBDState *s)
+{
+ s->connect_thread = g_new(NBDConnectThread, 1);
+
+ *s->connect_thread = (NBDConnectThread) {
+ .saddr = QAPI_CLONE(SocketAddress, s->saddr),
+ .state = CONNECT_THREAD_NONE,
+ .bh_func = connect_bh,
+ .bh_opaque = s,
+ };
+
+ qemu_mutex_init(&s->connect_thread->mutex);
+}
+
+static void nbd_free_connect_thread(NBDConnectThread *thr)
+{
+ if (thr->sioc) {
+ qio_channel_close(QIO_CHANNEL(thr->sioc), NULL);
+ }
+ error_free(thr->err);
+ qapi_free_SocketAddress(thr->saddr);
+ g_free(thr);
+}
+
+static void *connect_thread_func(void *opaque)
+{
+ NBDConnectThread *thr = opaque;
+ int ret;
+ bool do_free = false;
+
+ thr->sioc = qio_channel_socket_new();
+
+ error_free(thr->err);
+ thr->err = NULL;
+ ret = qio_channel_socket_connect_sync(thr->sioc, thr->saddr, &thr->err);
+ if (ret < 0) {
+ object_unref(OBJECT(thr->sioc));
+ thr->sioc = NULL;
+ }
+
+ qemu_mutex_lock(&thr->mutex);
+
+ switch (thr->state) {
+ case CONNECT_THREAD_RUNNING:
+ thr->state = ret < 0 ? CONNECT_THREAD_FAIL : CONNECT_THREAD_SUCCESS;
+ if (thr->bh_ctx) {
+ aio_bh_schedule_oneshot(thr->bh_ctx, thr->bh_func, thr->bh_opaque);
+
+ /* play safe, don't reuse bh_ctx on further connection attempts */
+ thr->bh_ctx = NULL;
+ }
+ break;
+ case CONNECT_THREAD_RUNNING_DETACHED:
+ do_free = true;
+ break;
+ default:
+ abort();
+ }
+
+ qemu_mutex_unlock(&thr->mutex);
+
+ if (do_free) {
+ nbd_free_connect_thread(thr);
+ }
+
+ return NULL;
+}
+
+static QIOChannelSocket *coroutine_fn
+nbd_co_establish_connection(BlockDriverState *bs, Error **errp)
+{
+ QemuThread thread;
+ BDRVNBDState *s = bs->opaque;
+ QIOChannelSocket *res;
+ NBDConnectThread *thr = s->connect_thread;
+
+ qemu_mutex_lock(&thr->mutex);
+
+ switch (thr->state) {
+ case CONNECT_THREAD_FAIL:
+ case CONNECT_THREAD_NONE:
+ error_free(thr->err);
+ thr->err = NULL;
+ thr->state = CONNECT_THREAD_RUNNING;
+ qemu_thread_create(&thread, "nbd-connect",
+ connect_thread_func, thr, QEMU_THREAD_DETACHED);
+ break;
+ case CONNECT_THREAD_SUCCESS:
+ /* Previous attempt finally succeeded in background */
+ thr->state = CONNECT_THREAD_NONE;
+ res = thr->sioc;
+ thr->sioc = NULL;
+ qemu_mutex_unlock(&thr->mutex);
+ return res;
+ case CONNECT_THREAD_RUNNING:
+ /* Already running, will wait */
+ break;
+ default:
+ abort();
+ }
+
+ thr->bh_ctx = qemu_get_current_aio_context();
+
+ qemu_mutex_unlock(&thr->mutex);
+
+
+ /*
+ * We are going to wait for connect-thread finish, but
+ * nbd_client_co_drain_begin() can interrupt.
+ *
+ * Note that wait_connect variable is not visible for connect-thread. It
+ * doesn't need mutex protection, it used only inside home aio context of
+ * bs.
+ */
+ s->wait_connect = true;
+ qemu_coroutine_yield();
+
+ qemu_mutex_lock(&thr->mutex);
+
+ switch (thr->state) {
+ case CONNECT_THREAD_SUCCESS:
+ case CONNECT_THREAD_FAIL:
+ thr->state = CONNECT_THREAD_NONE;
+ error_propagate(errp, thr->err);
+ thr->err = NULL;
+ res = thr->sioc;
+ thr->sioc = NULL;
+ break;
+ case CONNECT_THREAD_RUNNING:
+ case CONNECT_THREAD_RUNNING_DETACHED:
+ /*
+ * Obviously, drained section wants to start. Report the attempt as
+ * failed. Still connect thread is executing in background, and its
+ * result may be used for next connection attempt.
+ */
+ res = NULL;
+ error_setg(errp, "Connection attempt cancelled by other operation");
+ break;
+
+ case CONNECT_THREAD_NONE:
+ /*
+ * Impossible. We've seen this thread running. So it should be
+ * running or at least give some results.
+ */
+ abort();
+
+ default:
+ abort();
+ }
+
+ qemu_mutex_unlock(&thr->mutex);
+
+ return res;
+}
+
+/*
+ * nbd_co_establish_connection_cancel
+ * Cancel nbd_co_establish_connection asynchronously: it will finish soon, to
+ * allow drained section to begin.
+ *
+ * If detach is true, also cleanup the state (or if thread is running, move it
+ * to CONNECT_THREAD_RUNNING_DETACHED state). s->connect_thread becomes NULL if
+ * detach is true.
+ */
+static void nbd_co_establish_connection_cancel(BlockDriverState *bs,
+ bool detach)
+{
+ BDRVNBDState *s = bs->opaque;
+ NBDConnectThread *thr = s->connect_thread;
+ bool wake = false;
+ bool do_free = false;
+
+ qemu_mutex_lock(&thr->mutex);
+
+ if (thr->state == CONNECT_THREAD_RUNNING) {
+ /* We can cancel only in running state, when bh is not yet scheduled */
+ thr->bh_ctx = NULL;
+ if (s->wait_connect) {
+ s->wait_connect = false;
+ wake = true;
+ }
+ if (detach) {
+ thr->state = CONNECT_THREAD_RUNNING_DETACHED;
+ s->connect_thread = NULL;
+ }
+ } else if (detach) {
+ do_free = true;
+ }
+
+ qemu_mutex_unlock(&thr->mutex);
+
+ if (do_free) {
+ nbd_free_connect_thread(thr);
+ s->connect_thread = NULL;
+ }
+
+ if (wake) {
+ aio_co_wake(s->connection_co);
+ }
+}
+
static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
{
int ret;
@@ -289,7 +551,7 @@
s->ioc = NULL;
}
- sioc = nbd_establish_connection(s->saddr, &local_err);
+ sioc = nbd_co_establish_connection(s->bs, &local_err);
if (!sioc) {
ret = -ECONNREFUSED;
goto out;
@@ -1946,6 +2208,8 @@
/* successfully connected */
s->state = NBD_CLIENT_CONNECTED;
+ nbd_init_connect_thread(s);
+
s->connection_co = qemu_coroutine_create(nbd_connection_entry, s);
bdrv_inc_in_flight(bs);
aio_co_schedule(bdrv_get_aio_context(bs), s->connection_co);
diff --git a/configure b/configure
index f555923..922adbc 100755
--- a/configure
+++ b/configure
@@ -4920,6 +4920,12 @@
kcov=yes
fi
+# check for btrfs filesystem support (kernel must be 3.9+)
+btrfs=no
+if check_include linux/btrfs.h ; then
+ btrfs=yes
+fi
+
# If we're making warnings fatal, apply this to Sphinx runs as well
sphinx_werror=""
if test "$werror" = "yes"; then
@@ -6898,6 +6904,9 @@
if test "$kcov" = "yes" ; then
echo "CONFIG_KCOV=y" >> $config_host_mak
fi
+if test "$btrfs" = "yes" ; then
+ echo "CONFIG_BTRFS=y" >> $config_host_mak
+fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 69eede6..f3e7ced 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -1321,6 +1321,7 @@
};
void qapi_free_UserDefOne(UserDefOne *obj);
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC(UserDefOne, qapi_free_UserDefOne)
struct UserDefOneList {
UserDefOneList *next;
@@ -1328,6 +1329,7 @@
};
void qapi_free_UserDefOneList(UserDefOneList *obj);
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC(UserDefOneList, qapi_free_UserDefOneList)
struct q_obj_my_command_arg {
UserDefOneList *arg1;
diff --git a/docs/interop/qmp-spec.txt b/docs/interop/qmp-spec.txt
index adcf867..cdf5842 100644
--- a/docs/interop/qmp-spec.txt
+++ b/docs/interop/qmp-spec.txt
@@ -110,6 +110,9 @@
if provided. The "id" member can be any json-value. A json-number
incremented for each successive command works fine.
+The actual commands are documented in the QEMU QMP reference manual
+docs/interop/qemu-qmp-ref.{7,html,info,pdf,txt}.
+
2.3.1 Out-of-band execution
---------------------------
@@ -207,13 +210,13 @@
there is a failure to retrieve host time, both members of the
timestamp will be set to -1.
-For a listing of supported asynchronous events, please, refer to the
-qmp-events.txt file.
+The actual asynchronous events are documented in the QEMU QMP
+reference manual docs/interop/qemu-qmp-ref.{7,html,info,pdf,txt}.
Some events are rate-limited to at most one per second. If additional
"similar" events arrive within one second, all but the last one are
dropped, and the last one is delayed. "Similar" normally means same
-event type. See qmp-events.txt for details.
+event type.
2.6 Forcing the JSON parser into known-good state
-------------------------------------------------
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 9889521..245cdf2 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -125,7 +125,14 @@
* if=pflash, if=mtd, if=sd, if=xen are not yet available with -device
-For USB storage devices, you can use something like:
+For USB devices, the old way was actually different:
+
+ -usbdevice disk:format=FMT:FILENAME
+
+"Was" because "disk:" is gone since v2.12.0.
+
+The old way provided much less control than -drive's OPTS... The new
+way fixes that:
-device usb-storage,drive=DRIVE-ID,removable=RMB
@@ -178,6 +185,9 @@
-device usb-braille,chardev=braille -chardev braille,id=braille
+* -usbdevice serial::chardev is gone since v2.12.0. It became
+ -device usb-serial,chardev=dev.
+
LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
* null becomes -chardev null
@@ -231,6 +241,12 @@
-net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
+Except for USB it looked like this:
+
+ -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID
+
+"Looked" because "net:" is gone since v2.12.0.
+
The new way is -device:
-device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS...
@@ -328,6 +344,13 @@
* u2f -device u2f-{emulated,passthru}
* braille See "Character Devices"
+Until v2.12.0, we additionally had
+
+* host:... See "Host Device Assignment"
+* disk:... See "Block Devices"
+* serial:... See "Character Devices"
+* net:... See "Network Devices"
+
=== Watchdog Devices ===
Host and guest part of watchdog devices have always been separate.
@@ -343,7 +366,14 @@
-device vfio-pci,host=ADDR,id=ID
-To assign a host USB device use:
+The old way to assign a USB host device
+
+ -usbdevice host:auto:BUS.ADDR:VID:PRID
+
+was removed in v2.12.0. Any of BUS, ADDR, VID, PRID could be the
+wildcard *.
+
+The new way is
-device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID
diff --git a/include/crypto/block.h b/include/crypto/block.h
index d274819..7a65e8e 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -311,7 +311,5 @@
void qcrypto_block_free(QCryptoBlock *block);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlockCreateOptions,
- qapi_free_QCryptoBlockCreateOptions)
#endif /* QCRYPTO_BLOCK_H */
diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
index a5bbb2c..b281dfa 100644
--- a/include/exec/user/thunk.h
+++ b/include/exec/user/thunk.h
@@ -42,7 +42,7 @@
} argtype;
#define MK_PTR(type) TYPE_PTR, type
-#define MK_ARRAY(type, size) TYPE_ARRAY, size, type
+#define MK_ARRAY(type, size) TYPE_ARRAY, (int)(size), type
#define MK_STRUCT(id) TYPE_STRUCT, id
#define THUNK_TARGET 0
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index e2fc09b..585874f 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -174,6 +174,130 @@
IOCTL(FS_IOC32_GETVERSION, IOC_R, MK_PTR(TYPE_INT))
IOCTL(FS_IOC32_SETVERSION, IOC_W, MK_PTR(TYPE_INT))
+#ifdef BTRFS_IOC_SNAP_CREATE
+ IOCTL(BTRFS_IOC_SNAP_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_SCAN_DEV
+ IOCTL(BTRFS_IOC_SCAN_DEV, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_FORGET_DEV
+ IOCTL(BTRFS_IOC_FORGET_DEV, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_ADD_DEV
+ IOCTL(BTRFS_IOC_ADD_DEV, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_RM_DEV
+ IOCTL(BTRFS_IOC_RM_DEV, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_SUBVOL_CREATE
+ IOCTL(BTRFS_IOC_SUBVOL_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_SNAP_DESTROY
+ IOCTL(BTRFS_IOC_SNAP_DESTROY, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+#endif
+#ifdef BTRFS_IOC_INO_LOOKUP
+ IOCTL(BTRFS_IOC_INO_LOOKUP, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_args)))
+#endif
+#ifdef BTRFS_IOC_DEFAULT_SUBVOL
+ IOCTL(BTRFS_IOC_DEFAULT_SUBVOL, IOC_W, MK_PTR(TYPE_ULONGLONG))
+#endif
+#ifdef BTRFS_IOC_SUBVOL_GETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_GETFLAGS, IOC_R, MK_PTR(TYPE_ULONGLONG))
+#endif
+#ifdef BTRFS_IOC_SUBVOL_SETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_SETFLAGS, IOC_W, MK_PTR(TYPE_ULONGLONG))
+#endif
+#ifdef BTRFS_IOC_SCRUB
+ IOCTL(BTRFS_IOC_SCRUB, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_scrub_args)))
+#endif
+#ifdef BTRFS_IOC_SCRUB_CANCEL
+ IOCTL(BTRFS_IOC_SCRUB_CANCEL, 0, TYPE_NULL)
+#endif
+#ifdef BTRFS_IOC_SCRUB_PROGRESS
+ IOCTL(BTRFS_IOC_SCRUB_PROGRESS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_scrub_args)))
+#endif
+#ifdef BTRFS_IOC_DEV_INFO
+ IOCTL(BTRFS_IOC_DEV_INFO, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_dev_info_args)))
+#endif
+#ifdef BTRFS_IOC_INO_PATHS
+ IOCTL(BTRFS_IOC_INO_PATHS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_path_args)))
+#endif
+#ifdef BTRFS_IOC_LOGICAL_INO
+ IOCTL(BTRFS_IOC_LOGICAL_INO, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_logical_ino_args)))
+#endif
+#ifdef BTRFS_IOC_QUOTA_CTL
+ IOCTL(BTRFS_IOC_QUOTA_CTL, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_ctl_args)))
+#endif
+#ifdef BTRFS_IOC_QGROUP_ASSIGN
+ IOCTL(BTRFS_IOC_QGROUP_ASSIGN, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_assign_args)))
+#endif
+#ifdef BTRFS_IOC_QGROUP_CREATE
+ IOCTL(BTRFS_IOC_QGROUP_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_create_args)))
+#endif
+#ifdef BTRFS_IOC_QGROUP_LIMIT
+ IOCTL(BTRFS_IOC_QGROUP_LIMIT, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_limit_args)))
+#endif
+#ifdef BTRFS_IOC_QUOTA_RESCAN
+ IOCTL(BTRFS_IOC_QUOTA_RESCAN, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_rescan_args)))
+#endif
+#ifdef BTRFS_IOC_QUOTA_RESCAN_STATUS
+ IOCTL(BTRFS_IOC_QUOTA_RESCAN_STATUS, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_rescan_args)))
+#endif
+#ifdef BTRFS_IOC_QUOTA_RESCAN_WAIT
+ IOCTL(BTRFS_IOC_QUOTA_RESCAN_WAIT, 0, TYPE_NULL)
+#endif
+#ifdef BTRFS_IOC_GET_DEV_STATS
+ IOCTL(BTRFS_IOC_GET_DEV_STATS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_dev_stats)))
+#endif
+#ifdef BTRFS_IOC_GET_FEATURES
+ IOCTL(BTRFS_IOC_GET_FEATURES, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags)))
+#endif
+#ifdef BTRFS_IOC_SET_FEATURES
+ IOCTL(BTRFS_IOC_SET_FEATURES, IOC_W,
+ MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags), 2)))
+#endif
+#ifdef BTRFS_IOC_GET_SUPPORTED_FEATURES
+ IOCTL(BTRFS_IOC_GET_SUPPORTED_FEATURES, IOC_R,
+ MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags), 3)))
+#endif
+#ifdef BTRFS_IOC_LOGICAL_INO_V2
+ IOCTL(BTRFS_IOC_LOGICAL_INO_V2, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_logical_ino_args)))
+#endif
+#ifdef BTRFS_IOC_GET_SUBVOL_INFO
+ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
+#endif
+#ifdef BTRFS_IOC_GET_SUBVOL_ROOTREF
+ IOCTL(BTRFS_IOC_GET_SUBVOL_ROOTREF, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_rootref_args)))
+#endif
+#ifdef BTRFS_IOC_INO_LOOKUP_USER
+ IOCTL(BTRFS_IOC_INO_LOOKUP_USER, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_user_args)))
+#endif
+
#ifdef CONFIG_USBFS
/* USB ioctls */
IOCTL(USBDEVFS_CONTROL, IOC_RW,
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d14d849..93da3b9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -112,6 +112,9 @@
#include <linux/if_alg.h>
#include <linux/rtc.h>
#include <sound/asound.h>
+#ifdef CONFIG_BTRFS
+#include <linux/btrfs.h>
+#endif
#ifdef HAVE_DRM_H
#include <libdrm/drm.h>
#include <libdrm/i915_drm.h>
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 9d07991..33a414c 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1005,6 +1005,43 @@
#define TARGET_FS_IOC32_GETVERSION TARGET_IOR('v', 1, int)
#define TARGET_FS_IOC32_SETVERSION TARGET_IOW('v', 2, int)
+/* btrfs ioctls */
+#define TARGET_BTRFS_IOC_SNAP_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 1)
+#define TARGET_BTRFS_IOC_SCAN_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 4)
+#define TARGET_BTRFS_IOC_FORGET_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 5)
+#define TARGET_BTRFS_IOC_ADD_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 10)
+#define TARGET_BTRFS_IOC_RM_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 11)
+#define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
+#define TARGET_BTRFS_IOC_SNAP_DESTROY TARGET_IOWU(BTRFS_IOCTL_MAGIC, 15)
+#define TARGET_BTRFS_IOC_INO_LOOKUP TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 18)
+#define TARGET_BTRFS_IOC_DEFAULT_SUBVOL TARGET_IOW(BTRFS_IOCTL_MAGIC, 19,\
+ abi_ullong)
+#define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
+ abi_ullong)
+#define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+ abi_ullong)
+#define TARGET_BTRFS_IOC_SCRUB TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 27)
+#define TARGET_BTRFS_IOC_SCRUB_CANCEL TARGET_IO(BTRFS_IOCTL_MAGIC, 28)
+#define TARGET_BTRFS_IOC_SCRUB_PROGRESS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 29)
+#define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
+#define TARGET_BTRFS_IOC_INO_PATHS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 35)
+#define TARGET_BTRFS_IOC_LOGICAL_INO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 36)
+#define TARGET_BTRFS_IOC_QUOTA_CTL TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 40)
+#define TARGET_BTRFS_IOC_QGROUP_ASSIGN TARGET_IOWU(BTRFS_IOCTL_MAGIC, 41)
+#define TARGET_BTRFS_IOC_QGROUP_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 42)
+#define TARGET_BTRFS_IOC_QGROUP_LIMIT TARGET_IORU(BTRFS_IOCTL_MAGIC, 43)
+#define TARGET_BTRFS_IOC_QUOTA_RESCAN TARGET_IOWU(BTRFS_IOCTL_MAGIC, 44)
+#define TARGET_BTRFS_IOC_QUOTA_RESCAN_STATUS TARGET_IORU(BTRFS_IOCTL_MAGIC, 45)
+#define TARGET_BTRFS_IOC_QUOTA_RESCAN_WAIT TARGET_IO(BTRFS_IOCTL_MAGIC, 46)
+#define TARGET_BTRFS_IOC_GET_DEV_STATS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 52)
+#define TARGET_BTRFS_IOC_GET_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+#define TARGET_BTRFS_IOC_SET_FEATURES TARGET_IOWU(BTRFS_IOCTL_MAGIC, 57)
+#define TARGET_BTRFS_IOC_GET_SUPPORTED_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+#define TARGET_BTRFS_IOC_LOGICAL_INO_V2 TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 59)
+#define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
+#define TARGET_BTRFS_IOC_GET_SUBVOL_ROOTREF TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 61)
+#define TARGET_BTRFS_IOC_INO_LOOKUP_USER TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 62)
+
/* usb ioctls */
#define TARGET_USBDEVFS_CONTROL TARGET_IOWRU('U', 0)
#define TARGET_USBDEVFS_BULK TARGET_IOWRU('U', 2)
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 12bf348..ba2c151 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -358,6 +358,169 @@
MK_ARRAY(TYPE_CHAR, BLKPG_DEVNAMELTH), /* devname */
MK_ARRAY(TYPE_CHAR, BLKPG_VOLNAMELTH)) /* volname */
+#if defined(BTRFS_IOC_SUBVOL_CREATE) || defined(BTRFS_IOC_SNAP_CREATE) || \
+ defined(BTRFS_IOC_SNAP_DESTROY) || defined(BTRFS_IOC_SCAN_DEV) || \
+ defined(BTRFS_IOC_FORGET_DEV) || defined(BTRFS_IOC_ADD_DEV) || \
+ defined(BTRFS_IOC_RM_DEV) || defined(BTRFS_IOC_DEV_INFO)
+STRUCT(btrfs_ioctl_vol_args,
+ TYPE_LONGLONG, /* fd */
+ MK_ARRAY(TYPE_CHAR, BTRFS_PATH_NAME_MAX + 1)) /* name */
+#endif
+
+#ifdef BTRFS_IOC_GET_SUBVOL_INFO
+STRUCT(btrfs_ioctl_timespec,
+ TYPE_ULONGLONG, /* sec */
+ TYPE_INT) /* nsec */
+
+STRUCT(btrfs_ioctl_get_subvol_info_args,
+ TYPE_ULONGLONG, /* treeid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_VOL_NAME_MAX + 1),
+ TYPE_ULONGLONG, /* parentid */
+ TYPE_ULONGLONG, /* dirid */
+ TYPE_ULONGLONG, /* generation */
+ TYPE_ULONGLONG, /* flags */
+ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* uuid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* parent_uuid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* received_uuid */
+ TYPE_ULONGLONG, /* ctransid */
+ TYPE_ULONGLONG, /* otransid */
+ TYPE_ULONGLONG, /* stransid */
+ TYPE_ULONGLONG, /* rtransid */
+ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* ctime */
+ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* otime */
+ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* stime */
+ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* rtime */
+ MK_ARRAY(TYPE_ULONGLONG, 8)) /* reserved */
+#endif
+
+#ifdef BTRFS_IOC_INO_LOOKUP
+STRUCT(btrfs_ioctl_ino_lookup_args,
+ TYPE_ULONGLONG, /* treeid */
+ TYPE_ULONGLONG, /* objectid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_INO_LOOKUP_PATH_MAX)) /* name */
+#endif
+
+#ifdef BTRFS_IOC_INO_PATHS
+STRUCT(btrfs_ioctl_ino_path_args,
+ TYPE_ULONGLONG, /* inum */
+ TYPE_ULONGLONG, /* size */
+ MK_ARRAY(TYPE_ULONGLONG, 4), /* reserved */
+ TYPE_ULONGLONG) /* fspath */
+#endif
+
+#if defined(BTRFS_IOC_LOGICAL_INO) || defined(BTRFS_IOC_LOGICAL_INO_V2)
+STRUCT(btrfs_ioctl_logical_ino_args,
+ TYPE_ULONGLONG, /* logical */
+ TYPE_ULONGLONG, /* size */
+ MK_ARRAY(TYPE_ULONGLONG, 3), /* reserved */
+ TYPE_ULONGLONG, /* flags */
+ TYPE_ULONGLONG) /* inodes */
+#endif
+
+#ifdef BTRFS_IOC_INO_LOOKUP_USER
+STRUCT(btrfs_ioctl_ino_lookup_user_args,
+ TYPE_ULONGLONG, /* dirid */
+ TYPE_ULONGLONG, /* treeid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_VOL_NAME_MAX + 1), /* name */
+ MK_ARRAY(TYPE_CHAR, BTRFS_INO_LOOKUP_USER_PATH_MAX)) /* path */
+#endif
+
+#if defined(BTRFS_IOC_SCRUB) || defined(BTRFS_IOC_SCRUB_PROGRESS)
+STRUCT(btrfs_scrub_progress,
+ TYPE_ULONGLONG, /* data_extents_scrubbed */
+ TYPE_ULONGLONG, /* tree_extents_scrubbed */
+ TYPE_ULONGLONG, /* data_bytes_scrubbed */
+ TYPE_ULONGLONG, /* tree_bytes_scrubbed */
+ TYPE_ULONGLONG, /* read_errors */
+ TYPE_ULONGLONG, /* csum_errors */
+ TYPE_ULONGLONG, /* verify_errors */
+ TYPE_ULONGLONG, /* no_csum */
+ TYPE_ULONGLONG, /* csum_discards */
+ TYPE_ULONGLONG, /* super_errors */
+ TYPE_ULONGLONG, /* malloc_errors */
+ TYPE_ULONGLONG, /* uncorrectable_errors */
+ TYPE_ULONGLONG, /* corrected_er */
+ TYPE_ULONGLONG, /* last_physical */
+ TYPE_ULONGLONG) /* unverified_errors */
+
+STRUCT(btrfs_ioctl_scrub_args,
+ TYPE_ULONGLONG, /* devid */
+ TYPE_ULONGLONG, /* start */
+ TYPE_ULONGLONG, /* end */
+ TYPE_ULONGLONG, /* flags */
+ MK_STRUCT(STRUCT_btrfs_scrub_progress), /* progress */
+ MK_ARRAY(TYPE_ULONGLONG,
+ (1024 - 32 -
+ sizeof(struct btrfs_scrub_progress)) / 8)) /* unused */
+#endif
+
+#ifdef BTRFS_IOC_DEV_INFO
+STRUCT(btrfs_ioctl_dev_info_args,
+ TYPE_ULONGLONG, /* devid */
+ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* uuid */
+ TYPE_ULONGLONG, /* bytes_used */
+ TYPE_ULONGLONG, /* total_bytes */
+ MK_ARRAY(TYPE_ULONGLONG, 379), /* unused */
+ MK_ARRAY(TYPE_CHAR, BTRFS_DEVICE_PATH_NAME_MAX)) /* path */
+#endif
+
+#ifdef BTRFS_IOC_GET_SUBVOL_ROOTREF
+STRUCT(rootref,
+ TYPE_ULONGLONG, /* treeid */
+ TYPE_ULONGLONG) /* dirid */
+
+STRUCT(btrfs_ioctl_get_subvol_rootref_args,
+ TYPE_ULONGLONG, /* min_treeid */
+ MK_ARRAY(MK_STRUCT(STRUCT_rootref),
+ BTRFS_MAX_ROOTREF_BUFFER_NUM), /* rootref */
+ TYPE_CHAR, /* num_items */
+ MK_ARRAY(TYPE_CHAR, 7)) /* align */
+#endif
+
+#ifdef BTRFS_IOC_GET_DEV_STATS
+STRUCT(btrfs_ioctl_get_dev_stats,
+ TYPE_ULONGLONG, /* devid */
+ TYPE_ULONGLONG, /* nr_items */
+ TYPE_ULONGLONG, /* flags */
+ MK_ARRAY(TYPE_ULONGLONG, BTRFS_DEV_STAT_VALUES_MAX), /* values */
+ MK_ARRAY(TYPE_ULONGLONG,
+ 128 - 2 - BTRFS_DEV_STAT_VALUES_MAX)) /* unused */
+#endif
+
+STRUCT(btrfs_ioctl_quota_ctl_args,
+ TYPE_ULONGLONG, /* cmd */
+ TYPE_ULONGLONG) /* status */
+
+STRUCT(btrfs_ioctl_quota_rescan_args,
+ TYPE_ULONGLONG, /* flags */
+ TYPE_ULONGLONG, /* progress */
+ MK_ARRAY(TYPE_ULONGLONG, 6)) /* reserved */
+
+STRUCT(btrfs_ioctl_qgroup_assign_args,
+ TYPE_ULONGLONG, /* assign */
+ TYPE_ULONGLONG, /* src */
+ TYPE_ULONGLONG) /* dst */
+
+STRUCT(btrfs_ioctl_qgroup_create_args,
+ TYPE_ULONGLONG, /* create */
+ TYPE_ULONGLONG) /* qgroupid */
+
+STRUCT(btrfs_qgroup_limit,
+ TYPE_ULONGLONG, /* flags */
+ TYPE_ULONGLONG, /* max_rfer */
+ TYPE_ULONGLONG, /* max_excl */
+ TYPE_ULONGLONG, /* rsv_rfer */
+ TYPE_ULONGLONG) /* rsv_excl */
+
+STRUCT(btrfs_ioctl_qgroup_limit_args,
+ TYPE_ULONGLONG, /* qgroupid */
+ MK_STRUCT(STRUCT_btrfs_qgroup_limit)) /* lim */
+
+STRUCT(btrfs_ioctl_feature_flags,
+ TYPE_ULONGLONG, /* compat_flags */
+ TYPE_ULONGLONG, /* compat_ro_flags */
+ TYPE_ULONGLONG) /* incompat_flags */
+
STRUCT(rtc_time,
TYPE_INT, /* tm_sec */
TYPE_INT, /* tm_min */
diff --git a/meson.build b/meson.build
index 55c7d23..5aaa364 100644
--- a/meson.build
+++ b/meson.build
@@ -1095,12 +1095,9 @@
dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
qemu_io = executable('qemu-io', files('qemu-io.c'),
dependencies: [block, qemuutil], install: true)
- qemu_block_tools += [qemu_img, qemu_io]
- if targetos != 'windows'
- qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
+ qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
dependencies: [block, qemuutil], install: true)
- qemu_block_tools += [qemu_nbd]
- endif
+ qemu_block_tools += [qemu_img, qemu_io, qemu_nbd]
subdir('storage-daemon')
subdir('contrib/rdmacm-mux')
diff --git a/qapi/block-core.json b/qapi/block-core.json
index db08c58..55b58ba 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -4036,9 +4036,7 @@
##
# @blockdev-add:
#
-# Creates a new block device. If the @id option is given at the top level, a
-# BlockBackend will be created; otherwise, @node-name is mandatory at the top
-# level and no BlockBackend will be created.
+# Creates a new block device.
#
# Since: 2.9
#
diff --git a/qapi/char.json b/qapi/char.json
index 8aeedf9..b4d66ec 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -562,6 +562,8 @@
#
# @open: true if the guest has opened the virtio-serial port
#
+# Note: This event is rate-limited.
+#
# Since: 2.1
#
# Example:
diff --git a/qemu-img.c b/qemu-img.c
index 5308773..eb2fc1f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -41,6 +41,7 @@
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
+#include "qemu/sockets.h"
#include "qemu/units.h"
#include "qom/object_interfaces.h"
#include "sysemu/block-backend.h"
@@ -5410,6 +5411,7 @@
signal(SIGPIPE, SIG_IGN);
#endif
+ socket_init();
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_init_exec_dir(argv[0]);
diff --git a/qemu-io.c b/qemu-io.c
index 3adc5a7..7cc832b 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -25,6 +25,7 @@
#include "qemu/config-file.h"
#include "qemu/readline.h"
#include "qemu/log.h"
+#include "qemu/sockets.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qdict.h"
#include "qom/object_interfaces.h"
@@ -542,6 +543,7 @@
signal(SIGPIPE, SIG_IGN);
#endif
+ socket_init();
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_init_exec_dir(argv[0]);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d2657b8..33476a1 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -155,12 +155,13 @@
, name);
}
+#if HAVE_NBD_DEVICE
static void termsig_handler(int signum)
{
atomic_cmpxchg(&state, RUNNING, TERMINATE);
qemu_notify_event();
}
-
+#endif /* HAVE_NBD_DEVICE */
static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
const char *hostname)
@@ -587,6 +588,7 @@
unsigned socket_activation;
const char *pid_file_name = NULL;
+#if HAVE_NBD_DEVICE
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
*/
@@ -594,11 +596,13 @@
memset(&sa_sigterm, 0, sizeof(sa_sigterm));
sa_sigterm.sa_handler = termsig_handler;
sigaction(SIGTERM, &sa_sigterm, NULL);
+#endif /* HAVE_NBD_DEVICE */
#ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN);
#endif
+ socket_init();
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qcrypto_init(&error_fatal);
@@ -895,6 +899,7 @@
#endif
if ((device && !verbose) || fork_process) {
+#ifndef WIN32
int stderr_fd[2];
pid_t pid;
int ret;
@@ -958,6 +963,10 @@
*/
exit(errors);
}
+#else /* WIN32 */
+ error_report("Unable to fork into background on Windows hosts");
+ exit(EXIT_FAILURE);
+#endif /* WIN32 */
}
if (device != NULL && sockpath == NULL) {
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 3ad33af..3640f17 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -213,6 +213,7 @@
ret = mcgen('''
void qapi_free_%(c_name)s(%(c_name)s *obj);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(%(c_name)s, qapi_free_%(c_name)s)
''',
c_name=c_name(name))
return ret
diff --git a/scripts/qmp/qom-fuse b/scripts/qmp/qom-fuse
index 5fa6b3b..7c7cff8 100755
--- a/scripts/qmp/qom-fuse
+++ b/scripts/qmp/qom-fuse
@@ -3,17 +3,19 @@
# QEMU Object Model test tools
#
# Copyright IBM, Corp. 2012
+# Copyright (C) 2020 Red Hat, Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
+# Markus Armbruster <armbru@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2 or later. See
# the COPYING file in the top-level directory.
##
import fuse, stat
-from fuse import Fuse
-import os, posix
+from fuse import FUSE, FuseOSError, Operations
+import os, posix, sys
from errno import *
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
@@ -21,9 +23,8 @@
fuse.fuse_python_api = (0, 2)
-class QOMFS(Fuse):
- def __init__(self, qmp, *args, **kwds):
- Fuse.__init__(self, *args, **kwds)
+class QOMFS(Operations):
+ def __init__(self, qmp):
self.qmp = qmp
self.qmp.connect()
self.ino_map = {}
@@ -44,8 +45,10 @@
return False
def is_property(self, path):
+ path, prop = path.rsplit('/', 1)
+ if path == '':
+ path = '/'
try:
- path, prop = path.rsplit('/', 1)
for item in self.qmp.command('qom-list', path=path):
if item['name'] == prop:
return True
@@ -54,8 +57,10 @@
return False
def is_link(self, path):
+ path, prop = path.rsplit('/', 1)
+ if path == '':
+ path = '/'
try:
- path, prop = path.rsplit('/', 1)
for item in self.qmp.command('qom-list', path=path):
if item['name'] == prop:
if item['type'].startswith('link<'):
@@ -65,21 +70,23 @@
except:
return False
- def read(self, path, length, offset):
+ def read(self, path, length, offset, fh):
if not self.is_property(path):
return -ENOENT
path, prop = path.rsplit('/', 1)
+ if path == '':
+ path = '/'
try:
- data = str(self.qmp.command('qom-get', path=path, property=prop))
+ data = self.qmp.command('qom-get', path=path, property=prop)
data += '\n' # make values shell friendly
except:
- return -EPERM
+ raise FuseOSError(EPERM)
if offset > len(data):
return ''
- return str(data[offset:][:length])
+ return bytes(data[offset:][:length], encoding='utf-8')
def readlink(self, path):
if not self.is_link(path):
@@ -89,52 +96,52 @@
return prefix + str(self.qmp.command('qom-get', path=path,
property=prop))
- def getattr(self, path):
+ def getattr(self, path, fh=None):
if self.is_link(path):
- value = posix.stat_result((0o755 | stat.S_IFLNK,
- self.get_ino(path),
- 0,
- 2,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
+ value = { 'st_mode': 0o755 | stat.S_IFLNK,
+ 'st_ino': self.get_ino(path),
+ 'st_dev': 0,
+ 'st_nlink': 2,
+ 'st_uid': 1000,
+ 'st_gid': 1000,
+ 'st_size': 4096,
+ 'st_atime': 0,
+ 'st_mtime': 0,
+ 'st_ctime': 0 }
elif self.is_object(path):
- value = posix.stat_result((0o755 | stat.S_IFDIR,
- self.get_ino(path),
- 0,
- 2,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
+ value = { 'st_mode': 0o755 | stat.S_IFDIR,
+ 'st_ino': self.get_ino(path),
+ 'st_dev': 0,
+ 'st_nlink': 2,
+ 'st_uid': 1000,
+ 'st_gid': 1000,
+ 'st_size': 4096,
+ 'st_atime': 0,
+ 'st_mtime': 0,
+ 'st_ctime': 0 }
elif self.is_property(path):
- value = posix.stat_result((0o644 | stat.S_IFREG,
- self.get_ino(path),
- 0,
- 1,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
+ value = { 'st_mode': 0o644 | stat.S_IFREG,
+ 'st_ino': self.get_ino(path),
+ 'st_dev': 0,
+ 'st_nlink': 1,
+ 'st_uid': 1000,
+ 'st_gid': 1000,
+ 'st_size': 4096,
+ 'st_atime': 0,
+ 'st_mtime': 0,
+ 'st_ctime': 0 }
else:
- value = -ENOENT
+ raise FuseOSError(ENOENT)
return value
- def readdir(self, path, offset):
- yield fuse.Direntry('.')
- yield fuse.Direntry('..')
+ def readdir(self, path, fh):
+ yield '.'
+ yield '..'
for item in self.qmp.command('qom-list', path=path):
- yield fuse.Direntry(str(item['name']))
+ yield str(item['name'])
if __name__ == '__main__':
- import sys, os
+ import os
- fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
- fs.main(sys.argv)
+ fuse = FUSE(QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET'])),
+ sys.argv[1], foreground=True)
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index a802e89..e3b9806 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -1895,6 +1895,16 @@
if (!tcg_region_inited) {
tcg_region_inited = 1;
tcg_region_init();
+ /*
+ * If MTTCG, and we will create multiple cpus,
+ * then we will have cpus running in parallel.
+ */
+ if (qemu_tcg_mttcg_enabled()) {
+ MachineState *ms = MACHINE(qdev_get_machine());
+ if (ms->smp.max_cpus > 1) {
+ parallel_cpus = true;
+ }
+ }
}
if (qemu_tcg_mttcg_enabled() || !single_tcg_cpu_thread) {
@@ -1904,7 +1914,6 @@
if (qemu_tcg_mttcg_enabled()) {
/* create a thread per vCPU with TCG (MTTCG) */
- parallel_cpus = true;
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
cpu->cpu_index);
diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c
index 3707c0e..7ebd9e8 100644
--- a/tcg/tcg-op-gvec.c
+++ b/tcg/tcg-op-gvec.c
@@ -1570,18 +1570,16 @@
do_dup(vece, dofs, oprsz, maxsz, NULL, in, 0);
tcg_temp_free_i64(in);
}
- } else {
+ } else if (vece == 4) {
/* 128-bit duplicate. */
- /* ??? Dup to 256-bit vector. */
int i;
- tcg_debug_assert(vece == 4);
tcg_debug_assert(oprsz >= 16);
if (TCG_TARGET_HAS_v128) {
TCGv_vec in = tcg_temp_new_vec(TCG_TYPE_V128);
tcg_gen_ld_vec(in, cpu_env, aofs);
- for (i = 0; i < oprsz; i += 16) {
+ for (i = (aofs == dofs) * 16; i < oprsz; i += 16) {
tcg_gen_st_vec(in, cpu_env, dofs + i);
}
tcg_temp_free_vec(in);
@@ -1591,7 +1589,7 @@
tcg_gen_ld_i64(in0, cpu_env, aofs);
tcg_gen_ld_i64(in1, cpu_env, aofs + 8);
- for (i = 0; i < oprsz; i += 16) {
+ for (i = (aofs == dofs) * 16; i < oprsz; i += 16) {
tcg_gen_st_i64(in0, cpu_env, dofs + i);
tcg_gen_st_i64(in1, cpu_env, dofs + i + 8);
}
@@ -1601,6 +1599,54 @@
if (oprsz < maxsz) {
expand_clr(dofs + oprsz, maxsz - oprsz);
}
+ } else if (vece == 5) {
+ /* 256-bit duplicate. */
+ int i;
+
+ tcg_debug_assert(oprsz >= 32);
+ tcg_debug_assert(oprsz % 32 == 0);
+ if (TCG_TARGET_HAS_v256) {
+ TCGv_vec in = tcg_temp_new_vec(TCG_TYPE_V256);
+
+ tcg_gen_ld_vec(in, cpu_env, aofs);
+ for (i = (aofs == dofs) * 32; i < oprsz; i += 32) {
+ tcg_gen_st_vec(in, cpu_env, dofs + i);
+ }
+ tcg_temp_free_vec(in);
+ } else if (TCG_TARGET_HAS_v128) {
+ TCGv_vec in0 = tcg_temp_new_vec(TCG_TYPE_V128);
+ TCGv_vec in1 = tcg_temp_new_vec(TCG_TYPE_V128);
+
+ tcg_gen_ld_vec(in0, cpu_env, aofs);
+ tcg_gen_ld_vec(in1, cpu_env, aofs + 16);
+ for (i = (aofs == dofs) * 32; i < oprsz; i += 32) {
+ tcg_gen_st_vec(in0, cpu_env, dofs + i);
+ tcg_gen_st_vec(in1, cpu_env, dofs + i + 16);
+ }
+ tcg_temp_free_vec(in0);
+ tcg_temp_free_vec(in1);
+ } else {
+ TCGv_i64 in[4];
+ int j;
+
+ for (j = 0; j < 4; ++j) {
+ in[j] = tcg_temp_new_i64();
+ tcg_gen_ld_i64(in[j], cpu_env, aofs + j * 8);
+ }
+ for (i = (aofs == dofs) * 32; i < oprsz; i += 32) {
+ for (j = 0; j < 4; ++j) {
+ tcg_gen_st_i64(in[j], cpu_env, dofs + i + j * 8);
+ }
+ }
+ for (j = 0; j < 4; ++j) {
+ tcg_temp_free_i64(in[j]);
+ }
+ }
+ if (oprsz < maxsz) {
+ expand_clr(dofs + oprsz, maxsz - oprsz);
+ }
+ } else {
+ g_assert_not_reached();
}
}
@@ -2264,12 +2310,13 @@
tcg_gen_muli_i64(t, t, (1 << nbit) - 1);
/*
- * Invert (via xor -1) and add one (via sub -1).
+ * Invert (via xor -1) and add one.
* Because of the ordering the msb is cleared,
* so we never have carry into the next element.
*/
tcg_gen_xor_i64(d, b, t);
- tcg_gen_sub_i64(d, d, t);
+ tcg_gen_andi_i64(t, t, dup_const(vece, 1));
+ tcg_gen_add_i64(d, d, t);
tcg_temp_free_i64(t);
}
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 6d127e2..2b83c0c 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -19,8 +19,8 @@
virtual size: 2 GiB (2147483648 bytes)
=== Testing monolithicFlat with zeroed_grain ===
-qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
+qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
=== Testing big twoGbMaxExtentFlat ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
diff --git a/tests/qemu-iotests/259.out b/tests/qemu-iotests/259.out
index e27b9ff..1aaadfd 100644
--- a/tests/qemu-iotests/259.out
+++ b/tests/qemu-iotests/259.out
@@ -10,5 +10,5 @@
--- Testing creation for which the node would need to grow ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864 preallocation=metadata
-qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Image format driver does not support resize
+qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Cannot grow NBD nodes
*** done
diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index 6bacabf..e41b91a 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -417,7 +417,7 @@
static void test_visitor_in_struct_nested(TestInputVisitorData *data,
const void *unused)
{
- UserDefTwo *udp = NULL;
+ g_autoptr(UserDefTwo) udp = NULL;
Visitor *v;
v = visitor_input_test_init(data, "{ 'string0': 'string0', "
@@ -433,8 +433,6 @@
g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string");
g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2");
g_assert(udp->dict1->has_dict3 == false);
-
- qapi_free_UserDefTwo(udp);
}
static void test_visitor_in_list(TestInputVisitorData *data,
@@ -546,7 +544,7 @@
const void *unused)
{
Visitor *v;
- UserDefFlatUnion *tmp;
+ g_autoptr(UserDefFlatUnion) tmp = NULL;
UserDefUnionBase *base;
v = visitor_input_test_init(data,
@@ -563,8 +561,6 @@
base = qapi_UserDefFlatUnion_base(tmp);
g_assert(&base->enum1 == &tmp->enum1);
-
- qapi_free_UserDefFlatUnion(tmp);
}
static void test_visitor_in_alternate(TestInputVisitorData *data,
@@ -690,7 +686,7 @@
const void *unused,
UserDefListUnionKind kind)
{
- UserDefListUnion *cvalue = NULL;
+ g_autoptr(UserDefListUnion) cvalue = NULL;
Visitor *v;
GString *gstr_list = g_string_new("");
GString *gstr_union = g_string_new("");
@@ -782,7 +778,6 @@
g_string_free(gstr_union, true);
g_string_free(gstr_list, true);
- qapi_free_UserDefListUnion(cvalue);
}
static void test_visitor_in_list_union_int(TestInputVisitorData *data,
@@ -851,7 +846,7 @@
static void test_visitor_in_list_union_bool(TestInputVisitorData *data,
const void *unused)
{
- UserDefListUnion *cvalue = NULL;
+ g_autoptr(UserDefListUnion) cvalue = NULL;
boolList *elem = NULL;
Visitor *v;
GString *gstr_list = g_string_new("");
@@ -879,13 +874,12 @@
g_string_free(gstr_union, true);
g_string_free(gstr_list, true);
- qapi_free_UserDefListUnion(cvalue);
}
static void test_visitor_in_list_union_string(TestInputVisitorData *data,
const void *unused)
{
- UserDefListUnion *cvalue = NULL;
+ g_autoptr(UserDefListUnion) cvalue = NULL;
strList *elem = NULL;
Visitor *v;
GString *gstr_list = g_string_new("");
@@ -914,7 +908,6 @@
g_string_free(gstr_union, true);
g_string_free(gstr_list, true);
- qapi_free_UserDefListUnion(cvalue);
}
#define DOUBLE_STR_MAX 16
@@ -922,7 +915,7 @@
static void test_visitor_in_list_union_number(TestInputVisitorData *data,
const void *unused)
{
- UserDefListUnion *cvalue = NULL;
+ g_autoptr(UserDefListUnion) cvalue = NULL;
numberList *elem = NULL;
Visitor *v;
GString *gstr_list = g_string_new("");
@@ -957,7 +950,6 @@
g_string_free(gstr_union, true);
g_string_free(gstr_list, true);
- qapi_free_UserDefListUnion(cvalue);
}
static void input_visitor_test_add(const char *testpath,
@@ -1253,7 +1245,7 @@
static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data,
const QLitObject *qlit)
{
- SchemaInfoList *schema = NULL;
+ g_autoptr(SchemaInfoList) schema = NULL;
QObject *obj = qobject_from_qlit(qlit);
Visitor *v;
@@ -1262,7 +1254,6 @@
visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
g_assert(schema);
- qapi_free_SchemaInfoList(schema);
qobject_unref(obj);
visit_free(v);
}