#!/bin/bash
# SPDX-License-Identifier: GPL-3.0+
# Copyright (C) 2024, Oracle and/or its affiliates.
#
# Test to detect a race between loop detach and loop open which creates
# stale loop partitions when one process opens the loop partition and
# another process detaches the loop device.
#
# Regression test for commit:
# 18048c1af783 loop: Fix a race between loop detach and loop open

. tests/loop/rc
DESCRIPTION="check stale loop partition"
TIMED=1

requires() {
	_have_kver 6 11
	_have_program parted
	_have_program mkfs.xfs
}

create_loop() {
	local dev=$1

	while true
	do
		if losetup --partscan "$dev" "${image_file}" &> /dev/null; then
			blkid "$dev"p1 >& /dev/null
		fi
	done
}

detach_loop() {
	local dev=$1

	while true
	do
		if [[ -e "$dev" ]]; then
			losetup --detach "$dev" >& /dev/null
		fi
	done
}

test() {
	echo "Running ${TEST_NAME}"
	local loop_device
	local create_pid
	local detach_pid
	local image_file="$TMPDIR/loopImg"
	local grep_str

	truncate --size 1G "${image_file}"
	parted --align none --script "${image_file}" mklabel gpt
	loop_device="$(losetup --partscan --find --show "${image_file}")"
	parted --align none --script "${loop_device}" mkpart primary 64s 109051s

	udevadm settle

	if [ ! -e "${loop_device}" ]; then
		return 1
	fi

	mkfs.xfs --force "${loop_device}p1" >& /dev/null
	losetup --detach "${loop_device}" >&  /dev/null

	# This test generates udev events faster than the rate at which udevd
	# can process events. Stop systemd-udevd to prevent future test cases
	# fail.
	_systemd_stop_udevd

	create_loop "${loop_device}" &
	create_pid=$!
	detach_loop "${loop_device}" &
	detach_pid=$!

	sleep "${TIMEOUT:-90}"
	{
		kill -9 $create_pid
		wait $create_pid
		kill -9 $detach_pid
		wait $detach_pid
		sleep 1
	} 2>/dev/null

	losetup --detach "${loop_device}" >& /dev/null
	grep_str="partition scan of ${loop_device##*/} failed (rc=-16)"
	if _dmesg_since_test_start | grep --quiet "$grep_str"; then
		echo "Fail"
	fi

	_systemd_start_udevd

	echo "Test complete"
}
