Am 23.01.2013 12:43, schrieb Kevin Wolf:
> Am 22.01.2013 15:14, schrieb Kevin Wolf:
>> The series of requests to get into this state is somewhat tricky as it
>> requires a specific physical ordering of clusters in the image file:
>>
>> Host cluster h:     Guest cluster g is mapped to here
>> Host cluster h + 1: Free, can be allocated for not yet mapped g + 1
>> Host cluster h + 2: Guest cluster g + 2 is mapped to here
>>
>> I can get this with this command on a fresh qcow2 image (64k cluster size):
>>
>> ./qemu-io
>>   -c 'write -P 0x66 0 64k'
>>   -c 'write 64k 64k'
>>   -c 'write -P 0x88 128k 64k'
>>   -c 'discard 64k 64k'
>>   -c 'write -P 0x77 0 160k'
>>   /tmp/test.qcow2
>>
>> Now I get an additional COW for the area from 96k to 128k. However, this
>> alone doesn't corrupt an image - a copy on write by itself is harmless
>> because it only rewrites the data that is already there.
>>
>> The two things I'm going to check next are:
>>
>> a) What happens with concurrent requests now, are requests for the
>>    same area still correctly serialised?
>>
>> b) Can I modify the parameters so that copy_sectors() is working
>>    with values it wasn't designed for so that the data is copied to
>>    a wrong place or something like that. m->nb_available is used as
>>    an argument to it, so it certainly seems realistic.
> 
> I can reliably reproduce a bug with a) at least. It requires some
> backports to qemu-io in order to get more control of the timing of AIO
> requests, but then it works like this:
> 
> write -P 0x66 0 320k
> write 320k 128k
> write -P 0x88 448k 128k
> discard 320k 128k
> aio_flush
> 
> break cow_write A
> aio_write -P 0x77 0 480k
> wait_break A
> write -P 0x99 480k 32k
> resume A
> aio_flush
> 
> read -P 0x77 0 480k
> read -P 0x99 480k 32k
> read -P 0x88 512k 64k
> 
> What happens is that the write of 0x99 to 480k doesn't detect an overlap
> with the running AIO request (because obviously it doesn't overlap), but
> the COW is actually taking place in the wrong cluster and therefore
> unprotected. Stop the AIO request between the COW read and the COW write
> to write 0x99 to that area, and the wrong COW will overwrite it, i.e.
> corrupt the image.
> 
> Basing a real test case on this is not trivial, though, because I have
> to stop on the blkdebug event cow_write - which obviously isn't even
> emitted in the fixed version.
> 
> I still have to look into option b)

This is the reproducer using b):

write -P 0x66 0 320k
write 320k 128k
write -P 0x55 1M 128k
write -P 0x88 448k 128k
discard 320k 128k
aio_flush

write -P 0x77 0 480k
aio_flush

read -P 0x77 0 480k
read -P 0x88 480k 96k
read -P 0x55 1M 128k

Not sure if a stable branch for 1.1 is still maintained, but I'm copying
qemu-stable just in case. Commit b7ab0fea actually fixes a qcow2 data
corruption issue (even though under rare circumstances) and should
definitely be cherry-picked for any new 1.1.x release.

qemu 1.0 and older don't have the bug.

Kevin

Reply via email to