From nobody Sat Sep 26 23:52:38 2026 Received: from mail-pg1-f169.google.com (mail-pg1-f169.google.com [209.85.215.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A1B8C3D669A for ; Fri, 28 Aug 2026 07:20:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901635; cv=none; b=sXDDpvOPgCD4TVdoW9j9ZLrLqhv3LHiENEIHse3FrSQ+zuYpJyFfTa7+14jl+33W5q5ZOBGGXGl4gM6fTifU+ST/U4gZ1yMiy4hgWhXdpKYxUJeGB4oDHJnAW1W8oa8ybRza741xe24BFipwW7D9DlHzCuBfDA+3Eyq3eneHeIo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901635; c=relaxed/simple; bh=c9a3Rs+JcK15f2Ao6kns2VM1aDnooBIfad8L/a1jgf8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oZLCf2qGa1UNiPH9Alh0uVpxwn0p4TbPyNYwxLGg+Yk+tsi//DdBeoH1UPtU+D2ieeqWPPMpInwBgpzMrtuDTwpnH5+VH+wbnbnpexKONn/K8tSUII+2bInoVyJT8cQWo+OfHNcD/+/l1u0O5Cq4V85LT8TE1TpB8ML4dlz0cQE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Uq2V0jM2; arc=none smtp.client-ip=209.85.215.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Uq2V0jM2" Received: by mail-pg1-f169.google.com with SMTP id 41be03b00d2f7-cc1c73645a1so566812a12.1 for ; Fri, 28 Aug 2026 00:20:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787901633; x=1788506433; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GzEDMkX4yTC4NY1QHzlw8SSeuXFcMhPqxibPy+lQxOY=; b=Uq2V0jM2fWZxAIOauHMRejOrD19lw5Ra0YDemS6O7v81lzcN3CNbYLq4C3XVOf8jsh FN0LVVFPw5GllZuMC7SJGzghdA2mwnpdFWvsSx5oQ3BizISvs9gf2kCtTL17QZp+pcFj ekyXKeGrCdoH/EGU4lYhAAE8Zci25XNUaIOeZSmB9Wl8mjfcZ8DedM7SRmPsUY4r/ZBl kBGYzYFDPcjwj2rsgH1LylAhpg2aaF4TuKCVjNm00xw3tDJQNLrHUC7icEqVthRlF+Ei z8YuLIE+03aOkycbuocyPBcWGI0EEu4gUAL1JuW+yvflP1nfLEZXP2gJYCD6rQGca1wG o1QQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787901633; x=1788506433; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=GzEDMkX4yTC4NY1QHzlw8SSeuXFcMhPqxibPy+lQxOY=; b=L3dgOq6A1alDflix1Y+Oy6IRw6GvkluXTWGCZxTqZFsJByVNMd6NnRJQ4nh272iv2W u87PXzD+aQB5O/cp6t8P2hF/Eo68eKg/lrS93ANeGQ1RN2V/kgths0jf4MiXHXJr23qe kzJEJPZMXkGUhCrsTy/djS9MzoFjFxjF95daWJ82h1+1/Dh+er0Zef/V7qrCqqflau+L wAqGsptiH6mqYdv95nYDptuvROpAgwczfZNL1DpP0NDEAu8c9i4Z4ni5pYx+IlLHgD+T F6rSjeWwckieRRLZdLUpE/8oDrLdlJmLh5acqk7zKEQDe9stNsVSAK8QPePKtAunOof5 0fsQ== X-Forwarded-Encrypted: i=1; AHgh+RqWsUSi5NPTYj2Ht7hRyUNwcxJOgbX+kFUttGGmaNFHLquhr/Dv5nuDHzj+PS82ZzAAQE3Cj1g0XWOSPI0=@vger.kernel.org X-Gm-Message-State: AFuF++mxsjmAzdhshXdGXWEEsGtVaMxL2gspvwpyrKTvjKlM130ARR6S evfvzX6SGa2Z/uIjb8O+b2uCIBQVSJwHWjojMqC1y17wX13fy4UCZ4Wy X-Gm-Gg: AR+sD11dFVwYkVb4iZ58xjLBvhllxvXogUhBKhvvBsVmvUjqBCvx5HKikGuinKVeWHQ F9WEMUJtoWRIIr/XZ75Zom0Y63DowxpD0Bfz+dwkPGxEtWtX9MLviAX2FkriHIpa/i4suyMfFGl NKmMYUqKSauO3iQKA3IFmSkrZqffzJDXkNozMwMGLeMggch8IAXF3pK69dsgbI0UU+N8Pw56O53 pw2xBfb1MsJ8Jv6D7O6e7SZeEe4hS1HZB0rWXhBdlSjeO7t+Rzdr14AkXS9FOYKOOf+ZgJ8STvQ O6aT8rq3LHAlXQQpJHa/+sfkTYIaqKoZbPFa2mHDPw6HdpxdIA/YU+3T1N2N0KglvvKvOh60QeZ LCqPWho4gtZ/aeVWSPcDgOWndmsbH5urjnpI7Q7I4QZmbGAxB8GD8+fIbKIrguxdYZ7Qizlu5ix zNKNqrz/sSrd3z9T5T9wMxM7rieDPj44Qt8Ri5wSNFkRdpBSeRCr1W7c7cciqkSW5GEYA= X-Received: by 2002:a17:90b:17c3:b0:38f:240d:b857 with SMTP id 98e67ed59e1d1-396d0ea9ce7mr7311266a91.2.1787901632866; Fri, 28 Aug 2026 00:20:32 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-396b0ea7fa9sm6123731a91.4.2026.08.28.00.20.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 00:20:32 -0700 (PDT) From: Jeuk Kim X-Google-Original-From: Jeuk Kim To: Jaegeuk Kim , Chao Yu Cc: Yohan Joung , linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, j-young.choi@samsung.com, yunjae00.jo@samsung.com, keosung.park@samsung.com, Jeuk Kim Subject: [PATCH 1/3] f2fs: set FI_UPDATE_WRITE for in-place direct writes to pinned files Date: Fri, 28 Aug 2026 16:20:15 +0900 Message-ID: <20260828072017.44569-2-jeuk20.kim@samsung.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260828072017.44569-1-jeuk20.kim@samsung.com> References: <20260828072017.44569-1-jeuk20.kim@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" f2fs_dio_write_iter() does not set FI_UPDATE_WRITE when do_opu is true, assuming that the write landed on a newly allocated block. That assumption does not hold for pinned files. They are updated in place even in LFS mode. Without FI_UPDATE_WRITE and with no appended data, fdatasync() can return without issuing a device cache flush, leaving an in-place direct overwrite in a volatile write cache. Make do_opu false for pinned files so that FI_UPDATE_WRITE is set and the flush takes place. This can occur on zoned devices, which force LFS mode but allow direct I/O to pinned files, and on conventional devices when a file is pinned before the filesystem is remounted with mode=3Dlfs. Signed-off-by: Jeuk Kim --- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 089759366cdc..51518caee460 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -5166,7 +5166,7 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *iocb= , struct iov_iter *from, struct inode *inode =3D file_inode(file); struct f2fs_inode_info *fi =3D F2FS_I(inode); struct f2fs_sb_info *sbi =3D F2FS_I_SB(inode); - const bool do_opu =3D f2fs_lfs_mode(sbi); + const bool do_opu =3D f2fs_lfs_mode(sbi) && !f2fs_is_pinned_file(inode); const loff_t pos =3D iocb->ki_pos; const ssize_t count =3D iov_iter_count(from); unsigned int dio_flags; --=20 2.43.0 From nobody Sat Sep 26 23:52:38 2026 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B08B3C870E for ; Fri, 28 Aug 2026 07:20:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901637; cv=none; b=OiryQMbEN7Srw61g/PCm1dtTvIMQ1p7L70OVNDERlKqVlbOjuBP+WNcehrERKK9u4cOT3Fhy7sGX0C/uLPOoOZ2RsUWuEOJX66/BbruofO9ZPh6xXjkZztfP+bZNwC7lqXece69k3W1eKkff8yh1a4hW6bfHIP/TdPAhOxZ+jsE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901637; c=relaxed/simple; bh=CHyqnlH1pmwI+TbPQ39eQEuRDQk6wn3kbJqO5j1d4gk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YtwUVBOAwSBmbA5DeU+50hyp6045PrfjT+zU6ul7o/1R6qfnSGjlsZ4p13UoYWPVb0tXzBHDUTiwnaV8vGmvhunoLAnl3BbJ0Opze42atY9rWy9QvC+QfWjx585eCjCNMftIL0/OMnnUd0R8wjuZ1giOmgtBWxEklO7DSDWmFeQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jaSwbyJc; arc=none smtp.client-ip=209.85.216.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jaSwbyJc" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-38e58034d05so756109a91.2 for ; Fri, 28 Aug 2026 00:20:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787901635; x=1788506435; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=G6Ag/tYf1DhNwpo/YB9MI3UoakQSnyJqri54EN1XefQ=; b=jaSwbyJcWfcpOmAS7WBaloLbUBBBua22yw/VgWLxl2QNW16driyL1ynNBS3mxsre5n xt7QigEg0zKUmDd7B3RW7fnBtNLoRFRIfkVB5zb56e3OPeT94OM+Hlg8k02XYImvyGS3 wZN5GAo3PHENLYzM4dzlFM7PG4MYNHHPvEas++tZxHW3d0eUmqk0YYVRbJIXNYM7S7Y1 UrGdmNoPYrLVQX834Aq+fomPxtEbNLS8ixDXbib9eas/PVNiUBcagdjlaTUGn1QaaTZu ELvbVY7DuSkuNHEyUbyAE9igLF0LdPQRkd0Ah18HzvG6eChA+F0rIxZIzon/c0PQB3gk maqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787901635; x=1788506435; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=G6Ag/tYf1DhNwpo/YB9MI3UoakQSnyJqri54EN1XefQ=; b=JMuJQgAz+qlgYJk77Ur0q7SPQryGyKbgdHMNT9SikXf4Bc4cjF4BMLkAP/iI51OPFP iHgROuoBXPEHiXlsOzh9CSd/ekT44YX8vkRK9M1MNGs5iI/94F8uHe+0Ouy9STrK9UC5 xP2ZYH3F/uZcCVgSUe64Eh526d6E8x+EjJfIE/ogAit8FlIDOfkKevJh1tAu2C7+3CRu +uiBSQzH/5Nj+8WAiCf/z5w2rgFZnNk5b5ePbxPsYy7FfkQzO6d43NlG6He/V1TW2f35 hLFzfB/XbiR4ntcUJlToVzeRkwbyAa7eEqgTOzedWztaOn1Ys+RkxuMjn7yOaeHAqAzL LuLQ== X-Forwarded-Encrypted: i=1; AHgh+RpVPP+KfFfuqEbOwheV/ko44qCyF3AhBNdLKk5kbBVsBIwnhxfLFdK2pzkszftSosvA+M0/kXkIGIwyNbw=@vger.kernel.org X-Gm-Message-State: AFuF++ku2B0p6gQAS4KJa0nDY1ILdvZZow7ml18sNAuAaEoXp2cPJ1u7 SiYyMIcvboJVacc3u/P6+vvHnRwMuLer/o6hLMx2+vAjazyu6pbkK5oH X-Gm-Gg: AR+sD12beDK5rxIWPF00fobaQwpS/6Xh+Glhu6OIT2inyydqRHMyHIgDKgbtat6lTkn JlR4eNQH8Zl0k+JjR7WUuQlETNaHwxoMutStSNidrgGZgS9aMIRlvkiJ8WD8Kqxu8rXzsYdB4sy 2PWMSaUwZqRXzliuenTQaUJQ2mIPH+VxmrGOhh4FKNR2QN/L4PZZso1DKFLdwZgprtuRy/XUrdy tUS6MOXEvhNyg5j7jAUSXw7e4043aOLgCUA5WZWqKXCtWtUCX/QBdYZEHPQ+zIPtKPbS+ONYjK0 RpLhm0jNTw4ifUeVl7MFvhR8qrRpIRj1ucsuyO97J/WkeKPg4t3Kjjn9N0G3cCcVgWInUc6yVqm jJ1Qg6TbnSUNb3JWdChi5XEg1h7HohEpKZ6vAxJn3kIzLTBsZrpm6kzjsXIMKik/Ru+HLbsTsuM 2Wf2pwTizXxqfdUS5wzzVbmaakHcphR/0K4A5gZEz2ll4LOfMHh5v3Mf3Ukl3t41tI63A= X-Received: by 2002:a17:90b:2d82:b0:393:194d:5366 with SMTP id 98e67ed59e1d1-396d0f6f8bfmr10437037a91.10.1787901635511; Fri, 28 Aug 2026 00:20:35 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-396b0ea7fa9sm6123731a91.4.2026.08.28.00.20.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 00:20:35 -0700 (PDT) From: Jeuk Kim X-Google-Original-From: Jeuk Kim To: Jaegeuk Kim , Chao Yu Cc: Yohan Joung , linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, j-young.choi@samsung.com, yunjae00.jo@samsung.com, keosung.park@samsung.com, Jeuk Kim Subject: [PATCH 2/3] f2fs: fix in-place direct I/O overwrites in LFS mode Date: Fri, 28 Aug 2026 16:20:16 +0900 Message-ID: <20260828072017.44569-3-jeuk20.kim@samsung.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260828072017.44569-1-jeuk20.kim@samsung.com> References: <20260828072017.44569-1-jeuk20.kim@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Commit 351bc761338d ("f2fs: optimize f2fs DIO overwrites") stopped setting m_may_create for direct I/O overwrites of allocated blocks. In LFS mode, this causes the existing physical blocks to be reused instead of allocating new ones. The physical block address of logical block 0 after each overwrite was: initial buffered O_DIRECT mode=3Dlfs pre-fix 6596096 88066 88066 post-fix 6596096 88066 6596352 mode=3Dadaptive pre-fix 6596096 6596096 6596096 post-fix 6596096 6596096 6596096 Set m_may_create when a direct I/O write must use OPU. Since allocation may sleep, reject NOWAIT writes with -EAGAIN. Keep pinned files on the IPU path because their block addresses must not change. Add f2fs_should_opu() to keep these decisions consistent. Fixes: 351bc761338d ("f2fs: optimize f2fs DIO overwrites") Signed-off-by: Jeuk Kim --- fs/f2fs/data.c | 17 ++++++++++------- fs/f2fs/f2fs.h | 9 +++++++++ fs/f2fs/file.c | 11 +++-------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index dad5c2bd5888..618e6fc2da0c 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1644,7 +1644,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_= map_blocks *map, int flag) if (!maxblocks) return 0; =20 - lfs_dio_write =3D (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) && + lfs_dio_write =3D (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_should_opu(inod= e) && map->m_may_create); =20 if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) { @@ -1717,8 +1717,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_= map_blocks *map, int flag) =20 /* use out-place-update for direct IO under LFS mode */ if (map->m_may_create && (is_hole || - (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) && - !f2fs_is_pinned_file(inode) && map->m_last_pblk !=3D blkaddr))) { + (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_should_opu(inode) && + map->m_last_pblk !=3D blkaddr))) { if (unlikely(f2fs_cp_error(sbi))) { err =3D -EIO; goto sync_out; @@ -1810,7 +1810,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_= map_blocks *map, int flag) ofs++; map->m_len++; } else { - if (lfs_dio_write && !f2fs_is_pinned_file(inode)) + if (lfs_dio_write) map->m_last_pblk =3D blkaddr; goto sync_out; } @@ -4513,11 +4513,14 @@ static int f2fs_iomap_begin(struct inode *inode, lo= ff_t offset, loff_t length, } =20 /* - * If the blocks being overwritten are already allocated, - * f2fs_map_lock and f2fs_balance_fs are not necessary. + * Out-place-update must not reuse the existing block, so ask for an + * allocation even when the range is already mapped. Otherwise, if the + * blocks being overwritten are already allocated, f2fs_map_lock and + * f2fs_balance_fs are not necessary. */ if ((flags & IOMAP_WRITE) && - !__f2fs_overwrite_io(inode, offset, length, true)) + (f2fs_should_opu(inode) || + !__f2fs_overwrite_io(inode, offset, length, true))) map.m_may_create =3D true; =20 err =3D f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DIO); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8376bbe58ee3..e85d4db3a401 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4938,6 +4938,15 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info= *sbi) return F2FS_OPTION(sbi).fs_mode =3D=3D FS_MODE_LFS; } =20 +static inline bool f2fs_should_opu(struct inode *inode) +{ + /* pinned files must keep their block addresses */ + if (f2fs_is_pinned_file(inode)) + return false; + + return f2fs_lfs_mode(F2FS_I_SB(inode)); +} + static inline bool f2fs_is_sequential_zone_area(struct f2fs_sb_info *sbi, block_t blkaddr) { diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 51518caee460..37d4e5c8dbcb 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -5022,7 +5022,7 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb= , struct iov_iter *iter, int ret; =20 /* If it will be an out-of-place direct write, don't bother. */ - if (dio && f2fs_lfs_mode(sbi)) + if (dio && f2fs_should_opu(inode)) return 0; /* * Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into @@ -5166,7 +5166,7 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *iocb= , struct iov_iter *from, struct inode *inode =3D file_inode(file); struct f2fs_inode_info *fi =3D F2FS_I(inode); struct f2fs_sb_info *sbi =3D F2FS_I_SB(inode); - const bool do_opu =3D f2fs_lfs_mode(sbi) && !f2fs_is_pinned_file(inode); + const bool do_opu =3D f2fs_should_opu(inode); const loff_t pos =3D iocb->ki_pos; const ssize_t count =3D iov_iter_count(from); unsigned int dio_flags; @@ -5182,7 +5182,7 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *iocb= , struct iov_iter *from, =20 if (iocb->ki_flags & IOCB_NOWAIT) { /* f2fs_convert_inline_inode() and block allocation can block */ - if (f2fs_has_inline_data(inode) || + if (do_opu || f2fs_has_inline_data(inode) || !f2fs_overwrite_io(inode, pos, count)) { ret =3D -EAGAIN; goto out; @@ -5192,11 +5192,6 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *ioc= b, struct iov_iter *from, ret =3D -EAGAIN; goto out; } - if (do_opu && !f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) { - f2fs_up_read(&fi->i_gc_rwsem[WRITE]); - ret =3D -EAGAIN; - goto out; - } } else { ret =3D f2fs_convert_inline_inode(inode); if (ret) --=20 2.43.0 From nobody Sat Sep 26 23:52:38 2026 Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 20D681EB19B for ; Fri, 28 Aug 2026 07:20:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901640; cv=none; b=Oc8tm+1NBE9ztbMdvak9I4Jr/Sd5ca0MYC7F3+RrVUepmXhdSEQzv8INyqx/AppAokPsWZFkxBhOe2ce/r9BHZ/GubNgI4zBG+xEcZiQrp1T5Ixr6QJElkSmuZeYBEhrAb7TyOe/LfDv6rC686D6iIGwKve3bYwiiAn61Qza15s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787901640; c=relaxed/simple; bh=VG+hXsLXq4BKugwwvzbh3RHjloZDs7ndG/ibMSNUMWg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=A0jfafVFYQzbEq0h5NvvTBDwb36MErIFN51Anuc6x+AKYH+Mov3nszha99/rcP4fV9lSPifY4fTc37uJubusqBFq/CSxflCRMacPOM9/XDVrz9G19nem9hbDrLrG3YpUphQ0GfDFkQE2BvkEWZBaQ61QNut/6QZuYif4ui9Q90k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hb/Zx2lv; arc=none smtp.client-ip=209.85.214.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hb/Zx2lv" Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-2d58efc7356so6351245ad.1 for ; Fri, 28 Aug 2026 00:20:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787901638; x=1788506438; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vpJQdL71fncq3A1DKuUk0L7Wkeu7zNdyUOmsnNXN+mE=; b=hb/Zx2lvnNwNG/uDdGkdRSRwTjZRmb5SnVwcwoxxkbPG4JLwTSjk209jdkq6ivhcQX OZAtNgELQcEC4FBtH1JH9gBrdrbWgpdtPGBdv6LtESQfIruHs64r8Na2EFmVTh1JFfvG +isPfsuvj8wHAgWnoPVI347yrxIbgCqNLeHdrmCexE1op2nQlj2HmzsSB04mfLJiDdgB f3xtGeBDFjx3G2wZI8vGlRfyr2PUmHGw7IW3VA3W2H7N8ByqsKfmQagE2J/zDS9c4muw rx5awAS2Ls0eqb04M+BKjcHu+x9ku4GtBTlEf3WYMN2w9rKwd/ipTlPvtqFe0fOFpSyh 8jFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787901638; x=1788506438; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=vpJQdL71fncq3A1DKuUk0L7Wkeu7zNdyUOmsnNXN+mE=; b=iogcW5zdOGhVdmRah1GXgTTXpBfbjV+d21v+OreHtZF2dGzs7an24+TniIvRADVkPO BT3edZEoEnOqu1XTsgAKke5Xab0rgwWGa+8pQ6xV5y9FHOjEZ6GcJl05n35qg9Iq9yZf oRn73+ZT9FILUsZ30sNFWKWEoxh4vxPvhKKNiLvcZxMY/ZAtEY0sxYnyCySKzZH0JGLr 5okMBKr6e7/l7EA3Db7lKtvLQMGNyt/tB6L0RIpZbzk+aYtjZDi6AAIFDA7dqTKAXYgP NzyOf2wB9hFWSw/rlpeHiCcXaEZ+aBExKF4/6D9Lki8ptz/WbrbjRbzpEymv+XdwTPgk Y4UQ== X-Forwarded-Encrypted: i=1; AHgh+RpQbYxBrcucKsk1c23vnsWITriwha6aRaDHtTg5616O0bzJIpAxWaBWfeK3UQ+c1ewDTREWxiC3kQOjuJw=@vger.kernel.org X-Gm-Message-State: AFuF++nEU/3NNJKqsnBRFYZaK2OAiLz2OF/uLRVJrPFS1NITOvdT0emk vDFm6U81sKv0kqnfasZ6rXKLjULmFrdcmtVgW2MN++64PuJhSdQyQ4V3hRLDbg== X-Gm-Gg: AR+sD13Amy/csrdGTaFTIkkrWCDGNHFTXJQAmo4MK/YcmibQmTBLR4XPi2aCYu/r5gM nkHcdSwMCBBD1a76yuvihhd3rlKSSXMBHpoq8wAw3x1HjMe7yBOIBPR4F/LQtBQERtoghB1q0iF P1XWrkqolGWb6tyBidbbPaSH9seNIaxMsaayDxoNP0OSN4JMRLBNYwm+Y8woIE8o1AdykGR65RA GiD/BLO04b9Enbqb8MSYAw9ZXMg4AMV8oigVmZJkWHguUcWyyHy/x3WOMZHDgzbIfJ1/TnbYoX3 eZBjIazW1QMc23sBtx1wUfaXid4gHUp5BvMgJafDDl2qI0e5e6V4ct/xVB0lj8QZNl0Z3nR3rzj Mg/FlfTW3A7mDlfUjbHhLvl4wd+ESj7PrXlhiWV48KXz4Qx8K8OylEehkuB/4Iz1M94xmyI1ryX 40OxTMAnaI/whPfoxsHOcjJU+cGeLlGq0hhaBJq34N5NWJ+j4PCkj7d/NMLMA2C+EfjvQqrzBX+ XjIuQ== X-Received: by 2002:a17:90b:380a:b0:38f:de97:b06 with SMTP id 98e67ed59e1d1-396d0daf810mr9330220a91.5.1787901638253; Fri, 28 Aug 2026 00:20:38 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-396b0ea7fa9sm6123731a91.4.2026.08.28.00.20.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 00:20:37 -0700 (PDT) From: Jeuk Kim X-Google-Original-From: Jeuk Kim To: Jaegeuk Kim , Chao Yu Cc: Yohan Joung , linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, j-young.choi@samsung.com, yunjae00.jo@samsung.com, keosung.park@samsung.com, Jeuk Kim Subject: [PATCH 3/3] f2fs: add ioctl to force out-place-update per file Date: Fri, 28 Aug 2026 16:20:17 +0900 Message-ID: <20260828072017.44569-4-jeuk20.kim@samsung.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260828072017.44569-1-jeuk20.kim@samsung.com> References: <20260828072017.44569-1-jeuk20.kim@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Out-place-update can only be enabled for an entire filesystem, via the "mode=3Dlfs" mount option or the ipu_policy sysfs entry. There is no way to force OPU on a single file. Add F2FS_OPU_FL and F2FS_IOC_{SET,GET}_OPU_FILE to control OPU on a per-file basis. Reject OPU for pinned, swap, and device-alias files because they require stable block addresses. The flag forces OPU without enabling LFS mode, so block allocation may still use SSR. The flag is kept in the on-disk i_flags word, so it survives umount and inode eviction. An older kernel preserves the bit but ignores it and applies its normal update policy to the file. Signed-off-by: Jeuk Kim --- fs/f2fs/data.c | 25 ++++++++++---- fs/f2fs/f2fs.h | 9 ++++- fs/f2fs/file.c | 69 +++++++++++++++++++++++++++++++++++++-- include/uapi/linux/f2fs.h | 2 ++ 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 618e6fc2da0c..2babfcf1dae5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1639,12 +1639,13 @@ int f2fs_map_blocks(struct inode *inode, struct f2f= s_map_blocks *map, int flag) unsigned int start_pgofs; int bidx =3D 0; bool is_hole; - bool lfs_dio_write; + bool opu_dio_write; =20 if (!maxblocks) return 0; =20 - lfs_dio_write =3D (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_should_opu(inod= e) && + opu_dio_write =3D (flag =3D=3D F2FS_GET_BLOCK_DIO && + f2fs_should_opu(inode) && map->m_may_create); =20 if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) { @@ -1685,7 +1686,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_= map_blocks *map, int flag) =20 next_dnode: if (map->m_may_create) { - if (f2fs_lfs_mode(sbi)) + if (f2fs_lfs_mode(sbi) || f2fs_is_opu_file(inode)) f2fs_balance_fs(sbi, true); f2fs_map_lock(sbi, &lc, flag); } @@ -1715,9 +1716,10 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs= _map_blocks *map, int flag) goto sync_out; } =20 - /* use out-place-update for direct IO under LFS mode */ + /* use out-place-update for direct IO under LFS mode or on OPU files */ if (map->m_may_create && (is_hole || - (flag =3D=3D F2FS_GET_BLOCK_DIO && f2fs_should_opu(inode) && + (flag =3D=3D F2FS_GET_BLOCK_DIO && + f2fs_should_opu(inode) && map->m_last_pblk !=3D blkaddr))) { if (unlikely(f2fs_cp_error(sbi))) { err =3D -EIO; @@ -1804,13 +1806,13 @@ int f2fs_map_blocks(struct inode *inode, struct f2f= s_map_blocks *map, int flag) if (map->m_multidev_dio) map->m_bdev =3D FDEV(bidx).bdev; =20 - if (lfs_dio_write) + if (opu_dio_write) map->m_last_pblk =3D NULL_ADDR; } else if (map_is_mergeable(sbi, map, blkaddr, flag, bidx, ofs)) { ofs++; map->m_len++; } else { - if (lfs_dio_write) + if (opu_dio_write) map->m_last_pblk =3D blkaddr; goto sync_out; } @@ -2862,6 +2864,9 @@ bool f2fs_should_update_inplace(struct inode *inode, = struct f2fs_io_info *fio) if (f2fs_is_pinned_file(inode)) return true; =20 + if (f2fs_is_opu_file(inode)) + return false; + /* if this is cold file, we should overwrite to avoid fragmentation */ if (file_is_cold(inode) && !is_inode_flag_set(inode, FI_OPU_WRITE)) return true; @@ -2899,6 +2904,9 @@ bool f2fs_should_update_outplace(struct inode *inode,= struct f2fs_io_info *fio) if (is_inode_flag_set(inode, FI_OPU_WRITE)) return true; =20 + if (f2fs_is_opu_file(inode)) + return true; + if (fio) { if (page_private_gcing(fio->page)) return true; @@ -4357,6 +4365,9 @@ static int f2fs_swap_activate(struct swap_info_struct= *sis, struct file *file, if (f2fs_readonly(sbi->sb)) return -EROFS; =20 + if (f2fs_is_opu_file(inode)) + return -EINVAL; + if (f2fs_lfs_mode(sbi) && !f2fs_sb_has_blkzoned(sbi)) { f2fs_err(sbi, "Swapfile not supported in LFS mode"); return -EINVAL; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index e85d4db3a401..79f3f365432a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3322,6 +3322,7 @@ static inline void f2fs_change_bit(unsigned int nr, c= har *addr) #define F2FS_NOCOMP_FL 0x00000400 /* Don't compress */ #define F2FS_INDEX_FL 0x00001000 /* hash-indexed directory */ #define F2FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories onl= y) */ +#define F2FS_OPU_FL 0x01000000 /* File always uses out-place-update */ #define F2FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ #define F2FS_CASEFOLD_FL 0x40000000 /* Casefolded file */ #define F2FS_DEVICE_ALIAS_FL 0x80000000 /* File for aliasing a device */ @@ -3598,6 +3599,11 @@ static inline bool f2fs_is_pinned_file(struct inode = *inode) return is_inode_flag_set(inode, FI_PIN_FILE); } =20 +static inline bool f2fs_is_opu_file(struct inode *inode) +{ + return F2FS_I(inode)->i_flags & F2FS_OPU_FL; +} + static inline bool f2fs_is_atomic_file(struct inode *inode) { return is_inode_flag_set(inode, FI_ATOMIC_FILE); @@ -4944,7 +4950,8 @@ static inline bool f2fs_should_opu(struct inode *inod= e) if (f2fs_is_pinned_file(inode)) return false; =20 - return f2fs_lfs_mode(F2FS_I_SB(inode)); + return f2fs_lfs_mode(F2FS_I_SB(inode)) || + f2fs_is_opu_file(inode); } =20 static inline bool f2fs_is_sequential_zone_area(struct f2fs_sb_info *sbi, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 37d4e5c8dbcb..09731ad05d70 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -3558,6 +3558,9 @@ static int f2fs_ioc_set_pin_file(struct file *filp, u= nsigned long arg) goto done; } else if (f2fs_is_pinned_file(inode)) { goto done; + } else if (f2fs_is_opu_file(inode)) { + ret =3D -EINVAL; + goto out; } =20 if (F2FS_HAS_BLOCKS(inode)) { @@ -3606,6 +3609,62 @@ static int f2fs_ioc_get_pin_file(struct file *filp, = unsigned long arg) return put_user(pin, (u32 __user *)arg); } =20 +static int f2fs_ioc_set_opu_file(struct file *filp, unsigned long arg) +{ + struct inode *inode =3D file_inode(filp); + struct f2fs_sb_info *sbi =3D F2FS_I_SB(inode); + struct f2fs_inode_info *fi =3D F2FS_I(inode); + __u32 opu; + int ret; + + if (get_user(opu, (__u32 __user *)arg)) + return -EFAULT; + + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + if (f2fs_readonly(sbi->sb)) + return -EROFS; + + ret =3D mnt_want_write_file(filp); + if (ret) + return ret; + + inode_lock(inode); + + if (!opu) { + /* + * Direct writes issued while the flag was set may still be in + * flight with their blocks unwritten, so drain them before + * f2fs_file_read_iter() stops serializing against them. + */ + if (f2fs_is_opu_file(inode)) + inode_dio_wait(inode); + fi->i_flags &=3D ~F2FS_OPU_FL; + goto done; + } + + if (f2fs_is_pinned_file(inode) || IS_DEVICE_ALIASING(inode)) { + ret =3D -EINVAL; + goto out; + } + + fi->i_flags |=3D F2FS_OPU_FL; +done: + f2fs_mark_inode_dirty_sync(inode, true); + f2fs_update_time(sbi, REQ_TIME); +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return ret; +} + +static int f2fs_ioc_get_opu_file(struct file *filp, unsigned long arg) +{ + return put_user(f2fs_is_opu_file(file_inode(filp)) ? 1 : 0, + (__u32 __user *)arg); +} + static int f2fs_ioc_get_dev_alias_file(struct file *filp, unsigned long ar= g) { return put_user(IS_DEVICE_ALIASING(file_inode(filp)) ? 1 : 0, @@ -4740,6 +4799,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned= int cmd, unsigned long arg) return f2fs_ioc_get_dev_alias_file(filp, arg); case F2FS_IOC_IO_PRIO: return f2fs_ioc_io_prio(filp, arg); + case F2FS_IOC_SET_OPU_FILE: + return f2fs_ioc_set_opu_file(filp, arg); + case F2FS_IOC_GET_OPU_FILE: + return f2fs_ioc_get_opu_file(filp, arg); default: return -ENOTTY; } @@ -4936,8 +4999,8 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb= , struct iov_iter *to) =20 dio =3D f2fs_should_use_dio(inode, iocb, to); =20 - /* In LFS mode, if there is inflight dio, wait for its completion */ - if (f2fs_lfs_mode(F2FS_I_SB(inode)) && + /* For OPU direct writes, wait for any inflight dio to complete */ + if ((f2fs_lfs_mode(F2FS_I_SB(inode)) || f2fs_is_opu_file(inode)) && get_pages(F2FS_I_SB(inode), F2FS_DIO_WRITE) && (!f2fs_is_pinned_file(inode) || !dio)) inode_dio_wait(inode); @@ -5522,6 +5585,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned in= t cmd, unsigned long arg) case F2FS_IOC_COMPRESS_FILE: case F2FS_IOC_GET_DEV_ALIAS_FILE: case F2FS_IOC_IO_PRIO: + case F2FS_IOC_SET_OPU_FILE: + case F2FS_IOC_GET_OPU_FILE: break; default: return -ENOIOCTLCMD; diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h index 795e26258355..ebfef7e88bcb 100644 --- a/include/uapi/linux/f2fs.h +++ b/include/uapi/linux/f2fs.h @@ -45,6 +45,8 @@ #define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25) #define F2FS_IOC_GET_DEV_ALIAS_FILE _IOR(F2FS_IOCTL_MAGIC, 26, __u32) #define F2FS_IOC_IO_PRIO _IOW(F2FS_IOCTL_MAGIC, 27, __u32) +#define F2FS_IOC_SET_OPU_FILE _IOW(F2FS_IOCTL_MAGIC, 28, __u32) +#define F2FS_IOC_GET_OPU_FILE _IOR(F2FS_IOCTL_MAGIC, 29, __u32) =20 /* * should be same as XFS_IOC_GOINGDOWN. --=20 2.43.0