提交 73a8912b 编写于 作者: L Liang Li 提交者: Amit Shah

migration: Fix multi-thread compression bug

Recently, a bug related to multiple thread compression feature for
live migration is reported. The destination side will be blocked
during live migration if there are heavy workload in host and
memory intensive workload in guest, this is most likely to happen
when there is one decompression thread.

Some parts of the decompression code are incorrect:
1. The main thread receives data from source side will enter a busy
loop to wait for a free decompression thread.
2. A lock is needed to protect the decomp_param[idx]->start, because
it is checked in the main thread and is updated in the decompression
thread.

Fix these two issues by following the code pattern for compression.
Signed-off-by: NLiang Li <liang.z.li@intel.com>
Reported-by: NDaniel P. Berrange <berrange@redhat.com>
Reviewed-by: NDaniel P. Berrange <berrange@redhat.com>
Reviewed-by: NDr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: NJuan Quintela <quintela@redhat.com>
Tested-by: NDaniel P. Berrange <berrange@redhat.com>
Signed-off-by: NLiang Li <liang.z.li@intel.com>
Message-Id: <1462433579-13691-2-git-send-email-liang.z.li@intel.com>
Signed-off-by: NAmit Shah <amit.shah@redhat.com>
上级 6dcf6668
...@@ -265,6 +265,7 @@ typedef struct CompressParam CompressParam; ...@@ -265,6 +265,7 @@ typedef struct CompressParam CompressParam;
struct DecompressParam { struct DecompressParam {
bool start; bool start;
bool done;
QemuMutex mutex; QemuMutex mutex;
QemuCond cond; QemuCond cond;
void *des; void *des;
...@@ -289,6 +290,8 @@ static bool quit_comp_thread; ...@@ -289,6 +290,8 @@ static bool quit_comp_thread;
static bool quit_decomp_thread; static bool quit_decomp_thread;
static DecompressParam *decomp_param; static DecompressParam *decomp_param;
static QemuThread *decompress_threads; static QemuThread *decompress_threads;
static QemuMutex decomp_done_lock;
static QemuCond decomp_done_cond;
static int do_compress_ram_page(CompressParam *param); static int do_compress_ram_page(CompressParam *param);
...@@ -834,6 +837,7 @@ static inline void start_compression(CompressParam *param) ...@@ -834,6 +837,7 @@ static inline void start_compression(CompressParam *param)
static inline void start_decompression(DecompressParam *param) static inline void start_decompression(DecompressParam *param)
{ {
param->done = false;
qemu_mutex_lock(&param->mutex); qemu_mutex_lock(&param->mutex);
param->start = true; param->start = true;
qemu_cond_signal(&param->cond); qemu_cond_signal(&param->cond);
...@@ -2196,19 +2200,24 @@ static void *do_data_decompress(void *opaque) ...@@ -2196,19 +2200,24 @@ static void *do_data_decompress(void *opaque)
qemu_mutex_lock(&param->mutex); qemu_mutex_lock(&param->mutex);
while (!param->start && !quit_decomp_thread) { while (!param->start && !quit_decomp_thread) {
qemu_cond_wait(&param->cond, &param->mutex); qemu_cond_wait(&param->cond, &param->mutex);
}
if (!quit_decomp_thread) {
pagesize = TARGET_PAGE_SIZE; pagesize = TARGET_PAGE_SIZE;
if (!quit_decomp_thread) { /* uncompress() will return failed in some case, especially
/* uncompress() will return failed in some case, especially * when the page is dirted when doing the compression, it's
* when the page is dirted when doing the compression, it's * not a problem because the dirty page will be retransferred
* not a problem because the dirty page will be retransferred * and uncompress() won't break the data in other pages.
* and uncompress() won't break the data in other pages. */
*/ uncompress((Bytef *)param->des, &pagesize,
uncompress((Bytef *)param->des, &pagesize, (const Bytef *)param->compbuf, param->len);
(const Bytef *)param->compbuf, param->len);
}
param->start = false;
} }
param->start = false;
qemu_mutex_unlock(&param->mutex); qemu_mutex_unlock(&param->mutex);
qemu_mutex_lock(&decomp_done_lock);
param->done = true;
qemu_cond_signal(&decomp_done_cond);
qemu_mutex_unlock(&decomp_done_lock);
} }
return NULL; return NULL;
...@@ -2222,10 +2231,13 @@ void migrate_decompress_threads_create(void) ...@@ -2222,10 +2231,13 @@ void migrate_decompress_threads_create(void)
decompress_threads = g_new0(QemuThread, thread_count); decompress_threads = g_new0(QemuThread, thread_count);
decomp_param = g_new0(DecompressParam, thread_count); decomp_param = g_new0(DecompressParam, thread_count);
quit_decomp_thread = false; quit_decomp_thread = false;
qemu_mutex_init(&decomp_done_lock);
qemu_cond_init(&decomp_done_cond);
for (i = 0; i < thread_count; i++) { for (i = 0; i < thread_count; i++) {
qemu_mutex_init(&decomp_param[i].mutex); qemu_mutex_init(&decomp_param[i].mutex);
qemu_cond_init(&decomp_param[i].cond); qemu_cond_init(&decomp_param[i].cond);
decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE)); decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE));
decomp_param[i].done = true;
qemu_thread_create(decompress_threads + i, "decompress", qemu_thread_create(decompress_threads + i, "decompress",
do_data_decompress, decomp_param + i, do_data_decompress, decomp_param + i,
QEMU_THREAD_JOINABLE); QEMU_THREAD_JOINABLE);
...@@ -2261,9 +2273,10 @@ static void decompress_data_with_multi_threads(QEMUFile *f, ...@@ -2261,9 +2273,10 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
int idx, thread_count; int idx, thread_count;
thread_count = migrate_decompress_threads(); thread_count = migrate_decompress_threads();
qemu_mutex_lock(&decomp_done_lock);
while (true) { while (true) {
for (idx = 0; idx < thread_count; idx++) { for (idx = 0; idx < thread_count; idx++) {
if (!decomp_param[idx].start) { if (decomp_param[idx].done) {
qemu_get_buffer(f, decomp_param[idx].compbuf, len); qemu_get_buffer(f, decomp_param[idx].compbuf, len);
decomp_param[idx].des = host; decomp_param[idx].des = host;
decomp_param[idx].len = len; decomp_param[idx].len = len;
...@@ -2273,8 +2286,11 @@ static void decompress_data_with_multi_threads(QEMUFile *f, ...@@ -2273,8 +2286,11 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
} }
if (idx < thread_count) { if (idx < thread_count) {
break; break;
} else {
qemu_cond_wait(&decomp_done_cond, &decomp_done_lock);
} }
} }
qemu_mutex_unlock(&decomp_done_lock);
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册