Skip to content

Commit 3f51eeb

Browse files
committed
Merge PR ceph#64324 into main
* refs/pull/64324/head: qa/cephfs: fix test_subvolume_group_charmap_inheritance test doc: add name mangling documentation for subvolume group creation qa: add tests for name mangling in subvolume group creation pybind/mgr: add name mangling options to subvolume group creation Reviewed-by: Anthony D Atri <[email protected]> Reviewed-by: Patrick Donnelly <[email protected]> Reviewed-by: Venky Shankar <[email protected]>
2 parents 4d5ad8c + fe3d641 commit 3f51eeb

File tree

5 files changed

+161
-8
lines changed

5 files changed

+161
-8
lines changed

doc/cephfs/fs-volumes.rst

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Create a subvolume group by running the following command:
167167

168168
.. prompt:: bash #
169169

170-
ceph fs subvolumegroup create <vol_name> <group_name> [--size <size_in_bytes>] [--pool_layout <data_pool_name>] [--uid <uid>] [--gid <gid>] [--mode <octal_mode>]
170+
ceph fs subvolumegroup create <vol_name> <group_name> [--size <size_in_bytes>] [--pool_layout <data_pool_name>] [--uid <uid>] [--gid <gid>] [--mode <octal_mode>] [--normalization <form>] [--casesensitive <bool>]
171171

172172
The command succeeds even if the subvolume group already exists.
173173

@@ -178,6 +178,30 @@ a quota on it (see :doc:`/cephfs/quota`). By default, the subvolume group
178178
is created with octal file mode ``755``, uid ``0``, gid ``0`` and the data pool
179179
layout of its parent directory.
180180

181+
You can also specify an unicode normalization form using the ``--normalization``
182+
option. This will be used to internally mangle file names so that unicode
183+
characters that can be represented by different unicode code point sequences
184+
are all mapped to the same representation, which means that they will all
185+
access the same file. However, users will continue to see the same name that
186+
they used when the file was created.
187+
188+
The valid values for the unicode normalization form are:
189+
190+
- nfd: canonical decomposition (default)
191+
- nfc: canonical decomposition, followed by canonical composition
192+
- nfkd: compatibility decomposition
193+
- nfkc: compatibility decomposition, followed by canonical composition
194+
195+
To learn more about unicode normalization forms see https://unicode.org/reports/tr15
196+
197+
It's also possible to configure a subvolume group for case insensitive access
198+
when the ``--casesensitive=0`` option is used. When this option is added, file
199+
names that only differ in the case of its characters will be mapped to the same
200+
file. The case of the file name used when the file was created is preserved.
201+
202+
.. note:: Setting ``--casesensitive=0`` option implicitly enables
203+
unicode normalization on the subvolume group.
204+
181205
Remove a subvolume group by running a command of the following form:
182206

183207
.. prompt:: bash #

qa/tasks/cephfs/test_volumes.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,95 @@ def test_subvolume_group_create_with_size(self):
12171217
# remove group
12181218
self._fs_cmd("subvolumegroup", "rm", self.volname, group)
12191219

