Browse files

ZVOLs should not be allowed to have children

zfs create, receive and rename can bypass this hierarchy rule. Update
both userland and kernel module to prevent this issue and use pyzfs
unit tests to exercise the ioctls directly.

Note: this commit slightly changes zfs_ioc_create() ABI. This allow to
differentiate a generic error (EINVAL) from the specific case where we
tried to create a dataset below a ZVOL (ENOTDIR).

Signed-off-by: loli10K <>
  • Loading branch information...
loli10K committed Dec 4, 2018
1 parent 8bd2a28 commit 08babfc6f49c34cf83a956ae1beb2a5213892705
@@ -46,13 +46,14 @@ def lzc_create_translate_error(ret, name, ds_type, props):
if ret == 0:
if ret == errno.EINVAL:
# XXX: should raise lzc_exc.WrongParent if parent is ZVOL
raise lzc_exc.PropertyInvalid(name)
if ret == errno.EEXIST:
raise lzc_exc.FilesystemExists(name)
if ret == errno.ENOENT:
raise lzc_exc.ParentNotFound(name)
if ret == errno.ENOTDIR:
raise lzc_exc.WrongParent(_fs_name(name))
raise _generic_exception(ret, name, "Failed to create filesystem")

@@ -444,6 +445,8 @@ def _map(ret, name):
raise lzc_exc.SuspendedPool(_pool_name(snapname))
if ret == errno.EBADE: # ECKSUM
raise lzc_exc.BadStream()
if ret == errno.ENOTDIR:
raise lzc_exc.WrongParent(_fs_name(snapname))

raise lzc_exc.StreamIOError(ret)

@@ -596,6 +599,8 @@ def lzc_rename_translate_error(ret, source, target):
raise lzc_exc.FilesystemExists(target)
if ret == errno.ENOENT:
raise lzc_exc.FilesystemNotFound(source)
if ret == errno.ENOTDIR:
raise lzc_exc.WrongParent(target)
raise _generic_exception(ret, source, "Failed to rename dataset")

@@ -754,6 +754,8 @@ def lzc_receive(snapname, fd, force=False, raw=False, origin=None, props=None):
supported on this side.
:raises NameInvalid: if the name of either snapshot is invalid.
:raises NameTooLong: if the name of either snapshot is too long.
:raises WrongParent: if the parent dataset of the received destination is
not a filesystem (e.g. ZVOL)
.. note::
The ``origin`` is ignored if the actual stream is an incremental stream
@@ -1621,6 +1623,8 @@ def lzc_rename(source, target):
:raises FilesystemNotFound: if the target's parent does not exist.
:raises FilesystemExists: if the target already exists.
:raises PoolsDiffer: if the source and target belong to different pools.
:raises WrongParent: if the "new" parent dataset is not a filesystem
(e.g. ZVOL)
ret = _lib.lzc_rename(source, target)
errors.lzc_rename_translate_error(ret, source, target)
@@ -140,7 +140,7 @@ def __init__(self, name):

class WrongParent(ZFSError):
errno = errno.EINVAL
errno = errno.ENOTDIR
message = "Parent dataset is not a filesystem"

def __init__(self, name):
Oops, something went wrong.

0 comments on commit 08babfc

Please sign in to comment.