|
@@ -79,6 +79,30 @@ int qemu_file_shutdown(QEMUFile *f)
|
|
|
int ret = 0;
|
|
|
|
|
|
f->shutdown = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We must set qemufile error before the real shutdown(), otherwise
|
|
|
+ * there can be a race window where we thought IO all went though
|
|
|
+ * (because last_error==NULL) but actually IO has already stopped.
|
|
|
+ *
|
|
|
+ * If without correct ordering, the race can happen like this:
|
|
|
+ *
|
|
|
+ * page receiver other thread
|
|
|
+ * ------------- ------------
|
|
|
+ * qemu_get_buffer()
|
|
|
+ * do shutdown()
|
|
|
+ * returns 0 (buffer all zero)
|
|
|
+ * (we didn't check this retcode)
|
|
|
+ * try to detect IO error
|
|
|
+ * last_error==NULL, IO okay
|
|
|
+ * install ALL-ZERO page
|
|
|
+ * set last_error
|
|
|
+ * --> guest crash!
|
|
|
+ */
|
|
|
+ if (!f->last_error) {
|
|
|
+ qemu_file_set_error(f, -EIO);
|
|
|
+ }
|
|
|
+
|
|
|
if (!qio_channel_has_feature(f->ioc,
|
|
|
QIO_CHANNEL_FEATURE_SHUTDOWN)) {
|
|
|
return -ENOSYS;
|
|
@@ -88,9 +112,6 @@ int qemu_file_shutdown(QEMUFile *f)
|
|
|
ret = -EIO;
|
|
|
}
|
|
|
|
|
|
- if (!f->last_error) {
|
|
|
- qemu_file_set_error(f, -EIO);
|
|
|
- }
|
|
|
return ret;
|
|
|
}
|
|
|
|