diff --git a/diskimage_builder/block_device/blockdevice.py b/diskimage_builder/block_device/blockdevice.py
index 42d730d77..ad337c677 100644
--- a/diskimage_builder/block_device/blockdevice.py
+++ b/diskimage_builder/block_device/blockdevice.py
@@ -30,6 +30,47 @@ logger = logging.getLogger(__name__)
 
 
 class BlockDevice(object):
+    """Handles block devices.
+
+    This class handles the complete setup and deletion of all aspects
+    of the block device level.
+
+    A typical call sequence:
+
+    cmd_create: creates all the different aspects of the block
+       device. When this call is successful, the complete block level
+       device is set up, filesystems are created and are mounted at
+       the correct position.
+       After this call it is possible to copy / install all the needed
+       files into the appropriate directories.
+
+    cmd_umount: unmount and detaches all directories and used many
+       resources. After this call the used (e.g.) images are still
+       available for further handling, e.g. converting from raw in
+       some other format.
+
+    cmd_cleanup: removes everything that was created with the
+       'cmd_create' call, i.e. all images files themselves and
+       internal temporary configuration.
+
+    cmd_delete: unmounts and removes everything that was created
+       during the 'cmd_create' all.  This call should be used in error
+       conditions when there is the need to remove all allocated
+       resources immediately and as good as possible.
+       From the functional point of view this is mostly the same as a
+       call to 'cmd_umount' and 'cmd_cleanup' - but is typically more
+       error tolerance.
+
+    In a script this should be called in the following way:
+
+    dib-block-device --phase=create ...
+    trap "dib-block-device --phase=delete ..." EXIT
+    # copy / install files
+    dib-block-device --phase=umount ...
+    # convert image(s)
+    dib-block-device --phase=cleanup ...
+    trap - EXIT
+    """
 
     # Default configuration:
     # one image, one partition, mounted under '/'
diff --git a/diskimage_builder/block_device/level1/partitioning.py b/diskimage_builder/block_device/level1/partitioning.py
index 36284af21..9fe9d82f8 100644
--- a/diskimage_builder/block_device/level1/partitioning.py
+++ b/diskimage_builder/block_device/level1/partitioning.py
@@ -19,6 +19,8 @@ from diskimage_builder.block_device.utils import parse_abs_size_spec
 from diskimage_builder.block_device.utils import parse_rel_size_spec
 from diskimage_builder.graph.digraph import Digraph
 import logging
+import os
+import subprocess
 
 
 logger = logging.getLogger(__name__)
@@ -148,6 +150,51 @@ class Partitioning(object):
         for _, part in self.partitions.items():
             dg.add_node(part)
 
+    def _exec_sudo(self, cmd):
+        sudo_cmd = ["sudo"]
+        sudo_cmd.extend(cmd)
+        logger.info("Calling [%s]" % " ".join(sudo_cmd))
+        subp = subprocess.Popen(sudo_cmd)
+        rval = subp.wait()
+        if rval != 0:
+            logger.error("Calling [%s] failed with [%s]" %
+                         (" ".join(sudo_cmd), rval))
+            logger.error("Trying to continue")
+
+    def _all_part_devices_exist(self, expected_part_devices):
+        for part_device in expected_part_devices:
+            logger.debug("Checking if partition device [%s] exists" %
+                         part_device)
+            if not os.path.exists(part_device):
+                logger.info("Partition device [%s] does not exists"
+                            % part_device)
+                return False
+            logger.debug("Partition already exists [%s]" % part_device)
+        return True
+
+    def _notify_os_of_partition_changes(self, device_path, partition_devices):
+        """Notify of of partition table changes
+
+        There is the need to call some programs to inform the operating
+        system of partition tables changes.
+        These calls are highly distribution and version specific. Here
+        a couple of different methods are used to get the best result.
+        """
+        self._exec_sudo(["partprobe", device_path])
+        self._exec_sudo(["udevadm", "settle"])
+
+        if self._all_part_devices_exist(partition_devices):
+            return
+        # If running inside Docker, make our nodes manually, because udev
+        # will not be working.
+        if os.path.exists("/.dockerenv"):
+            # kpartx cannot run in sync mode in docker.
+            self._exec_sudo(["kpartx", "-av", device_path])
+            self._exec_sudo(["dmsetup", "--noudevsync", "mknodes"])
+            return
+
+        self._exec_sudo(["kpartx", "-avs", device_path])
+
     def create(self, result, rollback):
         image_path = result[self.base]['image']
         device_path = result[self.base]['device']
@@ -160,6 +207,7 @@ class Partitioning(object):
 
         assert self.label == 'mbr'
 
+        partition_devices = set()
         disk_size = self._size_of_block_dev(image_path)
         with MBR(image_path, disk_size, self.align) as part_impl:
             for part_name, part_cfg in self.partitions.items():
@@ -178,7 +226,10 @@ class Partitioning(object):
                                               part_size, part_type)
                 logger.debug("Create partition [%s] [%d]" %
                              (part_name, part_no))
-                result[part_name] = {'device': device_path + "p%d" % part_no}
+                partition_device_name = device_path + "p%d" % part_no
+                result[part_name] = {'device': partition_device_name}
+                partition_devices.add(partition_device_name)
 
         self.already_created = True
+        self._notify_os_of_partition_changes(device_path, partition_devices)
         return
diff --git a/diskimage_builder/lib/disk-image-create b/diskimage_builder/lib/disk-image-create
index 5f9fcb7ab..de52b7f5e 100644
--- a/diskimage_builder/lib/disk-image-create
+++ b/diskimage_builder/lib/disk-image-create
@@ -415,31 +415,6 @@ export EXTRA_DETACH="detach_loopback ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}"
 export EXTRA_UNMOUNT="dib-block-device --phase=cleanup \
                       --build-dir=\"${TMP_BUILD_DIR}\""
 
-# Create the partitions and make them visible to the system
-
-sudo partprobe $IMAGE_BLOCK_DEVICE_WITHOUT_PART
-
-# To ensure no race conditions exist from calling partprobe
-sudo udevadm settle
-
-# If the partition isn't under /dev/loop*p1, create it with kpartx
-DM=
-if [ ! -e "${IMAGE_BLOCK_DEVICE}" ]; then
-    DM=${IMAGE_BLOCK_DEVICE/#\/dev/\/dev\/mapper}
-    # If running inside Docker, make our nodes manually, because udev will not be working.
-    if [ -f /.dockerenv ]; then
-        # kpartx cannot run in sync mode in docker.
-        sudo kpartx -av ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
-        sudo dmsetup --noudevsync mknodes
-    else
-        sudo kpartx -asv ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
-    fi
-elif [[ "$ARCH" =~ "ppc" ]]; then
-    sudo kpartx -asv ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
-fi
-
-# End: Creation of the partitions
-
 sudo mkfs -t $FS_TYPE $MKFS_OPTS -L ${DIB_ROOT_LABEL} ${IMAGE_BLOCK_DEVICE}
 # Tuning the rootfs uuid works only for ext filesystems.
 if echo "$FS_TYPE" | grep -q "^ext"; then