1220+
def test_subvolume_group_create_without_normalization(self):
1221+
# create group
1222+
group = self._gen_subvol_grp_name()
1223+
self._fs_cmd("subvolumegroup", "create", self.volname, group)
1224+
1225+
# make sure it exists
1226+
grouppath = self._get_subvolume_group_path(self.volname, group)
1227+
self.assertNotEqual(grouppath, None)
1228+
1229+
# check normalization
1230+
try:
1231+
self._fs_cmd("subvolumegroup", "charmap", "get", self.volname, group, "normalization")
1232+
except CommandFailedError as ce:
1233+
self.assertEqual(ce.exitstatus, errno.ENODATA)
1234+
else:
1235+
self.fail("expected the 'fs subvolumegroup charmap' command to fail")
1236+
1237+
def test_subvolume_group_create_with_normalization(self):
1238+
# create group
1239+
group = self._gen_subvol_grp_name()
1240+
self._fs_cmd("subvolumegroup", "create", self.volname, group, "--normalization", "nfc")
1241+
1242+
# make sure it exists
1243+
grouppath = self._get_subvolume_group_path(self.volname, group)
1244+
self.assertNotEqual(grouppath, None)
1245+
1246+
# check normalization
1247+
normalization = self._fs_cmd("subvolumegroup", "charmap", "get", self.volname, group, "normalization")
1248+
self.assertEqual(normalization.strip(), "nfc")
1249+
1250+
def test_subvolume_group_create_without_case_sensitivity(self):
1251+
# create group
1252+
group = self._gen_subvol_grp_name()
1253+
self._fs_cmd("subvolumegroup", "create", self.volname, group)
1254+
1255+
# make sure it exists
1256+
grouppath = self._get_subvolume_group_path(self.volname, group)
1257+
self.assertNotEqual(grouppath, None)
1258+
1259+
# check case sensitivity
1260+
try:
1261+
self._fs_cmd("subvolumegroup", "charmap", "get", self.volname, group, "casesensitive")
1262+
except CommandFailedError as ce:
1263+
self.assertEqual(ce.exitstatus, errno.ENODATA)
1264+
else:
1265+
self.fail("expected the 'fs subvolumegroup charmap' command to fail")
1266+
1267+
def test_subvolume_group_create_with_case_insensitive(self):
1268+
# create group
1269+
group = self._gen_subvol_grp_name()
1270+
self._fs_cmd("subvolumegroup", "create", self.volname, group, "--casesensitive=0")
1271+
1272+
# make sure it exists
1273+
grouppath = self._get_subvolume_group_path(self.volname, group)
1274+
self.assertNotEqual(grouppath, None)
1275+
1276+
# check case sensitivity
1277+
case_sensitive = self._fs_cmd("subvolumegroup", "charmap", "get", self.volname, group, "casesensitive")
1278+
self.assertEqual(case_sensitive.strip(), "0")
1279+
1280+
# check normalization (it's implicitly enabled by --case-insensitive, with default value 'nfd')
1281+
normalization = self._fs_cmd("subvolumegroup", "charmap", "get", self.volname, group, "normalization")
1282+
self.assertEqual(normalization.strip(), "nfd")
1283+
1284+
def test_subvolume_group_charmap_inheritance(self):
1285+
# create group
1286+
group = self._gen_subvol_grp_name()
1287+
self._fs_cmd("subvolumegroup", "create", self.volname, group, "--casesensitive=0", "--normalization=nfc")
1288+
1289+
# make sure it exists
1290+
grouppath = self._get_subvolume_group_path(self.volname, group)
1291+
self.assertNotEqual(grouppath, None)
1292+
1293+
# create subvolume
1294+
subvolume = self._gen_subvol_name()
1295+
self._fs_cmd("subvolume", "create", self.volname, subvolume, "--group_name", group)
1296+
1297+
# make sure it exists
1298+
subvolpath = self._get_subvolume_path(self.volname, subvolume, group)
1299+
self.assertNotEqual(subvolpath, None)
1300+
1301+
# check case sensitivity
1302+
case_sensitive = self._fs_cmd("subvolume", "charmap", "get", self.volname, subvolume, "casesensitive", group)
1303+
self.assertEqual(case_sensitive.strip(), "0")
1304+
1305+
# check normalization (it's implicitly enabled by --case-insensitive, with default value 'nfd')
1306+
normalization = self._fs_cmd("subvolume", "charmap", "get", self.volname, subvolume, "normalization", group)
1307+
self.assertEqual(normalization.strip(), "nfc")
1308+
12201309
def test_subvolume_group_info(self):
12211310
# tests the 'fs subvolumegroup info' command
12221311

src/pybind/mgr/volumes/fs/operations/group.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ def info(self):
126126
except cephfs.Error as e:
127127
raise VolumeException(-e.args[0], e.args[1])
128128

129+
try:
130+
normalization = self.fs.getxattr(self.path, 'ceph.dir.normalization').decode('utf-8')
131+
except cephfs.NoData:
132+
normalization = "none"
133+
134+
try:
135+
casesensitive = self.fs.getxattr(self.path, 'ceph.dir.casesensitive').decode('utf-8')
136+
casesensitive = casesensitive == "1"
137+
except cephfs.NoData:
138+
casesensitive = True
139+
129140
return {'uid': int(st["uid"]),
130141
'gid': int(st["gid"]),
131142
'atime': str(st["atime"]),
@@ -136,7 +147,10 @@ def info(self):
136147
'created_at': str(st["btime"]),
137148
'bytes_quota': "infinite" if nsize == 0 else nsize,
138149
'bytes_used': int(usedbytes),
139-
'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0)}
150+
'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0),
151+
'normalization': normalization,
152+
'casesensitive': casesensitive,
153+
}
140154

141155
def resize(self, newsize, noshrink):
142156
try:
@@ -223,7 +237,21 @@ def set_group_attrs(fs, path, attrs):
223237
if mode is not None:
224238
fs.lchmod(path, mode)
225239

