]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Merge PR #62682 into main
authorVenky Shankar <vshankar@redhat.com>
Thu, 24 Jul 2025 05:07:31 +0000 (10:37 +0530)
committerVenky Shankar <vshankar@redhat.com>
Thu, 24 Jul 2025 05:07:31 +0000 (10:37 +0530)
* refs/pull/62682/head:

Reviewed-by: Patrick Donnelly <pdonnell@ibm.com>
Reviewed-by: Venky Shankar <vshankar@redhat.com>
1  2 
qa/tasks/cephfs/test_volumes.py
src/common/options/mds.yaml.in
src/mds/CInode.cc
src/mds/MDCache.cc
src/mds/MDSRank.cc
src/mds/Server.cc

index 6ad69ae6b3d758df1ef2c09332144f7c44c98b50,cda6aa9fd7bdf392472afcf206af5a2dd7ae1b51..27111d8d178c8484a02b1ebe6b64e28fefe1ad9e
@@@ -6583,225 -6711,132 +6692,350 @@@ class TestSubvolumeSnapshots(TestVolume
          # Clean tmp config file
          self.mount_a.run_shell(['sudo', 'rm', '-f', tmp_meta_path], omit_sudo=False)
  
+     def test_subvolume_snapshot_with_use_global_snaprealm_seq_config_disabled(self):
+         """
+         To verify that the subvolume snapshots doesn't unnecessarily cow old inodes of
+         parent directories of subvolume snapshot path when mds_use_global_snaprealm_seq_for_subvol
+         is disabled
+         """
+         # Disable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', False)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'false')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot)
+         self._verify_old_inodes(group, f"{subvolname}_1", False, False)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot)
+     def test_subvolume_snapshot_with_use_global_snaprealm_seq_config_enabled(self):
+         """
+         To verify that the subvolume snapshots unnecessarily cow old inodes of parent
+         directories of subvolume snapshot path when mds_use_global_snaprealm_seq_for_subvol
+         is enabled
+         """
+         # Enable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', True)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'true')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot)
+         self._verify_old_inodes(group, f"{subvolname}_1", True, False)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot)
+     def test_root_snapshot_with_use_global_snaprealm_seq_config_disabled(self):
+         """
+         To verify that the snapshots between root and subvolume snapshot directory triggers cow of
+         old inodes based on global snaprealm's seq number for snpashots between root and subvolume
+         directory. Also verify, it uses subvolume snaprealm's seq number for subvolume snapshots.
+         """
+         # Disable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', False)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'false')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot, True)
+         self._verify_old_inodes(group, f"{subvolname}_1", False, True)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot, True)
+     def test_subvolume_snapshot_with_use_global_snaprealm_seq_config_disabled_with_journal_flush(self):
+         """
+         To verify that the stale old inodes get trimmed during journal flush when the config
+         mds_use_global_snaprealm_seq_for_subvol is disabled
+         """
+         # Disable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', False)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'false')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot, False)
+         self._verify_old_inodes(group, f"{subvolname}_1", False, False, True)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot)
+     def test_subvolume_snapshot_with_use_global_snaprealm_seq_config_enabled_with_journal_flush(self):
+         """
+         To verify that the stale old inodes get trimmed during journal flush even when the config
+         mds_use_global_snaprealm_seq_for_subvol is enabled
+         """
+         # Enable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', True)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'true')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot, False)
+         self._verify_old_inodes(group, f"{subvolname}_1", True, False, True)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot)
+     def test_root_snapshot_with_use_global_snaprealm_seq_config_disabled_with_journal_flush(self):
+         """
+         To verify that the stale old inodes get trimmed during journal flush even when the config
+         mds_use_global_snaprealm_seq_for_subvol is disabled and root snapshot
+         """
+         # Disable the config
+         self.config_set('mds', 'mds_use_global_snaprealm_seq_for_subvol', False)
+         self.assertEqual(self.config_get('mds', 'mds_use_global_snaprealm_seq_for_subvol'), 'false')
+         subvolname = self._gen_subvol_name()
+         group = self._gen_subvol_grp_name()
+         snapshot = self._gen_subvol_snap_name()
+         self._create_subvolumes_and_snapshots(group, subvolname, snapshot, True)
+         self._verify_old_inodes(group, f"{subvolname}_1", False, True, True)
+         # cleanup
+         self._cleanup_subvolumes_and_snapshots(group, subvolname, snapshot, True)
  
 +class TestSubvolumeSnapshotGetpath(TestVolumesHelper):
 +
 +    def get_subvol_uuid(self, subvol_name, group_name=None):
 +        '''
 +        Return the UUID directory component obtained from the path of
 +        subvolume.
 +        '''
 +        if group_name:
 +            cmd = (f'fs subvolume getpath {self.volname} {subvol_name} '
 +                   f'{group_name}')
 +        else:
 +            cmd = f'fs subvolume getpath {self.volname} {subvol_name}'
 +
 +        subvol_path = self.get_ceph_cmd_stdout(cmd).strip()
 +
 +        subvol_uuid = os.path.basename(subvol_path)
 +        return subvol_uuid
 +
 +    def construct_snap_path_for_v2(self, subvol_name, snap_name, uuid,
 +                                   group_name='_nogroup'):
 +        return os.path.join('/volumes', group_name, subvol_name, '.snap',
 +                            snap_name, uuid)
 +
 +    def construct_snap_path_for_v1(self, subvol_name, snap_name, uuid,
 +                                   group_name='_nogroup'):
 +        return os.path.join('/volumes', group_name, subvol_name, uuid,
 +                            '.snap', snap_name)
 +
 +    def construct_snap_path_for_legacy(self, subvol_name, snap_name,
 +                                       group_name='_nogroup'):
 +        return os.path.join('/volumes', group_name, subvol_name, '.snap',
 +                            snap_name)
 +
 +    def test_snapshot_getpath(self):
 +        '''
 +        Test that "ceph fs subvolume snapshot getpath" command returns path to
 +        the specified snapshot in the specified subvolume.
 +        '''
 +        subvol_name = self._gen_subvol_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name}')
 +        sv_uuid = self.get_subvol_uuid(subvol_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
 +                                             f'{self.volname} {subvol_name} '
 +                                             f'{snap_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_v2(subvol_name, snap_name,
 +                                                        sv_uuid)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_in_group(self):
 +        '''
 +        Test that "ceph fs subvolume snapshot getpath" command returns path to
 +        the specified snapshot in the specified subvolume in the specified
 +        group.
 +        '''
 +        subvol_name = self._gen_subvol_name()
 +        group_name = self._gen_subvol_grp_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self.run_ceph_cmd(f'fs subvolumegroup create {self.volname} {group_name}')
 +        self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name} '
 +                          f'{group_name}')
 +        sv_uuid = self.get_subvol_uuid(subvol_name, group_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name} {group_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
 +                                             f'{self.volname} {subvol_name} '
 +                                             f'{snap_name} {group_name}')\
 +                                             .strip()
 +        exp_snap_path = self.construct_snap_path_for_v2(subvol_name, snap_name,
 +                                                        sv_uuid, group_name)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_on_retained_subvol(self):
 +        '''
 +        Test that "ceph fs subvolume snapshot getpath" command returns path to
 +        the specified snapshot in the specified subvolume that was deleted but
 +        snapshots on which is retained.
 +        '''
 +        subvol_name = self._gen_subvol_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name}')
 +        sv_uuid = self.get_subvol_uuid(subvol_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name}')
 +        self.run_ceph_cmd(f'fs subvolume rm {self.volname} {subvol_name} '
 +                           '--retain-snapshots')
 +
 +        snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
 +                                             f'{self.volname} {subvol_name} '
 +                                             f'{snap_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_v2(subvol_name, snap_name,
 +                                                        sv_uuid)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_on_retained_subvol_in_group(self):
 +        '''
 +        Test that "ceph fs subvolume snapshot getpath" command returns path to
 +        the specified snapshot in the specified subvolume that was deleted but
 +        snapshots on which is retained. And the deleted subvolume is located on
 +        a non-default group.
 +        '''
 +        subvol_name = self._gen_subvol_name()
 +        group_name = self._gen_subvol_grp_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self.run_ceph_cmd(f'fs subvolumegroup create {self.volname} {group_name}')
 +        self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name} '
 +                          f'{group_name}')
 +        sv_uuid = self.get_subvol_uuid(subvol_name, group_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name} {group_name}')
 +        self.run_ceph_cmd(f'fs subvolume rm {self.volname} {subvol_name} '
 +                          f'{group_name} --retain-snapshots')
 +
 +        snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
 +                                             f'{self.volname} {subvol_name} '
 +                                             f'{snap_name} {group_name}')\
 +                                             .strip()
 +        exp_snap_path = self.construct_snap_path_for_v2(subvol_name, snap_name,
 +                                                        sv_uuid, group_name)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_for_v1(self):
 +        subvol_name = self._gen_subvol_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self._create_v1_subvolume(subvol_name)
 +        sv_uuid = self.get_subvol_uuid(subvol_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(
 +            f'fs subvolume snapshot getpath {self.volname} {subvol_name} '
 +            f'{snap_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_v1(subvol_name, snap_name,
 +                                                        sv_uuid)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_in_group_for_v1(self):
 +        subvol_name = self._gen_subvol_name()
 +        group_name = self._gen_subvol_grp_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        self.run_ceph_cmd(f'fs subvolumegroup create {self.volname} '
 +                          f'{group_name}')
 +        self._create_v1_subvolume(subvol_name, group_name)
 +        sv_uuid = self.get_subvol_uuid(subvol_name, group_name)
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name} {group_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(
 +            f'fs subvolume snapshot getpath {self.volname} {subvol_name} '
 +            f'{snap_name} {group_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_v1(subvol_name, snap_name,
 +                                                        sv_uuid, group_name)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_for_upgraded_legacy(self):
 +        subvol_name = self._gen_subvol_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        sv_path = os.path.join('.', 'volumes', '_nogroup', subvol_name)
 +        self.mount_a.run_shell(f'sudo mkdir -p {sv_path}', omit_sudo=False)
 +
 +        sv_getpath = self.get_ceph_cmd_stdout(
 +            f'fs subvolume getpath {self.volname} {subvol_name}').strip()
 +        self.assertNotEqual(sv_getpath, None)
 +        # remove '/' at the beginning
 +        self.assertEqual(sv_path[1:], sv_getpath)
 +        self._assert_meta_location_and_version(self.volname, subvol_name,
 +                                               version=1, legacy=True)
 +
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(
 +            f'fs subvolume snapshot getpath {self.volname} {subvol_name} '
 +            f'{snap_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_legacy(subvol_name,
 +                                                            snap_name)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +    def test_snapshot_getpath_in_group_for_upgraded_legacy(self):
 +        subvol_name = self._gen_subvol_name()
 +        group_name = self._gen_subvol_grp_name()
 +        snap_name = self._gen_subvol_snap_name()
 +
 +        sv_path = os.path.join('.', 'volumes', group_name, subvol_name)
 +        self.mount_a.run_shell(f'sudo mkdir -p {sv_path}', omit_sudo=False)
 +
 +        sv_getpath = self.get_ceph_cmd_stdout(
 +            f'fs subvolume getpath {self.volname} {subvol_name} '
 +            f'{group_name}').strip()
 +        self.assertNotEqual(sv_getpath, None)
 +        # remove '/' at the beginning
 +        self.assertEqual(sv_path[1:], sv_getpath)
 +        self._assert_meta_location_and_version(self.volname, subvol_name,
 +                                               subvol_group=group_name,
 +                                               version=1, legacy=True)
 +
 +        self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
 +                          f'{subvol_name} {snap_name} {group_name}')
 +
 +        snap_path = self.get_ceph_cmd_stdout(
 +            f'fs subvolume snapshot getpath {self.volname} {subvol_name} '
 +            f'{snap_name} {group_name}').strip()
 +        exp_snap_path = self.construct_snap_path_for_legacy(subvol_name, snap_name,
 +                                                            group_name)
 +        self.assertEqual(snap_path, exp_snap_path)
 +
 +
  class TestSubvolumeSnapshotClones(TestVolumesHelper):
      """ Tests for FS subvolume snapshot clone operations."""
      def test_clone_subvolume_info(self):
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge