#!/bin/bash
# SPDX-License-Identifier: GPL-3.0+
# Copyright (C) 2018 Omar Sandoval
#
# Test the inflight counter in /sys/block/$dev/inflight, /sys/block/$dev/stat,
# and /proc/diskstats. Regression test for commit bf0ddaba65dd "blk-mq: fix
# sysfs inflight counter".

. tests/block/rc
. common/null_blk

DESCRIPTION="do I/O and check the inflight counter"
QUICK=1
CAN_BE_ZONED=1

requires() {
	_have_null_blk
}

show_inflight() {
	awk '{ printf "sysfs inflight reads %d\nsysfs inflight writes %d\n", $1, $2 }' \
		/sys/block/nullb1/inflight
	awk '{ print "sysfs stat " $9 }' /sys/block/nullb1/stat
	awk '$3 == "nullb1" { print "diskstats " $12 }' /proc/diskstats
}

# Measure how long it takes for inflight counter check using time command.
# Convert X.YYYs time format into integer in milliseconds.
counter_check_duration_in_millis()
{
	local show_seconds sub_second seconds

	show_seconds=$( { time show_inflight > /dev/null; } 2>&1 )
	show_seconds=${show_seconds/s/}
	sub_second=${show_seconds##*.}
	sub_second=$((10#${sub_second}))
	seconds=${show_seconds%%.*}
	echo $(( seconds * 1000 + sub_second ))
}

test() {
	local io_in_millis

	echo "Running ${TEST_NAME}"

	# Prepare null_blk to measure time to check inflight counters. IOs
	# should be inflight long enough to cover counter checks twice.
	if ! _configure_null_blk nullb1 irqmode=2 power=1; then
		return 1
	fi

	io_in_millis=$(( 500 + $(counter_check_duration_in_millis) * 2 ))

	_exit_null_blk

	# Prepare null_blk again with desired IO inflight duration
	if ! _configure_null_blk nullb1 irqmode=2 \
	     completion_nsec=$((io_in_millis * 1000 * 1000)) power=1; then
		return 1
	fi

	dd if=/dev/nullb1 of=/dev/null bs=4096 iflag=direct count=1 status=none &
	sleep 0.1
	show_inflight

	dd if=/dev/zero of=/dev/nullb1 bs=4096 oflag=direct count=1 status=none &
	sleep 0.1
	show_inflight

	wait
	show_inflight

	_exit_null_blk

	echo "Test complete"
}
