* [Qemu-devel] [PATCH] hw/block/nand: Fix bad offset in nand_blk_load for on-drive OOB
@ 2018-04-23 21:14 Karl Beldan
2018-04-23 22:14 ` Eric Blake
0 siblings, 1 reply; 3+ messages in thread
From: Karl Beldan @ 2018-04-23 21:14 UTC (permalink / raw)
To: Kevin Wolf, Max Reitz; +Cc: qemu-block, qemu-devel, Eric Blake
The logic wants 512-byte aligned blk ops.
To switch to byte-based block accesses, the fixed commit changed the
blk read offset,
PAGE_START(addr) >> 9
with
PAGE_START(addr)
which min alignment, for on-drive OOB, is the min OOB size.
Consequently the reads are offset by PAGE_START(addr) & 0x1ff.
Fixes: 9fc0d361cc41 ("nand: Switch to byte-based block access")
Cc: Eric Blake <eblake@redhat.com>
Signed-off-by: Karl Beldan <karl.beldan+oss@gmail.com>
---
hw/block/nand.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/block/nand.c b/hw/block/nand.c
index 919cb9b803..ed587f60f0 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -788,7 +788,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
OOB_SIZE);
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
} else {
- if (blk_pread(s->blk, PAGE_START(addr), s->io,
+ if (blk_pread(s->blk, PAGE_START(addr) & ~0x1ff, s->io,
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, PAGE_START(addr) >> 9);
--
2.16.1.72.g5be1f00
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [Qemu-devel] [PATCH] hw/block/nand: Fix bad offset in nand_blk_load for on-drive OOB 2018-04-23 21:14 [Qemu-devel] [PATCH] hw/block/nand: Fix bad offset in nand_blk_load for on-drive OOB Karl Beldan @ 2018-04-23 22:14 ` Eric Blake 2018-04-23 23:03 ` Karl Beldan 0 siblings, 1 reply; 3+ messages in thread From: Eric Blake @ 2018-04-23 22:14 UTC (permalink / raw) To: Karl Beldan, Kevin Wolf, Max Reitz; +Cc: qemu-block, qemu-devel, qemu-stable [-- Attachment #1: Type: text/plain, Size: 3980 bytes --] On 04/23/2018 04:14 PM, Karl Beldan wrote: > The logic wants 512-byte aligned blk ops. The commit you are referencing mentions that the code permits 256, 512, or 2048-byte alignment, based on the configuration of the hardware it is emulating. The whole file is hard to read, and I'm not surprised if what I thought was a patch with no semantic change didn't quite succeed. > To switch to byte-based block accesses, the fixed commit changed the > blk read offset, > PAGE_START(addr) >> 9 > with > PAGE_START(addr) > which min alignment, for on-drive OOB, is the min OOB size. > Consequently the reads are offset by PAGE_START(addr) & 0x1ff. Do you have a call trace where a caller is passing in an addr that is not aligned to 512? I agree that the old code was 512-aligned by virtue of the old interface; but the new code SHOULD be able to call into the block layer with whatever alignment it needs, where the block layer will do a larger read to satisfy block constraints, as needed (that is, if a caller requests a 256-byte read of a device that requires 512-alignment, blk_pread() will automatically widen out to a 512-byte read). > > Fixes: 9fc0d361cc41 ("nand: Switch to byte-based block access") > Cc: Eric Blake <eblake@redhat.com> > Signed-off-by: Karl Beldan <karl.beldan+oss@gmail.com> CC: qemu-stable@nongnu.org > --- > hw/block/nand.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/hw/block/nand.c b/hw/block/nand.c > index 919cb9b803..ed587f60f0 100644 > --- a/hw/block/nand.c > +++ b/hw/block/nand.c > @@ -788,7 +788,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, > OOB_SIZE); > s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; > } else { > - if (blk_pread(s->blk, PAGE_START(addr), s->io, > + if (blk_pread(s->blk, PAGE_START(addr) & ~0x1ff, s->io, > (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { I don't like the magic number masking. This should probably be written QEMU_ALIGN_DOWN(PAGE_START(addr), BDRV_SECTOR_SIZE). I would like to see some actual numbers from a backtrace to make sure we're doing this right, but my initial evaluation is done by assuming, for the sake of argument, that we're using a 256-byte page size (as that is most likely to be unaligned to a 512-byte boundary). I see that we can call into nand_blk_load_256() during processing of NAND_CMD_RANDOMREAD2 from nand_command(), although it gets harder to audit without an actual call trace whether addr and offset have 512-byte alignments at that point. But without analysis of whether this is an actual possibility, let's assume we can somehow trigger a code path that calls nand_blk_load_256(s, 768, 1). Before 9fc0d361cc41, this called: if (blk_read(s->blk, PAGE_START(addr) >> 9, s->io, (PAGE_SECTORS + 2)) < 0) { or, tracing macro-expansion blk_read(s->blk, (PAGE(addr) * (PAGE_SIZE + OOB_SIZE)) >> 9, s->io, (1 + 2)) blk_read(s->blk, (((addr) >> 8) * (256 + (1 << (PAGE_SHIFT - 5)))) >> 9, s->io, (1 + 2)) blk_read(s->blk, (((addr) >> 8) * (256 + 8)) >> 9, s->io, 3) which, for our given addr of 768, results in blk_read(s->blk, 792 >> 9, s->io, 3) or the 1536 bytes starting at offset 512 (which includes offset 792 that we are interested in). And indeed, post-patch, it now results in trying to read 1536 bytes, but starting at offset 792 rather than offset 512. So it looks like the fix is correct, once it is spelled in a more obvious way rather than with a magic number, and that the fact that this has been broken since 2.7 means that this device is not getting much actual testing :( -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 619 bytes --] ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [PATCH] hw/block/nand: Fix bad offset in nand_blk_load for on-drive OOB 2018-04-23 22:14 ` Eric Blake @ 2018-04-23 23:03 ` Karl Beldan 0 siblings, 0 replies; 3+ messages in thread From: Karl Beldan @ 2018-04-23 23:03 UTC (permalink / raw) To: Eric Blake; +Cc: Kevin Wolf, Max Reitz, qemu-block, qemu-devel, qemu-stable On Mon, Apr 23, 2018 at 05:14:03PM -0500, Eric Blake wrote: > On 04/23/2018 04:14 PM, Karl Beldan wrote: > > The logic wants 512-byte aligned blk ops. > > The commit you are referencing mentions that the code permits 256, 512, > or 2048-byte alignment, based on the configuration of the hardware it is > emulating. The whole file is hard to read, and I'm not surprised if > what I thought was a patch with no semantic change didn't quite succeed. > > > To switch to byte-based block accesses, the fixed commit changed the > > blk read offset, > > PAGE_START(addr) >> 9 > > with > > PAGE_START(addr) > > which min alignment, for on-drive OOB, is the min OOB size. > > Consequently the reads are offset by PAGE_START(addr) & 0x1ff. > > Do you have a call trace where a caller is passing in an addr that is > not aligned to 512? I agree that the old code was 512-aligned by virtue PAGE(addr) is ((addr) >> ADDR_SHIFT) PAGE_START(page) is (PAGE(page) * (PAGE_SIZE + OOB_SIZE)) Take the 2nd page, i.e page 1. > of the old interface; but the new code SHOULD be able to call into the > block layer with whatever alignment it needs, where the block layer will > do a larger read to satisfy block constraints, as needed (that is, if a > caller requests a 256-byte read of a device that requires 512-alignment, > blk_pread() will automatically widen out to a 512-byte read). > Indeed the block layer handles said alignements, but then you'd have to not add the offset twice. Keeping the logic homogenous seemed natural. > > > > Fixes: 9fc0d361cc41 ("nand: Switch to byte-based block access") > > Cc: Eric Blake <eblake@redhat.com> > > Signed-off-by: Karl Beldan <karl.beldan+oss@gmail.com> > > CC: qemu-stable@nongnu.org > > > --- > > hw/block/nand.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/hw/block/nand.c b/hw/block/nand.c > > index 919cb9b803..ed587f60f0 100644 > > --- a/hw/block/nand.c > > +++ b/hw/block/nand.c > > @@ -788,7 +788,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, > > OOB_SIZE); > > s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; > > } else { > > - if (blk_pread(s->blk, PAGE_START(addr), s->io, > > + if (blk_pread(s->blk, PAGE_START(addr) & ~0x1ff, s->io, > > (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { > > I don't like the magic number masking. This should probably be written > QEMU_ALIGN_DOWN(PAGE_START(addr), BDRV_SECTOR_SIZE). > There are many other occurences in this file of said "magic" number. In general or for ulterior "rework" of the driver everybody would agree on this , however doing that for _this_ fix would convey another intent as some other places in the code where this sector size mask is used, which isn't the case, so I'd very much keep it homogenous/coherent. > I would like to see some actual numbers from a backtrace to make sure > we're doing this right, but my initial evaluation is done by assuming, > for the sake of argument, that we're using a 256-byte page size (as that > is most likely to be unaligned to a 512-byte boundary). I see that we > can call into nand_blk_load_256() during processing of > NAND_CMD_RANDOMREAD2 from nand_command(), although it gets harder to > audit without an actual call trace whether addr and offset have 512-byte > alignments at that point. But without analysis of whether this is an > actual possibility, let's assume we can somehow trigger a code path that > calls nand_blk_load_256(s, 768, 1). > > Before 9fc0d361cc41, this called: > > if (blk_read(s->blk, PAGE_START(addr) >> 9, > s->io, (PAGE_SECTORS + 2)) < 0) { > > or, tracing macro-expansion > > blk_read(s->blk, (PAGE(addr) * (PAGE_SIZE + OOB_SIZE)) >> 9, > s->io, (1 + 2)) > > blk_read(s->blk, (((addr) >> 8) * (256 + (1 << (PAGE_SHIFT - 5)))) >> 9, > s->io, (1 + 2)) > > blk_read(s->blk, (((addr) >> 8) * (256 + 8)) >> 9, > s->io, 3) > > > which, for our given addr of 768, results in > blk_read(s->blk, 792 >> 9, s->io, 3) > > or the 1536 bytes starting at offset 512 (which includes offset 792 that > we are interested in). > > And indeed, post-patch, it now results in trying to read 1536 bytes, but > starting at offset 792 rather than offset 512. > > So it looks like the fix is correct, once it is spelled in a more > obvious way rather than with a magic number, and that the fact that this > has been broken since 2.7 means that this device is not getting much > actual testing :( > Still on my initial remark wrt magic. The pitfall becomes apparent very quickly, but only happens for on-disk OOB, and Linux/nandsim is a hard contender. Regards, Karl ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-04-23 23:03 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-04-23 21:14 [Qemu-devel] [PATCH] hw/block/nand: Fix bad offset in nand_blk_load for on-drive OOB Karl Beldan 2018-04-23 22:14 ` Eric Blake 2018-04-23 23:03 ` Karl Beldan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).