Monitor patches for 2018-06-30
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbN640AAoJEDhwtADrkYZTGxsQAKxuoAn1P40s3T2HQjFjUnHz BV2V5R0bUpnTOph9CAGXZg+y5Ea/XhN+W7qSpYpHTaNoKkbmOuhInWD5UywZrU0n 3+97PuUXw3wqr1XjzgkGGu5AaxL4dP8rkS/trOlkqSnXFZOO4ODgnPpWshjC1uTk FiMGNa2fSnz2sW2qTVasygQuQ1P6OXZwFP/0TH6S94JbofR2LRMqCARjOKquvECR gFRzL0yD5Oqvq3vJuJX8dyyCXItJK3LxVB4Af/pgmonRb5eLTMcd6q3JZyA6OBGO X5qZDBBoX9rq4WDU/3abkPTvsNIk4wkpnuIF8x/9qslw7KYz7d91NslDVjPwD8+3 RK1IrDtJtiILST37iv2lsfJxGAMPWERhW6ulO2966yB+GHZ9/mz1SsX0D8rNlPc5 W4uPFbawjQ80xjPILSHj0uusoZJ+4L1tCTr3LqFQFTzfKI09Kwizy+zgPvd8nPBO 9CKDai4Kci6SIiUGuoWN04QsgQCSIVnb6U2Zx1p2h51MRiJg+Sfrk9K4682u6Cua 2WlQmMruuWYf6XvT/y36qdlnjBQNdur0NY9Y77mK6Ok2VumnT0Lask4elqK0w8Dp C2HRWd4NvFWyOqXi+vTlW/sKIGY87BpYXroj2/RIDqPGDb592+FcUJw3MVicxre0 fNbK2PRlAhU4/oah5RdC =DW+w -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-monitor-2018-06-30' into staging Monitor patches for 2018-06-30 # gpg: Signature made Sat 30 Jun 2018 17:22:12 BST # gpg: using RSA key 3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-monitor-2018-06-30: docs: mention shared state protect for OOB tests: iotests: drop some stderr line monitor: flush qmp responses when CLOSED monitor: rename *_pop_one to *_pop_any chardev: comment details for CLOSED event Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e3800998e6
@ -666,22 +666,27 @@ command:
|
|||||||
|
|
||||||
- They are executed in order,
|
- They are executed in order,
|
||||||
- They run only in main thread of QEMU,
|
- They run only in main thread of QEMU,
|
||||||
- They have the BQL taken during execution.
|
- They run with the BQL held.
|
||||||
|
|
||||||
When a command is executed with OOB, the following changes occur:
|
When a command is executed with OOB, the following changes occur:
|
||||||
|
|
||||||
- They can be completed before a pending in-band command,
|
- They can be completed before a pending in-band command,
|
||||||
- They run in a dedicated monitor thread,
|
- They run in a dedicated monitor thread,
|
||||||
- They do not take the BQL during execution.
|
- They run with the BQL not held.
|
||||||
|
|
||||||
OOB command handlers must satisfy the following conditions:
|
OOB command handlers must satisfy the following conditions:
|
||||||
|
|
||||||
- It executes extremely fast,
|
- It terminates quickly,
|
||||||
- It does not take any lock, or, it can take very small locks if all
|
|
||||||
critical regions also follow the rules for OOB command handler code,
|
|
||||||
- It does not invoke system calls that may block,
|
- It does not invoke system calls that may block,
|
||||||
- It does not access guest RAM that may block when userfaultfd is
|
- It does not access guest RAM that may block when userfaultfd is
|
||||||
enabled for postcopy live migration.
|
enabled for postcopy live migration,
|
||||||
|
- It takes only "fast" locks, i.e. all critical sections protected by
|
||||||
|
any lock it takes also satisfy the conditions for OOB command
|
||||||
|
handler code.
|
||||||
|
|
||||||
|
The restrictions on locking limit access to shared state. Such access
|
||||||
|
requires synchronization, but OOB commands can't take the BQL or any
|
||||||
|
other "slow" lock.
|
||||||
|
|
||||||
If in doubt, do not implement OOB execution support.
|
If in doubt, do not implement OOB execution support.
|
||||||
|
|
||||||
|
@ -22,7 +22,16 @@ typedef enum {
|
|||||||
CHR_EVENT_OPENED, /* new connection established */
|
CHR_EVENT_OPENED, /* new connection established */
|
||||||
CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
|
CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
|
||||||
CHR_EVENT_MUX_OUT, /* mux-focus will move on */
|
CHR_EVENT_MUX_OUT, /* mux-focus will move on */
|
||||||
CHR_EVENT_CLOSED /* connection closed */
|
CHR_EVENT_CLOSED /* connection closed. NOTE: currently this event
|
||||||
|
* is only bound to the read port of the chardev.
|
||||||
|
* Normally the read port and write port of a
|
||||||
|
* chardev should be the same, but it can be
|
||||||
|
* different, e.g., for fd chardevs, when the two
|
||||||
|
* fds are different. So when we received the
|
||||||
|
* CLOSED event it's still possible that the out
|
||||||
|
* port is still open. TODO: we should only send
|
||||||
|
* the CLOSED event when both ports are closed.
|
||||||
|
*/
|
||||||
} QEMUChrEvent;
|
} QEMUChrEvent;
|
||||||
|
|
||||||
#define CHR_READ_BUF_LEN 4096
|
#define CHR_READ_BUF_LEN 4096
|
||||||
|
52
monitor.c
52
monitor.c
@ -541,37 +541,54 @@ struct QMPResponse {
|
|||||||
};
|
};
|
||||||
typedef struct QMPResponse QMPResponse;
|
typedef struct QMPResponse QMPResponse;
|
||||||
|
|
||||||
|
static QObject *monitor_qmp_response_pop_one(Monitor *mon)
|
||||||
|
{
|
||||||
|
QObject *data;
|
||||||
|
|
||||||
|
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
|
||||||
|
data = g_queue_pop_head(mon->qmp.qmp_responses);
|
||||||
|
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_qmp_response_flush(Monitor *mon)
|
||||||
|
{
|
||||||
|
QObject *data;
|
||||||
|
|
||||||
|
while ((data = monitor_qmp_response_pop_one(mon))) {
|
||||||
|
monitor_json_emitter_raw(mon, data);
|
||||||
|
qobject_unref(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return one QMPResponse. The response is only valid if
|
* Pop a QMPResponse from any monitor's response queue into @response.
|
||||||
* response.data is not NULL.
|
* Return false if all the queues are empty; else true.
|
||||||
*/
|
*/
|
||||||
static QMPResponse monitor_qmp_response_pop_one(void)
|
static bool monitor_qmp_response_pop_any(QMPResponse *response)
|
||||||
{
|
{
|
||||||
Monitor *mon;
|
Monitor *mon;
|
||||||
QObject *data = NULL;
|
QObject *data = NULL;
|
||||||
|
|
||||||
qemu_mutex_lock(&monitor_lock);
|
qemu_mutex_lock(&monitor_lock);
|
||||||
QTAILQ_FOREACH(mon, &mon_list, entry) {
|
QTAILQ_FOREACH(mon, &mon_list, entry) {
|
||||||
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
|
data = monitor_qmp_response_pop_one(mon);
|
||||||
data = g_queue_pop_head(mon->qmp.qmp_responses);
|
|
||||||
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
response->mon = mon;
|
||||||
|
response->data = data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qemu_mutex_unlock(&monitor_lock);
|
qemu_mutex_unlock(&monitor_lock);
|
||||||
return (QMPResponse) { .mon = mon, .data = data };
|
return data != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void monitor_qmp_bh_responder(void *opaque)
|
static void monitor_qmp_bh_responder(void *opaque)
|
||||||
{
|
{
|
||||||
QMPResponse response;
|
QMPResponse response;
|
||||||
|
|
||||||
while (true) {
|
while (monitor_qmp_response_pop_any(&response)) {
|
||||||
response = monitor_qmp_response_pop_one();
|
|
||||||
if (!response.data) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
monitor_json_emitter_raw(response.mon, response.data);
|
monitor_json_emitter_raw(response.mon, response.data);
|
||||||
qobject_unref(response.data);
|
qobject_unref(response.data);
|
||||||
}
|
}
|
||||||
@ -4199,7 +4216,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
|
|||||||
* when we process one request on a specific monitor, we put that
|
* when we process one request on a specific monitor, we put that
|
||||||
* monitor to the end of mon_list queue.
|
* monitor to the end of mon_list queue.
|
||||||
*/
|
*/
|
||||||
static QMPRequest *monitor_qmp_requests_pop_one(void)
|
static QMPRequest *monitor_qmp_requests_pop_any(void)
|
||||||
{
|
{
|
||||||
QMPRequest *req_obj = NULL;
|
QMPRequest *req_obj = NULL;
|
||||||
Monitor *mon;
|
Monitor *mon;
|
||||||
@ -4231,7 +4248,7 @@ static QMPRequest *monitor_qmp_requests_pop_one(void)
|
|||||||
|
|
||||||
static void monitor_qmp_bh_dispatcher(void *data)
|
static void monitor_qmp_bh_dispatcher(void *data)
|
||||||
{
|
{
|
||||||
QMPRequest *req_obj = monitor_qmp_requests_pop_one();
|
QMPRequest *req_obj = monitor_qmp_requests_pop_any();
|
||||||
|
|
||||||
if (req_obj) {
|
if (req_obj) {
|
||||||
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
|
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
|
||||||
@ -4458,6 +4475,13 @@ static void monitor_qmp_event(void *opaque, int event)
|
|||||||
mon_refcount++;
|
mon_refcount++;
|
||||||
break;
|
break;
|
||||||
case CHR_EVENT_CLOSED:
|
case CHR_EVENT_CLOSED:
|
||||||
|
/*
|
||||||
|
* Note: this is only useful when the output of the chardev
|
||||||
|
* backend is still open. For example, when the backend is
|
||||||
|
* stdio, it's possible that stdout is still open when stdin
|
||||||
|
* is closed.
|
||||||
|
*/
|
||||||
|
monitor_qmp_response_flush(mon);
|
||||||
monitor_qmp_cleanup_queues(mon);
|
monitor_qmp_cleanup_queues(mon);
|
||||||
json_message_parser_destroy(&mon->qmp.parser);
|
json_message_parser_destroy(&mon->qmp.parser);
|
||||||
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
|
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
|
||||||
|
@ -33,6 +33,14 @@ _cleanup()
|
|||||||
}
|
}
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# Sometimes the error line might be dumped before/after an event
|
||||||
|
# randomly. Mask it out for specific test that may trigger this
|
||||||
|
# uncertainty for current test for now.
|
||||||
|
_filter_io_error()
|
||||||
|
{
|
||||||
|
sed '/Input\/output error/d'
|
||||||
|
}
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
@ -464,7 +472,7 @@ echo "{'execute': 'qmp_capabilities'}
|
|||||||
}}" \
|
}}" \
|
||||||
-incoming exec:'cat /dev/null' \
|
-incoming exec:'cat /dev/null' \
|
||||||
2>&1 \
|
2>&1 \
|
||||||
| _filter_qmp | _filter_qemu_io
|
| _filter_qmp | _filter_qemu_io | _filter_io_error
|
||||||
|
|
||||||
echo
|
echo
|
||||||
# Image should not have been marked corrupt
|
# Image should not have been marked corrupt
|
||||||
|
@ -428,7 +428,6 @@ QMP_VERSION
|
|||||||
{"return": {}}
|
{"return": {}}
|
||||||
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed
|
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed
|
||||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
|
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
|
||||||
read failed: Input/output error
|
|
||||||
{"return": ""}
|
{"return": ""}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
|
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
|
||||||
|
Loading…
Reference in New Issue
Block a user