| #! /bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # Copyright (c) 2022-2024 Oracle and/or its affiliates. All Rights Reserved. |
| # |
| # 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 |
| # |
| _xfs_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 |
| } |
| |
| # |
| # _xfs_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" |
| # |
| _xfs_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 |
| echo "$SCRATCH_MNT/$parent_path not found" |
| else |
| echo "*** $parent_path OK" |
| fi |
| |
| # Verify child exists |
| if [ ! -f $SCRATCH_MNT/$child_path ]; then |
| echo "$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 |
| echo "$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 -s -i $pino -n $parent_pointer_name" $SCRATCH_MNT/$child_path)) |
| if [[ $? != 0 ]]; then |
| echo "No parent pointers found for $child_path" |
| fi |
| |
| # Parse parent pointer output. |
| # This sets PPINO PPGEN PPNAME PPNAME_LEN |
| _xfs_parse_parent_pointer $parents $pino $parent_pointer_name |
| |
| # If we didnt find one, bail out |
| if [ $? -ne 0 ]; then |
| echo "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 |
| echo "Bad parent pointer name value for $child_path."\ |
| "$SCRATCH_MNT/$parent_ppath belongs to inode $PPPINO,"\ |
| "but should be $cino" |
| fi |
| |
| # Make sure path printing works by checking that the paths returned |
| # all point to the same inode. |
| local tgt="$SCRATCH_MNT/$child_path" |
| $XFS_IO_PROG -x -c 'parent -p' "$tgt" | while read pptr_path; do |
| test "$tgt" -ef "$pptr_path" || \ |
| echo "$tgt parent pointer $pptr_path should be the same file" |
| done |
| |
| echo "*** Verified parent pointer:"\ |
| "name:$PPNAME, namelen:$PPNAME_LEN" |
| echo "*** Parent pointer OK for child $child_path" |
| } |
| |
| # |
| # _xfs_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 |
| # |
| _xfs_verify_no_parent() |
| { |
| local parent_pname=$1 |
| local pino=$2 |
| local child_path=$3 |
| |
| # Verify child exists |
| if [ ! -f $SCRATCH_MNT/$child_path ]; then |
| echo "$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 -s -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 |
| _xfs_parse_parent_pointer $parents $pino $parent_pname |
| |
| # If we didnt find one, return sucess |
| if [ $? -ne 0 ]; then |
| return 0 |
| fi |
| |
| echo "Parent pointer entry found where none should:"\ |
| "inode:$PPINO, gen:$PPGEN," |
| "name:$PPNAME, namelen:$PPNAME_LEN" |
| } |