)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"2142a28be83570a05d534fe01fbe776e12f723c9","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     haixin \u003chaixin@inspur.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2020-08-10 14:44:15 +0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Optimize volume copy logic"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"   when we migration, retype or backup an volume, it need to call"},{"line_number":10,"context_line":"_transfer_data function in volume_utils.py, especially in the"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"9f560f44_8685a609","line":7,"range":{"start_line":7,"start_character":0,"end_line":7,"end_character":8},"updated":"2020-08-10 13:11:29.000000000","message":"This is a fix, not an optimization.","commit_id":"fdb6f9292a3c18a2c5c23badcca8420b83ac1e9c"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Fix volume copy logic"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"   when we migration, retype or backup an volume, it need to call"},{"line_number":10,"context_line":"_transfer_data function in volume_utils.py, especially in the"},{"line_number":11,"context_line":"RBD volume that we use a lot."},{"line_number":12,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"9f560f44_09b8b5c5","line":9,"range":{"start_line":9,"start_character":32,"end_line":9,"end_character":38},"updated":"2020-09-24 10:34:38.000000000","message":"-1: Backup for the Ceph driver doesn\u0027t use the _transfer_data method in volume_utils, it uses the method _transfer_data method in cinder/backup/drivers/ceph.py, which also has the same check of b\u0027\u0027, so this patch should also fix it there.","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"   if the volume is thin volume, and the file in the volume is sparse"},{"line_number":14,"context_line":"file, before we reached the end of src vol, if we get a chunk is all"},{"line_number":15,"context_line":"made up of \u0027\\0xx\u0027, then we no need to write the chunk to dest, just"},{"line_number":16,"context_line":"need to seek the dest, this will increase copy speed."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"and add a read retry mechanism."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"3f65232a_8e6f6fc4","line":15,"range":{"start_line":15,"start_character":11,"end_line":15,"end_character":61},"updated":"2020-10-21 10:59:37.000000000","message":"We cannot determine whether to write it to the destination based only on that. What if we are overwriting the contents of a volume (like in restore a backup to a volume) and the zeroes from the source volume are actual data that we need to have in the destination?\n\nIn that case we wouldn\u0027t be writing the right data (all those zeroes) and the destination would have whatever it had before instead.\n\nI think we could only do it this way if the destination was a thin provisioned volume, where empty chunks will return zeroes on read.\n\nTo detect sparse chunks using SCSI we would have to get the LBA status and see if it is Deallocated, Anchored, or Mapped, and for RBD I\u0027m not sure how this could be done.\n\nIn my opinion, we cannot skip chunks so easily, this requires a more complete solution.","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"}],"cinder/volume/volume_utils.py":[{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        before \u003d time.time()"},{"line_number":531,"context_line":"        data \u003d tpool.execute(src.read, min(chunk_size, remaining_length))"},{"line_number":532,"context_line":""},{"line_number":533,"context_line":"        # (haixin)If the src is sparse file, this means it may not the end of"},{"line_number":534,"context_line":"        # file when read b\u0027\u0027,we should continue to read and make sure that we"},{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_e978e18f","line":533,"range":{"start_line":533,"start_character":10,"end_line":533,"end_character":18},"updated":"2020-09-24 10:34:38.000000000","message":"We are no longer adding our handles in front of notes, please remove it.","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":30407,"name":"haixin","email":"haixin_haixin@qq.com","username":"haixin"},"change_message_id":"ae01b7823e68cc179c48b1b03d245c2cf7c8ba92","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        before \u003d time.time()"},{"line_number":531,"context_line":"        data \u003d tpool.execute(src.read, min(chunk_size, remaining_length))"},{"line_number":532,"context_line":""},{"line_number":533,"context_line":"        # (haixin)If the src is sparse file, this means it may not the end of"},{"line_number":534,"context_line":"        # file when read b\u0027\u0027,we should continue to read and make sure that we"},{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_def2fee2","line":533,"range":{"start_line":533,"start_character":10,"end_line":533,"end_character":18},"in_reply_to":"9f560f44_e978e18f","updated":"2020-10-10 08:20:25.000000000","message":"Done","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        before \u003d time.time()"},{"line_number":531,"context_line":"        data \u003d tpool.execute(src.read, min(chunk_size, remaining_length))"},{"line_number":532,"context_line":""},{"line_number":533,"context_line":"        # (haixin)If the src is sparse file, this means it may not the end of"},{"line_number":534,"context_line":"        # file when read b\u0027\u0027,we should continue to read and make sure that we"},{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":537,"context_line":"            skip_chunks +\u003d 1"},{"line_number":538,"context_line":"            tpool.execute(dest.seek, src.tell())"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_a4ea909c","line":535,"range":{"start_line":533,"start_character":18,"end_line":535,"end_character":45},"updated":"2020-09-24 10:34:38.000000000","message":"-1: As mentioned in the Python docs [1] \"If 0 bytes are returned, and size was not 0, this indicates end of file\", and it should be true for sparse files as well.\n\nUsually we get zeroes when we read empty portions of a sparse file/device.\n\nYou can easily confirm this with some python code:\n\n  import os\n  # Create sparse file\n  f \u003d open(\u0027test.txt\u0027, \u0027ab\u0027)\n  f.truncate(1024000)\n  f.close()\n\n  print(\u0027Used blocks in disk are %s\u0027 % os.stat(\u0027test.txt\u0027).st_blocks)\n\n  f \u003d open(\u0027test.txt\u0027, \u0027rb\u0027)\n  print(repr(f.read(10))\n  \nIf we are talking about RBD, then it\u0027s probably a problem that needs to be fixed somewhere else...\n\nFor example in the os-brick code that has the actual read method [2], where we are returning b\u0027\u0027 when we read beyond the length of the file.\n\nLooking at the Python rbd/rados bindings for the read method [3] one thing that could be happening is getting fewer bytes than we requested [4] (maybe even zero?), which is accepted behavior for the Python read method [1]: \"Fewer than size bytes may be returned if the operating system call returns fewer than size bytes.\"\n\nBut if that\u0027s the case, then it doesn\u0027t mean that we can skip that chunk, but that we have to retry it...\n\nCan you provide steps to reproduce the issue with the RBD driver?  Because I don\u0027t think this is the solution.\n\n\n[1]: https://docs.python.org/3/library/io.html#io.RawIOBase.read\n\n[2]: https://github.com/openstack/os-brick/blob/165c8017e4e11f0f0e60a166cc1b399735eab29e/os_brick/initiator/linuxrbd.py#L179-L183\n\n[3]: https://github.com/ceph/ceph/blob/ae4fd30ffc55faf9300dc6553aa4cb149a9663ab/src/pybind/rbd/rbd.pyx#L4271-L4315\n\n[4]: https://github.com/ceph/ceph/blob/ae4fd30ffc55faf9300dc6553aa4cb149a9663ab/src/pybind/rbd/rbd.pyx#L4306-L4307","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":30407,"name":"haixin","email":"haixin_haixin@qq.com","username":"haixin"},"change_message_id":"ae01b7823e68cc179c48b1b03d245c2cf7c8ba92","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        before \u003d time.time()"},{"line_number":531,"context_line":"        data \u003d tpool.execute(src.read, min(chunk_size, remaining_length))"},{"line_number":532,"context_line":""},{"line_number":533,"context_line":"        # (haixin)If the src is sparse file, this means it may not the end of"},{"line_number":534,"context_line":"        # file when read b\u0027\u0027,we should continue to read and make sure that we"},{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":537,"context_line":"            skip_chunks +\u003d 1"},{"line_number":538,"context_line":"            tpool.execute(dest.seek, src.tell())"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_c1022308","line":535,"range":{"start_line":533,"start_character":18,"end_line":535,"end_character":45},"in_reply_to":"9f560f44_a4ea909c","updated":"2020-10-10 08:20:25.000000000","message":"if the data we get is b\u0027\u0027,that means we have reached end of source, it should be true for sparse files as well. \nif data is not b\u0027\u0027, but all characters in the data are \\x00, that means src maybe sparse files, so we need to read next chunk.\n\ni think the os-brick is right, no need to fix.","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":537,"context_line":"            skip_chunks +\u003d 1"},{"line_number":538,"context_line":"            tpool.execute(dest.seek, src.tell())"},{"line_number":539,"context_line":"            continue"},{"line_number":540,"context_line":""},{"line_number":541,"context_line":"        write_chunks +\u003d 1"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_295939fc","line":538,"updated":"2020-09-24 10:34:38.000000000","message":"-1: I don\u0027t think we should do this.  If we know that the source\u0027s `read` method is not properly implemented (it returns b\u0027\u0027 when reading an empty chunk), how can we assume that it has actually moved the current position?\n\nIf the `read` method is actually failing this way, then we need to keep track of the position ourselves and use it to do the seek in both the source and the destination.","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":30407,"name":"haixin","email":"haixin_haixin@qq.com","username":"haixin"},"change_message_id":"ae01b7823e68cc179c48b1b03d245c2cf7c8ba92","unresolved":false,"context_lines":[{"line_number":535,"context_line":"        # write full data of src to the dest."},{"line_number":536,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":537,"context_line":"            skip_chunks +\u003d 1"},{"line_number":538,"context_line":"            tpool.execute(dest.seek, src.tell())"},{"line_number":539,"context_line":"            continue"},{"line_number":540,"context_line":""},{"line_number":541,"context_line":"        write_chunks +\u003d 1"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_9e124660","line":538,"in_reply_to":"9f560f44_295939fc","updated":"2020-10-10 08:20:25.000000000","message":"I\u0027ve added the retry mechanism，and saved the source file before the location, easy to try to read again.","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":549,"context_line":"        # yield to any other pending operations"},{"line_number":550,"context_line":"        eventlet.sleep(0)"},{"line_number":551,"context_line":""},{"line_number":552,"context_line":"    LOG.debug(\"skip %(skip)s chunks, write %(write)s chunks,\","},{"line_number":553,"context_line":"              {\u0027skip\u0027: skip_chunks, \u0027write\u0027: write_chunks})"},{"line_number":554,"context_line":"    tpool.execute(dest.flush)"},{"line_number":555,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_a941c938","line":552,"range":{"start_line":552,"start_character":59,"end_line":552,"end_character":60},"updated":"2020-09-24 10:34:38.000000000","message":"nit: Phrase should end with a period as in chunks.\",","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":30407,"name":"haixin","email":"haixin_haixin@qq.com","username":"haixin"},"change_message_id":"ae01b7823e68cc179c48b1b03d245c2cf7c8ba92","unresolved":false,"context_lines":[{"line_number":549,"context_line":"        # yield to any other pending operations"},{"line_number":550,"context_line":"        eventlet.sleep(0)"},{"line_number":551,"context_line":""},{"line_number":552,"context_line":"    LOG.debug(\"skip %(skip)s chunks, write %(write)s chunks,\","},{"line_number":553,"context_line":"              {\u0027skip\u0027: skip_chunks, \u0027write\u0027: write_chunks})"},{"line_number":554,"context_line":"    tpool.execute(dest.flush)"},{"line_number":555,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9f560f44_1e2596bf","line":552,"range":{"start_line":552,"start_character":59,"end_line":552,"end_character":60},"in_reply_to":"9f560f44_a941c938","updated":"2020-10-10 08:20:25.000000000","message":"Done","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"e06acedc7a841a223f10b946c7471b18fc89c75d","unresolved":false,"context_lines":[{"line_number":540,"context_line":"                data \u003d tpool.execute(src.read,"},{"line_number":541,"context_line":"                                     min(chunk_size, remaining_length))"},{"line_number":542,"context_line":"                break"},{"line_number":543,"context_line":"            except:"},{"line_number":544,"context_line":"                retry_time +\u003d 1"},{"line_number":545,"context_line":"                if retry_time \u003e 2:"},{"line_number":546,"context_line":"                    exception_message \u003d _(\"Transfer data: failed to read\""}],"source_content_type":"text/x-python","patch_set":3,"id":"9f560f44_940d07e9","line":543,"updated":"2020-10-10 12:35:31.000000000","message":"pep8: E722 do not use bare \u0027except\u0027","commit_id":"03983d62099d05bf469d6d062704d9b6477ed970"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"e06acedc7a841a223f10b946c7471b18fc89c75d","unresolved":false,"context_lines":[{"line_number":540,"context_line":"                data \u003d tpool.execute(src.read,"},{"line_number":541,"context_line":"                                     min(chunk_size, remaining_length))"},{"line_number":542,"context_line":"                break"},{"line_number":543,"context_line":"            except:"},{"line_number":544,"context_line":"                retry_time +\u003d 1"},{"line_number":545,"context_line":"                if retry_time \u003e 2:"},{"line_number":546,"context_line":"                    exception_message \u003d _(\"Transfer data: failed to read\""}],"source_content_type":"text/x-python","patch_set":3,"id":"9f560f44_f4f563cd","line":543,"updated":"2020-10-10 12:35:31.000000000","message":"pep8: H201: no \u0027except:\u0027 at least use \u0027except Exception:\u0027","commit_id":"03983d62099d05bf469d6d062704d9b6477ed970"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":545,"context_line":"                if retry_time \u003e 2:"},{"line_number":546,"context_line":"                    exception_message \u003d _(\"Transfer data: failed to read\""},{"line_number":547,"context_line":"                                          \"chunk from src\")"},{"line_number":548,"context_line":"                    LOG.error(exception_message)"},{"line_number":549,"context_line":"                    raise exception.VolumeBackendAPIException("},{"line_number":550,"context_line":"                        message\u003dexception_message)"},{"line_number":551,"context_line":"                # seek src to previous position, in order to read again"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f65232a_6e2653ba","line":548,"range":{"start_line":548,"start_character":24,"end_line":548,"end_character":29},"updated":"2020-10-21 10:59:37.000000000","message":"-1: I think we either use `LOG.exception` or we include the exception\u0027s message in the message","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":546,"context_line":"                    exception_message \u003d _(\"Transfer data: failed to read\""},{"line_number":547,"context_line":"                                          \"chunk from src\")"},{"line_number":548,"context_line":"                    LOG.error(exception_message)"},{"line_number":549,"context_line":"                    raise exception.VolumeBackendAPIException("},{"line_number":550,"context_line":"                        message\u003dexception_message)"},{"line_number":551,"context_line":"                # seek src to previous position, in order to read again"},{"line_number":552,"context_line":"                tpool.execute(src.seek, src_begin_seek)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f65232a_ae3cebbf","line":549,"range":{"start_line":549,"start_character":36,"end_line":549,"end_character":61},"updated":"2020-10-21 10:59:37.000000000","message":"-1: This doesn\u0027t look like the right exception, as we didn\u0027t have a problem calling the backend\u0027s API, the issue was in the data path.","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":549,"context_line":"                    raise exception.VolumeBackendAPIException("},{"line_number":550,"context_line":"                        message\u003dexception_message)"},{"line_number":551,"context_line":"                # seek src to previous position, in order to read again"},{"line_number":552,"context_line":"                tpool.execute(src.seek, src_begin_seek)"},{"line_number":553,"context_line":""},{"line_number":554,"context_line":"        # If data is b\u0027\u0027, that means we have reached end of source, it should"},{"line_number":555,"context_line":"        # be true for sparse files as well."}],"source_content_type":"text/x-python","patch_set":4,"id":"3f65232a_6e0db336","line":552,"updated":"2020-10-21 10:59:37.000000000","message":"?: What if the seek fails and raises an exception? Then we don\u0027t show the nice error message, we just show a traceback","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":555,"context_line":"        # be true for sparse files as well."},{"line_number":556,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":557,"context_line":"            break"},{"line_number":558,"context_line":"        # data is not b\u0027\u0027, and all characters in the data are \\x00, that means"},{"line_number":559,"context_line":"        # src maybe sparse files, so we need to read next chunk."},{"line_number":560,"context_line":"        elif data.strip(\u0027\\x00\u0027) \u003d\u003d b\u0027\u0027:"},{"line_number":561,"context_line":"            skip_chunks +\u003d 1"},{"line_number":562,"context_line":"            # here we can make sure that the src has successfully read a chunk,"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f65232a_e3a71c4f","line":559,"range":{"start_line":558,"start_character":0,"end_line":559,"end_character":64},"updated":"2020-10-21 10:59:37.000000000","message":"-1: What if it\u0027s not an empty chuck, but actual zeros and we don\u0027t copy them?  This could be problematic if we are overwriting a volume\u0027s data.","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"},{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"ce7bc8fa013f2c0e990fa8513e5bc6446217d544","unresolved":false,"context_lines":[{"line_number":557,"context_line":"            break"},{"line_number":558,"context_line":"        # data is not b\u0027\u0027, and all characters in the data are \\x00, that means"},{"line_number":559,"context_line":"        # src maybe sparse files, so we need to read next chunk."},{"line_number":560,"context_line":"        elif data.strip(\u0027\\x00\u0027) \u003d\u003d b\u0027\u0027:"},{"line_number":561,"context_line":"            skip_chunks +\u003d 1"},{"line_number":562,"context_line":"            # here we can make sure that the src has successfully read a chunk,"},{"line_number":563,"context_line":"            # so we just need to seek the dest base on src.tell()."}],"source_content_type":"text/x-python","patch_set":4,"id":"3f65232a_a3ad2433","line":560,"range":{"start_line":560,"start_character":8,"end_line":560,"end_character":12},"updated":"2020-10-21 10:59:37.000000000","message":"nit: no need for elif, we can just use if, since the previous if breaks from the loop","commit_id":"85f741756c10500fc93842d3ebcad300bb84baaf"}],"releasenotes/notes/fix-volume-copy-logic-60dafccd1fb371ae.yaml":[{"author":{"_account_id":9535,"name":"Gorka Eguileor","email":"geguileo@redhat.com","username":"Gorka"},"change_message_id":"9829bbfe709b9b8c8de1c99fccaa628e4dc657d3","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"fixes:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Fix volume copy logic, if the file in src volume is sparse file, this"},{"line_number":5,"context_line":"    means it may not the end of file when read b\u0027\u0027, so we should continue to"},{"line_number":6,"context_line":"    read and make sure that we write full data of src to the dest."},{"line_number":7,"context_line":"    Fixes `bug 1890979 \u003chttps://bugs.launchpad.net/cinder/+bug/1890979\u003e`__."}],"source_content_type":"text/x-yaml","patch_set":2,"id":"9f560f44_69cb3149","line":4,"updated":"2020-09-24 10:34:38.000000000","message":"-1: Please update to use the new format\n\n    `Bug #1890979 \u003chttps://bugs.launchpad.net/cinder/+bug/1890979\u003e`_: Fix\n\nAs explained in: https://docs.openstack.org/cinder/latest/contributor/releasenotes.html","commit_id":"0bbe13929a0c202e769de3cc16992b880c402d51"}]}
