virtiofs and migration pull 2021-03-15
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAmBPvXcACgkQBRYzHrxb /edQLhAAt12aD4LfEHVzm2Z0KestZvGMJ6rzb84gv44MumfDAHoVvGxT7c12DsnW 1ct9gG3P7ri4+pDulycOlO1dk2V8c1tX4gGeeShARwAL7UWVwJ6kBxA83kJ+HD5u xUMKpzRC2vOhYQW81FHY4NZsZjrmeWsR4rxS8FJbmEpNUYw5KMn3rTYVWEuyXMla fQRM1Sge7O//eCgtzK8FNL5TR1v1yaP+HF2lfzSq2mlAb389QzcDRwll9xS/7onP 8VNhIWqZfCIo6EmaFEzG+E0/9gjD14cDhFb3vMBuhKoEky4M7m0IAkeSMy7spf+N AIF6x0Rv28hpgC750q9XySnxSvojl8Dg9hYI6GKl3GYpRw54YDUFH7EYOeP1JDEc svAq0dz4CCD0tN5FZXlpkYkvUyi8W07wE1UsjLe6jZS42V9zRu4E0gM42zpB/CBn aTuUDQ+ErbK/mdMrlTPFG06fyh7HBXTcyGYdpoz555d7BoUQKMU1bo9PaeRv7S+C bEqGAONK8FBDciL+YkjPIhb9GnFmZvrtHFlSVHkD23xZFy/G4EtkZqiXQsd2X2x5 OitZJZc8Lo90b2azAMfrqn96iMr+y+HmujYU897Wr/zqz+0a676s38fXmkNAylh0 XRvwtdYXeM0sTcenc3g3bNfg44X9F0XaJfIowYYS9BXZbQ60e0s= =9k2c -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-virtiofs-20210315' into staging virtiofs and migration pull 2021-03-15 Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> # gpg: Signature made Mon 15 Mar 2021 20:03:03 GMT # gpg: using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7 # gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full] # Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7 * remotes/dgilbert-gitlab/tags/pull-virtiofs-20210315: migration: Replaced qemu_mutex_lock calls with QEMU_LOCK_GUARD monitor: Replaced qemu_mutex_lock calls with QEMU_LOCK_GUARD migration/tls: add error handling in multifd_tls_handshake_thread migration/tls: fix inverted semantics in multifd_channel_connect virtiofsd: Convert some functions to return bool virtiofsd: Don't allow empty paths in lookup_name() virtiofsd: Don't allow empty filenames virtiofsd: Add qemu version and copyright info virtiofsd: Release vu_dispatch_lock when stopping queue Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5d1428d6c4
|
@ -323,7 +323,7 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
|
|||
int ret = 0;
|
||||
|
||||
trace_migrate_send_rp_message((int)message_type, len);
|
||||
qemu_mutex_lock(&mis->rp_mutex);
|
||||
QEMU_LOCK_GUARD(&mis->rp_mutex);
|
||||
|
||||
/*
|
||||
* It's possible that the file handle got lost due to network
|
||||
|
@ -331,7 +331,7 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
|
|||
*/
|
||||
if (!mis->to_src_file) {
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_put_be16(mis->to_src_file, (unsigned int)message_type);
|
||||
|
@ -342,8 +342,6 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
|
|||
/* It's possible that qemu file got error during sending */
|
||||
ret = qemu_file_get_error(mis->to_src_file);
|
||||
|
||||
error:
|
||||
qemu_mutex_unlock(&mis->rp_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -739,7 +739,16 @@ static void multifd_tls_outgoing_handshake(QIOTask *task,
|
|||
} else {
|
||||
trace_multifd_tls_outgoing_handshake_complete(ioc);
|
||||
}
|
||||
multifd_channel_connect(p, ioc, err);
|
||||
|
||||
if (!multifd_channel_connect(p, ioc, err)) {
|
||||
/*
|
||||
* Error happen, mark multifd_send_thread status as 'quit' although it
|
||||
* is not created, and then tell who pay attention to me.
|
||||
*/
|
||||
p->quit = true;
|
||||
qemu_sem_post(&multifd_send_state->channels_ready);
|
||||
qemu_sem_post(&p->sem_sync);
|
||||
}
|
||||
}
|
||||
|
||||
static void *multifd_tls_handshake_thread(void *opaque)
|
||||
|
@ -798,9 +807,9 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
|
|||
* function after the TLS handshake,
|
||||
* so we mustn't call multifd_send_thread until then
|
||||
*/
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* update for tls qio channel */
|
||||
|
@ -808,10 +817,10 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
|
|||
qemu_thread_create(&p->thread, p->name, multifd_send_thread, p,
|
||||
QEMU_THREAD_JOINABLE);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void multifd_new_send_channel_cleanup(MultiFDSendParams *p,
|
||||
|
@ -844,7 +853,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque)
|
|||
p->c = QIO_CHANNEL(sioc);
|
||||
qio_channel_set_delay(p->c, false);
|
||||
p->running = true;
|
||||
if (multifd_channel_connect(p, sioc, local_err)) {
|
||||
if (!multifd_channel_connect(p, sioc, local_err)) {
|
||||
goto cleanup;
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -819,7 +819,7 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
|
|||
{
|
||||
bool ret;
|
||||
|
||||
qemu_mutex_lock(&rs->bitmap_mutex);
|
||||
QEMU_LOCK_GUARD(&rs->bitmap_mutex);
|
||||
|
||||
/*
|
||||
* Clear dirty bitmap if needed. This _must_ be called before we
|
||||
|
@ -852,7 +852,6 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
|
|||
if (ret) {
|
||||
rs->migration_dirty_pages--;
|
||||
}
|
||||
qemu_mutex_unlock(&rs->bitmap_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3275,7 +3274,7 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
|
|||
int idx, thread_count;
|
||||
|
||||
thread_count = migrate_decompress_threads();
|
||||
qemu_mutex_lock(&decomp_done_lock);
|
||||
QEMU_LOCK_GUARD(&decomp_done_lock);
|
||||
while (true) {
|
||||
for (idx = 0; idx < thread_count; idx++) {
|
||||
if (decomp_param[idx].done) {
|
||||
|
@ -3295,7 +3294,6 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
|
|||
qemu_cond_wait(&decomp_done_cond, &decomp_done_lock);
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock(&decomp_done_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -349,7 +349,7 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
|
|||
evconf = &monitor_qapi_event_conf[event];
|
||||
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
|
||||
|
||||
qemu_mutex_lock(&monitor_lock);
|
||||
QEMU_LOCK_GUARD(&monitor_lock);
|
||||
|
||||
if (!evconf->rate) {
|
||||
/* Unthrottled event */
|
||||
|
@ -391,8 +391,6 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
|
|||
timer_mod_ns(evstate->timer, now + evconf->rate);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&monitor_lock);
|
||||
}
|
||||
|
||||
void qapi_event_emit(QAPIEvent event, QDict *qdict)
|
||||
|
@ -447,7 +445,7 @@ static void monitor_qapi_event_handler(void *opaque)
|
|||
MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
|
||||
|
||||
trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
|
||||
qemu_mutex_lock(&monitor_lock);
|
||||
QEMU_LOCK_GUARD(&monitor_lock);
|
||||
|
||||
if (evstate->qdict) {
|
||||
int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
|
||||
|
@ -462,8 +460,6 @@ static void monitor_qapi_event_handler(void *opaque)
|
|||
timer_free(evstate->timer);
|
||||
g_free(evstate);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&monitor_lock);
|
||||
}
|
||||
|
||||
static unsigned int qapi_event_throttle_hash(const void *key)
|
||||
|
|
|
@ -76,7 +76,7 @@ static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon)
|
|||
|
||||
static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
|
||||
{
|
||||
qemu_mutex_lock(&mon->qmp_queue_lock);
|
||||
QEMU_LOCK_GUARD(&mon->qmp_queue_lock);
|
||||
|
||||
/*
|
||||
* Same condition as in monitor_qmp_dispatcher_co(), but before
|
||||
|
@ -103,7 +103,6 @@ static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
|
|||
monitor_resume(&mon->common);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
||||
}
|
||||
|
||||
void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
|
||||
|
@ -179,7 +178,7 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
|
|||
Monitor *mon;
|
||||
MonitorQMP *qmp_mon;
|
||||
|
||||
qemu_mutex_lock(&monitor_lock);
|
||||
QEMU_LOCK_GUARD(&monitor_lock);
|
||||
|
||||
QTAILQ_FOREACH(mon, &mon_list, entry) {
|
||||
if (!monitor_is_qmp(mon)) {
|
||||
|
@ -205,8 +204,6 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
|
|||
QTAILQ_INSERT_TAIL(&mon_list, mon, entry);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&monitor_lock);
|
||||
|
||||
return req_obj;
|
||||
}
|
||||
|
||||
|
@ -376,31 +373,31 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
|
|||
req_obj->err = err;
|
||||
|
||||
/* Protect qmp_requests and fetching its length. */
|
||||
qemu_mutex_lock(&mon->qmp_queue_lock);
|
||||
WITH_QEMU_LOCK_GUARD(&mon->qmp_queue_lock) {
|
||||
|
||||
/*
|
||||
* Suspend the monitor when we can't queue more requests after
|
||||
* this one. Dequeuing in monitor_qmp_dispatcher_co() or
|
||||
* monitor_qmp_cleanup_queue_and_resume() will resume it.
|
||||
* Note that when OOB is disabled, we queue at most one command,
|
||||
* for backward compatibility.
|
||||
*/
|
||||
if (!qmp_oob_enabled(mon) ||
|
||||
mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
|
||||
monitor_suspend(&mon->common);
|
||||
/*
|
||||
* Suspend the monitor when we can't queue more requests after
|
||||
* this one. Dequeuing in monitor_qmp_dispatcher_co() or
|
||||
* monitor_qmp_cleanup_queue_and_resume() will resume it.
|
||||
* Note that when OOB is disabled, we queue at most one command,
|
||||
* for backward compatibility.
|
||||
*/
|
||||
if (!qmp_oob_enabled(mon) ||
|
||||
mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
|
||||
monitor_suspend(&mon->common);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the request to the end of queue so that requests will be
|
||||
* handled in time order. Ownership for req_obj, req,
|
||||
* etc. will be delivered to the handler side.
|
||||
*/
|
||||
trace_monitor_qmp_in_band_enqueue(req_obj, mon,
|
||||
mon->qmp_requests->length);
|
||||
assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
|
||||
g_queue_push_tail(mon->qmp_requests, req_obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the request to the end of queue so that requests will be
|
||||
* handled in time order. Ownership for req_obj, req,
|
||||
* etc. will be delivered to the handler side.
|
||||
*/
|
||||
trace_monitor_qmp_in_band_enqueue(req_obj, mon,
|
||||
mon->qmp_requests->length);
|
||||
assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
|
||||
g_queue_push_tail(mon->qmp_requests, req_obj);
|
||||
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
||||
|
||||
/* Kick the dispatcher routine */
|
||||
if (!qatomic_xchg(&qmp_dispatcher_co_busy, true)) {
|
||||
aio_co_wake(qmp_dispatcher_co);
|
||||
|
|
|
@ -792,7 +792,13 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
|
|||
assert(0);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Temporarily drop write-lock taken in virtio_loop() so that
|
||||
* the queue thread doesn't block in virtio_send_msg().
|
||||
*/
|
||||
vu_dispatch_unlock(vud);
|
||||
fv_queue_cleanup_thread(vud, qidx);
|
||||
vu_dispatch_wrlock(vud);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu-version.h"
|
||||
#include "qemu-common.h"
|
||||
#include "fuse_virtio.h"
|
||||
#include "fuse_log.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
|
@ -221,22 +223,27 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st,
|
|||
static int xattr_map_client(const struct lo_data *lo, const char *client_name,
|
||||
char **out_name);
|
||||
|
||||
static int is_dot_or_dotdot(const char *name)
|
||||
static bool is_dot_or_dotdot(const char *name)
|
||||
{
|
||||
return name[0] == '.' &&
|
||||
(name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
|
||||
}
|
||||
|
||||
/* Is `path` a single path component that is not "." or ".."? */
|
||||
static int is_safe_path_component(const char *path)
|
||||
static bool is_safe_path_component(const char *path)
|
||||
{
|
||||
if (strchr(path, '/')) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !is_dot_or_dotdot(path);
|
||||
}
|
||||
|
||||
static bool is_empty(const char *name)
|
||||
{
|
||||
return name[0] == '\0';
|
||||
}
|
||||
|
||||
static struct lo_data *lo_data(fuse_req_t req)
|
||||
{
|
||||
return (struct lo_data *)fuse_req_userdata(req);
|
||||
|
@ -1083,6 +1090,11 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
|||
fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n", parent,
|
||||
name);
|
||||
|
||||
if (is_empty(name)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't use is_safe_path_component(), allow "." and ".." for NFS export
|
||||
* support.
|
||||
|
@ -1174,6 +1186,11 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
|
|||
struct fuse_entry_param e;
|
||||
struct lo_cred old = {};
|
||||
|
||||
if (is_empty(name)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_safe_path_component(name)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
|
@ -1246,6 +1263,11 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
|
|||
char procname[64];
|
||||
int saverr;
|
||||
|
||||
if (is_empty(name)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_safe_path_component(name)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
|
@ -1308,8 +1330,7 @@ static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
res = do_statx(lo, dir->fd, name, &attr,
|
||||
AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, &mnt_id);
|
||||
res = do_statx(lo, dir->fd, name, &attr, AT_SYMLINK_NOFOLLOW, &mnt_id);
|
||||
lo_inode_put(lo, &dir);
|
||||
if (res == -1) {
|
||||
return NULL;
|
||||
|
@ -1324,6 +1345,11 @@ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
|
|||
struct lo_inode *inode;
|
||||
struct lo_data *lo = lo_data(req);
|
||||
|
||||
if (is_empty(name)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_safe_path_component(name)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
|
@ -1353,6 +1379,11 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||
struct lo_inode *newinode = NULL;
|
||||
struct lo_data *lo = lo_data(req);
|
||||
|
||||
if (is_empty(name) || is_empty(newname)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_safe_path_component(name) || !is_safe_path_component(newname)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
|
@ -1406,6 +1437,11 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
|
|||
struct lo_inode *inode;
|
||||
struct lo_data *lo = lo_data(req);
|
||||
|
||||
if (is_empty(name)) {
|
||||
fuse_reply_err(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_safe_path_component(name)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
|
@ -3666,6 +3702,11 @@ static void fuse_lo_data_cleanup(struct lo_data *lo)
|
|||
free(lo->source);
|
||||
}
|
||||
|
||||
static void qemu_version(void)
|
||||
{
|
||||
printf("virtiofsd version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
|
@ -3737,6 +3778,7 @@ int main(int argc, char *argv[])
|
|||
ret = 0;
|
||||
goto err_out1;
|
||||
} else if (opts.show_version) {
|
||||
qemu_version();
|
||||
fuse_lowlevel_version();
|
||||
ret = 0;
|
||||
goto err_out1;
|
||||
|
|
Loading…
Reference in a new issue