mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Chao Yu <chao@kernel.org>
To: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: chao@kernel.org, stable@kernel.org,
	Daeho Jeong <daehojeong@google.com>,
	linux-kernel@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH] f2fs: fix to avoid potential section-unaligned pinfile
Date: Fri, 3 Jul 2026 08:17:16 +0800	[thread overview]
Message-ID: <703b2fea-5a20-4b48-be9d-f0787d2f22b5@kernel.org> (raw)
In-Reply-To: <akZ1H45tI_Cqm2vR@google.com>

On 7/2/26 22:26, Jaegeuk Kim wrote:
> Hi Chao,
> 
> On 06/29, Chao Yu via Linux-f2fs-devel wrote:
>> Blocks of pinfile may not aligned to section size due to wrong use
>> on pinfile, result in heavy overhead of GC, let avoid this by
>> adding additional check condition in f2fs_setattr().
>>
>> - truncate -s 8mb pinfile
>> : random checkpoint may persist filesize w/ inode
>> - fallocate -o 0 -l 8mb pinfile
>>   - f2fs_fallocate
>>    - f2fs_expand_inode_data
>>     - f2fs_allocate_pinning_section
>>     - f2fs_map_blocks
>>      - f2fs_map_lock
>>      - __allocate_data_block
>>      - file_need_truncate
>>      : w/ FADVISE_TRUNC_BIT, we can expect unaligned mapping can be
>>        truncated while open() if f2fs is not umount abnormally
>>      - f2fs_map_unlock
>>      : following f2fs checkpoint and sudden power-cut
>>
>> - mount
>> - open pinfile
>>   - f2fs_file_open
>>    - finish_preallocate_blocks
>>     - truncate_setsize
>>     : filesize is 8mb
>>     - f2fs_truncate
>>     : can only truncate block outside filesize, rather than truncating
>>       unaligned blocks inside filesize
> 
> Have we reproduced this?

Jaegeuk, I reproduced w/ below script:

#!/bin/bash

set -euo pipefail

DEV="/dev/vdb"
MNT="/mnt/f2fs"
PINFILE="${MNT}/pinfile"
CHUNK_SIZE=$((2 * 1024 * 1024)) # 2MB

# Ensure running as root
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
     echo "Error: This script must be run as root." >&2
     exit 1
fi

# 0. Format f2fs image w/ /dev/vdb, and mount /dev/vdb to /mnt/f2fs/
echo "[+] Unmounting ${MNT} if currently mounted..."
umount "${MNT}" 2>/dev/null || true

echo "[+] Formatting ${DEV} with f2fs..."
mkfs.f2fs -f "${DEV}"

echo "[+] Creating mount point ${MNT} and mounting..."
mkdir -p "${MNT}"
mount "${DEV}" "${MNT}"

# 1. Create a pinfile in f2fs image
echo "[+] Creating pinfile at ${PINFILE}..."
touch "${PINFILE}"
f2fs_io pinfile set "${PINFILE}" 2>/dev/null || f2fs_io pinfile 1 "${PINFILE}"
truncate -s 8G "${PINFILE}"
sync

# Task 1: Call appendly fallocate on pinfile inside the range of [0, filesize]
task1_fallocate_append() {
     local file="$1"
     local chunk="$2"
     local max_size
     max_size=$(stat -c %s "$file" 2>/dev/null || echo 0)
     if [ "$max_size" -eq 0 ]; then
         max_size=$((8 * 1024 * 1024 * 1024))
     fi
     local offset=0
     while true; do
         # Try standard fallocate, fallback to f2fs_io fallocate
         fallocate -o "$offset" -l "$chunk" "$file" 2>/dev/null || \
         f2fs_io fallocate 0 "$offset" "$chunk" "$file" 2>/dev/null || break

         offset=$((offset + chunk))
         if [ "$offset" -ge "$max_size" ]; then
             offset=0
         fi
     done
}

# Task 2: Call f2fs checkpoint ioctl and then call shutdown 2 ioctl
task2_checkpoint_shutdown() {
     local target="$1"
     # Small delay to allow Task 1 to begin appending
     sleep 2

     # Call F2FS shutdown ioctl level 2
     f2fs_io shutdown 1 "$target"
}