226-
def create_group(fs, vol_spec, groupname, size, pool, mode, uid, gid):
240+
normalization = attrs.get("normalization")
241+
if normalization is not None:
242+
try:
243+
fs.setxattr(path, "ceph.dir.normalization", normalization.encode('utf-8'), 0)
244+
except cephfs.Error as e:
245+
raise VolumeException(-e.args[0], e.args[1])
246+
247+
casesensitive = attrs.get("casesensitive")
248+
if casesensitive is False:
249+
try:
250+
fs.setxattr(path, "ceph.dir.casesensitive", "0".encode('utf-8'), 0)
251+
except cephfs.Error as e:
252+
raise VolumeException(-e.args[0], e.args[1])
253+
254+
def create_group(fs, vol_spec, groupname, size, pool, mode, uid, gid, normalization, casesensitive):
227255
"""
228256
create a subvolume group.
229257
@@ -235,6 +263,8 @@ def create_group(fs, vol_spec, groupname, size, pool, mode, uid, gid):
235263
:param mode: the user permissions
236264
:param uid: the user identifier
237265
:param gid: the group identifier
266+
:param normalization: the unicode normalization form to use (nfd, nfc, nfkd or nfkc)
267+
:param casesensitive: whether to make the subvolume case insensitive or not
238268
:return: None
239269
"""
240270
group = Group(fs, vol_spec, groupname)
@@ -249,7 +279,9 @@ def create_group(fs, vol_spec, groupname, size, pool, mode, uid, gid):
249279
'uid': uid,
250280
'gid': gid,
251281
'data_pool': pool,
252-
'quota': size
282+
'quota': size,
283+
'normalization': normalization,
284+
'casesensitive': casesensitive,
253285
}
254286
set_group_attrs(fs, path, attrs)
255287
except (cephfs.Error, VolumeException) as e:

src/pybind/mgr/volumes/fs/volume.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,8 @@ def create_subvolume_group(self, **kwargs):
10871087
uid = kwargs['uid']
10881088
gid = kwargs['gid']
10891089
mode = kwargs['mode']
1090+
normalization = kwargs['normalization']
1091+
casesensitive = kwargs['casesensitive']
10901092

10911093
try:
10921094
with open_volume(self, volname) as fs_handle:
@@ -1098,13 +1100,15 @@ def create_subvolume_group(self, **kwargs):
10981100
'gid': gid,
10991101
'mode': octal_str_to_decimal_int(mode),
11001102
'data_pool': pool,
1101-
'quota': size
1103+
'quota': size,
1104+
'normalization': normalization,
1105+
'casesensitive': casesensitive,
11021106
}
11031107
set_group_attrs(fs_handle, group.path, attrs)
11041108
except VolumeException as ve:
11051109
if ve.errno == -errno.ENOENT:
11061110
oct_mode = octal_str_to_decimal_int(mode)
1107-
create_group(fs_handle, self.volspec, groupname, size, pool, oct_mode, uid, gid)
1111+
create_group(fs_handle, self.volspec, groupname, size, pool, oct_mode, uid, gid, normalization, casesensitive)
11081112
else:
11091113
raise
11101114
except VolumeException as ve:

src/pybind/mgr/volumes/module.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
9191
'name=pool_layout,type=CephString,req=false '
9292
'name=uid,type=CephInt,req=false '
9393
'name=gid,type=CephInt,req=false '
94-
'name=mode,type=CephString,req=false ',
94+
'name=mode,type=CephString,req=false '
95+
'name=normalization,type=CephChoices,strings=nfd|nfc|nfkd|nfkc,req=false '
96+
'name=casesensitive,type=CephBool,req=false ',
9597
'desc': "Create a CephFS subvolume group in a volume, and optionally, "
9698
"with a specific data pool layout, and a specific numeric mode",
9799
'perm': 'rw'
@@ -727,7 +729,9 @@ def _cmd_fs_subvolumegroup_create(self, inbuf, cmd):
727729
return self.vc.create_subvolume_group(
728730
vol_name=cmd['vol_name'], group_name=cmd['group_name'], size=cmd.get('size', None),
729731
pool_layout=cmd.get('pool_layout', None), mode=cmd.get('mode', '755'),
730-
uid=cmd.get('uid', None), gid=cmd.get('gid', None))
732+
uid=cmd.get('uid', None), gid=cmd.get('gid', None),
733+
normalization=cmd.get('normalization', None),
734+
casesensitive=cmd.get('casesensitive', None))
731735

732736
@mgr_cmd_wrap
733737
def _cmd_fs_subvolumegroup_rm(self, inbuf, cmd):

0 commit comments

Comments
 (0)