mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Dave Jiang <dave.jiang@intel.com>
To: Anisa Su <anisa.su887@gmail.com>,
	linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: nvdimm@lists.linux.dev, Dan Williams <djbw@kernel.org>,
	Jonathan Cameron <jic23@kernel.org>,
	Davidlohr Bueso <dave@stgolabs.net>,
	Ira Weiny <iweiny@kernel.org>,
	Alison Schofield <alison.schofield@intel.com>,
	John Groves <John@Groves.net>, Gregory Price <gourry@gourry.net>,
	Ira Weiny <ira.weiny@intel.com>
Subject: Re: [PATCH v6 7/7] cxl/test: Add Dynamic Capacity tests
Date: Mon, 8 Jun 2026 17:24:08 -0700	[thread overview]
Message-ID: <d58b398a-eba8-4b4e-b1ab-cfed64fe11e8@intel.com> (raw)
In-Reply-To: <20260523095043.471098-8-anisa.su@samsung.com>



On 5/23/26 2:50 AM, Anisa Su wrote:
> From: Ira Weiny <ira.weiny@intel.com>
> 
> cxl_test provides a good way to ensure quick smoke and regression
> testing.  The complexity of DCD and the new sparse DAX regions
> required to use them benefits greatly with a series of smoke tests.
> 
> The only part of the kernel stack which must be bypassed is the actual
> irq of DCD events.  However, the event processing itself can be tested
> via cxl_test calling directly into the event processing.
> 
> In this way the rest of the stack; management of sparse regions, the
> extent device lifetimes, and the dax device operations can be tested.
> 
> Add Dynamic Capacity Device tests for kernels which have DCD support.
> 
> Signed-off-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Anisa Su <anisa.su887@gmail.com>

A nit below. Otherwise

Reviewed-by: Dave Jiang <dave.jiang@intel.com>


