From: Artem Blagodarenko Test ext4 LUFID set/get operations on dirdata fields. This test verifies that the EXT4_IOC_SET_LUFID ioctl can be used to attach LUFID data to a directory entry and that `debugfs ls -lD` can read this data. Verification uses `debugfs ls -lD` to check for `fid:` markers, indicating the presence of LUFID data in directory entries. Signed-off-by: Artem Blagodarenko --- tests/ext4/066 | 158 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/066.out | 4 ++ 2 files changed, 162 insertions(+) diff --git a/tests/ext4/066 b/tests/ext4/066 new file mode 100755 index 00000000..ae98fb45 --- /dev/null +++ b/tests/ext4/066 @@ -0,0 +1,158 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 The Lustre Collective. All Rights Reserved. +# Author: Artem Blagodarenko +# +# FS QA Test ext4/066 +# +# Test the ext4 dirdata feature with LUFID ioctl functionality. +# LUFID is a 16-byte identifier that can be attached +# to directory entries. It is used for quick access to file metadata. +# EXT4_IOC_SET_LUFID is an ioctl that allows LUFID data to be set on a +# directory entry. + +. ./common/preamble +_begin_fstest auto quick + +# Import common functions +. ./common/filter +. ./common/ext4 + +_exclude_fs ext2 +_exclude_fs ext3 + +_require_scratch_nocheck +_require_command "$SET_LUFID_PROG" + +# Check if dirdata feature is supported (required for LUFID IOCTL) +_require_scratch_dirdata() +{ + if test ! -f /sys/fs/ext4/features/dirdata ; then + _notrun "dirdata feature not supported by kernel (required for LUFID)" + fi + + # Verify that mkfs supports dirdata + if ! $MKFS_EXT4_PROG -O dirdata -n $SCRATCH_DEV &>>$seqres.full ; then + _notrun "mkfs.ext4 does not support dirdata feature" + fi + + # Verify kernel can mount filesystem with dirdata + if ! _scratch_mkfs -O dirdata &>>$seqres.full ; then + _notrun "failed to create filesystem with dirdata" + fi + if ! _try_scratch_mount &>>$seqres.full ; then + _notrun "kernel cannot mount filesystem with dirdata" + fi + _scratch_unmount +} + +_require_scratch_dirdata + +_u32_to_le_hex() +{ + local v=$1 + local h + + h=$(printf '%08x' "$((v & 0xffffffff))") + printf '%s%s%s%s' "${h:6:2}" "${h:4:2}" "${h:2:2}" "${h:0:2}" +} + +_build_default_expected_fid() +{ + local path=$1 + local inode + local version + local ino_hi ino_lo + local ver_hi ver_lo + local seq_hex oid_hex ver_hex + + inode=$(stat -c '%i' "$path") || return 1 + version=$(debugfs -R "stat <${inode}>" $SCRATCH_DEV 2>/dev/null | \ + sed -n 's/.*Generation:[[:space:]]*\([0-9xa-fA-F]\+\).*/\1/p' | head -n 1) + + if [ -z "$version" ]; then + return 1 + fi + + ino_hi=$(((inode >> 32) & 0xffffffff)) + ino_lo=$((inode & 0xffffffff)) + ver_lo=$((version & 0xffffffff)) + ver_hi=$(((version >> 32) & 0xffffffff)) + + # Match lu_fid cast semantics: set_lufid stores u32 words in native memory + # order; debugfs reads lu_fid fields and prints f_seq/f_oid/f_ver. + seq_hex="$(_u32_to_le_hex "$ino_hi")$(_u32_to_le_hex "$ino_lo")" + oid_hex="$(_u32_to_le_hex "$ver_lo")" + ver_hex="$(_u32_to_le_hex "$ver_hi")" + + printf '[0x%x:0x%x:0x%x]' "$((16#$seq_hex))" "$((16#$oid_hex))" \ + "$((16#$ver_hex))" +} + +# Create a filesystem with dirdata feature +_scratch_mkfs -O dirdata &>>$seqres.full +_scratch_mount + +# Test: Create file and set multiple 16-byte LUFIDs on the same file +echo "Test: Set multiple 16-byte LUFIDs on the same file" +mkdir -p $SCRATCH_MNT/lufid_test +echo "test content" > $SCRATCH_MNT/lufid_test/testfile.txt + +# Set both LUFIDs on the file at the same time (32 bytes total: two 16-byte FIDs) +# First FID: [part1 (8 bytes):part2 (4 bytes):part3 (4 bytes)] +# Second FID: [part1 (8 bytes):part2 (4 bytes):part3 (4 bytes)] +set_lufid $SCRATCH_MNT/lufid_test testfile.txt >>$seqres.full +if [ $? -ne 0 ]; then + echo "FAIL: Could not set both LUFIDs on testfile.txt" + _scratch_unmount + _check_scratch_fs + status=1 + exit +fi + +# Verify file is still accessible +if [ ! -f $SCRATCH_MNT/lufid_test/testfile.txt ]; then + echo "FAIL: File not accessible after setting LUFIDs" + _scratch_unmount + _check_scratch_fs + status=1 + exit +fi + +# Verify file content is preserved +content=$(cat $SCRATCH_MNT/lufid_test/testfile.txt 2>/dev/null) +if [ "$content" != "test content" ]; then + echo "FAIL: File content not preserved after setting LUFIDs" + _scratch_unmount + _check_scratch_fs + status=1 + exit +fi + +expected_fid=$(_build_default_expected_fid $SCRATCH_MNT/lufid_test/testfile.txt) +if [ -z "$expected_fid" ]; then + echo "FAIL: Could not calculate expected default LUFID" + _scratch_unmount + _check_scratch_fs + status=1 + exit +fi + +echo "Successfully set and verified both 16-byte LUFIDs on same file at the same time" + +# Dump directory structure to verify dirdata +if ! _dump_dir_structure $SCRATCH_MNT/lufid_test testfile.txt "$expected_fid"; then + echo "FAIL: Stored LUFID does not match expected default value" + _scratch_unmount + _check_scratch_fs + status=1 + exit +fi + +# Cleanup and verify filesystem +_scratch_unmount +_check_scratch_fs + +# success, all done +status=0 +exit diff --git a/tests/ext4/066.out b/tests/ext4/066.out new file mode 100644 index 00000000..4ec0fd6d --- /dev/null +++ b/tests/ext4/066.out @@ -0,0 +1,4 @@ +QA output created by 066 +Test: Set multiple 16-byte LUFIDs on the same file +Successfully set and verified both 16-byte LUFIDs on same file at the same time + Directory structure of lufid_test: OK (dirdata verified) -- 2.43.7