Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 382

kvm-83-270.el5_11.src.rpm

From 520c1bed649362c7e4b86c4d61888a67193c06e8 Mon Sep 17 00:00:00 2001
From: Alex Williamson <alex.williamson@redhat.com>
Date: Thu, 7 Apr 2011 16:38:44 -0300
Subject: [PATCH 3/3] ide: Optionally include pio inflight data in savevm

RH-Author: Alex Williamson <alex.williamson@redhat.com>
Message-id: <20110407163844.5885.88120.stgit@localhost6.localdomain6>
Patchwork-id: 21643
O-Subject: [RHEL5.7 kvm PATCH 2/2] ide: Optionally include pio inflight data in
	savevm
Bugzilla: 666225
RH-Acked-by: Juan Quintela <quintela@redhat.com>
RH-Acked-by: Avi Kivity <avi@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=666225
Brew build: https://brewweb.devel.redhat.com/taskinfo?taskID=3240237
Upstream commit: N/A (based on 50641c5c)

Use the register_optional_savevm() interface as a substitute for upstream
subsections.  This will allow us to maintain migration compatibility in
the normal case.  We'll include another savevm section with the inflight
information only if it's needed.  This will intentionally cause new->old
migration to fail when the data is there.  We also order the savevms
with the pio data first so we can add a test in the main load function
to determine if inflight data should have been included, but isn't.  This
lets us intentionally cause old->new migrations to fail if we can't
ensure integrity of the current operation.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

 qemu/hw/ide.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 111 insertions(+), 3 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 qemu/hw/ide.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/qemu/hw/ide.c b/qemu/hw/ide.c
index f96db2d..bf8f4cb 100644
--- a/qemu/hw/ide.c
+++ b/qemu/hw/ide.c
@@ -440,6 +440,7 @@ typedef struct IDEState {
     uint32_t mdata_size;
     uint8_t *mdata_storage;
     int media_changed;
+    uint8_t inflight_pio_loaded:1;
 } IDEState;
 
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
@@ -2868,7 +2869,6 @@ static void ide_save(QEMUFile* f, IDEState *s, int version_id)
 
     qemu_put_8s(f, &s->sense_key);
     qemu_put_8s(f, &s->asc);
-    /* XXX: if a transfer is pending, we do not save it yet */
     if (version_id > 3) {
 	uint8_t write_cache = 0;
 	if (s->bs) {
@@ -2880,7 +2880,7 @@ static void ide_save(QEMUFile* f, IDEState *s, int version_id)
 }
 
 /* load per IDE drive data */
-static void ide_load(QEMUFile* f, IDEState *s, int version_id)
+static int ide_load(QEMUFile* f, IDEState *s, int version_id)
 {
     uint8_t write_cache = 0;
 
@@ -2906,13 +2906,19 @@ static void ide_load(QEMUFile* f, IDEState *s, int version_id)
 
     qemu_get_8s(f, &s->sense_key);
     qemu_get_8s(f, &s->asc);
-    /* XXX: if a transfer is pending, we do not save it yet */
     if (version_id > 3) {
         qemu_get_8s(f, &write_cache);
     }
     if (s->bs) {
         s->bs->enable_write_cache = write_cache;
     }
+
+    if ((s->status & DRQ_STAT) && !s->inflight_pio_loaded) {
+        fprintf(stderr, "IDE status reports inflight pio, but no pio section included in data stream.  Rejecting migration.\n");
+        return -EINVAL;
+    }
+    s->inflight_pio_loaded = 0;
+    return 0;
 }
 
 /***********************************************************/
@@ -3296,6 +3302,101 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id)
     return 0;
 }
 
+static EndTransferFunc* transfer_end_table[] = {
+        ide_sector_read,
+        ide_sector_write,
+        ide_transfer_stop,
+        ide_atapi_cmd_reply_end,
+        ide_atapi_cmd,
+        ide_dummy_transfer_stop,
+};
+
+static void pci_ide_pio_save(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+        uint8_t idx;
+
+        qemu_put_8s(f, &s->status);
+        if (!(s->status & DRQ_STAT)) {
+            continue;
+        }
+
+        qemu_put_sbe32s(f, &s->req_nb_sectors);
+        qemu_put_buffer(f, s->io_buffer, IDE_DMA_BUF_SECTORS*512 + 4);
+        qemu_put_sbe32(f, s->data_ptr - s->io_buffer);
+        qemu_put_sbe32(f, s->data_end - s->data_ptr);
+
+        for (idx = 0; idx < ARRAY_SIZE(transfer_end_table); idx++) {
+            if (transfer_end_table[idx] == s->end_transfer_func) {
+                break;
+            }
+        }
+
+        if (idx >= ARRAY_SIZE(transfer_end_table)) {
+            fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
+                            __func__);
+            idx = 2;
+        }
+
+        qemu_put_8s(f, &idx);
+        qemu_put_sbe32s(f, &s->elementary_transfer_size);
+        qemu_put_sbe32s(f, &s->packet_transfer_size);
+    }
+}
+
+static int pci_ide_pio_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+        int io_buffer_offset, io_buffer_len;
+        uint8_t status, idx;
+
+        qemu_get_8s(f, &status);
+        if (!(status & DRQ_STAT)) {
+            continue;
+        }
+
+        qemu_get_sbe32s(f, &s->req_nb_sectors);
+        qemu_get_buffer(f, s->io_buffer, IDE_DMA_BUF_SECTORS*512 + 4);
+        qemu_get_sbe32s(f, &io_buffer_offset);
+        qemu_get_sbe32s(f, &io_buffer_len);
+        qemu_get_8s(f, &idx);
+        qemu_get_sbe32s(f, &s->elementary_transfer_size);
+        qemu_get_sbe32s(f, &s->packet_transfer_size);
+
+        if (idx >= ARRAY_SIZE(transfer_end_table)) {
+            return -EINVAL;
+        }
+
+        s->end_transfer_func = transfer_end_table[idx];
+        s->data_ptr = s->io_buffer + io_buffer_offset;
+        s->data_end = s->data_ptr + io_buffer_len;
+        s->inflight_pio_loaded = 1;
+    }
+    return 0;
+}
+
+static int pci_ide_pio_needed(void *opaque)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+        if (s->status & DRQ_STAT) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
 /* XXX: call it also when the MRDMODE is changed from the PCI config
    registers */
 static void cmd646_update_irq(PCIIDEState *d)
@@ -3456,6 +3557,13 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
             }
         }
     }
+
+    /* Register the optional pio state first so that the main savevm
+     * function can detect if it's been processed and reject migrations
+     * where it should be required, but isn't included.  This prevents
+     * old->new migrations where we could lose inflight pio. */
+    register_optional_savevm("ide/pio_state", 0, 1, pci_ide_pio_save,
+                             pci_ide_pio_load, pci_ide_pio_needed, d);
     register_savevm("ide", 0, version_id, pci_ide_save, pci_ide_load, d);
 }
 
-- 
1.7.3.2