# Check mapping alignment using f2fs_io fiemap
check_mapping_alignment() {
     local file="$1"
     local align_2mb=$((2 * 1024 * 1024)) # 2MB in bytes
     local align_blocks=512               # 2MB in 4KB blocks

     local fiemap_out
     fiemap_out=$(f2fs_io fiemap 0 4294967295 "$file" 2>/dev/null || f2fs_io fiemap "$file" 2>/dev/null || true)
     if [[ -z "$fiemap_out" ]]; then
         echo "Error: Failed to run f2fs_io fiemap on $file" >&2
         return 1
     fi

     echo "$fiemap_out"

     local aligned=true
     while IFS= read -r line; do
         [[ -z "$line" || "$line" =~ [Ff]iemap|[Ll]ogical|[Pp]hysical|[Ll]ength|[Ff]lags ]] && continue

         local -a cols
         read -r -a cols <<< "$line"
         local phy_str len_str
         if [[ ${#cols[@]} -ge 5 ]]; then
             phy_str="${cols[2]}"
             len_str="${cols[3]}"
         elif [[ ${#cols[@]} -ge 3 ]]; then
             phy_str="${cols[1]}"
             len_str="${cols[2]}"
         else
             continue
         fi

         local phy_val len_val
         if [[ "$phy_str" =~ ^0x || "$phy_str" =~ [a-fA-F] || "${#phy_str}" -gt 10 ]]; then
             phy_val=$((16#${phy_str#0x}))
         else
             phy_val=$((phy_str))
         fi

         if [[ "$len_str" =~ ^0x || "$len_str" =~ [a-fA-F] || "${#len_str}" -gt 10 ]]; then
             len_val=$((16#${len_str#0x}))
         else
             len_val=$((len_str))
         fi

         local unit_align=$align_blocks
         [[ "$len_val" -ge 4096 ]] && unit_align=$align_2mb

         if [[ $((phy_val % unit_align)) -ne 0 || $((len_val % unit_align)) -ne 0 ]]; then
             echo "[!] Unaligned extent mapping detected: $line" >&2
             aligned=false
         fi
     done <<< "$fiemap_out"

     $aligned
}

# 2. Test loop running the two tasks
iteration=0
while true; do
     iteration=$((iteration + 1))
     echo "[*] --- Iteration ${iteration} ---"

     # Task 1: call appendly fallocate on pinfile inside [0, filesize]
     task1_fallocate_append "${PINFILE}" "${CHUNK_SIZE}" &
     task1_pid=$!

     # Task 2: call f2fs checkpoint ioctl and then call shutdown 2 ioctl
     task2_checkpoint_shutdown "${PINFILE}" &
     task2_pid=$!

     # Wait for Task 2 to complete shutdown
     wait "${task2_pid}" 2>/dev/null || true

     # Terminate Task 1 and any child fallocate processes
     pkill -9 -P "${task1_pid}" 2>/dev/null || true
     kill -9 "${task1_pid}" 2>/dev/null || true
     wait "${task1_pid}" 2>/dev/null || true

     # Umount the image -> mount the image
     umount "${MNT}"
     mount "${DEV}" "${MNT}"

     # Use f2fs_io fiemap to check mapping
     if ! check_mapping_alignment "${PINFILE}"; then
         echo "[-] Mapping is not 2MB aligned. Print and break out."
         break
     fi

     echo "[+] Mapping is 2MB aligned."

     # Check space after test; if space exceed 80%, remove the file and call sync
     used_pct=$(df --output=pcent "${MNT}" | tail -n 1 | tr -dc '0-9')
     if [[ "${used_pct:-0}" -ge 80 ]]; then
         echo "[!] Space (${used_pct}%) exceeded 80%. Removing file and calling sync..."
         rm -f "${PINFILE}"
         sync
         touch "${PINFILE}"
         f2fs_io pinfile set "${PINFILE}" 2>/dev/null || f2fs_io pinfile 1 "${PINFILE}"
         truncate -s 8G "${PINFILE}"
     fi
done

> 
>>
>> Fixes: f5a53edcf01e ("f2fs: support aligned pinned file")
>> Cc: stable@kernel.org
>> Cc: Daeho Jeong <daehojeong@google.com>
>> Signed-off-by: Chao Yu <chao@kernel.org>
>> ---
>>   fs/f2fs/file.c | 28 +++++++++++++++++-----------
>>   1 file changed, 17 insertions(+), 11 deletions(-)
>>
>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>> index f4facd409d9b..11cc8d79c235 100644
>> --- a/fs/f2fs/file.c
>> +++ b/fs/f2fs/file.c
>> @@ -1107,17 +1107,23 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
>>   			!IS_ALIGNED(attr->ia_size,
>>   			F2FS_BLK_TO_BYTES(fi->i_cluster_size)))
>>   			return -EINVAL;
>> -		/*
>> -		 * To prevent scattered pin block generation, we don't allow
>> -		 * smaller/equal size unaligned truncation for pinned file.
>> -		 * We only support overwrite IO to pinned file, so don't
>> -		 * care about larger size truncation.
>> -		 */
>> -		if (f2fs_is_pinned_file(inode) &&
>> -			attr->ia_size <= i_size_read(inode) &&
>> -			!IS_ALIGNED(attr->ia_size,
>> -			F2FS_BLK_TO_BYTES(CAP_BLKS_PER_SEC(sbi))))
>> -			return -EINVAL;
>> +
>> +		if (f2fs_is_pinned_file(inode)) {
>> +			/*
>> +			 * It may break section-aligned fallocate recovery
>> +			 * mechanism, so do not allow larger size truncation.
>> +			 */
>> +			if (attr->ia_size > i_size_read(inode))
>> +				return -EINVAL;
>> +			/*
>> +			 * To prevent scattered pin block generation, we don't
>> +			 * allow smaller/equal size unaligned truncation for
>> +			 * pinned file.
>> +			 */
>> +			else if (!IS_ALIGNED(attr->ia_size,
>> +				F2FS_BLK_TO_BYTES(CAP_BLKS_PER_SEC(sbi))))
>> +				return -EINVAL;
>> +		}
>>   	}
>>   
>>   	if (is_quota_modification(idmap, inode, attr)) {
>> -- 
>> 2.49.0
>>
>>
>>
>> _______________________________________________
>> Linux-f2fs-devel mailing list
>> Linux-f2fs-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


  reply	other threads:[~2026-07-03  0:17 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-29 11:49 Chao Yu
2026-06-30  8:50 ` [f2fs-dev] " Zhiguo Niu
2026-06-30 11:02   ` Chao Yu
2026-07-01  3:26     ` Zhiguo Niu
2026-07-02 14:26 ` Jaegeuk Kim
2026-07-03  0:17   ` Chao Yu [this message]
2026-07-14  3:00 ` patchwork-bot+f2fs

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=703b2fea-5a20-4b48-be9d-f0787d2f22b5@kernel.org \
    --to=chao@kernel.org \
    --cc=daehojeong@google.com \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@kernel.org \
    /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