diff mbox series

[v3,1/4] common: add helpers for parent pointer tests

Message ID 20221028215605.17973-2-catherine.hoang@oracle.com (mailing list archive)
State Superseded
Headers show
Series xfstests: add parent pointer tests | expand

Commit Message

Catherine Hoang Oct. 28, 2022, 9:56 p.m. UTC
From: Allison Henderson <allison.henderson@oracle.com>

Add helper functions in common/parent to parse and verify parent
pointers. Also add functions to check that mkfs, kernel, and xfs_io
support parent pointers.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Signed-off-by: Catherine Hoang <catherine.hoang@oracle.com>
---
 common/parent | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++
 common/rc     |   3 +
 common/xfs    |  12 +++
 3 files changed, 213 insertions(+)
 create mode 100644 common/parent

Comments

Zorro Lang Nov. 1, 2022, 6:18 a.m. UTC | #1
On Fri, Oct 28, 2022 at 02:56:02PM -0700, Catherine Hoang wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Add helper functions in common/parent to parse and verify parent
> pointers. Also add functions to check that mkfs, kernel, and xfs_io
> support parent pointers.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Signed-off-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---

Looks good to me, just a few typo problem as below ...

>  common/parent | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  common/rc     |   3 +
>  common/xfs    |  12 +++
>  3 files changed, 213 insertions(+)
>  create mode 100644 common/parent
> 
> diff --git a/common/parent b/common/parent
> new file mode 100644
> index 00000000..a0ba7d92
> --- /dev/null
> +++ b/common/parent
> @@ -0,0 +1,198 @@
> +#
> +# Parent pointer common functions
> +#
> +
> +#
> +# parse_parent_pointer parents parent_inode parent_pointer_name
> +#
> +# Given a list of parent pointers, find the record that matches
> +# the given inode and filename
> +#
> +# inputs:
> +# parents	: A list of parent pointers in the format of:
> +#		  inode/generation/name_length/name
> +# parent_inode	: The parent inode to search for
> +# parent_name	: The parent name to search for
> +#
> +# outputs:
> +# PPINO         : Parent pointer inode
> +# PPGEN         : Parent pointer generation
> +# PPNAME        : Parent pointer name
> +# PPNAME_LEN    : Parent pointer name length
> +#
> +_parse_parent_pointer()
> +{
> +	local parents=$1
> +	local pino=$2
> +	local parent_pointer_name=$3
> +
> +	local found=0
> +
> +	# Find the entry that has the same inode as the parent
> +	# and parse out the entry info
> +	while IFS=\/ read PPINO PPGEN PPNAME_LEN PPNAME; do
> +		if [ "$PPINO" != "$pino" ]; then
> +			continue
> +		fi
> +
> +		if [ "$PPNAME" != "$parent_pointer_name" ]; then
> +			continue
> +		fi
> +
> +		found=1
> +		break
> +	done <<< $(echo "$parents")
> +
> +	# Check to see if we found anything
> +	# We do not fail the test because we also use this
> +	# routine to verify when parent pointers should
> +	# be removed or updated  (ie a rename or a move
> +	# operation changes your parent pointer)
> +	if [ $found -eq "0" ]; then
> +		return 1
> +	fi
> +
> +	# Verify the parent pointer name length is correct
> +	if [ "$PPNAME_LEN" -ne "${#parent_pointer_name}" ]
> +	then
> +		echo "*** Bad parent pointer:"\
> +			"name:$PPNAME, namelen:$PPNAME_LEN"
> +	fi
> +
> +	#return sucess
> +	return 0
> +}
> +
> +#
> +# _verify_parent parent_path parent_pointer_name child_path
> +#
> +# Verify that the given child path lists the given parent as a parent pointer
> +# and that the parent pointer name matches the given name
> +#
> +# Examples:
> +#
> +# #simple example
> +# mkdir testfolder1
> +# touch testfolder1/file1
> +# verify_parent testfolder1 file1 testfolder1/file1

_verify_parent

