diff --git a/src/rockstor/fs/btrfs.py b/src/rockstor/fs/btrfs.py index dc652af9c..7a168b44e 100644 --- a/src/rockstor/fs/btrfs.py +++ b/src/rockstor/fs/btrfs.py @@ -1181,7 +1181,7 @@ def remove_share(pool, share_name, pqgroup, force=False): # TODO: Consider also using the following command to allow delete of the # initial (anomalous) temp replication snap as share; but this also blindly # circumvents ro 'protection' for any other share! - # set_property(subvol_mnt_pt, 'ro', 'false', mount=False) + # set_property(subvol_mnt_pt, 'ro', 'false', mount=False, force=True) toggle_path_rw(subvol_mnt_pt, rw=True) if force: o, e, rc = run_command([BTRFS, "subvolume", "list", "-o", subvol_mnt_pt]) @@ -2308,9 +2308,16 @@ def btrfs_uuid(disk): return o[0].split()[3] -def set_property(mnt_pt, name, val, mount=True): +def set_property(mnt_pt, name, val, mount=True, force=False): + """ + https://btrfs.readthedocs.io/en/latest/btrfs-property.html + https://btrfs.readthedocs.io/en/latest/btrfs-subvolume.html + """ if mount is not True or is_mounted(mnt_pt): - cmd = [BTRFS, "property", "set", mnt_pt, name, val] + if not force: + cmd = [BTRFS, "property", "set", mnt_pt, name, val] + else: + cmd = [BTRFS, "property", "set", "-f", mnt_pt, name, val] return run_command(cmd) diff --git a/src/rockstor/storageadmin/views/clone_helpers.py b/src/rockstor/storageadmin/views/clone_helpers.py index 57914c0ee..452aa9fdd 100644 --- a/src/rockstor/storageadmin/views/clone_helpers.py +++ b/src/rockstor/storageadmin/views/clone_helpers.py @@ -41,7 +41,7 @@ def create_repclone(share, request, logger, snapshot): """ - Variant of create_clone but where the share already exists and is to be + Variant of create_clone but where the share may already exist and is to be supplanted by a snapshot which is effectively moved into the shares prior position, both in the db and on the file system. This is achieved thus: Unmount target share - (via remove_share()). @@ -74,7 +74,7 @@ def create_repclone(share, request, logger, snapshot): # Normalise source name across initial quirk share & subsequent snaps. source_name = snapshot.name.split("/")[-1] # Note in the above we have to use Object.name for polymorphism, but - # our share is passed by it's subvol (potential fragility point). + # our share is passed by its subvol (potential fragility point). snap_path = "{}/.snapshots/{}/{}".format( share.pool.mnt_pt, share.name, source_name ).replace("//", "/") @@ -91,7 +91,11 @@ def create_repclone(share, request, logger, snapshot): # unmounts and then subvol deletes our on disk share remove_share(share.pool, share.name, PQGROUP_DEFAULT) # Remove read only flag on our snapshot subvol - set_property(snap_path, "ro", "false", mount=False) + # N.B. more recent btrfs has force requirement re safeguard on received_uuid set. + # However, Rockstor replication cascades ro snapshots used in send/receive. + # The oldest of 3 received snapshot sends is promoted to Share, from 4th replication event onwards. + # As such this subvol is no longer referenced in the ongoing btrfs send/receive cascade. + set_property(snap_path, "ro", "false", mount=False, force=True) # Ensure removed share path is clean, ie remove mount point. run_command(["/usr/bin/rm", "-rf", share_path], throw=False) # Now move snapshot to prior shares location. Given both a share and