qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 02/10] qcow2: add qcow2_co_write_compressed


From: Stefan Hajnoczi
Subject: Re: [Qemu-devel] [PATCH 02/10] qcow2: add qcow2_co_write_compressed
Date: Wed, 1 Jun 2016 13:06:11 -0700
User-agent: Mutt/1.6.1 (2016-04-27)

On Wed, Jun 01, 2016 at 11:25:57AM +0200, Kevin Wolf wrote:
> Am 27.05.2016 um 19:33 hat Stefan Hajnoczi geschrieben:
> > On Sat, May 14, 2016 at 03:45:50PM +0300, Denis V. Lunev wrote:
> > > +    qemu_co_mutex_lock(&s->lock);
> > > +    cluster_offset = \
> > > +        qcow2_alloc_compressed_cluster_offset(bs, sector_num << 9, 
> > > out_len);
> > 
> > The backslash isn't necessary for wrapping lines in C.  This kind of
> > thing is only necessary in languages like Python where the grammar is
> > whitespace sensistive.
> > 
> > The C compiler is happy with an arbitrary amount of whitespace
> > (newlines) in the middle of a statement.  The backslash in C is handled
> > by the preprocessor: it joins the line.  That's useful for macro
> > definitions where you need to tell the preprocessor that several lines
> > belong to one macro definition.  But it's not needed for normal C code.
> > 
> > > +    if (!cluster_offset) {
> > > +        qemu_co_mutex_unlock(&s->lock);
> > > +        ret = -EIO;
> > > +        goto fail;
> > > +    }
> > > +    cluster_offset &= s->cluster_offset_mask;
> > >  
> > > -        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
> > > -        ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, 
> > > out_len);
> > > -        if (ret < 0) {
> > > -            goto fail;
> > > -        }
> > > +    ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
> > > +    qemu_co_mutex_unlock(&s->lock);
> > > +    if (ret < 0) {
> > > +        goto fail;
> > >      }
> > >  
> > > +    iov = (struct iovec) {
> > > +        .iov_base   = out_buf,
> > > +        .iov_len    = out_len,
> > > +    };
> > > +    qemu_iovec_init_external(&hd_qiov, &iov, 1);
> > > +
> > > +    BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
> > > +    ret = bdrv_co_pwritev(bs->file->bs, cluster_offset, out_len, 
> > > &hd_qiov, 0);
> > 
> > There is a race condition here:
> > 
> > If the newly allocated cluster is only partially filled by compressed
> > data then qcow2_alloc_compressed_cluster_offset() remembers that more
> > bytes are still available in the cluster.  The
> > qcow2_alloc_compressed_cluster_offset() caller will continue filling the
> > same cluster.
> > 
> > Imagine two compressed writes running at the same time.  Write A
> > allocates just a few bytes so write B shares a sector with the first
> > write:
> > 
> >      Sector 1
> >   |AAABBBBBBBBB|
> > 
> > The race condition is that bdrv_co_pwritev() uses read-modify-write (a
> > bounce buffer).  If both requests call bdrv_co_pwritev() around the same
> > time then the following could happen:
> > 
> >      Sector 1
> >   |000BBBBBBBBB|
> > 
> > or:
> > 
> >      Sector 1
> >   |AAA000000000|
> > 
> > It's necessary to hold s->lock around the compressed data write to avoid
> > this race condition.
> 
> I don't think this race condition exists. bdrv_co_pwritev() can indeed
> perform RMW if the lower layer requires alignment, but that's not
> something callers need to care about (which would be an awful API) but
> is fully handled there by marking requests serialising if they involve
> RMW.

Good point.

Stefan

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]