> +#
> +# # In this above example, we want to verify that "testfolder1"
> +# # appears as a parent pointer of "testfolder1/file1".  Additionally
> +# # we verify that the name record of the parent pointer is "file1"
> +#
> +#
> +# #hardlink example
> +# mkdir testfolder1
> +# mkdir testfolder2
> +# touch testfolder1/file1
> +# ln testfolder1/file1 testfolder2/file1_ln
> +# verify_parent testfolder2 file1_ln testfolder1/file1

_verify_parent

> +#
> +# # In this above example, we want to verify that "testfolder2"
> +# # appears as a parent pointer of "testfolder1/file1".  Additionally
> +# # we verify that the name record of the parent pointer is "file1_ln"
> +#
> +_verify_parent()
> +{
> +	local parent_path=$1
> +	local parent_pointer_name=$2
> +	local child_path=$3
> +
> +	local parent_ppath="$parent_path/$parent_pointer_name"
> +
> +	# Verify parent exists
> +	if [ ! -d $SCRATCH_MNT/$parent_path ]; then
> +		_fail "$SCRATCH_MNT/$parent_path not found"
> +	else
> +		echo "*** $parent_path OK"
> +	fi
> +
> +	# Verify child exists
> +	if [ ! -f $SCRATCH_MNT/$child_path ]; then
> +		_fail "$SCRATCH_MNT/$child_path not found"
> +	else
> +		echo "*** $child_path OK"
> +	fi
> +
> +	# Verify the parent pointer name exists as a child of the parent
> +	if [ ! -f $SCRATCH_MNT/$parent_ppath ]; then
> +		_fail "$SCRATCH_MNT/$parent_ppath not found"
> +	else
> +		echo "*** $parent_ppath OK"
> +	fi
> +
> +	# Get the inodes of both parent and child
> +	pino="$(stat -c '%i' $SCRATCH_MNT/$parent_path)"
> +	cino="$(stat -c '%i' $SCRATCH_MNT/$child_path)"
> +
> +	# Get all the parent pointers of the child
> +	parents=($($XFS_IO_PROG -x -c \
> +	 "parent -f -i $pino -n $parent_pointer_name" $SCRATCH_MNT/$child_path))
> +	if [[ $? != 0 ]]; then
> +		 _fail "No parent pointers found for $child_path"
> +	fi
> +
> +	# Parse parent pointer output.
> +	# This sets PPINO PPGEN PPNAME PPNAME_LEN
> +	_parse_parent_pointer $parents $pino $parent_pointer_name
> +
> +	# If we didnt find one, bail out
> +	if [ $? -ne 0 ]; then
> +		_fail "No parent pointer record found for $parent_path"\
> +			"in $child_path"
> +	fi
> +
> +	# Verify the inode generated by the parent pointer name is
> +	# the same as the child inode
> +	pppino="$(stat -c '%i' $SCRATCH_MNT/$parent_ppath)"
> +	if [ $cino -ne $pppino ]
> +	then
> +		_fail "Bad parent pointer name value for $child_path."\
> +			"$SCRATCH_MNT/$parent_ppath belongs to inode $PPPINO,"\
> +			"but should be $cino"
> +	fi
> +
> +	echo "*** Verified parent pointer:"\
> +			"name:$PPNAME, namelen:$PPNAME_LEN"
> +	echo "*** Parent pointer OK for child $child_path"
> +}
> +
> +#
> +# _verify_parent parent_pointer_name pino child_path

_verify_no_parent

