#!/bin/bash # Simple management of null_blk devices, useful for zoned device testing # Version: 0.1 # # Commands: # # nullb setup # - load required modules and mount configfs # # nullb create [-s size] [-z zonesize] # - create a new device with given sizes, allocating the first free index, # device is /dev/nullb$index # # nullb ls # nullb list # - show table of created null_blk devices, size and zone sizes # # nullb rm NAME # nullb delete NAME # - delete existing null_blk device by name, must match the device node name # like 'nullb0' CMD="$1" DEBUG=false # Defaults SIZE='2048' ZONESIZE='256' SYSFS='/sys/kernel/config/nullb' # create # list # delete # setup function _error() { echo "ERROR: $@" exit 1 } function _warn() { echo "WARNING: $@" } function _msg() { echo "INFO: $@" } function _dbg() { $DEBUG && echo "DEBUG: $@" > /dev/tty } function _check_setup() { if ! modinfo -n null_blk > /dev/null; then _error "module not compiled/loaded" fi if ! grep -q configfs /proc/filesystems; then _error "configfs not mounted" fi if ! grep -q zoned "$SYSFS/features"; then _warn "null_blk module does not support zoned devices" fi } function _check_cd() { if ! [ -d "$1" ]; then _error "$1 not accessible" fi cd "$1" } function _find_free_index() { _check_cd "$SYSFS" found=-1 for index in `seq 0 1 10`; do _dbg "index $index" ok=true for dir in $(ls -df1 * 2>/dev/null); do if ! [ -d "$dir" ]; then continue fi _dbg "found $dir" idx=$(cat "$dir/index") if [ "$idx" = "$index" ]; then ok=false break fi done if $ok; then found=$index break fi done if [ "$found" = "-1" ]; then _error "no free index found" fi _dbg "first free index: $found" echo -n "$found" } function _parse_device_size() { local size="$SIZE" _dbg "parse size $@" while [ $# -gt 0 ]; do _dbg "ARG: $1" if [ "$1" = '-s' ]; then size="$2" if [ -z "$size" ]; then _error "-s requires size" fi shift fi shift done echo -en "$size" } function _parse_zone_size() { local zonesize="$ZONESIZE" _dbg "parse zone size $@" while [ $# -gt 0 ]; do _dbg "ARG: $1" if [ "$1" = '-z' ]; then zonesize="$2" if [ -z "$zonesize" ]; then _error "-z requires size" fi shift fi shift done echo -en "$zonesize" } # main() if [ "$CMD" = 'setup' ]; then _msg "setup module and mounts" modprobe configfs modprobe null_blk nr_devices=0 _check_setup fi if [ "$CMD" = 'create' ]; then _check_setup index=$(_find_free_index) name="nullb$index" # size in MB size=$(_parse_device_size "$@") # size in MB zonesize=$(_parse_zone_size "$@") _msg "Create nullb$index" _check_cd "$SYSFS" if mkdir "$name"; then _check_cd "$name" echo "$size" > size echo 1 > zoned echo 1 > memory_backed echo "$zonesize" > zone_size echo 1 > power node=$(cat "$SYSFS/$name/index") node="nullb${node}" _msg "name=$node" _msg "size=${size}M zone_size=${zonesize}M" # last printed line is the exact name for later use echo "/dev/$node" else _error "already exists" fi fi if [ "$CMD" = 'ls' -o "$CMD" = 'list' ]; then _msg "device nodes:" ls /dev/nullb* 2>/dev/null _msg "created devices:" _check_cd "$SYSFS" printf '%-2s %-8s %-16s %11s %11s %-2s ' \ "No" \ "Name" \ "Device" \ "Size" \ "Zone size" \ "On" for dir in $(ls -df1 * 2>/dev/null); do [ -d "$dir" ] || continue printf '%2d %-8s %-16s %10dM %10dM %2d ' \ $(cat "$dir/index") \ "$dir" \ "/dev/nullb"$(cat "$dir/index") \ $(cat "$dir/size") \ $(cat "$dir/zone_size") \ $(cat "$dir/power") done fi if [ "$CMD" = 'rm' -o "$CMD" = 'delete' ]; then _check_cd "$SYSFS" name="$2" _dbg "deleting $name" if [ -d "$name" ]; then _msg "check mounts" mount | grep -- "$name" _msg "removing $name" rmdir -- "$SYSFS/$name" else _error "no such device name: $name" fi fi