)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"535693d48661ddfccc3d33d69a33483e34179ca9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"35774ce3_31705c61","updated":"2026-04-22 14:00:28.000000000","message":"Everpure are in the process of working on a similar feature which we were going to create a spec for. Happy to work with you on this.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"32b0fa2edd6cfef143f23e9d9e5a3b1733ded3c0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"4939647d_ea06e461","updated":"2026-06-09 17:05:50.000000000","message":"Another aspect that we should consider for backup software consuming this API:\n\nIt would be useful to be able to query the list of written blocks initially for the first (full) backup as well, to enable performing a sparse backup there.\n\nMaybe this should be baked into get_cbt_extents() with None provided for the from_snapshot arg, or maybe it needs to take a different shape -- not sure.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"5472fbee389f85d55a6199661e25a16f74788f03","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"07069e74_a953489c","updated":"2026-06-01 19:40:28.000000000","message":"I have put up an implementation of this https://review.opendev.org/c/openstack/cinder/+/990923 with a vendor driver support patch as well: https://review.opendev.org/c/openstack/cinder/+/990982","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"85dd522c226f5a717ca9cfd6033c2a60d324cefa","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"49ee46b0_28a3bd40","updated":"2026-05-12 18:01:16.000000000","message":"I\u0027m biased on this as I am very keen to get this going....LGTM","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"8544adbd_67f6db3c","updated":"2026-06-01 13:15:15.000000000","message":"I\u0027m changing my +1 based on this additional review:\n\nOverall the interface shape here is solid, but it\u0027s quite Ceph-RBD-specific in places (snapshot lifecycle, metadata storage, cleanup). I\u0027ve implemented this against a non-RBD backend (FlashArray get_volumes_diff()) and hit several points where the spec assumes Ceph\u0027s existing snapshot chain. Suggesting changes below to make the contract backend-agnostic and to firm up two correctness/lifecycle details.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"b28f482f_f4ead4a3","updated":"2026-05-01 17:03:51.000000000","message":"Sorry for the late response, and thank you so much for the thorough review!\nYou mentioned similar work underway at Pure Storage — would you like\nto include Pure Storage FlashArray CBT support in this spec as well?\nHappy to collaborate if so.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"c7448666_bc27a24e","updated":"2026-06-21 15:47:09.000000000","message":"Thanks everyone for the thorough review — I\u0027ve updated the spec to address all the comments above. Special thanks to Simon for the implementation work, which informed a lot of these changes. Please take another look when you have a chance.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"a19d79a8_720c45fd","updated":"2026-06-16 14:08:06.000000000","message":"Thanks for the spec. It looks well written. Added some comments.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"670bcf873ea9ca791a7111ef5f963e8bbe8a9f0b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"378fcff6_c50bf2d9","updated":"2026-06-01 14:20:36.000000000","message":"This spec currently targets use of CBT information from a backend by cinder-backup, but if we are going to introduce a get_cbt_extents() driver API, I think we should expose the changed block info as a Cinder API as well.\n\nBackup vendors are interested in being able to query for changed blocks to backup volume data outside of cinder-backup. IMO this would make this feature more complete.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"61e3aba1_2fa13d4b","in_reply_to":"18a336e9_308afa80","updated":"2026-06-21 15:47:09.000000000","message":"Added a new os-list_changed_blocks volume action so external backup tools can query CBT info without going through cinder-backup, modeled on Simon\u0027s existing implementation at https://review.opendev.org/c/openstack/cinder/+/990923. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"83ec60f2435a8660cf4aad7c161a88331e360401","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"18a336e9_308afa80","in_reply_to":"378fcff6_c50bf2d9","updated":"2026-06-01 14:31:13.000000000","message":"That is a fair comment. I agree with this Eric.\nI\u0027ll update my implementation of this spec with your suggestion.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"44b1f3ff0f369a56b3623e1348eb50e0727bc33d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"c10cfb20_7272efe6","in_reply_to":"4939647d_ea06e461","updated":"2026-06-12 17:11:37.000000000","message":"Agreed, this is worth supporting and I don\u0027t think it needs a new method. Letting from_snapshot\u003dNone mean \"diff against an empty image\" makes get_cbt_extents(volume, None, to_snapshot) return the volume\u0027s allocation map — exactly the written-block list needed for a sparse full backup. It maps cleanly on both reference backends (diff_iterate2(fromsnapname\u003dNULL) on Ceph, and the FlashArray diff API with no prior snapshot), and it fits the \"return only the regions that need to be shipped\" semantics: the full backup is just the from_snapshot\u003dNone case, with never-allocated holes omitted.\n\nI\u0027ve folded this into the two implementation patches I\u0027ve already put up — so the sparse-full path is covered there.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"de6e4238_8d395aa5","in_reply_to":"61e3aba1_2fa13d4b","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"d70b1ddd_b5214b63","in_reply_to":"a5f4c62d_1ca6759f","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"a5f4c62d_1ca6759f","in_reply_to":"c10cfb20_7272efe6","updated":"2026-06-21 15:47:09.000000000","message":"Defined from_snapshot\u003dNone as \"diff against an empty volume\" so a full/bootstrap backup can be sparse too — same mechanism Simon converged on. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"d0b2765ec21fb669551e369345179dec54851ed3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"32247149_2858e613","updated":"2026-06-23 16:25:46.000000000","message":"LGTM","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"9a28efaee5907d96da0e2a38fde5b4baa1098a8b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"d7a439ef_759b27c6","updated":"2026-06-22 13:49:35.000000000","message":"Thanks for the very thorough revision, Inyong — this addresses all of the feedback from Eric, Anoop, and myself, and it lines up cleanly with the reference implementation.\n\nConfirming the key points are resolved:\n\n * The lifecycle is now split into create_cbt_snapshot() / get_cbt_extents() / delete_cbt_snapshot(), with get_cbt_extents() side-effect-free — much cleaner contract.\n * `exists` is inverted to \"True \u003d must back up, False \u003d safe to skip\", and from_snapshot\u003dNone is defined as the allocation-map (sparse full/bootstrap) path.\n * Two distinct fallbacks (non-CBT parent → SHA-diff; lost reference → re-bootstrap), reference point stored transactionally in Backup.metadata, backend-neutral cleanup in the backup manager, and the normative \"Driver Responsibilities\" section.\n * Interface reframed as backend-agnostic with both Ceph RBD and FlashArray sketches, the public os-list_changed_blocks action for external tools, and the RPC 3.21 bump with assert_min_rpc_version.\n\nOne non-blocking note for the implementation phase rather than the spec: with the inverted exists, please make sure the Ceph reference path maps a region that was deallocated since the base snapshot (data → unmap/zero) to exists\u003dTrue so it\u0027s still shipped — RBD\u0027s native exists flag has the opposite polarity (\"allocated in image\"), and we don\u0027t want a discard to be silently skipped on restore. The array-backed path is conservative here since it ships every region the diff returns.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":10,"id":"f47f7b1f_d86df79a","updated":"2026-07-17 13:42:35.000000000","message":"A few final thoughts","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"}],"specs/2026.1/incremental-backup-cbt.rst":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"7520efd6_63759579","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"updated":"2026-04-22 13:37:38.000000000","message":"can you create a short pseudocode sketch of the wrapper class:\n* What other methods it exposes?\n* Does it wrap the raw file handle, or sit alongside?\n* How does chunkeddriver.py detect whether the wrapped volume_file has get_cbt_extents available (simple hasattr check? A protocol class?)\n* What is the lifetime of the wrapper — is it created per-backup-operation or per-volume?","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"bd3d3e91_0cb870fd","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"in_reply_to":"7520efd6_63759579","updated":"2026-05-01 17:03:51.000000000","message":"Added detailed pseudocode for CBTVolumeFileWrapper, backup/manager.py\nwrapper creation, and chunkeddriver.py CBT detection. Also clarified\nthat snapshot creation and diff_iterate run in the same RBD session,\nfollowing the same pattern as CephBackupDriver._backup_rbd().","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"476eec7a_c6dfd0a4","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"in_reply_to":"bd3d3e91_0cb870fd","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"137903c8_611dc2d7","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"updated":"2026-04-22 13:37:38.000000000","message":"Are you going to do this NetApp work? If not, I would not mention NetApp. If you aren\u0027t doing the work and still want to mention NetApp then you should also mention other vendors wit the same capabilities, such as the Everpure FlashArray.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"2486bc1a_6ae93cd8","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"in_reply_to":"137903c8_611dc2d7","updated":"2026-05-01 17:03:51.000000000","message":"Removed. checked that NetApp SnapDiff API only works with SnapMirror,\nnot general snapshot-based CBT. NetApp section has been dropped.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"46d89f9c_9c52e798","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"in_reply_to":"2486bc1a_6ae93cd8","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"7b9ba4be_8eb070bf","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"updated":"2026-04-22 13:37:38.000000000","message":"what is the lifecycle of this reference_point? who creates it and when, who deletes it and when, what happens is a snapshot deletion fails, what happens if the backup fails after the snapshot is created but before the metadata is written?\nYou should specify:\n* The reference point snapshot is created at the start of a backup operation and recorded in metadata on success\n* On the next incremental backup, after the new reference point is successfully recorded, the previous reference point snapshot is deleted\n* If backup fails after snapshot creation, the snapshot is cleaned up as part of the backup failure path\n* A periodic audit/cleanup mechanism should be noted as a follow-on work item for orphaned reference snapshots","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"ed4912af_d13b2220","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"in_reply_to":"276ba4a3_dad4724d","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"276ba4a3_dad4724d","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"in_reply_to":"7b9ba4be_8eb070bf","updated":"2026-05-01 17:03:51.000000000","message":"Added full snapshot lifecycle documentation: creation inside\nget_cbt_extents(), retention via backup_ceph_max_snapshots (recommended\nvalue: 1), failure cleanup in except block, and crash recovery via\n_cleanup_temp_volumes_snapshots_for_one_backup(). Naming follows existing\nCeph-to-Ceph convention using _get_new_snap_name().","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"97513bce_f8ceffdb","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"updated":"2026-04-22 13:37:38.000000000","message":"what log level and what message content should be supplied here?","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"d02c3bef_9536e140","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"in_reply_to":"97513bce_f8ceffdb","updated":"2026-05-01 17:03:51.000000000","message":"Added explicit log levels: LOG.info for CBT usage with extent stats,\nLOG.info for fallback cases with reason.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"b62c3775_a092861e","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"in_reply_to":"d02c3bef_9536e140","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"c074bf05_cda03465","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"updated":"2026-04-22 13:37:38.000000000","message":"The changed_blocks array stored in cbt_metadata is not purely informational — it is the only record of which byte ranges were written during a CBT incremental backup. Without it, a restore of a CBT incremental has no way to know which extents to apply to the target volume or in what order.\nYou should add a Restore Path section covering chain reconstruction, extent ordering and integrity and cross-backend restore","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"e070b114_5b0952c4","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"in_reply_to":"c074bf05_cda03465","updated":"2026-05-01 17:03:51.000000000","message":"Added Restore Path section. CBT does not affect restore — the existing\nChunkedBackupDriver.restore() handles chain reconstruction via parent_id,\nordered application, MD5 integrity, and cross-backend restore using\nchunk offsets stored in backup storage. See inline comment for details.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"212464f1_9cbffed4","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"in_reply_to":"e070b114_5b0952c4","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"44b8d014_919a3212","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"updated":"2026-04-22 13:37:38.000000000","message":"this is convenient, but can create a scale problem. For example, a 10 TB volume with 4 KB block granularity and 10% change rate, the changed block list could contain on the order of 250,000 entries. At approximately 80 bytes per JSON entry (offset, length, exists, plus a checksum if added), that is ~20 MB of JSON in a single backup metadata field. Most database backends have practical limits on field size well below this.\nSpecify either a maximum extent map size and define what happens when it is exceeded or note that the changed_blocks array should store consolidated extents — merging adjacent or near-adjacent changed regions into single entries — rather than raw block-level granularity from the backend API.\nI would add a note to the Data Model section specifying that adjacent extents should be consolidated by the driver before being stored, and document a recommended maximum for the changed_blocks array size (suggest 10,000 entries as a soft limit, with fallback to full scan if exceeded).","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9a219ce1_b8673c50","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"in_reply_to":"44b8d014_919a3212","updated":"2026-05-01 17:03:51.000000000","message":"Resolved by removing changed_blocks from backup metadata entirely.\nThe list is used only in memory during backup and discarded afterward.\nChunk objects already store offset/length, so no persistent storage needed.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"d602e733_48561f4d","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"in_reply_to":"9a219ce1_b8673c50","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"d7dc1c67_5c6bdb7c","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"updated":"2026-04-22 13:37:38.000000000","message":"This whole section is pitched entirely at software-defined storage, eg. Ceph, but array-backed volumes may have near zero CBT query overhead, so mentioning this will add weight to this spec as a generic interface.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"ebcf7de0_9305c756","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"in_reply_to":"d7dc1c67_5c6bdb7c","updated":"2026-05-01 17:03:51.000000000","message":"Added note to Performance Impact: hardware storage arrays implement CBT\nin hardware, resulting in near-zero overhead compared to software-defined\nbackends.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"7b69c408_a3b013d4","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"in_reply_to":"ebcf7de0_9305c756","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":365,"context_line":"  volume driver and wrap ``volume_file`` with a lightweight CBT-aware wrapper"},{"line_number":366,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":367,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":368,"context_line":"* Evaluate NetApp CBT integration feasibility with volume driver"},{"line_number":369,"context_line":"  cooperation (NetApp SnapDiff API may provide CBT capabilities but requires"},{"line_number":370,"context_line":"  volume driver cooperation)"},{"line_number":371,"context_line":"* Implement automatic fallback behavior"},{"line_number":372,"context_line":"* Unit tests for CBT detection and fallback"},{"line_number":373,"context_line":"* Unit tests for CBT API integration (mocked backends)"}],"source_content_type":"text/x-rst","patch_set":6,"id":"fa69d174_9e0ba80c","line":370,"range":{"start_line":368,"start_character":2,"end_line":370,"end_character":28},"updated":"2026-04-22 13:37:38.000000000","message":"see previous comment","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":365,"context_line":"  volume driver and wrap ``volume_file`` with a lightweight CBT-aware wrapper"},{"line_number":366,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":367,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":368,"context_line":"* Evaluate NetApp CBT integration feasibility with volume driver"},{"line_number":369,"context_line":"  cooperation (NetApp SnapDiff API may provide CBT capabilities but requires"},{"line_number":370,"context_line":"  volume driver cooperation)"},{"line_number":371,"context_line":"* Implement automatic fallback behavior"},{"line_number":372,"context_line":"* Unit tests for CBT detection and fallback"},{"line_number":373,"context_line":"* Unit tests for CBT API integration (mocked backends)"}],"source_content_type":"text/x-rst","patch_set":6,"id":"5182a6e8_8d1c5e84","line":370,"range":{"start_line":368,"start_character":2,"end_line":370,"end_character":28},"in_reply_to":"fa69d174_9e0ba80c","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"426d43c8_9bdfe949","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"updated":"2026-06-16 14:08:06.000000000","message":"Since this is an upstream spec, can we keep it driver neutral and use Ceph as an example in places where explanation needs to be provided?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"a1cc40e4_ce6d8ecb","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"in_reply_to":"2f3e153a_ae819e62","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"2f3e153a_ae819e62","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"in_reply_to":"426d43c8_9bdfe949","updated":"2026-06-21 15:47:09.000000000","message":"Reframed the intro to state the interface is backend-agnostic, with Ceph as the running example. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"4ce4f939_f971d61d","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"updated":"2026-06-01 13:15:15.000000000","message":"Recommend distinguishing two fallback cases, because a blanket \"full scan\" permanently degrades a CBT chain:\n\n* Parent is a non-CBT backup (has a SHA256 file) → fall back to the existing SHA-diff incremental (efficient, no full read needed).\n* Parent is a CBT backup but the diff can\u0027t run (reference snapshot deleted on the array, decode error, API failure) → re-bootstrap: create a fresh reference point and do a one-off full scan, so the next backup is a CBT incremental again. \n\nWithout this, a single lost reference snapshot drops the chain to full-scan/SHA forever until an operator manually runs a new full backup.\nThis self-healing behavior matters a lot operationally when reference snapshots can disappear out-of-band.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"d9d60e89_0ce4610b","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"in_reply_to":"149ee4e9_117ebbe8","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"149ee4e9_117ebbe8","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"in_reply_to":"4ce4f939_f971d61d","updated":"2026-06-21 15:47:09.000000000","message":"Split into two fallback cases as suggested: no-reference-point uses the existing SHA-diff path, lost-reference re-bootstraps with a fresh snapshot. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"998e5bd6_8d86eb3d","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"updated":"2026-06-01 13:15:15.000000000","message":"This needs tightening, and I\u0027d suggest inverting it. Define the diff as returning only the regions that need to be shipped, and make exists an explicit skip signal:\n\n`exists\u003dTrue` — region changed and must be backed up. A block that changed to zero is still exists\u003dTrue (read from the device, which returns zeros). This preserves restore correctness for data→zero transitions.\n`exists\u003dFalse` — region is unallocated/sparse and can be skipped, inheriting from the parent chain on restore.\n\nAs written (\"read and store all exists\u003dFalse\"), the flag carries no benefit — you store zeros either way. With the skip semantics it becomes a real I/O/space optimization for sparse volumes, while data→zero correctness is handled by reporting those as exists\u003dTrue. Worth stating the data→zero rule explicitly, because the obvious reading of \"exists\u003dFalse \u003d zeroed → skip it\" would silently corrupt incrementals.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"1834d34b_38261226","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"in_reply_to":"2ab8a620_3605f5a7","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"2ab8a620_3605f5a7","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"in_reply_to":"998e5bd6_8d86eb3d","updated":"2026-06-21 15:47:09.000000000","message":"Inverted as suggested — exists\u003dTrue now means \"must back up\" (including data→zero), exists\u003dFalse means \"safe to skip\". Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"10b91dcb_bc11cfcf","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"updated":"2026-06-16 14:08:06.000000000","message":"What would be passed in to_snapshot? Since the snapshot is yet to be taken?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"d61ea30a_499f0561","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"in_reply_to":"10b91dcb_bc11cfcf","updated":"2026-06-21 15:47:09.000000000","message":"Resolved structurally — create_cbt_snapshot() now creates it before get_cbt_extents() is ever called, so to_snapshot always exists by then. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"91c30ada_012efa6d","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"in_reply_to":"d61ea30a_499f0561","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"9a9c2bfd_5f360278","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"updated":"2026-06-16 14:08:06.000000000","message":"What is the expectation from driver response if the diff cannot be evaluated and driver cannot respond to get_cbt_extents() API?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"ffbca324_c82f857b","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"in_reply_to":"9a9c2bfd_5f360278","updated":"2026-06-21 15:47:09.000000000","message":"get_cbt_extents() must return None on any failure (no partial/guessed diff) — stated at its definition and in the new Driver Responsibilities section. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"45df9a5a_340ecd60","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"in_reply_to":"ffbca324_c82f857b","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"f846ba85_0bff42ae","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"updated":"2026-06-01 13:15:15.000000000","message":"Recommend splitting the snapshot lifecycle out of get_cbt_extents() into two additional optional driver methods:\n\ncreate_cbt_snapshot(volume, snapshot)   # establish a reference point\ndelete_cbt_snapshot(volume, snapshot)   # idempotent, best-effort\n\nFolding creation into get_cbt_extents() works for Ceph because the RBD backup driver already maintains a snapshot chain, but backends without that machinery (e.g. FlashArray) have no way to establish the first reference point for the initial incremental. Explicit create/delete lets the backup manager bootstrap a reference point on the full backup, so CBT is available from the very first incremental rather than only after a second CBT-aware backup has run. It also gives the manager a defined hook to reclaim superseded snapshots instead of relying on a Ceph-only retention mechanism (see comment on _remove_last_snapshots). Keep all three as no-op base stubs returning None","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"3460c81e_e3627764","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"in_reply_to":"cf073182_5f67c4c9","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"cf073182_5f67c4c9","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"in_reply_to":"f846ba85_0bff42ae","updated":"2026-06-21 15:47:09.000000000","message":"Split into create_cbt_snapshot() / get_cbt_extents() / delete_cbt_snapshot() as you proposed — get_cbt_extents() is now side-effect-free. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"a3a36e20_464a4902","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"updated":"2026-06-01 13:15:15.000000000","message":"This is Ceph-RBD-specific and won\u0027t generalize. Suggest defining cleanup in backend-neutral terms in the backup manager:\n\n* On a successful incremental, drop the now-superseded parent reference snapshot via delete_cbt_snapshot() (Cinder incremental chains are linear, so it has no other consumer).\n* On cancel/error, drop the freshly created (now orphaned) reference snapshot.\n* Require delete_cbt_snapshot() to be idempotent for an already-absent snapshot.\n\nThe Ceph driver can still map these onto its existing retention internally, but the contract shouldn\u0027t bake backup_ceph_max_snapshots into the framework.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"093c0324_bc7ed907","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"1a3bb66d_59a26fc2","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"1a3bb66d_59a26fc2","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"2c1ed8e7_0786592d","updated":"2026-06-21 15:47:09.000000000","message":"Moved cleanup into the backup manager in backend-neutral terms (delete superseded on success, delete orphan on error/cancel), dropped backup_ceph_max_snapshots. Also made delete_cbt_snapshot() explicitly idempotent, and the framework doesn\u0027t require synchronous deletion — a driver may soft-delete and reclaim later as long as the call itself doesn\u0027t block the backup. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"2c1ed8e7_0786592d","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"a3a36e20_464a4902","updated":"2026-06-16 14:08:06.000000000","message":"Agreed that delete should be idempotent and driver should handle the deletion if not possible from backend by either soft deleting and later on deleting the snapshot in a looped call if possible (best effort).","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"b74f525c_492a80ac","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"updated":"2026-06-16 14:08:06.000000000","message":"Any failure scenarios to be covered if restoring one of the snapshots fails?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"2e07c3e0_0e3ac620","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"in_reply_to":"9cc42bd2_875f0ead","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"9cc42bd2_875f0ead","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"in_reply_to":"b74f525c_492a80ac","updated":"2026-06-21 15:47:09.000000000","message":"Restore failure handling for the incremental chain (e.g. a checksum mismatch or missing chunk while applying one of the backups) is existing ChunkedBackupDriver.restore() behavior, completely unchanged by CBT — CBT only affects how data is read during backup, not how it\u0027s applied during restore. So this is out of scope for this spec.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"9fe112ce_348895d6","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"updated":"2026-06-01 13:15:15.000000000","message":"Suggest storing the reference-point metadata in the Backup.metadata field (a DictOfStringsField) instead of a side object in the backup store. Rationale:\n\n* The backup manager needs the parent\u0027s reference point to plan the next incremental; reading it from the DB avoids an extra object-store round-trip (and credentials/availability dependency on the target) before the backup even starts.\n* It\u0027s written transactionally with the backup record via the existing object, rather than as a separate object that can be orphaned or partially written.\n* It\u0027s queryable and travels with the backup record through normal Cinder mechanisms.\n\nConcretely: \n\nbackup.metadata[\u0027cbt_metadata\u0027] \u003d json.dumps(\n    {\u0027reference_snapshot\u0027: ...,\n     \u0027cbt_backend\u0027: ...}\n) \n\nIf object-store storage is kept for a reason I\u0027m missing, please spell out why DB storage was rejected in the Alternatives section.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"499dd2a3_4793acfb","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"in_reply_to":"54520f73_accac167","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"54520f73_accac167","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"in_reply_to":"9fe112ce_348895d6","updated":"2026-06-21 15:47:09.000000000","message":"Moved cbt_metadata into Backup.metadata (DB field) instead of an object-store file, per your rationale. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"c8cd80d1_b423bec8","line":433,"updated":"2026-06-01 13:15:15.000000000","message":"Recommend adding a short normative subsection \"Driver responsibilities\" so vendor drivers have a single source of truth:\n\n* All CBT methods must return None/no-op on failure rather than raise.\nReference snapshots must persist until the framework deletes them (no array-side auto-expiry), since a lost reference forces a re-bootstrap.\n* On a missing baseline in get_cbt_extents(), return None (never a partial/guessed diff — that\u0027s the one path to silent corruption) and roll back any to_snapshot the driver created in that call.\n* Drivers should consolidate adjacent same-type extents before returning, to bound the RPC payload.\n\n(I wrote exactly this up as a contributor guide while implementing — happy to fold it into the spec.)","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"f095260a_b0dff202","line":433,"in_reply_to":"c8cd80d1_b423bec8","updated":"2026-06-21 15:47:09.000000000","message":"Added a \"Driver Responsibilities\" subsection covering all the points you listed. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"dc9c822e_f9785444","line":433,"in_reply_to":"f095260a_b0dff202","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"bb300cb1_b4c7360d","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"updated":"2026-06-01 13:15:15.000000000","message":"Suggest framing the interface as explicitly backend-agnostic and listing a second reference implementation to prove that: FlashArray via the volumes/diff REST API (get_volumes_diff(base_name\u003d…, names\u003d[…], block_size\u003d…, segment_length\u003d…)), which returns changed (offset, length) extents. This also surfaces a consistency caveat worth adding to the spec: the diff is computed against a backend snapshot, while the backup reads the attached device — so the source must be static for the backup duration (Cinder\u0027s snapshot-based backup of in-use volumes satisfies this). RBD\u0027s diff_iterate against a snapshot has the same requirement; stating it once in the spec helps every future driver author.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"69e9d039_b39d744d","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"in_reply_to":"4fba89c2_e0a977a3","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"4fba89c2_e0a977a3","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"in_reply_to":"bb300cb1_b4c7360d","updated":"2026-06-21 15:47:09.000000000","message":"Reframed the interface as backend-agnostic and added a storage-array (FlashArray) implementation sketch alongside Ceph RBD, plus the static-source consistency requirement. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"58ad6f78_6dc65329","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"updated":"2026-06-01 13:15:15.000000000","message":"Two additions:\n\n* Include create_cbt_snapshot() and delete_cbt_snapshot() in the RPC list.\n* Call out the cinder-volume RPC API version bump explicitly (we\u0027re using 3.21 as the next availble) and the upgrade ordering (volume before backup). The methods should be guarded with assert_min_rpc_version so a not-yet-upgraded volume service degrades gracefully to full scan rather than erroring. Also worth specifying that supports_cbt() returns True only when the driver actually overrides BaseVD.get_cbt_extents (a class-identity check), so the stub doesn\u0027t falsely advertise support.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"ef0510ef_8735b73d","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"in_reply_to":"58ad6f78_6dc65329","updated":"2026-06-21 15:47:09.000000000","message":"Added all four RPC methods, bumped to RPC version 3.21 with assert_min_rpc_version, documented upgrade ordering, and made supports_cbt() a class-identity check. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"b80891aa_e50c21fd","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"in_reply_to":"ef0510ef_8735b73d","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"6adb5604bcb060038cfb22c0f7afc8d4c1cea5aa","unresolved":true,"context_lines":[{"line_number":113,"context_line":"* ``create_cbt_snapshot(volume, snapshot)``: create a backend reference"},{"line_number":114,"context_line":"  snapshot identified by ``snapshot``. Returns the reference identifier on"},{"line_number":115,"context_line":"  success, or ``None`` if it could not be established."},{"line_number":116,"context_line":"* ``get_cbt_extents(volume, from_snapshot, to_snapshot)``: return the list"},{"line_number":117,"context_line":"  of changed extents between two *already existing* reference snapshots."},{"line_number":118,"context_line":"  This call is **side-effect-free** — it only diffs, it never creates or"},{"line_number":119,"context_line":"  deletes a snapshot — so the same contract can be reused by other callers"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6aebfa1a_1b5fe882","line":116,"range":{"start_line":116,"start_character":2,"end_line":116,"end_character":55},"updated":"2026-07-01 20:53:06.000000000","message":"define from_snapshot/to_snapshot as backend snapshot identifiers consistent with provider_id, and require CBT drivers to set provider_id on snapshots","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":113,"context_line":"* ``create_cbt_snapshot(volume, snapshot)``: create a backend reference"},{"line_number":114,"context_line":"  snapshot identified by ``snapshot``. Returns the reference identifier on"},{"line_number":115,"context_line":"  success, or ``None`` if it could not be established."},{"line_number":116,"context_line":"* ``get_cbt_extents(volume, from_snapshot, to_snapshot)``: return the list"},{"line_number":117,"context_line":"  of changed extents between two *already existing* reference snapshots."},{"line_number":118,"context_line":"  This call is **side-effect-free** — it only diffs, it never creates or"},{"line_number":119,"context_line":"  deletes a snapshot — so the same contract can be reused by other callers"}],"source_content_type":"text/x-rst","patch_set":8,"id":"3dd48963_4b3d8ffe","line":116,"range":{"start_line":116,"start_character":2,"end_line":116,"end_character":55},"in_reply_to":"6aebfa1a_1b5fe882","updated":"2026-07-02 15:04:51.000000000","message":"Done. I clarified that from_snapshot and to_snapshot are backend snapshot identifiers, not Cinder snapshot UUIDs, and that they must be consistent with the corresponding snapshot.provider_id values.\n\nI also added this to the Driver Responsibilities section: create_cbt_snapshot() must set snapshot.provider_id to the backend snapshot identifier, and get_cbt_extents()/delete_cbt_snapshot() consume those provider identifiers.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"71a9ea49e5831db809b955ddcef8d54e614d5b59","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6bb3a6c1_5fb5a926","line":773,"updated":"2026-07-01 14:26:02.000000000","message":"Has anyone looked at doing this in the LVM driver? I think that may be important for backup vendors etc wanting to implement support for this Cinder API.  A fake driver implementation might also be useful.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"916114157506774ae486017bb4997f57ea1daac1","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6d999b9f_c1a06093","line":773,"in_reply_to":"6bb3a6c1_5fb5a926","updated":"2026-07-01 19:06:43.000000000","message":"I\u0027ve cretaed a fake driver - https://review.opendev.org/c/openstack/cinder/+/995703\nI\u0027ll look at the LVM driver next","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6ce9c54f_b21189fb","line":773,"in_reply_to":"6d999b9f_c1a06093","updated":"2026-07-02 15:04:51.000000000","message":"Thanks Simon!","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"71a9ea49e5831db809b955ddcef8d54e614d5b59","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"7eef3713_a701c7d4","line":844,"updated":"2026-07-01 14:26:02.000000000","message":"I think this is the first Cinder API that will return megabytes of data over RPC and the HTTP API. We should build a cinder-tempest-plugin test that generates a worst-case scenario for changes in a volume (i.e. many writes with gaps between them) and ensure that we don\u0027t run into issues at the amqp/http layers.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"08a4f229_2beceb0a","line":844,"in_reply_to":"3b32eaa2_1663582a","updated":"2026-07-02 15:04:51.000000000","message":"Thanks Simon!","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"916114157506774ae486017bb4997f57ea1daac1","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"3b32eaa2_1663582a","line":844,"in_reply_to":"7eef3713_a701c7d4","updated":"2026-07-01 19:06:43.000000000","message":"Agreed - I\u0027ll work on both an LVM driver for this and a tempest scenario","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":214,"context_line":""},{"line_number":215,"context_line":"        return extents"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"**A second backend, to confirm the interface generalizes**: a storage"},{"line_number":218,"context_line":"array driver (e.g. Pure Storage FlashArray) can implement the same three"},{"line_number":219,"context_line":"methods on top of its own native APIs instead of RBD\u0027s. ``create_cbt_snapshot()``"},{"line_number":220,"context_line":"and ``delete_cbt_snapshot()`` map to the array\u0027s snapshot create/delete"},{"line_number":221,"context_line":"calls, and ``get_cbt_extents()`` maps to the array\u0027s own diff API (for"},{"line_number":222,"context_line":"FlashArray, ``volumes/diff``, called with the two reference snapshot"},{"line_number":223,"context_line":"names and a block size), which likewise returns a list of changed"},{"line_number":224,"context_line":"``(offset, length)`` extents that the driver converts into the same"},{"line_number":225,"context_line":"``{offset, length, exists}`` shape. No part of the interface assumes RBD."},{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"}],"source_content_type":"text/x-rst","patch_set":9,"id":"14632276_fe7ca6ad","line":225,"range":{"start_line":217,"start_character":0,"end_line":225,"end_character":73},"updated":"2026-07-03 18:05:40.000000000","message":"The spec says two reference implementations (Ceph RBD + an array driver) were built to prove the interface generalises. In practice the landed set is LVM-thin (995738) and Pure FlashArray (990982), plus a backend-agnostic fake reference driver (995703) intended as vendor-facing worked example. Worth updating the spec\u0027s wording to name the actual references (and the fake driver), since Ceph RBD is used as the narrative example but isn\u0027t the landed second implementation.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":214,"context_line":""},{"line_number":215,"context_line":"        return extents"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"**A second backend, to confirm the interface generalizes**: a storage"},{"line_number":218,"context_line":"array driver (e.g. Pure Storage FlashArray) can implement the same three"},{"line_number":219,"context_line":"methods on top of its own native APIs instead of RBD\u0027s. ``create_cbt_snapshot()``"},{"line_number":220,"context_line":"and ``delete_cbt_snapshot()`` map to the array\u0027s snapshot create/delete"},{"line_number":221,"context_line":"calls, and ``get_cbt_extents()`` maps to the array\u0027s own diff API (for"},{"line_number":222,"context_line":"FlashArray, ``volumes/diff``, called with the two reference snapshot"},{"line_number":223,"context_line":"names and a block size), which likewise returns a list of changed"},{"line_number":224,"context_line":"``(offset, length)`` extents that the driver converts into the same"},{"line_number":225,"context_line":"``{offset, length, exists}`` shape. No part of the interface assumes RBD."},{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"}],"source_content_type":"text/x-rst","patch_set":9,"id":"482e98d6_741363ec","line":225,"range":{"start_line":217,"start_character":0,"end_line":225,"end_character":73},"in_reply_to":"14632276_fe7ca6ad","updated":"2026-07-05 14:23:57.000000000","message":"Done — the spec now names the actual references (LVM-thin, FlashArray, and the fake driver) and keeps Ceph RBD as the narrative example only; I\u0027m planning to implement the Ceph RBD driver as a follow-up.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"},{"line_number":229,"context_line":"*attached device*. This is only correct if the source does not change"},{"line_number":230,"context_line":"between when the reference snapshots are taken and when the backup"},{"line_number":231,"context_line":"finishes reading — which Cinder\u0027s snapshot-based backup of in-use volumes"},{"line_number":232,"context_line":"already guarantees. Any future driver implementing these methods must"},{"line_number":233,"context_line":"preserve this property."},{"line_number":234,"context_line":""}],"source_content_type":"text/x-rst","patch_set":9,"id":"41266a87_24dd62c1","line":231,"range":{"start_line":229,"start_character":19,"end_line":231,"end_character":16},"updated":"2026-07-17 13:42:35.000000000","message":"The lifecycle assumes create_cbt_snapshot() always makes a fresh reference on the volume. For an in-use volume, cinder-backup already freezes a temp snapshot to read a consistent image; the framework adopts that temp snapshot as the CBT reference (uses its provider_id, records its Cinder id, clears temp_snapshot_id on success so temp cleanup doesn\u0027t delete it) rather than creating a second snapshot on the live volume. Cleanup is then identifier-aware: adopted references delete via the snapshot API, driver-created ones via delete_cbt_snapshot(). This also means a single get_cbt_extents() call can legitimately mix a create_cbt_snapshot return (from) with an adopted snapshot\u0027s provider_id (to), which drivers must resolve identically. Worth adding to the lifecycle/Driver-Responsibilities sections. (Implemented in 990923.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":275,"context_line":"    from_snapshot \u003d None"},{"line_number":276,"context_line":"    with open(device_path, \u0027rb\u0027) as device_file:"},{"line_number":277,"context_line":"        # Use CBT if parent backup exists and volume driver supports it"},{"line_number":278,"context_line":"        if backup.parent_id and volume_rpcapi.supports_cbt(context, volume):"},{"line_number":279,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":280,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":281,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"}],"source_content_type":"text/x-rst","patch_set":9,"id":"d388c350_fff1b4f6","line":278,"updated":"2026-07-17 13:42:35.000000000","message":"The manager only checks backup.parent_id and supports_cbt(volume) before creating a reference snapshot. It should also gate on the configured backup driver being a ChunkedBackupDriver. CBT is only consumed by the chunked drivers; with a non-chunked backup driver the reference (and, for in-use volumes, the adopted temp snapshot) is never recorded or cleaned up and leaks on every backup. Worth calling out explicitly since Ceph — the spec\u0027s running example as a volume backend — is a non-chunked backup driver, so the distinction (volume-backend-that-does-CBT vs backup-driver-that-consumes-it) is easy to conflate. (Fixed in 990923.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":461,"context_line":"* **Parent backup has no reference point** (predates CBT, or CBT was"},{"line_number":462,"context_line":"  never enabled for that chain): use the existing SHA-diff incremental"},{"line_number":463,"context_line":"  approach. No CBT API call is attempted."},{"line_number":464,"context_line":"* **Parent backup has a reference point, but the CBT diff cannot be"},{"line_number":465,"context_line":"  computed against it** (reference snapshot removed out-of-band, decode"},{"line_number":466,"context_line":"  error, or backend API failure): re-bootstrap — create a fresh reference"},{"line_number":467,"context_line":"  snapshot and, as with a true first backup, attempt"},{"line_number":468,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` for a sparse full backup"},{"line_number":469,"context_line":"  before falling back to a dense full scan. Either way, record the fresh"},{"line_number":470,"context_line":"  reference snapshot as this backup\u0027s reference point so the next backup"},{"line_number":471,"context_line":"  can resume CBT."},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"In every case (including the two above and the normal CBT path), a new"},{"line_number":474,"context_line":"reference snapshot is created at the end of the backup and recorded in"}],"source_content_type":"text/x-rst","patch_set":9,"id":"2b3e72a2_2f1844fc","line":471,"range":{"start_line":464,"start_character":0,"end_line":471,"end_character":17},"updated":"2026-07-17 13:42:35.000000000","message":"The re-bootstrap bullet prescribes a sparse full backup (get_cbt_extents(volume, None, to_snapshot)) before falling back to dense. That\u0027s unsafe: a re-bootstrapped backup still has parent_id, so on restore it\u0027s layered on the parent chain. A sparse (allocation-map) backup omits regions that were deallocated since the parent (guest fstrim/discard), so restore leaves the parent\u0027s stale data there → silent corruption. A re-bootstrap must be a dense full scan (ship every block so restore overwrites the whole volume), not a sparse allocation map. The sparse optimization is only safe for a true first backup (no parent). (Fixed in 990923; recommend the spec say re-bootstrap is always dense.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":654,"context_line":"``os-list_changed_blocks``, gated by a new microversion, so any Cinder API"},{"line_number":655,"context_line":"consumer (not just ``cinder-backup``) can query CBT information directly:"},{"line_number":656,"context_line":""},{"line_number":657,"context_line":"* **Request**: ``target_snapshot_id`` (required), ``base_snapshot_id``"},{"line_number":658,"context_line":"  (optional — omitted or ``null`` requests the volume\u0027s full allocation"},{"line_number":659,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":660,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"}],"source_content_type":"text/x-rst","patch_set":9,"id":"bec54a56_e56fcfe9","line":661,"range":{"start_line":657,"start_character":0,"end_line":661,"end_character":22},"updated":"2026-07-03 18:05:40.000000000","message":"The changed-blocks action is implemented with full pagination/windowing, which the spec should capture: the request accepts offset/length (a byte window) and marker/limit, and the response returns changed_blocks_next_marker alongside changed_blocks; the microversion is 3.72. Importantly, the window is threaded all the way down to the driver\u0027s get_cbt_extents (via a shared volume_utils.window_cbt_page helper that over-fetches one extent past limit so the API can detect further pages) — so it bounds the extent list held in memory and crossing Oslo RPC, not just the HTTP response. Implemented in cinder 990923; documented in api-ref/admin guide 995964; reference driver 995703 shows the one-line driver pattern.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":654,"context_line":"``os-list_changed_blocks``, gated by a new microversion, so any Cinder API"},{"line_number":655,"context_line":"consumer (not just ``cinder-backup``) can query CBT information directly:"},{"line_number":656,"context_line":""},{"line_number":657,"context_line":"* **Request**: ``target_snapshot_id`` (required), ``base_snapshot_id``"},{"line_number":658,"context_line":"  (optional — omitted or ``null`` requests the volume\u0027s full allocation"},{"line_number":659,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":660,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"}],"source_content_type":"text/x-rst","patch_set":9,"id":"1397f2bc_cb1b44ab","line":661,"range":{"start_line":657,"start_character":0,"end_line":661,"end_character":22},"in_reply_to":"bec54a56_e56fcfe9","updated":"2026-07-05 14:23:57.000000000","message":"Done — documented offset/length, marker/limit, changed_blocks_next_marker and microversion 3.72, including the window being threaded down to get_cbt_extents via window_cbt_page.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"9b9d7168_746511e4","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"updated":"2026-07-03 18:05:40.000000000","message":"Still open: a consumer only learns a backend lacks CBT by calling and getting a 409; there\u0027s no advertised capability. We documented the 409-probe approach but did not implement discovery (volume-type capability / extension flag). The spec should either accept 409-on-use as the contract or list capability advertisement as a work item. This is the one substantive gap remaining.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"4c15d946_17f35cb9","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"9b9d7168_746511e4","updated":"2026-07-05 14:23:57.000000000","message":"Agreed — the spec now explicitly adopts 409-on-use as the contract and lists capability advertisement as future work.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"Security impact"},{"line_number":673,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"b5421f61_47f601bd","line":670,"updated":"2026-07-03 18:05:40.000000000","message":"Recommend the spec state explicitly that the action returns only the changed-block map, not the data; reading the changed bytes stays on the normal Cinder data path (create-volume-from-snapshot → attach → read). We\u0027ve locked this as the design (documented in 995964) and deliberately scoped a first-class \"read snapshot region\" data API out. Please confirm that scoping in the spec.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"Security impact"},{"line_number":673,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"31fc6f48_6d393dcf","line":670,"in_reply_to":"b5421f61_47f601bd","updated":"2026-07-05 14:23:57.000000000","message":"Done — added a Scope note: the action returns only the changed-block map, reads stay on the normal Cinder data path, and a \"read snapshot region\" data API is deliberately out of scope.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":802,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":803,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":804,"context_line":"* Implement automatic fallback behavior"},{"line_number":805,"context_line":"* Handle large extent lists that may exceed Oslo RPC default message size"},{"line_number":806,"context_line":"  limits (~128MB) — evaluate pagination or streaming approach"},{"line_number":807,"context_line":"* Evaluate compact extent representation (e.g. tuples instead of dicts) to"},{"line_number":808,"context_line":"  reduce RPC message size for large volumes"},{"line_number":809,"context_line":"* Add the ``os-list_changed_blocks`` volume action (new microversion,"}],"source_content_type":"text/x-rst","patch_set":9,"id":"3d7ebe5c_e56f858d","line":806,"range":{"start_line":805,"start_character":0,"end_line":806,"end_character":61},"updated":"2026-07-03 18:05:40.000000000","message":"This work item (\"evaluate pagination or streaming\") is resolved: pagination is pushed down to the driver, so no call materialises or transfers more than one page. The neighbouring item (line ~807, \"evaluate compact extent representation, tuples instead of dicts\") is therefore optional — windowing plus the existing adjacent-extent consolidation bound the payload; a compact/packed encoding remains a possible future optimisation but is no longer needed for correctness at scale. Suggest marking one done and the other optional.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":802,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":803,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":804,"context_line":"* Implement automatic fallback behavior"},{"line_number":805,"context_line":"* Handle large extent lists that may exceed Oslo RPC default message size"},{"line_number":806,"context_line":"  limits (~128MB) — evaluate pagination or streaming approach"},{"line_number":807,"context_line":"* Evaluate compact extent representation (e.g. tuples instead of dicts) to"},{"line_number":808,"context_line":"  reduce RPC message size for large volumes"},{"line_number":809,"context_line":"* Add the ``os-list_changed_blocks`` volume action (new microversion,"}],"source_content_type":"text/x-rst","patch_set":9,"id":"851e53c5_8412b026","line":806,"range":{"start_line":805,"start_character":0,"end_line":806,"end_character":61},"in_reply_to":"3d7ebe5c_e56f858d","updated":"2026-07-05 14:23:57.000000000","message":"Done — marked the pagination item as done and the compact extent representation as an optional future optimization.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":852,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":853,"context_line":""},{"line_number":854,"context_line":""},{"line_number":855,"context_line":"Documentation Impact"},{"line_number":856,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":857,"context_line":""},{"line_number":858,"context_line":"Admin guide:"},{"line_number":859,"context_line":""},{"line_number":860,"context_line":"* Explanation of CBT optimization and benefits"},{"line_number":861,"context_line":"* Configuration options for enabling/disabling CBT"},{"line_number":862,"context_line":"* Prerequisites for Ceph RBD"},{"line_number":863,"context_line":"* Troubleshooting guide for CBT-related issues"},{"line_number":864,"context_line":""},{"line_number":865,"context_line":"Release notes:"},{"line_number":866,"context_line":""},{"line_number":867,"context_line":"* New feature announcement"},{"line_number":868,"context_line":"* Performance improvements"},{"line_number":869,"context_line":"* Configuration requirements"},{"line_number":870,"context_line":""},{"line_number":871,"context_line":""},{"line_number":872,"context_line":"References"},{"line_number":873,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"a058d248_03a0b4c1","line":870,"range":{"start_line":855,"start_character":0,"end_line":870,"end_character":0},"updated":"2026-07-03 18:05:40.000000000","message":"api-ref for os-list_changed_blocks (request/response, exists semantics, pagination, 409) and an admin \"consuming CBT from the REST API\" guide now exist in 995964; recommend listing api-ref as an explicit deliverable here so the spec\u0027s doc plan matches what shipped.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":852,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":853,"context_line":""},{"line_number":854,"context_line":""},{"line_number":855,"context_line":"Documentation Impact"},{"line_number":856,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":857,"context_line":""},{"line_number":858,"context_line":"Admin guide:"},{"line_number":859,"context_line":""},{"line_number":860,"context_line":"* Explanation of CBT optimization and benefits"},{"line_number":861,"context_line":"* Configuration options for enabling/disabling CBT"},{"line_number":862,"context_line":"* Prerequisites for Ceph RBD"},{"line_number":863,"context_line":"* Troubleshooting guide for CBT-related issues"},{"line_number":864,"context_line":""},{"line_number":865,"context_line":"Release notes:"},{"line_number":866,"context_line":""},{"line_number":867,"context_line":"* New feature announcement"},{"line_number":868,"context_line":"* Performance improvements"},{"line_number":869,"context_line":"* Configuration requirements"},{"line_number":870,"context_line":""},{"line_number":871,"context_line":""},{"line_number":872,"context_line":"References"},{"line_number":873,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"882da38e_84d1accb","line":870,"range":{"start_line":855,"start_character":0,"end_line":870,"end_character":0},"in_reply_to":"a058d248_03a0b4c1","updated":"2026-07-05 14:23:57.000000000","message":"Done — listed the api-ref (request/response, exists, pagination, 409) and the \"Consuming CBT from the REST API\" admin guide as explicit deliverables, with 995964 linked in References.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"}]}