> +#
> +# Verify that the given child path contains no parent pointer entry
> +# for the given inode and file name
> +#
> +_verify_no_parent()
> +{
> +	local parent_pname=$1
> +	local pino=$2
> +	local child_path=$3
> +
> +	# Verify child exists
> +	if [ ! -f $SCRATCH_MNT/$child_path ]; then
> +		_fail "$SCRATCH_MNT/$child_path not found"
> +	else
> +		echo "*** $child_path OK"
> +	fi
> +
> +	# Get all the parent pointers of the child
> +	local parents=($($XFS_IO_PROG -x -c \
> +	 "parent -f -i $pino -n $parent_pname" $SCRATCH_MNT/$child_path))
> +	if [[ $? != 0 ]]; then
> +		return 0
> +	fi
> +
> +	# Parse parent pointer output.
> +	# This sets PPINO PPGEN PPNAME PPNAME_LEN
> +	_parse_parent_pointer $parents $pino $parent_pname
> +
> +	# If we didnt find one, return sucess
> +	if [ $? -ne 0 ]; then
> +		return 0
> +	fi
> +
> +	_fail "Parent pointer entry found where none should:"\
> +			"inode:$PPINO, gen:$PPGEN,"
> +			"name:$PPNAME, namelen:$PPNAME_LEN"
> +}
> diff --git a/common/rc b/common/rc
> index d1f3d56b..9fc0a785 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -2539,6 +2539,9 @@ _require_xfs_io_command()
>  		echo $testio | grep -q "invalid option" && \
>  			_notrun "xfs_io $command support is missing"
>  		;;
> +	"parent")
> +		testio=`$XFS_IO_PROG -x -c "parent" $TEST_DIR 2>&1`
> +		;;
>  	"pwrite")
>  		# -N (RWF_NOWAIT) only works with direct vectored I/O writes
>  		local pwrite_opts=" "
> diff --git a/common/xfs b/common/xfs
> index 170dd621..7233a2db 100644
> --- a/common/xfs
> +++ b/common/xfs
> @@ -1399,3 +1399,15 @@ _xfs_filter_mkfs()
>  		print STDOUT "realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX\n";
>  	}'
>  }
> +
> +# this test requires the xfs parent pointers feature
> +#
> +_require_xfs_parent()
> +{
> +	_scratch_mkfs_xfs_supported -n parent > /dev/null 2>&1 \
> +		|| _notrun "mkfs.xfs does not support parent pointers"
> +	_scratch_mkfs_xfs -n parent > /dev/null 2>&1
> +	_try_scratch_mount >/dev/null 2>&1 \
> +		|| _notrun "kernel does not support parent pointers"
> +	_scratch_unmount
> +}
> -- 
> 2.25.1
>
Catherine Hoang Nov. 2, 2022, 11:02 p.m. UTC | #2
> On Oct 31, 2022, at 11:18 PM, Zorro Lang <zlang@redhat.com> wrote:
> 
> On Fri, Oct 28, 2022 at 02:56:02PM -0700, Catherine Hoang wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>> 
>> Add helper functions in common/parent to parse and verify parent
>> pointers. Also add functions to check that mkfs, kernel, and xfs_io
>> support parent pointers.
>> 
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> Signed-off-by: Catherine Hoang <catherine.hoang@oracle.com>
>> ---
> 
> Looks good to me, just a few typo problem as below ...

