From: Peter Wu <peter@lekensteyn.nl>
To: John Snow <jsnow@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
qemu-devel@nongnu.org, Stefan Hajnoczi <stefanha@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 10/10] block/dmg: improve zeroes handling
Date: Tue, 06 Jan 2015 01:21:39 +0100 [thread overview]
Message-ID: <6669944.WW8izJTkuB@al> (raw)
In-Reply-To: <54AAEA73.30904@redhat.com>
On Monday 05 January 2015 14:48:03 John Snow wrote:
> On 12/27/2014 10:01 AM, Peter Wu wrote:
> > Disk images may contain large all-zeroes gaps (1.66k sectors or 812 MiB
> > is seen in the real world). These blocks (type 2) do not need to be
> > extracted into a temporary buffer, there is no need to allocate memory
> > for these blocks nor to check its length.
> >
> > (For the test image, the maximum uncompressed size is 1054371 bytes,
> > probably for a bzip2-compressed block.)
> >
> > Signed-off-by: Peter Wu <peter@lekensteyn.nl>
> > ---
> > block/dmg.c | 18 +++++++++++++-----
> > 1 file changed, 13 insertions(+), 5 deletions(-)
> >
> > diff --git a/block/dmg.c b/block/dmg.c
> > index 67d4e2b..b84ba7e 100644
> > --- a/block/dmg.c
> > +++ b/block/dmg.c
> > @@ -137,7 +137,9 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
> > uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
> > break;
> > case 2: /* zero */
> > - uncompressed_sectors = s->sectorcounts[chunk];
> > + /* as the all-zeroes block may be large, it is treated specially: the
> > + * sector is not copied from a large buffer, a simple memset is used
> > + * instead. Therefore uncompressed_sectors does not need to be set. */
> > break;
> > }
> >
> > @@ -260,7 +262,9 @@ static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds,
> > s->sectorcounts[i] = buff_read_uint64(buffer, offset);
> > offset += 8;
> >
> > - if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
> > + /* all-zeroes sector (type 2) does not need to be "uncompressed" and can
> > + * therefore be unbounded. */
> > + if (s->types[i] != 2 && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
> > error_report("sector count %" PRIu64 " for chunk %" PRIu32
> > " is larger than max (%u)",
> > s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
> > @@ -621,9 +625,6 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
> > return -1;
> > }
> > break;
> > - case 2: /* zero */
> > - memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]);
> > - break;
>
> This is just a personal preference, but I might actually prefer a little
> comment here that guards against anyone helpfully re-adding this case
> statement again in the future, if you really want to split it out.
Ok, makes sense. I'll add an appropriate comment here.
> > }
> > s->current_chunk = chunk;
> > }
> > @@ -641,6 +642,13 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
> > if (dmg_read_chunk(bs, sector_num + i) != 0) {
> > return -1;
> > }
> > + /* Special case: current chunk is all zeroes. Do not perform a memcpy as
> > + * s->uncompressed_chunk may be too small to cover the large all-zeroes
> > + * section. */
> > + if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */
> > + memset(buf + i * 512, 0, 512);
> > + continue;
> > + }
>
> Why even call dmg_read_chunk first if we just ignore it? You can
> probably move this special case forward and only do the dmg_read_chunk
> if it fails.
dmg_read_chunk is needed to find the current sector (which requires a
binary search if the sector is not within the current chunk). I have
updated the comments to clarify this.
> Or maybe we can keep this from becoming too fragmented by giving the
> read_chunk function access to the destination buffer somehow (parameter,
> structure member) and keeping all the logic for re-inflating the chunks
> together at the same layer.
dmg_read_chunk could be modified to return a pointer inside
s->uncompressed_chunk (adjusted to the sector number), but this just
moves the special case inside dmg_read_chunk. Alternatively, the whole
memcpy/memset stuff could be moved into dmg_read_chunk, but then the
function could be renamed to dmg_read_into_sector.
I treat dmg_read_chunk as a function which reads the current chunk (if
not already read), and returns the cached chunk otherwise. Then the
caller can decide on the part of the chunk it is interested in. As the
zero chunk does not really update the "current chunk contents", it'll
need special treatment.
The "continue" keyword is used while it actually means "either memset or
memcpy", this approach was chosen to avoid re-indenting the below memcpy
code.
Kind regards,
Peter
> > sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
> > memcpy(buf + i * 512,
> > s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
> >
>
> Looks good, otherwise. Thank you :)
>
> --j
next prev parent reply other threads:[~2015-01-06 0:21 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-27 15:01 [Qemu-devel] [PATCH 00/10] block/dmg: (compatibility) fixes and bzip2 support Peter Wu
2014-12-27 15:01 ` [Qemu-devel] [PATCH 01/10] block/dmg: properly detect the UDIF trailer Peter Wu
2015-01-02 23:58 ` John Snow
2015-01-03 9:39 ` Peter Wu
2015-01-06 13:35 ` Stefan Hajnoczi
2014-12-27 15:01 ` [Qemu-devel] [PATCH 02/10] block/dmg: extract mish block decoding functionality Peter Wu
2015-01-02 23:59 ` John Snow
2015-01-03 11:05 ` Peter Wu
2015-01-06 13:42 ` Stefan Hajnoczi
2014-12-27 15:01 ` [Qemu-devel] [PATCH 03/10] block/dmg: extract processing of resource forks Peter Wu
2015-01-03 0:01 ` John Snow
2015-01-03 11:24 ` Peter Wu
2014-12-27 15:01 ` [Qemu-devel] [PATCH 04/10] block/dmg: process a buffer instead of reading ints Peter Wu
2015-01-03 0:01 ` John Snow
2014-12-27 15:01 ` [Qemu-devel] [PATCH 05/10] block/dmg: validate chunk size to avoid overflow Peter Wu
2015-01-03 0:02 ` John Snow
2014-12-27 15:01 ` [Qemu-devel] [PATCH 06/10] block/dmg: process XML plists Peter Wu
2015-01-03 0:04 ` John Snow
2015-01-03 11:54 ` Peter Wu
2015-01-05 16:46 ` John Snow
2015-01-05 16:54 ` John Snow
2014-12-27 15:01 ` [Qemu-devel] [PATCH 07/10] block/dmg: set virtual size to a non-zero value Peter Wu
2015-01-03 0:04 ` John Snow
2014-12-27 15:01 ` [Qemu-devel] [PATCH 08/10] block/dmg: fix sector data offset calculation Peter Wu
2015-01-03 0:05 ` John Snow
2015-01-03 12:47 ` Peter Wu
2014-12-27 15:01 ` [Qemu-devel] [PATCH 09/10] block/dmg: support bzip2 block entry types Peter Wu
2015-01-05 19:32 ` John Snow
2015-01-07 10:29 ` Paolo Bonzini
2015-01-07 10:31 ` Peter Wu
2015-01-07 10:53 ` Paolo Bonzini
2014-12-27 15:01 ` [Qemu-devel] [PATCH 10/10] block/dmg: improve zeroes handling Peter Wu
2015-01-05 19:48 ` John Snow
2015-01-06 0:21 ` Peter Wu [this message]
2015-01-02 14:14 ` [Qemu-devel] [PATCH 00/10] block/dmg: (compatibility) fixes and bzip2 support Stefan Hajnoczi
2015-01-02 16:31 ` John Snow
2015-01-02 18:46 ` Peter Wu
2015-01-02 18:58 ` John Snow
2015-01-02 21:49 ` Peter Wu
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=6669944.WW8izJTkuB@al \
--to=peter@lekensteyn.nl \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/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 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).