Create a subvolume using::
- $ ceph fs subvolume create <vol_name> <subvol_name> [--size <size_in_bytes> --group_name <subvol_group_name> --pool_layout <data_pool_name> --uid <uid> --gid <gid> --mode <octal_mode>]
+ $ ceph fs subvolume create <vol_name> <subvol_name> [--size <size_in_bytes> --group_name <subvol_group_name> --pool_layout <data_pool_name> --uid <uid> --gid <gid> --mode <octal_mode> --namespace-isolated]
The command succeeds even if the subvolume already exists.
When creating a subvolume you can specify its subvolume group, data pool layout,
uid, gid, file mode in octal numerals, and size in bytes. The size of the subvolume is
-specified by setting a quota on it (see :doc:`/cephfs/quota`). By default a
-subvolume is created within the default subvolume group, and with an octal file
+specified by setting a quota on it (see :doc:`/cephfs/quota`). The subvolume can be
+created in a separate RADOS namespace by specifying --namespace-isolated option. By
+default a subvolume is created within the default subvolume group, and with an octal file
mode '755', uid of its subvolume group, gid of its subvolume group, data pool layout of
its parent directory and no size limit.
* data_pool: data pool the subvolume belongs to
* path: absolute path of a subvolume
* type: subvolume type indicating whether it's clone or subvolume
+* pool_namespace: RADOS namespace of the subvolume
List subvolumes using::
# verify trash dir is clean
self._wait_for_trash_empty()
+ def test_subvolume_create_isolated_namespace(self):
+ """
+ Create subvolume in separate rados namespace
+ """
+
+ # create subvolume
+ subvolume = self._generate_random_subvolume_name()
+ self._fs_cmd("subvolume", "create", self.volname, subvolume, "--namespace-isolated")
+
+ # get subvolume metadata
+ subvol_info = json.loads(self._get_subvolume_info(self.volname, subvolume))
+ self.assertNotEqual(len(subvol_info), 0)
+ self.assertEqual(subvol_info["pool_namespace"], "fsvolumens_" + subvolume)
+
+ # remove subvolumes
+ self._fs_cmd("subvolume", "rm", self.volname, subvolume)
+
+ # verify trash dir is clean
+ self._wait_for_trash_empty()
+
def test_subvolume_create_with_invalid_data_pool_layout(self):
subvolume = self._generate_random_subvolume_name()
data_pool = "invalid_pool"
# tests the 'fs subvolume info' command
subvol_md = ["atime", "bytes_pcent", "bytes_quota", "bytes_used", "created_at", "ctime",
- "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "type", "uid"]
+ "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "pool_namespace",
+ "type", "uid"]
# create subvolume
subvolume = self._generate_random_subvolume_name()
if subvol_info["bytes_quota"] != "infinite":
raise RuntimeError("bytes_quota should be set to infinite if quota is not set")
+ self.assertEqual(subvol_info["pool_namespace"], "")
nsize = self.DEFAULT_FILE_SIZE*1024*1024
try:
# tests the 'fs subvolume info' command for a clone
subvol_md = ["atime", "bytes_pcent", "bytes_quota", "bytes_used", "created_at", "ctime",
- "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "type", "uid"]
+ "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "pool_namespace",
+ "type", "uid"]
subvolume = self._generate_random_subvolume_name()
snapshot = self._generate_random_snapshot_name()
try:
data_pool = self.fs.getxattr(subvolpath, 'ceph.dir.layout.pool').decode('utf-8')
+ pool_namespace = self.fs.getxattr(subvolpath, 'ceph.dir.layout.pool_namespace').decode('utf-8')
except cephfs.Error as e:
raise VolumeException(-e.args[0], e.args[1])
'atime': str(st["atime"]), 'mtime': str(st["mtime"]), 'ctime': str(st["ctime"]),
'mode': int(st["mode"]), 'data_pool': data_pool, 'created_at': str(st["btime"]),
'bytes_quota': "infinite" if nsize == 0 else nsize, 'bytes_used': int(usedbytes),
- 'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0)}
+ 'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0),
+ 'pool_namespace': pool_namespace}
uid = kwargs['uid']
gid = kwargs['gid']
mode = kwargs['mode']
+ isolate_nspace = kwargs['namespace_isolated']
oct_mode = octal_str_to_decimal_int(mode)
try:
create_subvol(
- fs_handle, self.volspec, group, subvolname, size, False, pool, oct_mode, uid, gid)
+ fs_handle, self.volspec, group, subvolname, size, isolate_nspace, pool, oct_mode, uid, gid)
except VolumeException as ve:
# kick the purge threads for async removal -- note that this
# assumes that the subvolume is moved to trashcan for cleanup on error.
pool = kwargs['pool_layout']
uid = kwargs['uid']
gid = kwargs['gid']
+ isolate_nspace = kwargs['namespace_isolated']
try:
with open_volume(self, volname) as fs_handle:
# idempotent creation -- valid. Attributes set is supported.
uid = uid if uid else subvolume.uid
gid = gid if gid else subvolume.gid
- subvolume.set_attrs(subvolume.path, size, False, pool, uid, gid)
+ subvolume.set_attrs(subvolume.path, size, isolate_nspace, pool, uid, gid)
except VolumeException as ve:
if ve.errno == -errno.ENOENT:
self._create_subvolume(fs_handle, volname, group, subvolname, **kwargs)
'name=pool_layout,type=CephString,req=false '
'name=uid,type=CephInt,req=false '
'name=gid,type=CephInt,req=false '
- 'name=mode,type=CephString,req=false ',
+ 'name=mode,type=CephString,req=false '
+ 'name=namespace_isolated,type=CephBool,req=false ',
'desc': "Create a CephFS subvolume in a volume, and optionally, "
"with a specific size (in bytes), a specific data pool layout, "
- "a specific mode, and in a specific subvolume group",
+ "a specific mode, in a specific subvolume group and in separate "
+ "RADOS namespace",
'perm': 'rw'
},
{
pool_layout=cmd.get('pool_layout', None),
uid=cmd.get('uid', None),
gid=cmd.get('gid', None),
- mode=cmd.get('mode', '755'))
+ mode=cmd.get('mode', '755'),
+ namespace_isolated=cmd.get('namespace_isolated', False))
def _cmd_fs_subvolume_rm(self, inbuf, cmd):
"""