Thanks for the reviews! I’ll fix the typos in the next version
> 
>> common/parent | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> common/rc     |   3 +
>> common/xfs    |  12 +++
>> 3 files changed, 213 insertions(+)
>> create mode 100644 common/parent
>> 
>> diff --git a/common/parent b/common/parent
>> new file mode 100644
>> index 00000000..a0ba7d92
>> --- /dev/null
>> +++ b/common/parent
>> @@ -0,0 +1,198 @@
>> +#
>> +# Parent pointer common functions
>> +#
>> +
>> +#
>> +# parse_parent_pointer parents parent_inode parent_pointer_name
>> +#
>> +# Given a list of parent pointers, find the record that matches
>> +# the given inode and filename
>> +#
>> +# inputs:
>> +# parents	: A list of parent pointers in the format of:
>> +#		  inode/generation/name_length/name
>> +# parent_inode	: The parent inode to search for
>> +# parent_name	: The parent name to search for
>> +#
>> +# outputs:
>> +# PPINO         : Parent pointer inode
>> +# PPGEN         : Parent pointer generation
>> +# PPNAME        : Parent pointer name
>> +# PPNAME_LEN    : Parent pointer name length
>> +#
>> +_parse_parent_pointer()
>> +{
>> +	local parents=$1
>> +	local pino=$2
>> +	local parent_pointer_name=$3
>> +
>> +	local found=0
>> +
>> +	# Find the entry that has the same inode as the parent
>> +	# and parse out the entry info
>> +	while IFS=\/ read PPINO PPGEN PPNAME_LEN PPNAME; do
>> +		if [ "$PPINO" != "$pino" ]; then
>> +			continue
>> +		fi
>> +
>> +		if [ "$PPNAME" != "$parent_pointer_name" ]; then
>> +			continue
>> +		fi
>> +
>> +		found=1
>> +		break
>> +	done <<< $(echo "$parents")
>> +
>> +	# Check to see if we found anything
>> +	# We do not fail the test because we also use this
>> +	# routine to verify when parent pointers should
>> +	# be removed or updated  (ie a rename or a move
>> +	# operation changes your parent pointer)
>> +	if [ $found -eq "0" ]; then
>> +		return 1
>> +	fi
>> +
>> +	# Verify the parent pointer name length is correct
>> +	if [ "$PPNAME_LEN" -ne "${#parent_pointer_name}" ]
>> +	then
>> +		echo "*** Bad parent pointer:"\
>> +			"name:$PPNAME, namelen:$PPNAME_LEN"
>> +	fi
>> +
>> +	#return sucess
>> +	return 0
>> +}
>> +
>> +#
>> +# _verify_parent parent_path parent_pointer_name child_path
>> +#
>> +# Verify that the given child path lists the given parent as a parent pointer
>> +# and that the parent pointer name matches the given name
>> +#
>> +# Examples:
>> +#
>> +# #simple example
>> +# mkdir testfolder1
>> +# touch testfolder1/file1
>> +# verify_parent testfolder1 file1 testfolder1/file1
> 
> _verify_parent
> 
>> +#
>> +# # In this above example, we want to verify that "testfolder1"
>> +# # appears as a parent pointer of "testfolder1/file1".  Additionally
>> +# # we verify that the name record of the parent pointer is "file1"
>> +#
>> +#
>> +# #hardlink example
>> +# mkdir testfolder1
>> +# mkdir testfolder2
>> +# touch testfolder1/file1
>> +# ln testfolder1/file1 testfolder2/file1_ln
>> +# verify_parent testfolder2 file1_ln testfolder1/file1
> 
> _verify_parent
> 
>> +#
>> +# # In this above example, we want to verify that "testfolder2"
>> +# # appears as a parent pointer of "testfolder1/file1".  Additionally
>> +# # we verify that the name record of the parent pointer is "file1_ln"
>> +#
>> +_verify_parent()
>> +{
>> +	local parent_path=$1
>> +	local parent_pointer_name=$2
>> +	local child_path=$3
>> +
>> +	local parent_ppath="$parent_path/$parent_pointer_name"
>> +
>> +	# Verify parent exists
>> +	if [ ! -d $SCRATCH_MNT/$parent_path ]; then
>> +		_fail "$SCRATCH_MNT/$parent_path not found"
>> +	else
>> +		echo "*** $parent_path OK"
>> +	fi
>> +
>> +	# Verify child exists
>> +	if [ ! -f $SCRATCH_MNT/$child_path ]; then
>> +		_fail "$SCRATCH_MNT/$child_path not found"
>> +	else
>> +		echo "*** $child_path OK"
>> +	fi
>> +
>> +	# Verify the parent pointer name exists as a child of the parent
>> +	if [ ! -f $SCRATCH_MNT/$parent_ppath ]; then
>> +		_fail "$SCRATCH_MNT/$parent_ppath not found"
>> +	else
>> +		echo "*** $parent_ppath OK"
>> +	fi
>> +
>> +	# Get the inodes of both parent and child
>> +	pino="$(stat -c '%i' $SCRATCH_MNT/$parent_path)"
>> +	cino="$(stat -c '%i' $SCRATCH_MNT/$child_path)"
>> +
>> +	# Get all the parent pointers of the child
>> +	parents=($($XFS_IO_PROG -x -c \
>> +	 "parent -f -i $pino -n $parent_pointer_name" $SCRATCH_MNT/$child_path))
>> +	if [[ $? != 0 ]]; then
>> +		 _fail "No parent pointers found for $child_path"
>> +	fi
>> +
>> +	# Parse parent pointer output.
>> +	# This sets PPINO PPGEN PPNAME PPNAME_LEN
>> +	_parse_parent_pointer $parents $pino $parent_pointer_name
>> +
>> +	# If we didnt find one, bail out
>> +	if [ $? -ne 0 ]; then
>> +		_fail "No parent pointer record found for $parent_path"\
>> +			"in $child_path"
>> +	fi
>> +
>> +	# Verify the inode generated by the parent pointer name is
>> +	# the same as the child inode
>> +	pppino="$(stat -c '%i' $SCRATCH_MNT/$parent_ppath)"
>> +	if [ $cino -ne $pppino ]
>> +	then
>> +		_fail "Bad parent pointer name value for $child_path."\
>> +			"$SCRATCH_MNT/$parent_ppath belongs to inode $PPPINO,"\
>> +			"but should be $cino"
>> +	fi
>> +
>> +	echo "*** Verified parent pointer:"\
>> +			"name:$PPNAME, namelen:$PPNAME_LEN"
>> +	echo "*** Parent pointer OK for child $child_path"
>> +}
>> +
>> +#
>> +# _verify_parent parent_pointer_name pino child_path
> 
> _verify_no_parent
> 
>> +#
>> +# Verify that the given child path contains no parent pointer entry
>> +# for the given inode and file name
>> +#
>> +_verify_no_parent()
>> +{
>> +	local parent_pname=$1
>> +	local pino=$2
>> +	local child_path=$3
>> +
>> +	# Verify child exists
>> +	if [ ! -f $SCRATCH_MNT/$child_path ]; then
>> +		_fail "$SCRATCH_MNT/$child_path not found"
>> +	else
>> +		echo "*** $child_path OK"
>> +	fi
>> +
>> +	# Get all the parent pointers of the child
>> +	local parents=($($XFS_IO_PROG -x -c \
>> +	 "parent -f -i $pino -n $parent_pname" $SCRATCH_MNT/$child_path))
>> +	if [[ $? != 0 ]]; then
>> +		return 0
>> +	fi
>> +
>> +	# Parse parent pointer output.
>> +	# This sets PPINO PPGEN PPNAME PPNAME_LEN
>> +	_parse_parent_pointer $parents $pino $parent_pname
>> +
>> +	# If we didnt find one, return sucess
>> +	if [ $? -ne 0 ]; then
>> +		return 0
>> +	fi
>> +
>> +	_fail "Parent pointer entry found where none should:"\
>> +			"inode:$PPINO, gen:$PPGEN,"
>> +			"name:$PPNAME, namelen:$PPNAME_LEN"
>> +}
>> diff --git a/common/rc b/common/rc
>> index d1f3d56b..9fc0a785 100644
>> --- a/common/rc
>> +++ b/common/rc
>> @@ -2539,6 +2539,9 @@ _require_xfs_io_command()
>> 		echo $testio | grep -q "invalid option" && \
>> 			_notrun "xfs_io $command support is missing"
>> 		;;
>> +	"parent")
>> +		testio=`$XFS_IO_PROG -x -c "parent" $TEST_DIR 2>&1`
>> +		;;
>> 	"pwrite")
>> 		# -N (RWF_NOWAIT) only works with direct vectored I/O writes
>> 		local pwrite_opts=" "
>> diff --git a/common/xfs b/common/xfs
>> index 170dd621..7233a2db 100644
>> --- a/common/xfs
>> +++ b/common/xfs
>> @@ -1399,3 +1399,15 @@ _xfs_filter_mkfs()
>> 		print STDOUT "realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX\n";
>> 	}'
>> }
>> +
>> +# this test requires the xfs parent pointers feature
>> +#
>> +_require_xfs_parent()
>> +{
>> +	_scratch_mkfs_xfs_supported -n parent > /dev/null 2>&1 \
>> +		|| _notrun "mkfs.xfs does not support parent pointers"
>> +	_scratch_mkfs_xfs -n parent > /dev/null 2>&1
>> +	_try_scratch_mount >/dev/null 2>&1 \
>> +		|| _notrun "kernel does not support parent pointers"
>> +	_scratch_unmount
>> +}
>> -- 
>> 2.25.1
>> 
>
diff mbox series

