Skip to content

Zoned Block Device Emulation with nullblk

Linux® null_blk driver is a powerful tool to emulate various types of block devices for tests. Since kernel 4.19, the null_blk driver gain the ability to emulate zoned block devices. With the addition of memory backup for data read and writen to a null_blk device, this driver provides an easy to use but yet powerful tool for application development and tests.

Creating a Zoned null Block Device

The simplest method to create a null_blk emulated zoned block device is to specify the zoned=1 argument to null_blk modrpobe command line.

$ modprobe null_blk nr_devices=1 zoned=1

This creates a single host managed zoned block device with a zone size of 256M and a total capacity of 250 GB (1000 zones). No conventional zones are created with this simple command.

$ znc_report_zones /dev/nullb0
Device /dev/nullb0:
    Vendor ID: Unknown
    Zoned block device interface, Host-managed zone model
    524288000 512-bytes sectors
    524288000 logical blocks of 512 B
    524288000 physical blocks of 512 B
    268.435 GB capacity
    Read commands are unrestricted
    127 KiB max R/W size
    Maximum number of open sequential write required zones: 128
    1000 zones from 0, reporting option 0x00
1000 / 1000 zones:
Zone 00000: type 0x2 (Sequential-write-required), cond 0x1 (Empty), reset recommended 0, non_seq 0, sector 0, 524288 sectors, wp 0
Zone 00001: type 0x2 (Sequential-write-required), cond 0x1 (Empty), reset recommended 0, non_seq 0, sector 524288, 524288 sectors, wp 524288
...
Zone 00998: type 0x2 (Sequential-write-required), cond 0x1 (Empty), reset recommended 0, non_seq 0, sector 523239424, 524288 sectors, wp 523239424
Zone 00999: type 0x2 (Sequential-write-required), cond 0x1 (Empty), reset recommended 0, non_seq 0, sector 523763712, 524288 sectors, wp 523763712

null_blk Zoned Block Device Parameters

The configfs interface of the null_blk driver provides a more powerful method for creating zoned null_blk devices. The configfs of the null_blk driver can be listed with the following command.

$ cat /sys/kernel/config/nullb/features
memory_backed,discard,bandwidth,cache,badblocks,zoned,zone_size,zone_nr_conv

The parameters related to the zoned mode emulation are shown in the table below.

Argument Value Description
zoned 0 or 1 Disable or enable zoned mode (default: disabled)
zone_size size in MiB Zone size to emulate (default: 256)
zone_nr_conv number Number of conventional zones to emulate (default: 0 )

The following script shows how the configfs interface can be used to create scripts for easily creating emulated zoned block devices with different zone configurations.

#!/bin/bash

if [ $# != 4 ]; then
        echo "Usage: $0 <sect size (B)> <zone size (MB)> <nr conv zones> <nr seq zones>"
        exit 1
fi

scriptdir="$(cd "$(dirname "$0")" && pwd)"

modprobe null_blk nr_devices=0 || return $?

function create_zoned_nullb()
{
        local nid=0
        local bs=$1
        local zs=$2
        local nr_conv=$3
        local nr_seq=$4

        cap=$(( zs * (nr_conv + nr_seq) ))

        while [ 1 ]; do
                if [ ! -b "/dev/nullb$nid" ]; then
                        break
                fi
                nid=$(( nid + 1 ))
        done

        dev="/sys/kernel/config/nullb/nullb$nid"
        mkdir "$dev"

        echo $bs > "$dev"/blocksize
        echo 0 > "$dev"/completion_nsec
        echo 0 > "$dev"/irqmode
        echo 2 > "$dev"/queue_mode
        echo 1024 > "$dev"/hw_queue_depth
        echo 1 > "$dev"/memory_backed
        echo 1 > "$dev"/zoned

        echo $cap > "$dev"/size
        echo $zs > "$dev"/zone_size
        echo $nr_conv > "$dev"/zone_nr_conv

        echo 1 > "$dev"/power

        echo mq-deadline > /sys/block/nullb$nid/queue/scheduler

        echo "$nid"
}

nulldev=$(create_zoned_nullb $1 $2 $3 $4)
echo "Created /dev/nullb$nulldev"

This script (nullblk-zoned.sh) takes four arguments: the emulated device sector size in bytes, the device zone size in MiB, the number of conventional zones (which can be 0) and the number of sequential write required zones. Memory backing for writen sectors is turned on with this script (memory_backed=1) which enables run-time persistancy of the data in the writen sectors of the device. The writen data is lost when the emulated device is deleted.

For example, a small zoned device with 4 conventional zones and 8 sequential write required zones of 64 MiB can be created with the following command.

$ nullblk-zoned.sh 4096 64 4 8
Created /dev/nullb0
$ blkzone report /dev/nullb0 
  start: 0x000000000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 0(nw) [type: 1(CONVENTIONAL)]
  start: 0x000020000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 0(nw) [type: 1(CONVENTIONAL)]
  start: 0x000040000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 0(nw) [type: 1(CONVENTIONAL)]
  start: 0x000060000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 0(nw) [type: 1(CONVENTIONAL)]
  start: 0x000080000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x0000a0000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x0000c0000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x0000e0000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x000100000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x000120000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x000140000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]
  start: 0x000160000, len 0x020000, wptr 0x000000 reset:0 non-seq:0, zcond: 1(em) [type: 2(SEQ_WRITE_REQUIRED)]

The following script is the counter part of the zoned block device creationg script show above. It can be used to destroy created null_blk devices.

#!/bin/bash

if [ $# != 1 ]; then
    echo "Usage: $0 <nullb ID>"
    exit 1
fi

nid=$1

if [ ! -b "/dev/nullb$nid" ]; then
    echo "/dev/nullb$nid: No such device"
    exit 1
fi

echo 0 > /sys/kernel/config/nullb/nullb$nid/power
rmdir /sys/kernel/config/nullb/nullb$nid

echo "Destroyed /dev/nullb$nid"