From: Jason Baron <jbaron@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: aliguori@us.ibm.com, armbru@redhat.com, agraf@suse.de,
qemu-devel@nongnu.org, alex.williamson@redhat.com,
avi@redhat.com, pbonzini@redhat.com
Subject: Re: [Qemu-devel] [PATCH 1/2] ahci: Fix ahci cdrom read corruptions for reads > 128k
Date: Fri, 27 Jul 2012 10:50:34 -0400 [thread overview]
Message-ID: <20120727145034.GB11480@redhat.com> (raw)
In-Reply-To: <50124A45.6000405@redhat.com>
On Fri, Jul 27, 2012 at 09:59:01AM +0200, Kevin Wolf wrote:
> Am 26.07.2012 21:40, schrieb Jason Baron:
> > While testing q35, which has its cdrom attached to the ahci controller, I found
> > that the Fedora 17 install would panic on boot. The panic occurs while
> > squashfs is trying to read from the cdrom. The errors are:
> >
> > [ 8.622711] SQUASHFS error: xz_dec_run error, data probably corrupt
> > [ 8.625180] SQUASHFS error: squashfs_read_data failed to read block
> > 0x20be48a
> >
> > I was also able to produce corrupt data reads using an installed piix based
> > qemu machine, using 'dd'. I found that the corruptions were only occuring when
> > the read size was greater than 128k. For example, the following command
> > results in corrupted reads:
> >
> > dd if=/dev/sr0 of=/tmp/blah bs=256k iflag=direct
> >
> > The > 128k size reads exercise a different code path than 128k and below. In
> > ide_atapi_cmd_read_dma_cb() s->io_buffer_size is capped at 128k. Thus,
> > ide_atapi_cmd_read_dma_cb() is called a second time when the read is > 128k.
> > However, ahci_dma_rw_buf() restart the read from offset 0, instead of at 128k.
> > Thus, resulting in a corrupted read.
> >
> > To fix this, I've introduced 'io_buffer_offset' field in IDEState to keep
> > track of the offset. I've also modified ahci_populate_sglist() to take a new
> > 3rd offset argument, so that the sglist is property initialized.
> >
> > I've tested this patch using 'dd' testing, and Fedora 17 now correctly boots
> > and installs on q35 with the cdrom ahci controller.
> >
> > Signed-off-by: Jason Baron <jbaron@redhat.com>
> > ---
> > hw/ide/ahci.c | 41 ++++++++++++++++++++++++++++++++++-------
> > hw/ide/internal.h | 1 +
> > 2 files changed, 35 insertions(+), 7 deletions(-)
> >
> > diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
> > index efea93f..9c95714 100644
> > --- a/hw/ide/ahci.c
> > +++ b/hw/ide/ahci.c
> > @@ -636,7 +636,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
> > }
> > }
> >
> > -static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
> > +static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
> > {
> > AHCICmdHdr *cmd = ad->cur_cmd;
> > uint32_t opts = le32_to_cpu(cmd->opts);
> > @@ -647,6 +647,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
> > uint8_t *prdt;
> > int i;
> > int r = 0;
> > + int sum = 0;
> > + int off_idx = -1;
> > + int off_pos = 0;
> > + int tbl_entry_size;
> >
> > if (!sglist_alloc_hint) {
> > DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
> > @@ -669,10 +673,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
> > /* Get entries in the PRDT, init a qemu sglist accordingly */
> > if (sglist_alloc_hint > 0) {
> > AHCI_SG *tbl = (AHCI_SG *)prdt;
> > -
> > - qemu_sglist_init(sglist, sglist_alloc_hint, ad->hba->dma);
> > + sum = 0;
> > for (i = 0; i < sglist_alloc_hint; i++) {
> > /* flags_size is zero-based */
> > + tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
> > + if (offset <= (sum + tbl_entry_size)) {
> > + off_idx = i;
> > + off_pos = offset - sum;
> > + break;
> > + }
> > + sum += tbl_entry_size;
> > + }
> > + if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
> > + fprintf(stderr, "%s: Incorrect offset! "
> > + "off_idx: %d, off_pos: %d\n",
> > + __func__, off_idx, off_pos);
>
> I would use DPRINTF here, it's not a good idea to allow the guest to
> trigger fprintfs.
>
ok.
I'm also wondering if we need to 0 s->io_buffer_offset in more places
than 'ahci_start_dma()'. For example, do we need it in ahci_dma_reset(),
or ahci_dma_prepare_buf()? hw/ide/pci.c seems to do that.
I didn't include those places in my original patch, because I saw that
start_dma was always called before rw_buf. But perhaps, there is another
codepath that I missed.
Thanks,
-Jason
next prev parent reply other threads:[~2012-07-27 14:50 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-26 19:40 [Qemu-devel] [PATCH 0/2] ahci: fix cdrom read corruption Jason Baron
2012-07-26 19:40 ` [Qemu-devel] [PATCH 1/2] ahci: Fix ahci cdrom read corruptions for reads > 128k Jason Baron
2012-07-27 7:59 ` Kevin Wolf
2012-07-27 14:50 ` Jason Baron [this message]
2012-07-27 11:28 ` Andreas Färber
2012-07-26 19:40 ` [Qemu-devel] [PATCH 2/2] ahci: Fix sglist memleak in ahci_dma_rw_buf() Jason Baron
2012-07-27 7:16 ` Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120727145034.GB11480@redhat.com \
--to=jbaron@redhat.com \
--cc=agraf@suse.de \
--cc=alex.williamson@redhat.com \
--cc=aliguori@us.ibm.com \
--cc=armbru@redhat.com \
--cc=avi@redhat.com \
--cc=kwolf@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.