Patch

diff --git a/common/parent b/common/parent
new file mode 100644
index 00000000..a0ba7d92
--- /dev/null
+++ b/common/parent
@@ -0,0 +1,198 @@ 
+#
+# Parent pointer common functions
+#
+
+#
+# parse_parent_pointer parents parent_inode parent_pointer_name
+#
+# Given a list of parent pointers, find the record that matches
+# the given inode and filename
+#
+# inputs:
+# parents	: A list of parent pointers in the format of:
+#		  inode/generation/name_length/name
+# parent_inode	: The parent inode to search for
+# parent_name	: The parent name to search for
+#
+# outputs:
+# PPINO         : Parent pointer inode
+# PPGEN         : Parent pointer generation
+# PPNAME        : Parent pointer name
+# PPNAME_LEN    : Parent pointer name length
+#
+_parse_parent_pointer()
+{
+	local parents=$1
+	local pino=$2
+	local parent_pointer_name=$3
+
+	local found=0
+
+	# Find the entry that has the same inode as the parent
+	# and parse out the entry info
+	while IFS=\/ read PPINO PPGEN PPNAME_LEN PPNAME; do
+		if [ "$PPINO" != "$pino" ]; then
+			continue
+		fi
+
+		if [ "$PPNAME" != "$parent_pointer_name" ]; then
+			continue
+		fi
+
+		found=1
+		break
+	done <<< $(echo "$parents")
+
+	# Check to see if we found anything
+	# We do not fail the test because we also use this
+	# routine to verify when parent pointers should
+	# be removed or updated  (ie a rename or a move
+	# operation changes your parent pointer)
+	if [ $found -eq "0" ]; then
+		return 1
+	fi
+
+	# Verify the parent pointer name length is correct
+	if [ "$PPNAME_LEN" -ne "${#parent_pointer_name}" ]
+	then
+		echo "*** Bad parent pointer:"\
+			"name:$PPNAME, namelen:$PPNAME_LEN"
+	fi
+
+	#return sucess
+	return 0
+}
+
+#
+# _verify_parent parent_path parent_pointer_name child_path
+#
+# Verify that the given child path lists the given parent as a parent pointer
+# and that the parent pointer name matches the given name
+#
+# Examples:
+#
+# #simple example
+# mkdir testfolder1
+# touch testfolder1/file1
+# verify_parent testfolder1 file1 testfolder1/file1
+#
+# # In this above example, we want to verify that "testfolder1"
+# # appears as a parent pointer of "testfolder1/file1".  Additionally
+# # we verify that the name record of the parent pointer is "file1"
+#
+#
+# #hardlink example
+# mkdir testfolder1
+# mkdir testfolder2
+# touch testfolder1/file1
+# ln testfolder1/file1 testfolder2/file1_ln
+# verify_parent testfolder2 file1_ln testfolder1/file1
+#
+# # In this above example, we want to verify that "testfolder2"
+# # appears as a parent pointer of "testfolder1/file1".  Additionally
+# # we verify that the name record of the parent pointer is "file1_ln"
+#
+_verify_parent()
+{
+	local parent_path=$1
+	local parent_pointer_name=$2
+	local child_path=$3
+
+	local parent_ppath="$parent_path/$parent_pointer_name"
+
+	# Verify parent exists
+	if [ ! -d $SCRATCH_MNT/$parent_path ]; then
+		_fail "$SCRATCH_MNT/$parent_path not found"
+	else
+		echo "*** $parent_path OK"
+	fi
+
+	# Verify child exists
+	if [ ! -f $SCRATCH_MNT/$child_path ]; then
+		_fail "$SCRATCH_MNT/$child_path not found"
+	else
+		echo "*** $child_path OK"
+	fi
+
+	# Verify the parent pointer name exists as a child of the parent
+	if [ ! -f $SCRATCH_MNT/$parent_ppath ]; then
+		_fail "$SCRATCH_MNT/$parent_ppath not found"
+	else
+		echo "*** $parent_ppath OK"
+	fi
+
+	# Get the inodes of both parent and child
+	pino="$(stat -c '%i' $SCRATCH_MNT/$parent_path)"
+	cino="$(stat -c '%i' $SCRATCH_MNT/$child_path)"
+
+	# Get all the parent pointers of the child
+	parents=($($XFS_IO_PROG -x -c \
+	 "parent -f -i $pino -n $parent_pointer_name" $SCRATCH_MNT/$child_path))
+	if [[ $? != 0 ]]; then
+		 _fail "No parent pointers found for $child_path"
+	fi
+
+	# Parse parent pointer output.
+	# This sets PPINO PPGEN PPNAME PPNAME_LEN
+	_parse_parent_pointer $parents $pino $parent_pointer_name
+
+	# If we didnt find one, bail out
+	if [ $? -ne 0 ]; then
+		_fail "No parent pointer record found for $parent_path"\
+			"in $child_path"
+	fi
+
+	# Verify the inode generated by the parent pointer name is
+	# the same as the child inode
+	pppino="$(stat -c '%i' $SCRATCH_MNT/$parent_ppath)"
+	if [ $cino -ne $pppino ]
+	then
+		_fail "Bad parent pointer name value for $child_path."\
+			"$SCRATCH_MNT/$parent_ppath belongs to inode $PPPINO,"\
+			"but should be $cino"
+	fi
+
+	echo "*** Verified parent pointer:"\
+			"name:$PPNAME, namelen:$PPNAME_LEN"
+	echo "*** Parent pointer OK for child $child_path"
+}
+
+#
+# _verify_parent parent_pointer_name pino child_path
+#
+# Verify that the given child path contains no parent pointer entry
+# for the given inode and file name
+#
+_verify_no_parent()
+{
+	local parent_pname=$1
+	local pino=$2
+	local child_path=$3
+
+	# Verify child exists
+	if [ ! -f $SCRATCH_MNT/$child_path ]; then
+		_fail "$SCRATCH_MNT/$child_path not found"
+	else
+		echo "*** $child_path OK"
+	fi
+
+	# Get all the parent pointers of the child
+	local parents=($($XFS_IO_PROG -x -c \
+	 "parent -f -i $pino -n $parent_pname" $SCRATCH_MNT/$child_path))
+	if [[ $? != 0 ]]; then
+		return 0
+	fi
+
+	# Parse parent pointer output.
+	# This sets PPINO PPGEN PPNAME PPNAME_LEN
+	_parse_parent_pointer $parents $pino $parent_pname
+
+	# If we didnt find one, return sucess
+	if [ $? -ne 0 ]; then
+		return 0
+	fi
+
+	_fail "Parent pointer entry found where none should:"\
+			"inode:$PPINO, gen:$PPGEN,"
+			"name:$PPNAME, namelen:$PPNAME_LEN"
+}
diff --git a/common/rc b/common/rc
index d1f3d56b..9fc0a785 100644
--- a/common/rc
+++ b/common/rc
@@ -2539,6 +2539,9 @@  _require_xfs_io_command()
 		echo $testio | grep -q "invalid option" && \
 			_notrun "xfs_io $command support is missing"
 		;;
+	"parent")
+		testio=`$XFS_IO_PROG -x -c "parent" $TEST_DIR 2>&1`
+		;;
 	"pwrite")
 		# -N (RWF_NOWAIT) only works with direct vectored I/O writes
 		local pwrite_opts=" "
diff --git a/common/xfs b/common/xfs
index 170dd621..7233a2db 100644
--- a/common/xfs
+++ b/common/xfs
@@ -1399,3 +1399,15 @@  _xfs_filter_mkfs()
 		print STDOUT "realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX\n";
 	}'
 }
+
+# this test requires the xfs parent pointers feature
+#
+_require_xfs_parent()
+{
+	_scratch_mkfs_xfs_supported -n parent > /dev/null 2>&1 \
+		|| _notrun "mkfs.xfs does not support parent pointers"
+	_scratch_mkfs_xfs -n parent > /dev/null 2>&1
+	_try_scratch_mount >/dev/null 2>&1 \
+		|| _notrun "kernel does not support parent pointers"
+	_scratch_unmount
+}