> 
> ---
> Changes:
> [anisa: align tests with kernel DCD redesign + add sharable coverage]
> 
> Rewrite tests against the post-redesign kernel (uuid sysfs claim,
> sparse size-grow rejection, tag-group atomic release, cross-More
> uniqueness):
> 
>   - Use real UUID strings; route untagged claims via --uuid "0" so
>     daxctl exercises the kernel uuid_store path end to end.
>   - Pre-existing-extent test handles the tagged pre2_ext (deadbeef)
>     separately from the untagged pre_ext.
>   - Spanning / aggregation tests drive both extents in one More-chain:
>     cross-event tagged adds are dropped by the cross-More uniqueness
>     gate, and untagged events become independent dax_resources so
>     only one is claimed per --uuid "0".
>   - test_dax_device_ops asserts that sparse size grow returns
>     -EOPNOTSUPP after a shrink (real grow path is --uuid only).
>   - test_reject_overlapping math now produces an actual overlap
>     inside the DC region (the prior arithmetic landed past the end).
> 
> Add coverage for new validators:
>   - test_uuid_no_match / test_uuid_no_match_seed_intact
>   - test_uuid_show (reads back the dax-dev uuid sysfs attribute)
>   - test_cross_more_uniqueness (rejects tag reuse across More-chains)
>   - test_alignment_rejection (rejects misaligned extents)
> 
> Sharable-partition coverage (test_shared_extent_inject,
> test_seq_integrity_gap) is routed at runtime to a dedicated mock
> memdev that tools/testing/cxl stamps with serial 0xDCDC; the script
> enumerates both regimes from one cxl_test module load.
> 
> Localize positional-arg assignments in every helper so functions
> no longer clobber caller globals (the previous behavior leaked
> the sharable memdev into later tests).
> 
> Update inject_extent to optionally pass shared_extn_seq (5th arg)
> and remove_extent to carry the tag (now required by the mock's
> delete sysfs).  Add inject_shared_extent for dc_inject_shared_extent.
> ---
>  test/cxl-dcd.sh  | 1267 ++++++++++++++++++++++++++++++++++++++++++++++
>  test/meson.build |    2 +
>  2 files changed, 1269 insertions(+)
>  create mode 100644 test/cxl-dcd.sh
> 
> diff --git a/test/cxl-dcd.sh b/test/cxl-dcd.sh
> new file mode 100644
> index 0000000..3194b00
> --- /dev/null
> +++ b/test/cxl-dcd.sh
> @@ -0,0 +1,1267 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2024 Intel Corporation. All rights reserved.
> +
> +. "$(dirname "$0")/common"
> +
> +rc=77
> +set -ex
> +
> +trap 'err $LINENO' ERR
> +
> +check_prereq "jq"
> +
> +rc=1
> +
> +dev_path="/sys/bus/platform/devices"
> +cxl_path="/sys/bus/cxl/devices"
> +
> +# test extent tags (UUIDs).  pre_ext_tag matches the second pre-injected
> +# extent tag in the kernel mock (tools/testing/cxl/test/mem.c).
> +pre_ext_tag="deadbeef-cafe-baad-f00d-fedcba987654"
> +test_tag_a="11111111-1111-1111-1111-111111111111"
> +test_tag_b="22222222-2222-2222-2222-222222222222"
> +unknown_tag="33333333-3333-3333-3333-333333333333"
> +
> +#
> +# The test devices have 2G of non DC capacity.  A single DC reagion of 1G is
> +# added beyond that.
> +#
> +# The testing centers around 3 extents.  Two are "pre-existing" on test load
> +# called pre-ext and pre2-ext.  The other is created within this script alone
> +# called base.
> +
> +#
> +# | 2G non- |      DC region (1G)                                   |
> +# |  DC cap |                                                       |
> +# |  ...    |-------------------------------------------------------|
> +# |         |--------|       |----------|      |----------|         |
> +# |         | (base) |       |(pre-ext) |      |(pre2-ext)|         |
> +
> +dra_size=""
> +
> +base_dpa=0x80000000
> +
> +# base extent at dpa 2G - 64M long
> +base_ext_offset=0x0
> +base_ext_dpa=$(($base_dpa + $base_ext_offset))
> +base_ext_length=0x4000000
> +
> +# pre existing extent base + 128M, 64M length
> +# 0x00000088000000-0x0000008bffffff
> +pre_ext_offset=0x8000000
> +pre_ext_dpa=$(($base_dpa + $pre_ext_offset))
> +pre_ext_length=0x4000000
> +
> +# pre2 existing extent base + 256M, 64M length
> +# 0x00000090000000-0x00000093ffffff
> +pre2_ext_offset=0x10000000
> +pre2_ext_dpa=$(($base_dpa + $pre2_ext_offset))
> +pre2_ext_length=0x4000000
> +
> +mem=""
> +bus=""
> +device=""
> +decoder=""
> +
> +# ========================================================================
> +# Support functions
> +# ========================================================================
> +
> +create_dcd_region()
> +{
> +	local mem="$1"
> +	local decoder="$2"
> +	local reg_size_string=""
> +	local region
> +	if [ "$3" != "" ]; then
> +		reg_size_string="-s $3"
> +	fi
> +
> +	# create region
> +	region=$($CXL create-region -t dynamic_ram_a -d "$decoder" -m "$mem" ${reg_size_string} | jq -r ".region")
> +
> +	if [[ ! $region ]]; then
> +		echo "create-region failed for $decoder / $mem"
> +		err "$LINENO"
> +	fi
> +
> +	echo ${region}
> +}
> +
> +check_region()
> +{
> +	local search=$1
> +	local region_size=$2
> +	local result
> +
> +	result=$($CXL list -r "$search" | jq -r ".[].region")
> +	if [ "$result" != "$search" ]; then
> +		echo "check region failed to find $search"
> +		err "$LINENO"
> +	fi
> +
> +	result=$($CXL list -r "$search" | jq -r ".[].size")
> +	if [ "$result" != "$region_size" ]; then
> +		echo "check region failed invalid size $result != $region_size"
> +		err "$LINENO"
> +	fi
> +}
> +
> +check_not_region()
> +{
> +	local search=$1
> +	local result
> +
> +	result=$($CXL list -r "$search" | jq -r ".[].region")
> +	if [ "$result" == "$search" ]; then
> +		echo "check not region failed; $search found"
> +		err "$LINENO"
> +	fi
> +}
> +
> +destroy_region()
> +{
> +	local region=$1
> +	$CXL disable-region $region
> +	$CXL destroy-region $region
> +}
> +
> +inject_extent()
> +{
> +	local device="$1"
> +	local dpa="$2"
> +	local length="$3"
> +	local tag="$4"
> +	local seq="$6"
> +	local more="0"
> +	local cmd
> +
> +	if [ "$5" != "" ]; then
> +		more="1"
> +	fi
> +
> +	cmd="${dpa}:${length}:${tag}:${more}"
> +	if [ -n "$seq" ]; then
> +		cmd="${cmd}:${seq}"
> +	fi
> +	echo ${cmd} > "${dev_path}/${device}/dc_inject_extent"
> +}
> +
> +# Shared-extent inject targets a *sharable* DC partition.  The mock
> +# stamps the sentinel serial onto a single cxl_mem instance, and the
> +# script routes shared-extent tests to that memdev via $sharable_device.
> +inject_shared_extent()
> +{
> +	local device="$1"
> +	local dpa="$2"
> +	local length="$3"
> +	local tag="$4"
> +	local seq="$6"
> +	local more="0"
> +	local cmd
> +
> +	if [ "$5" != "" ]; then
> +		more="1"
> +	fi
> +
> +	cmd="${dpa}:${length}:${tag}:${more}"
> +	if [ -n "$seq" ]; then
> +		cmd="${cmd}:${seq}"
> +	fi
> +	echo ${cmd} > "${dev_path}/${device}/dc_inject_shared_extent"
> +}
> +
> +remove_extent()
> +{
> +	local device="$1"
> +	local dpa="$2"
> +	local length="$3"
> +	local tag="$4"
> +
> +	echo ${dpa}:${length}:${tag} > "${dev_path}/${device}/dc_del_extent"
> +}
> +
> +create_dax_dev()
> +{
> +	local reg="$1"
> +	local dax_dev
> +
> +	dax_dev=$($DAXCTL create-device -r $reg | jq -er '.[].chardev')
> +
> +	echo ${dax_dev}
> +}
> +
> +create_dax_dev_with_uuid()
> +{
> +	local reg="$1"
> +	local uuid="$2"
> +	local dax_dev
> +
> +	dax_dev=$($DAXCTL create-device -r $reg --uuid "$uuid" \
> +			| jq -er '.[].chardev')
> +
> +	echo ${dax_dev}
> +}
> +
> +fail_create_dax_dev_with_uuid()
> +{
> +	local reg="$1"
> +	local uuid="$2"
> +	local create_rc
> +
> +	set +e
> +	$DAXCTL create-device -r $reg --uuid "$uuid"
> +	create_rc=$?
> +	set -e
> +	if [ $create_rc -eq 0 ]; then
> +		echo "FAIL create-device with uuid $uuid unexpectedly succeeded"
> +		err "$LINENO"
> +	fi
> +}
> +
> +fail_create_dax_dev()
> +{
> +	local reg="$1"
> +	local result
> +
> +	set +e
> +	result=$($DAXCTL create-device -r $reg)
> +	set -e
> +	if [ "$result" == "0" ]; then
> +		echo "FAIL device created"
> +		err "$LINENO"
> +	fi
> +}
> +
> +# Try to resize a sparse dax device via reconfigure -s; must fail because
> +# the kernel rejects any non-zero size_store on a dynamic dax region with
> +# -EOPNOTSUPP (drivers/dax/bus.c:dev_dax_resize).  The only valid resize is
> +# to size 0, which is the path `daxctl destroy-device` takes.
> +fail_resize_dax_dev()
> +{
> +	local dev="$1"
> +	local new_size="$2"
> +	local resize_rc
> +
> +	$DAXCTL disable-device $dev
> +	set +e
> +	$DAXCTL reconfigure-device $dev -s $new_size
> +	resize_rc=$?
> +	set -e
> +	# Re-enable regardless so subsequent checks/cleanup work.
> +	$DAXCTL enable-device $dev
> +	if [ $resize_rc -eq 0 ]; then
> +		echo "FAIL resize of $dev to $new_size unexpectedly succeeded"
> +		err "$LINENO"
> +	fi
> +}
> +
> +# Read /sys/bus/dax/devices/<dax>/uuid and compare to $expected.  "0"
> +# matches the null UUID (kernel emits "0\n" when the resource is empty,
> +# untagged, or non-DCD).
> +check_dax_uuid()
> +{
> +	local dax_dev="$1"
> +	local expected="$2"
> +	local uuid_path got want
> +
> +	uuid_path="/sys/bus/dax/devices/${dax_dev}/uuid"
> +	if [ ! -e "$uuid_path" ]; then
> +		echo "FAIL no uuid attribute at $uuid_path"
> +		err "$LINENO"
> +	fi
> +	got=$(cat "$uuid_path" | tr -d '[:space:]')
> +	want=$(echo "$expected" | tr -d '[:space:]')
> +	if [ "$got" != "$want" ]; then
> +		echo "FAIL uuid show on $dax_dev: got '$got' want '$want'"
> +		err "$LINENO"
> +	fi
> +}
> +
> +destroy_dax_dev()
> +{
> +	local dev="$1"
> +
> +	$DAXCTL disable-device $dev
> +	$DAXCTL destroy-device $dev
> +}
> +
> +check_dax_dev()
> +{
> +	local search="$1"
> +	local size=$(($2))
> +	local result
> +
> +	result=$($DAXCTL list -d $search | jq -er '.[].chardev')
> +	if [ "$result" != "$search" ]; then
> +		echo "check dax device failed to find $search"
> +		err "$LINENO"
> +	fi
> +	result=$($DAXCTL list -d $search | jq -er '.[].size')
> +	if [ "$result" -ne "$size" ]; then
> +		echo "check dax device failed incorrect size $result; exp $size"
> +		err "$LINENO"
> +	fi
> +}
> +
> +# check that the dax device is not there.
> +check_not_dax_dev()
> +{
> +	local reg="$1"
> +	local search="$2"
> +	local result
> +	result=$($DAXCTL list -r $reg -D | jq -r '.[].chardev')
> +	if [ "$result" == "$search" ]; then
> +		echo "FAIL found $search"
> +		err "$LINENO"
> +	fi
> +}
> +
> +check_extent()
> +{
> +	local region=$1
> +	local offset=$(($2))
> +	local length=$(($3))
> +	local result
> +
> +	result=$($CXL list -r "$region" -N | jq -r ".[].extents[] | select(.offset == ${offset}) | .length")
> +	if [[ $result != $length ]]; then
> +		echo "FAIL region $1 could not find extent @ $offset ($length)"
> +		err "$LINENO"
> +	fi
> +}
> +
> +check_extent_cnt()
> +{
> +	local region=$1
> +	local count=$(($2))
> +	local result
> +
> +	result=$($CXL list -r $region -N | jq -r '.[].extents[].offset' | wc -l)
> +	if [[ $result != $count ]]; then
> +		echo "FAIL region $1: found wrong number of extents $result; expect $count"
> +		err "$LINENO"
> +	fi
> +}
> +
> +
> +# ========================================================================
> +# Tests
> +# ========================================================================
> +
> +# testing pre existing extents must be called first as the extents were created
> +# by cxl-test being loaded.  The mock fixture is one untagged extent at
> +# pre_ext_dpa and one tagged (pre_ext_tag) extent at pre2_ext_dpa, so the
> +# untagged extent is claimed via --uuid "0" and the tagged one via its UUID.
> +test_pre_existing_extents()
> +{
> +	echo ""
> +	echo "Test: pre-existing extents (untagged + tagged)"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                   |----------|         |----------|   |
> +	# |         |                   |(pre-ext) |         |(pre2-ext)|   |
> +	# |         |                   | untagged |         | tagged   |   |
> +	check_region ${region} ${dra_size}
> +	check_extent ${region} ${pre_ext_offset} ${pre_ext_length}
> +	check_extent ${region} ${pre2_ext_offset} ${pre2_ext_length}
> +
> +	# Untagged claim picks up the untagged pre-extent only
> +	dax_dev_u=$(create_dax_dev_with_uuid ${region} "0")
> +	check_dax_dev ${dax_dev_u} $pre_ext_length
> +
> +	# Tagged claim picks up the tagged pre2-extent
> +	dax_dev_t=$(create_dax_dev_with_uuid ${region} "$pre_ext_tag")
> +	check_dax_dev ${dax_dev_t} $pre2_ext_length
> +
> +	destroy_dax_dev ${dax_dev_u}
> +	destroy_dax_dev ${dax_dev_t}
> +
> +	# Release events must carry the tag identity so cxl_rm_extent's
> +	# uuid_equal lookup matches the right region_extent.
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	remove_extent ${device} $pre2_ext_dpa $pre2_ext_length "$pre_ext_tag"
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_remove_extent_under_dax_device()
> +{
> +	# Remove the pre-created test extent out from under dax device
> +	# stack should hold ref until dax device deleted
> +	echo ""
> +	echo "Test: Remove extent from under DAX dev"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                                                       |
> +	# |         |                                                       |
> +
> +	
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	# |         |                   |----------|                        |
> +	# |         |                   |(pre-ext) |                        |
> +	check_extent ${region} ${pre_ext_offset} ${pre_ext_length}
> +
> +	# Sparse seed starts at size 0; --uuid "0" is the only sizing path.
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "0")
> +	# |         |                   |----------|                        |
> +	# |         |                   |(pre-ext) |                        |
> +	# |         |                   | daxX.1   |                        |
> +	check_extent_cnt ${region} 1
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	# In-use extents are not released (dax-layer EBUSY defers release).
> +	check_dax_dev ${dax_dev} $pre_ext_length
> +
> +	check_extent_cnt ${region} 1
> +	destroy_dax_dev ${dax_dev}
> +	# |         |                   |----------|                        |
> +	# |         |                   |(pre-ext) |                        |
> +	check_not_dax_dev ${region} ${dax_dev}
> +
> +	check_extent_cnt ${region} 1
> +	# Re-issuing the release after the dax device dropped its hold
> +	# completes the deferred release.
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	# |         |                                                       |
> +	# |         |                                                       |
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_remove_extents_in_use()
> +{
> +	echo ""
> +	echo "Test: Remove extents under sparse dax device"
> +	echo ""
> +	# Tagged release events are deferred while a dax device pins the
> +	# tag group; extent count stays at 2.
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 2
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 2
> +}
> +
> +test_create_dax_dev_spanning_two_extents()
> +{
> +	echo ""
> +	echo "Test: Create dax device spanning 2 extents in a tagged group"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	#
> +	# A single dax device spanning two extents is only possible when
> +	# both extents belong to the same tagged More-chain.  Cross-event
> +	# tagged adds are rejected by the cross-More uniqueness gate;
> +	# untagged adds become independent dax_resources and only one is
> +	# claimed per --uuid "0".  Drive both extents in one More-chain:
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a" 1
> +	check_extent_cnt ${region} 0   # held off until More=0 closes chain
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	check_extent ${region} ${pre_ext_offset} ${pre_ext_length}
> +	check_extent ${region} ${base_ext_offset} ${base_ext_length}
> +	# |         |--------|          |----------|                        |
> +	# |         | (base) |          |(pre-ext) |     tag_a              |
> +
> +	check_extent_cnt ${region} 2
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	# |         |--------|          |----------|                        |
> +	# |         | (base) |          |(pre-ext) |                        |
> +	# |         | daxX.1 |          | daxX.1   |                        |
> +
> +	echo "Checking if dev dax is spanning sparse extents"
> +	ext_sum_length="$(($base_ext_length + $pre_ext_length))"
> +	check_dax_dev ${dax_dev} $ext_sum_length
> +
> +	test_remove_extents_in_use
> +
> +	destroy_dax_dev ${dax_dev}
> +	check_not_dax_dev ${region} ${dax_dev}
> +
> +	# In-use extents were not released.  Check they can be removed after
> +	# the dax device is removed.
> +	check_extent_cnt ${region} 2
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_inject_tag_support()
> +{
> +	echo ""
> +	echo "Test: inject untagged + tagged extents, claim each via --uuid"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# untagged extent
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	check_extent ${region} ${pre_ext_offset} ${pre_ext_length}
> +	# tagged extent (different DPA so both can land)
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +
> +	# both extents should be accepted
> +	check_extent_cnt ${region} 2
> +
> +	# claim the tagged extent into one dax device
> +	dax_dev_a=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	check_dax_dev ${dax_dev_a} $base_ext_length
> +
> +	# claim the untagged extent into a second dax device via "0"
> +	dax_dev_0=$(create_dax_dev_with_uuid ${region} "0")
> +	check_dax_dev ${dax_dev_0} $pre_ext_length
> +
> +	destroy_dax_dev ${dax_dev_a}
> +	destroy_dax_dev ${dax_dev_0}
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 0
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_uuid_no_match()
> +{
> +	echo ""
> +	echo "Test: daxctl create-device --uuid with no matching extent fails"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# inject only one tagged extent; ask daxctl to claim a different uuid
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 1
> +
> +	fail_create_dax_dev_with_uuid ${region} "$unknown_tag"
> +
> +	# the extent should still be claimable via its real tag
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	check_dax_dev ${dax_dev} $pre_ext_length
> +	destroy_dax_dev ${dax_dev}
> +
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_uuid_aggregation()
> +{
> +	echo ""
> +	echo "Test: multiple extents in a single More-chain aggregate under one tag"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# Both extents must arrive in the same More-chain to land in the
> +	# same tag group.  Re-using a tag across More-chains hits the
> +	# cross-More uniqueness gate and the second event would be dropped.
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a" 1
> +	check_extent_cnt ${region} 0
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 2
> +
> +	# a single --uuid claim should pick up both extents
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	expected=$(($base_ext_length + $pre_ext_length))
> +	check_dax_dev ${dax_dev} $expected
> +
> +	destroy_dax_dev ${dax_dev}
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +
> +test_partial_extent_remove ()
> +{
> +	echo ""
> +	echo "Test: partial extent remove"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +
> +	inject_extent ${device} $base_ext_dpa $base_ext_length ""
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|                                              |
> +	# |         | (base) |                                              |
> +
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "0")
> +
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|                                              |
> +	# |         | (base) |                                              |
> +	# |         | daxX.1 |                                              |
> +
> +	partial_ext_dpa="$(($base_ext_dpa + ($base_ext_length / 2)))"
> +	partial_ext_length="$(($base_ext_length / 2))"
> +	echo "Removing Partial : $partial_ext_dpa $partial_ext_length"
> +
> +	# |         |    |---|                                              |
> +	#                  Partial
> +
> +	remove_extent ${device} $partial_ext_dpa $partial_ext_length ""
> +	# In-use extents are not released.
> +	check_extent_cnt ${region} 1
> +
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|                                              |
> +	# |         | (base) |                                              |
> +	# |         | daxX.1 |                                              |
> +
> +	destroy_dax_dev ${dax_dev}
> +	check_not_dax_dev ${region} ${dax_dev}
> +
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|                                              |
> +	# |         | (base) |                                              |
> +
> +	# Partial release event re-targets the whole containing region_extent.
> +	check_extent_cnt ${region} 1
> +	remove_extent ${device} $partial_ext_dpa $partial_ext_length ""
> +	# |         |    |---|                                              |
> +	#                  Partial
> +	check_extent_cnt ${region} 0
> +
> +	# |  ...    |-------------------------------------------------------|
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_multiple_extent_remove ()
> +{
> +	# Per-tag-group release: a release event whose DPA range straddles
> +	# multiple region_extents in the same tag group should target them
> +	# atomically.  Set up two extents in one tagged More-chain.
> +	echo ""
> +	echo "Test: per-group release event covering two extents"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a" 1
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|          |-------------------|               |
> +	# |         | (base) |          | (pre)-existing    |   tag_a       |
> +
> +	check_extent_cnt ${region} 2
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +
> +	# |         | daxX.1 |          | daxX.1            |   tag_a       |
> +
> +	# A release event addressed at any DPA inside the tag group releases
> +	# the whole group atomically.  Use base_ext_dpa so the kernel finds
> +	# the tag group's region_extent on that DPA.
> +	echo "Issuing tag-group release at $base_ext_dpa"
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +
> +	# In-use extents are not released (dax-layer EBUSY defer).
> +	check_extent_cnt ${region} 2
> +
> +	destroy_dax_dev ${dax_dev}
> +	check_not_dax_dev ${region} ${dax_dev}
> +
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|          |-------------------|               |
> +	# |         | (base) |          | (pre)-existing    |               |
> +
> +	# Now that the dax dev is gone, re-issue the release(s) for each
> +	# extent.  Each release event targets the containing region_extent.
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 0
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_destroy_region_without_extent_removal ()
> +{
> +	echo ""
> +	echo "Test: Destroy region without extent removal"
> +	echo ""
> +	
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	inject_extent ${device} $base_ext_dpa $base_ext_length ""
> +	check_extent_cnt ${region} 2
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_destroy_with_extent_and_dax ()
> +{
> +	echo ""
> +	echo "Test: Destroy region with extents and dax devices"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	check_extent_cnt ${region} 0
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                   |----------|                        |
> +	# |         |                   |(pre-ext) |                        |
> +
> +	check_extent_cnt ${region} 1
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "0")
> +	# |         |                   |<dax_dev> |                        |
> +	check_dax_dev ${dax_dev} ${pre_ext_length}
> +	destroy_region ${region}
> +	check_not_region ${region}
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                                                       |
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_dax_device_ops ()
> +{
> +	echo ""
> +	echo "Test: Fail sparse dax dev creation without space"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                   |-------------------|               |
> +	# |         |                   | (pre)-existing    |               |
> +
> +	check_extent_cnt ${region} 1
> +
> +	# |         |                   | daxX.1            |               |
> +
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "0")
> +	check_dax_dev ${dax_dev} $pre_ext_length
> +	# No more untagged dax_resource avail: untagged claim returns -ENOENT
> +	fail_create_dax_dev_with_uuid ${region} "0"
> +	# Plain create-device on sparse: size grow is -EOPNOTSUPP
> +	fail_create_dax_dev ${region}
> +
> +	# DC dax devices cannot be resized to a non-zero size.  The
> +	# kernel rejects any size_store with -EOPNOTSUPP unless size == 0,
> +	# in which case dev_dax_shrink releases every range -- the same path
> +	# `daxctl destroy-device` takes.
> +	echo ""
> +	echo "Test: Resize of sparse dax device to non-zero is rejected"
> +	echo ""
> +	half=$(($pre_ext_length / 2))
> +	fail_resize_dax_dev ${dax_dev} $half
> +	check_dax_dev ${dax_dev} $pre_ext_length
> +
> +	# Destroy (size=0) is the only valid resize.  After it the
> +	# dax_resource has avail again, so --uuid "0" can claim it back
> +	# into a new dax device.
> +	# |         |                   | daxX.2            |               |
> +	echo ""
> +	echo "Test: Destroy (size=0) of sparse dax device releases the resource"
> +	echo ""
> +	destroy_dax_dev ${dax_dev}
> +	check_not_dax_dev ${region} ${dax_dev}
> +	dax_dev2=$(create_dax_dev_with_uuid ${region} "0")
> +	check_dax_dev ${dax_dev2} $pre_ext_length
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +
> +	# Multi-extent device must come from a single tagged group; cross-
> +	# event untagged adds land in independent dax_resources and cannot
> +	# be claimed as one dax device.  The no-resize rule applies equally
> +	# across the tagged group.
> +	echo ""
> +	echo "Test: Resize of tagged multi-extent dax device is rejected"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a" 1
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |--------|          |-------------------|               |
> +	# |         | (base) |          | (pre)-existing    |    tag_a      |
> +
> +	check_extent_cnt ${region} 2
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	ext_sum_length="$(($base_ext_length + $pre_ext_length))"
> +	check_dax_dev ${dax_dev} $ext_sum_length
> +
> +	# Any non-zero resize (here a shrink to 32M, which would sit inside
> +	# the first extent of the group) is rejected.
> +	fail_resize_dax_dev ${dax_dev} 33554432 # 32MB
> +	check_dax_dev ${dax_dev} $ext_sum_length
> +
> +	# Only size=0 / destroy is valid for the tagged group too.
> +	destroy_dax_dev ${dax_dev}
> +	check_not_dax_dev ${region} ${dax_dev}
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_reject_overlapping ()
> +{
> +	echo ""
> +	echo "Test: Rejecting overlapping extents"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +
> +	# | 2G non- |      DC region                                        |
> +	# |  DC cap |                                                       |
> +	# |  ...    |-------------------------------------------------------|
> +	# |         |                   |-------------------|               |
> +	# |         |                   | (pre)-existing    |               |
> +
> +	check_extent_cnt ${region} 1
> +
> +	# Attempt overlapping extent: start halfway through pre_ext, same
> +	# length so it straddles the end of pre_ext.
> +	#
> +	# |         |                   |---------|---------|               |
> +	# |         |                   |(pre-ext)| overlap |               |
> +
> +	partial_ext_dpa="$(($pre_ext_dpa + ($pre_ext_length / 2)))"
> +	partial_ext_length=$pre_ext_length
> +	inject_extent ${device} $partial_ext_dpa $partial_ext_length ""
> +
> +	# Should only see the original ext
> +	check_extent_cnt ${region} 1
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_two_regions()
> +{
> +	echo ""
> +	echo "Test: create 2 regions in the same DC partition"
> +	echo ""
> +	region_size=$(($dra_size / 2))
> +	region=$(create_dcd_region ${mem} ${decoder} ${region_size})
> +	check_region ${region} ${region_size}
> +	
> +	region_two=$(create_dcd_region ${mem} ${decoder} ${region_size})
> +	check_region ${region_two} ${region_size}
> +	
> +	destroy_region ${region_two}
> +	check_not_region ${region_two}
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_more_bit()
> +{
> +	echo ""
> +	echo "Test: More bit"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "" 1
> +	# More bit should hold off surfacing extent until the more bit is 0
> +	check_extent_cnt ${region} 0
> +	inject_extent ${device} $base_ext_dpa $base_ext_length ""
> +	check_extent_cnt ${region} 2
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_driver_tear_down()
> +{
> +	echo ""
> +	echo "Test: driver remove tear down"
> +	echo ""
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	check_extent ${region} ${pre_ext_offset} ${pre_ext_length}
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "0")
> +	# remove driver releases extents
> +	modprobe -r dax_cxl
> +	check_extent_cnt ${region} 0
> +}
> +
> +test_driver_bring_up()
> +{
> +	# leave region up, driver removed.
> +	echo ""
> +	echo "Test: no driver inject ok"
> +	echo ""
> +	check_region ${region} ${dra_size}
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	check_extent_cnt ${region} 1
> +
> +	modprobe dax_cxl
> +	check_extent_cnt ${region} 1
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_driver_reload()
> +{
> +	test_driver_tear_down
> +	test_driver_bring_up
> +}
> +
> +# Verify the dax dev's uuid sysfs attribute reflects the claim source:
> +# "0" for untagged seed/claim, the tag string for tagged claims.
> +test_uuid_show()
> +{
> +	echo ""
> +	echo "Test: dax dev uuid attribute reflects the claim source"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# Pre-claim the seed device's uuid (before any extent injected)
> +	# must read back as "0".  -i includes the idle seed at size 0.
> +	seed=$($DAXCTL list -r ${region} -D -i | jq -r '.[].chardev')
> +	check_dax_uuid ${seed} "0"
> +
> +	# Untagged extent + claim: uuid stays "0"
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	dax_u=$(create_dax_dev_with_uuid ${region} "0")
> +	check_dax_uuid ${dax_u} "0"
> +
> +	# Tagged extent + claim: uuid reads back as the tag
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	dax_t=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	check_dax_uuid ${dax_t} "$test_tag_a"
> +
> +	destroy_dax_dev ${dax_u}
> +	destroy_dax_dev ${dax_t}
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length ""
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +# --uuid <unknown> on a sparse region must return -ENOENT before any
> +# size is committed.  The region's available_size must be unchanged and
> +# the underlying extent must still be claimable via its real tag.
> +test_uuid_no_match_seed_intact()
> +{
> +	echo ""
> +	echo "Test: --uuid mismatch does not consume any extent space"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 1
> +
> +	# Capture region available size before the failed claim
> +	avail_before=$($DAXCTL list -r ${region} | jq -r '.[].available_size')
> +
> +	fail_create_dax_dev_with_uuid ${region} "$unknown_tag"
> +
> +	avail_after=$($DAXCTL list -r ${region} | jq -r '.[].available_size')
> +	if [ "$avail_before" != "$avail_after" ]; then
> +		echo "FAIL avail size changed by unmatched --uuid: $avail_before -> $avail_after"
> +		err "$LINENO"
> +	fi
> +
> +	# The real tag still claims successfully
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	check_dax_dev ${dax_dev} $pre_ext_length
> +
> +	destroy_dax_dev ${dax_dev}
> +	remove_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +# A second tagged Add-event reusing a previously committed tag must be
> +# dropped by the cross-More uniqueness gate (firmware-bug path).  Skipped
> +# for the null UUID.
> +test_cross_more_uniqueness()
> +{
> +	echo ""
> +	echo "Test: cross-More uniqueness drops second event with same tag"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# First Add-event (single extent) commits tag_a at base_ext_dpa.
> +	inject_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 1
> +
> +	# Second Add-event reuses tag_a at a different DPA: must be dropped.
> +	inject_extent ${device} $pre_ext_dpa $pre_ext_length "$test_tag_a"
> +	check_extent_cnt ${region} 1
> +
> +	# The original tag_a allocation is still usable.
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_a")
> +	check_dax_dev ${dax_dev} $base_ext_length
> +
> +	destroy_dax_dev ${dax_dev}
> +	remove_extent ${device} $base_ext_dpa $base_ext_length "$test_tag_a"
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +# Sharable-partition test: two extents in one tagged More-chain with
> +# device-stamped seq 1..2.  Uses the sharable memdev (serial 0xDCDC).
> +test_shared_extent_inject()
> +{
> +	echo ""
> +	echo "Test: shared extent inject on sharable partition"
> +	echo ""
> +
> +	region=$(create_dcd_region ${sharable_mem} ${sharable_decoder})
> +	check_region ${region} ${sharable_dra_size}
> +
> +	inject_shared_extent ${sharable_device} $base_ext_dpa $base_ext_length \
> +		"$test_tag_b" 1 1
> +	check_extent_cnt ${region} 0
> +	inject_shared_extent ${sharable_device} $pre_ext_dpa $pre_ext_length \
> +		"$test_tag_b" "" 2
> +	check_extent_cnt ${region} 2
> +
> +	dax_dev=$(create_dax_dev_with_uuid ${region} "$test_tag_b")
> +	expected=$(($base_ext_length + $pre_ext_length))
> +	check_dax_dev ${dax_dev} $expected
> +
> +	destroy_dax_dev ${dax_dev}
> +	remove_extent ${sharable_device} $base_ext_dpa $base_ext_length "$test_tag_b"
> +	remove_extent ${sharable_device} $pre_ext_dpa $pre_ext_length "$test_tag_b"
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +# Sharable extents must arrive with a dense 1..n shared_extn_seq.  A gap
> +# (1, 3) lets the cxl side accept the extents but uuid_claim_tagged
> +# refuses the group on its density check.  Uses the sharable memdev.
> +test_seq_integrity_gap()
> +{
> +	echo ""
> +	echo "Test: sharable extents with seq gap (1,3) refused on claim"
> +	echo ""
> +
> +	region=$(create_dcd_region ${sharable_mem} ${sharable_decoder})
> +	check_region ${region} ${sharable_dra_size}
> +
> +	inject_shared_extent ${sharable_device} $base_ext_dpa $base_ext_length \
> +		"$test_tag_b" 1 1
> +	check_extent_cnt ${region} 0
> +	inject_shared_extent ${sharable_device} $pre_ext_dpa $pre_ext_length \
> +		"$test_tag_b" "" 3
> +
> +	if [ "$(jq -r '.[].extents | length' <($CXL list -r ${region} -N))" = "2" ]; then
> +		fail_create_dax_dev_with_uuid ${region} "$test_tag_b"
> +		remove_extent ${sharable_device} $base_ext_dpa $base_ext_length "$test_tag_b"
> +		remove_extent ${sharable_device} $pre_ext_dpa $pre_ext_length "$test_tag_b"
> +	fi
> +	check_extent_cnt ${region} 0
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +# CXL_DCD_EXTENT_ALIGN is 2M; an extent that is not 2M-aligned must drop
> +# the whole group.  Inject a 64M extent at a 1M-offset DPA.
> +test_alignment_rejection()
> +{
> +	echo ""
> +	echo "Test: misaligned extent drops the group"
> +	echo ""
> +
> +	region=$(create_dcd_region ${mem} ${decoder})
> +	check_region ${region} ${dra_size}
> +
> +	# 1M past base — not 2M aligned
> +	mis_dpa=$(($base_ext_dpa + 0x100000))
> +	inject_extent ${device} $mis_dpa $base_ext_length ""
> +	check_extent_cnt ${region} 0
> +
> +	destroy_region ${region}
> +	check_not_region ${region}
> +}
> +
> +test_event_reporting()
> +{
> +	# Test event reporting
> +	# results expected
> +	num_dcd_events_expected=2
> +
> +	echo "Test: Prep event trace"
> +	echo "" > /sys/kernel/tracing/trace
> +	echo 1 > /sys/kernel/tracing/events/cxl/enable
> +	echo 1 > /sys/kernel/tracing/tracing_on
> +
> +	inject_extent ${device} $base_ext_dpa $base_ext_length ""
> +	remove_extent ${device} $base_ext_dpa $base_ext_length

Missing the tag arg

DJ

> +
> +	echo 0 > /sys/kernel/tracing/tracing_on
> +
> +	echo "Test: Events seen"
> +	trace_out=$(cat /sys/kernel/tracing/trace)
> +
> +	# Look for DCD events
> +	num_dcd_events=$(grep -c "cxl_dynamic_capacity" <<< "${trace_out}")
> +	echo "     LOG     (Expected) : (Found)"
> +	echo "     DCD events    ($num_dcd_events_expected) : $num_dcd_events"
> +
> +	if [ "$num_dcd_events" -ne $num_dcd_events_expected ]; then
> +		err "$LINENO"
> +	fi
> +}
> +
> +
> +# ========================================================================
> +# main()
> +# ========================================================================
> +
> +modprobe -r cxl_test
> +modprobe cxl_test
> +
> +# The mock stamps a single cxl_mem instance with this serial (0xDCDC).
> +# That memdev's DC partition is advertised as sharable in CDAT and is
> +# the only one that can host the shared-extent tests.  All other DCD
> +# memdevs stay non-sharable and host the rest of the suite.
> +MOCK_DC_SHARABLE_SERIAL=56540
> +
> +readarray -t memdevs < <("$CXL" list -b cxl_test -Mi | jq -r '.[].memdev')
> +
> +sharable_mem=""
> +sharable_decoder=""
> +sharable_bus=""
> +sharable_device=""
> +sharable_dra_size=""
> +
> +for cand in ${memdevs[@]}; do
> +	cand_dra=$($CXL list -m $cand | jq -r '.[].dynamic_ram_a_size')
> +	if [ "$cand_dra" == "null" ]; then
> +		continue
> +	fi
> +	cand_decoder=$($CXL list -b cxl_test -D -d root -m "$cand" |
> +		  jq -r ".[] |
> +		  select(.volatile_capable == true) |
> +		  select(.nr_targets == 1) |
> +		  select(.max_available_extent >= ${cand_dra}) |
> +		  .decoder")
> +	if [[ -z "$cand_decoder" ]]; then
> +		continue
> +	fi
> +	cand_serial=$($CXL list -m $cand | jq -r '.[].serial')
> +	cand_bus=`"$CXL" list -b cxl_test -m ${cand} | jq -r '.[].bus'`
> +	cand_device=$($CXL list -m $cand | jq -r '.[].host')
> +
> +	if [ "$cand_serial" == "$MOCK_DC_SHARABLE_SERIAL" ]; then
> +		if [ -z "$sharable_mem" ]; then
> +			sharable_mem="$cand"
> +			sharable_decoder="$cand_decoder"
> +			sharable_bus="$cand_bus"
> +			sharable_device="$cand_device"
> +			sharable_dra_size="$cand_dra"
> +		fi
> +	else
> +		if [ -z "$mem" ]; then
> +			mem="$cand"
> +			decoder="$cand_decoder"
> +			bus="$cand_bus"
> +			device="$cand_device"
> +			dra_size="$cand_dra"
> +		fi
> +	fi
> +
> +	if [ -n "$mem" ] && [ -n "$sharable_mem" ]; then
> +		break
> +	fi
> +done
> +
> +echo "TEST: non-sharable bus:${bus} decoder:${decoder} mem:${mem} device:${device} size:${dra_size}"
> +echo "TEST: sharable     bus:${sharable_bus} decoder:${sharable_decoder} mem:${sharable_mem} device:${sharable_device} size:${sharable_dra_size}"
> +
> +if [ "$decoder" == "" ] || [ "$device" == "" ] || [ "$dra_size" == "" ]; then
> +	echo "No non-sharable mem device/decoder found with DCD support"
> +	exit 77
> +fi
> +
> +if [ "$sharable_mem" == "" ]; then
> +	echo "No sharable mem device found (mock did not stamp MOCK_DC_SHARABLE_SERIAL)"
> +	exit 77
> +fi
> +
> +# testing pre existing extents must be called first as the extents were created
> +# by cxl-test being loaded
> +test_pre_existing_extents
> +test_remove_extent_under_dax_device
> +test_create_dax_dev_spanning_two_extents
> +test_inject_tag_support
> +test_uuid_no_match
> +test_uuid_no_match_seed_intact
> +test_uuid_aggregation
> +test_uuid_show
> +# These two run on the sharable memdev (serial $MOCK_DC_SHARABLE_SERIAL).
> +test_shared_extent_inject
> +test_seq_integrity_gap
> +test_cross_more_uniqueness
> +test_alignment_rejection
> +test_partial_extent_remove
> +test_multiple_extent_remove
> +test_destroy_region_without_extent_removal
> +test_destroy_with_extent_and_dax
> +test_dax_device_ops
> +test_reject_overlapping
> +test_two_regions
> +test_more_bit
> +test_driver_reload
> +test_event_reporting
> +
> +modprobe -r cxl_test
> +
> +check_dmesg "$LINENO"
> +
> +exit 0
> diff --git a/test/meson.build b/test/meson.build
> index e0e2193..cd06bf8 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -171,6 +171,7 @@ cxl_translate = find_program('cxl-translate.sh')
>  cxl_elc = find_program('cxl-elc.sh')
>  cxl_dax_hmem = find_program('cxl-dax-hmem.sh')
>  cxl_region_replay = find_program('cxl-region-replay.sh')
> +cxl_dcd = find_program('cxl-dcd.sh')
>  
>  tests = [
>    [ 'libndctl',               libndctl,		  'ndctl' ],
> @@ -207,6 +208,7 @@ tests = [
>    [ 'cxl-elc.sh',             cxl_elc,            'cxl'   ],
>    [ 'cxl-dax-hmem.sh',        cxl_dax_hmem,       'cxl'   ],
>    [ 'cxl-region-replay.sh',   cxl_region_replay,  'cxl'   ],
> +  [ 'cxl-dcd.sh',             cxl_dcd,            'cxl'   ],
>  ]
>  
>  if get_option('destructive').enabled()


  reply	other threads:[~2026-06-09  0:24 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-23  9:50 [PATCH v6 0/7] ndctl: Dynamic Capacity additions for cxl-cli Anisa Su
2026-05-23  9:50 ` [PATCH v6 1/7] " Anisa Su
2026-06-08 23:18   ` Dave Jiang
2026-05-23  9:50 ` [PATCH v6 2/7] libcxl: Add Dynamic RAM A partition mode support Anisa Su
2026-06-08 23:19   ` Dave Jiang
2026-06-10  3:51     ` Richard Cheng
2026-06-10 16:55       ` Dave Jiang
2026-06-25  9:08         ` Anisa Su
2026-06-25  9:07     ` Anisa Su
2026-05-23  9:50 ` [PATCH v6 3/7] cxl/region: Add cxl-cli support for dynamic RAM A Anisa Su
2026-06-08 23:58   ` Dave Jiang
2026-05-23  9:50 ` [PATCH v6 4/7] libcxl: Add extent functionality to DC regions Anisa Su
2026-06-09  0:05   ` Dave Jiang
2026-06-25  9:18     ` Anisa Su
2026-05-23  9:50 ` [PATCH v6 5/7] cxl/region: Add extent output to region query Anisa Su
2026-06-09  0:08   ` Dave Jiang
2026-06-10  3:55     ` Richard Cheng
2026-06-16 10:47       ` Anisa Su
2026-06-16 10:45     ` Anisa Su
2026-05-23  9:50 ` [PATCH v6 6/7] daxctl: Add --uuid option to create-device for sparse regions Anisa Su
2026-06-09  0:12   ` Dave Jiang
2026-06-25  9:30     ` Anisa Su
2026-05-23  9:50 ` [PATCH v6 7/7] cxl/test: Add Dynamic Capacity tests Anisa Su
2026-06-09  0:24   ` Dave Jiang [this message]
2026-06-25  9:34     ` Anisa Su
2026-06-05  5:43 ` [PATCH v6 0/7] ndctl: Dynamic Capacity additions for cxl-cli Alison Schofield
2026-06-08  8:11   ` Anisa Su
2026-06-17  7:10   ` Alison Schofield
2026-06-18  5:52     ` Anisa Su
2026-06-19  0:38       ` Alison Schofield
2026-06-24  4:51         ` Anisa Su

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d58b398a-eba8-4b4e-b1ab-cfed64fe11e8@intel.com \
    --to=dave.jiang@intel.com \
    --cc=John@Groves.net \
    --cc=alison.schofield@intel.com \
    --cc=anisa.su887@gmail.com \
    --cc=dave@stgolabs.net \
    --cc=djbw@kernel.org \
    --cc=gourry@gourry.net \
    --cc=ira.weiny@intel.com \
    --cc=iweiny@kernel.org \
    --cc=jic23@kernel.org \
    --cc=linux-cxl@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nvdimm@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome