{"id":2230333,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2230333/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/patch/177747215490.4110156.16017408606598893564.stgit@frogsfrogsfrogs/","project":{"id":8,"url":"http://patchwork.ozlabs.org/api/1.1/projects/8/?format=json","name":"Linux ext4 filesystem development","link_name":"linux-ext4","list_id":"linux-ext4.vger.kernel.org","list_email":"linux-ext4@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<177747215490.4110156.16017408606598893564.stgit@frogsfrogsfrogs>","date":"2026-04-29T15:00:11","name":"[06/10] fuse2fs: use coarse timestamps for iomap mode","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"54e1f19944c3ad7d69331a6caf4060aeef94e2ce","submitter":{"id":77032,"url":"http://patchwork.ozlabs.org/api/1.1/people/77032/?format=json","name":"Darrick J. Wong","email":"djwong@kernel.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-ext4/patch/177747215490.4110156.16017408606598893564.stgit@frogsfrogsfrogs/mbox/","series":[{"id":502091,"url":"http://patchwork.ozlabs.org/api/1.1/series/502091/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/list/?series=502091","date":"2026-04-29T14:59:24","name":"[01/10] fuse2fs: add strictatime/lazytime mount options","version":1,"mbox":"http://patchwork.ozlabs.org/series/502091/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230333/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2230333/checks/","tags":{},"headers":{"Return-Path":"\n <SRS0=y1C+=C4=vger.kernel.org=linux-ext4+bounces-16218-patchwork-incoming=ozlabs.org@ozlabs.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-ext4@vger.kernel.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","patchwork-incoming@ozlabs.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=tVQo9MXc;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=2404:9400:2221:ea00::3; helo=mail.ozlabs.org;\n envelope-from=srs0=y1c+=c4=vger.kernel.org=linux-ext4+bounces-16218-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)","gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=172.234.253.10 arc.chain=subspace.kernel.org","gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org","gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=tVQo9MXc;\n\tdkim-atps=neutral","gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.234.253.10; helo=sea.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16218-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"tVQo9MXc\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5LF61CCFz1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 01:04:42 +1000 (AEST)","from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4g5LF60kbLz4wHs\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 01:04:42 +1000 (AEST)","by gandalf.ozlabs.org (Postfix)\n\tid 4g5LF60fMvz4wSR; Thu, 30 Apr 2026 01:04:42 +1000 (AEST)","from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4g5LF060T2z4wHs\n\tfor <patchwork-incoming@ozlabs.org>; Thu, 30 Apr 2026 01:04:36 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id C1D903034669\n\tfor <patchwork-incoming@ozlabs.org>; Wed, 29 Apr 2026 15:00:12 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id CA50E2F8BF0;\n\tWed, 29 Apr 2026 15:00:11 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 8CF92308F23;\n\tWed, 29 Apr 2026 15:00:11 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 5E6D9C19425;\n\tWed, 29 Apr 2026 15:00:11 +0000 (UTC)"],"ARC-Seal":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1777475082; cv=pass;\n\tb=TJngnYHLC8JR8DsciGSLH5e86OvIH9GKZ/j0mz0eFQmxenUlctwd74fMdbd1ekaeId/fbf3KgeObtm/mFF3d5ov7Ic/MoLMWdFKWBB1/6+N5KwEsTh0szr2PK4G/nBzW7upvXEfU/dAvO5S2BCW40SCmRaG1HfzTURj+75Y7k5ImSeKsztxrTaMXrjlCxpRSx4F+xynQj3MOTlUcqxo7oJcGqEWdcVeXyV61hC3VHRN58t2iiKR6mHTds84nC8H9vZ27/OOc32Ynpd/I72Na7Izo9J5ogT046sk1Wq4FrM7ug3Y+57Y0oDxJlsjPCLr7GpLi44R7C8EZ3Tg8FHZuzw==","i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777474811; cv=none;\n b=BfYOnCwWqkzqxG746DUK6QB2ESRj5YLD4tqc+HNBBlxTsOsnasTsdGh0o4U7IQ9TrVHMEuXyDR5tqXUCoo/LYk+GYNtimIn8tZJEJ+dzMTOulzMJPGMUSzYI+FOPqDaHizlB2cAuCDopQtyt9mBg7X9IjtfxYsa2kM7lLhukdq4="],"ARC-Message-Signature":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1777475082; c=relaxed/relaxed;\n\tbh=oupTlDDH3yGx05jQ3brSzTMzIWYDSINulQYsL5xltto=;\n\th=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=H9LADOxUFYVEa9M5xi/g6iE9W4PQZ4qdRx0VGwXwCkUnUKC+GCKA84tpUM30Zy0UXn1k2csvMp6VHcuYSQj56p409Ovi6MyAbUtzqCnjq+uD1pLtKMcvxtLQXGCtwvjgD/GJSHt6RqeU6clBTf+ib9WQcwOWafBNsEMxjwh/v6PNan51/cGhMC6SVFW/WkQfP7RHuCFeOYZhe1grebnTxjnCj0sbTFnL32EjayPS5j4krbBIVhPtrItCbc3hrQteb/pi1VwEgIIStTOG/i0Lh1eFDTLR3XoRsZPkijku9QwBYlaBb4vIyO2URFYZyZhVqcJqBaeTKFyOzadWhgWNkA==","i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777474811; c=relaxed/simple;\n\tbh=VMzFwbpTknTCG0L5VYbN/WSNN1fFC7Tck7nyL6u7sXA=;\n\th=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=BpYpOnqfUjV4RbX8lCoyBWDFhQf+svaK3uQxzN0ZzfEf6jXZTM7Y5YbLzERypegaAhH90+Fu//sXkHe4CVi+yE6HRgXGoV1a16WwmBrjsC7pXFHCjSmjP1lh/EIn3bb4V+ItXj5vESj0vc2j/TNBDqr1BV6EA+Lrbtv1ILFBq4c="],"ARC-Authentication-Results":["i=2; gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org;\n dkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=tVQo9MXc; dkim-atps=neutral;\n spf=pass (client-ip=172.234.253.10; helo=sea.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16218-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org","i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=tVQo9MXc; arc=none smtp.client-ip=10.30.226.201"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777474811;\n\tbh=VMzFwbpTknTCG0L5VYbN/WSNN1fFC7Tck7nyL6u7sXA=;\n\th=Date:Subject:From:To:Cc:In-Reply-To:References:From;\n\tb=tVQo9MXcdA/9GzxBaVO44/za2Be8tt1M9QMUrI86SC0dgcoHZIqjvnC9Kjc0LIUZO\n\t 1RtnHPk5o9TEyyLmm7f3wN1jJ4dbxLKXEigkTwGpy2Sh1vLXMD7cw1exVBjaTHFz0b\n\t peciMU8xOLJhDxy7VsFeOAPjkgktxTD4Gcb6a8VdNAW3ypi35TandnVpBMNM/RjzBA\n\t dvBdV8uSoWQSCzPhuGkyFdOY3fSNlr04rbObqJshkbcRvOe2ddaLHr5J3zeKdZ/yxK\n\t 79mQo49aFMshXToCIv4hVooRT6P64ORLh4prTIYMDBoHQCaCisF2L4oWslPESFnQmA\n\t QmKuoOkt+yVAw==","Date":"Wed, 29 Apr 2026 08:00:11 -0700","Subject":"[PATCH 06/10] fuse2fs: use coarse timestamps for iomap mode","From":"\"Darrick J. Wong\" <djwong@kernel.org>","To":"tytso@mit.edu","Cc":"bernd@bsbernd.com, miklos@szeredi.hu, linux-ext4@vger.kernel.org,\n neal@gompa.dev, linux-fsdevel@vger.kernel.org, fuse-devel@lists.linux.dev,\n joannelkoong@gmail.com","Message-ID":"<177747215490.4110156.16017408606598893564.stgit@frogsfrogsfrogs>","In-Reply-To":"<177747215344.4110156.17216553139316774040.stgit@frogsfrogsfrogs>","References":"<177747215344.4110156.17216553139316774040.stgit@frogsfrogsfrogs>","Precedence":"bulk","X-Mailing-List":"linux-ext4@vger.kernel.org","List-Id":"<linux-ext4.vger.kernel.org>","List-Subscribe":"<mailto:linux-ext4+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-ext4+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","X-Spam-Status":"No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1","X-Spam-Checker-Version":"SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org"},"content":"From: Darrick J. Wong <djwong@kernel.org>\n\nIn iomap mode, the kernel is responsible for maintaining timestamps\nbecause file writes don't upcall to fuse2fs.  The kernel's predicate for\ndeciding if [cm]time should be updated bases its decisions off [cm]time\nbeing an exact match for the coarse clock (instead of checking that\n[cm]time < coarse_clock) which means that fuse2fs setting a fine-grained\ntimestamp that is slightly ahead of the coarse clock can result in\ntimestamps appearing to go backwards.  generic/423 doesn't like seeing\nbtime > ctime from statx, so we'll use the coarse clock in iomap mode.\n\nSigned-off-by: \"Darrick J. Wong\" <djwong@kernel.org>\n---\n fuse4fs/fuse4fs.c |  110 +++++++++++++++++++++++++++++++----------------------\n misc/fuse2fs.c    |   34 ++++++++++++----\n 2 files changed, 90 insertions(+), 54 deletions(-)","diff":"diff --git a/fuse4fs/fuse4fs.c b/fuse4fs/fuse4fs.c\nindex 567b576e5f5779..8a9ada8905983d 100644\n--- a/fuse4fs/fuse4fs.c\n+++ b/fuse4fs/fuse4fs.c\n@@ -1043,8 +1043,24 @@ static inline void fuse4fs_dump_extents(struct fuse4fs *ff, ext2_ino_t ino,\n \text2fs_extent_free(extents);\n }\n \n-static void get_now(struct timespec *now)\n+static void fuse4fs_get_now(struct fuse4fs *ff, struct timespec *now)\n {\n+#ifdef CLOCK_REALTIME_COARSE\n+\t/*\n+\t * In iomap mode, the kernel is responsible for maintaining timestamps\n+\t * because file writes don't upcall to fuse4fs.  The kernel's predicate\n+\t * for deciding if [cm]time should be updated bases its decisions off\n+\t * [cm]time being an exact match for the coarse clock (instead of\n+\t * checking that [cm]time < coarse_clock) which means that fuse4fs\n+\t * setting a fine-grained timestamp that is slightly ahead of the\n+\t * coarse clock can result in timestamps appearing to go backwards.\n+\t * generic/423 doesn't like seeing btime > ctime from statx, so we'll\n+\t * use the coarse clock in iomap mode.\n+\t */\n+\tif (fuse4fs_iomap_enabled(ff) &&\n+\t    !clock_gettime(CLOCK_REALTIME_COARSE, now))\n+\t\treturn;\n+#endif\n #ifdef CLOCK_REALTIME\n \tif (!clock_gettime(CLOCK_REALTIME, now))\n \t\treturn;\n@@ -1067,11 +1083,12 @@ static void increment_version(struct ext2_inode_large *inode)\n \t\tinode->i_version_hi = ver >> 32;\n }\n \n-static void init_times(struct ext2_inode_large *inode)\n+static void fuse4fs_init_timestamps(struct fuse4fs *ff,\n+\t\t\t\t    struct ext2_inode_large *inode)\n {\n \tstruct timespec now;\n \n-\tget_now(&now);\n+\tfuse4fs_get_now(ff, &now);\n \tEXT4_INODE_SET_XTIME(i_atime, &now, inode);\n \tEXT4_INODE_SET_XTIME(i_ctime, &now, inode);\n \tEXT4_INODE_SET_XTIME(i_mtime, &now, inode);\n@@ -1079,14 +1096,15 @@ static void init_times(struct ext2_inode_large *inode)\n \tincrement_version(inode);\n }\n \n-static int update_ctime(ext2_filsys fs, ext2_ino_t ino,\n-\t\t\tstruct ext2_inode_large *pinode)\n+static int fuse4fs_update_ctime(struct fuse4fs *ff, ext2_ino_t ino,\n+\t\t\t\tstruct ext2_inode_large *pinode)\n {\n-\terrcode_t err;\n \tstruct timespec now;\n \tstruct ext2_inode_large inode;\n+\text2_filsys fs = ff->fs;\n+\terrcode_t err;\n \n-\tget_now(&now);\n+\tfuse4fs_get_now(ff, &now);\n \n \t/* If user already has a inode buffer, just update that */\n \tif (pinode) {\n@@ -1110,12 +1128,13 @@ static int update_ctime(ext2_filsys fs, ext2_ino_t ino,\n \treturn 0;\n }\n \n-static int update_atime(ext2_filsys fs, ext2_ino_t ino)\n+static int fuse4fs_update_atime(struct fuse4fs *ff, ext2_ino_t ino)\n {\n-\terrcode_t err;\n \tstruct ext2_inode_large inode, *pinode;\n \tstruct timespec atime, mtime, now;\n+\text2_filsys fs = ff->fs;\n \tdouble datime, dmtime, dnow;\n+\terrcode_t err;\n \n \terr = fuse4fs_read_inode(fs, ino, &inode);\n \tif (err)\n@@ -1124,7 +1143,7 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)\n \tpinode = &inode;\n \tEXT4_INODE_GET_XTIME(i_atime, &atime, pinode);\n \tEXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);\n-\tget_now(&now);\n+\tfuse4fs_get_now(ff, &now);\n \n \tdatime = atime.tv_sec + ((double)atime.tv_nsec / NSEC_PER_SEC);\n \tdmtime = mtime.tv_sec + ((double)mtime.tv_nsec / NSEC_PER_SEC);\n@@ -1146,15 +1165,16 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)\n \treturn 0;\n }\n \n-static int update_mtime(ext2_filsys fs, ext2_ino_t ino,\n-\t\t\tstruct ext2_inode_large *pinode)\n+static int fuse4fs_update_mtime(struct fuse4fs *ff, ext2_ino_t ino,\n+\t\t\t\tstruct ext2_inode_large *pinode)\n {\n-\terrcode_t err;\n \tstruct ext2_inode_large inode;\n \tstruct timespec now;\n+\text2_filsys fs = ff->fs;\n+\terrcode_t err;\n \n \tif (pinode) {\n-\t\tget_now(&now);\n+\t\tfuse4fs_get_now(ff, &now);\n \t\tEXT4_INODE_SET_XTIME(i_mtime, &now, pinode);\n \t\tEXT4_INODE_SET_XTIME(i_ctime, &now, pinode);\n \t\tincrement_version(pinode);\n@@ -1165,7 +1185,7 @@ static int update_mtime(ext2_filsys fs, ext2_ino_t ino,\n \tif (err)\n \t\treturn translate_error(fs, ino, err);\n \n-\tget_now(&now);\n+\tfuse4fs_get_now(ff, &now);\n \tEXT4_INODE_SET_XTIME(i_mtime, &now, &inode);\n \tEXT4_INODE_SET_XTIME(i_ctime, &now, &inode);\n \tincrement_version(&inode);\n@@ -2701,7 +2721,7 @@ static void op_readlink(fuse_req_t req, fuse_ino_t fino)\n \tbuf[len] = 0;\n \n \tif (fuse4fs_is_writeable(ff)) {\n-\t\tret = update_atime(fs, ino);\n+\t\tret = fuse4fs_update_atime(ff, ino);\n \t\tif (ret)\n \t\t\tgoto out;\n \t}\n@@ -2970,7 +2990,7 @@ static void op_mknod(fuse_req_t req, fuse_ino_t fino, const char *name,\n \t\tgoto out2;\n \t}\n \n-\tret = update_mtime(fs, parent, NULL);\n+\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \tif (ret)\n \t\tgoto out2;\n \n@@ -2993,7 +3013,7 @@ static void op_mknod(fuse_req_t req, fuse_ino_t fino, const char *name,\n \t}\n \n \tinode.i_generation = ff->next_generation++;\n-\tinit_times(&inode);\n+\tfuse4fs_init_timestamps(ff, &inode);\n \terr = fuse4fs_write_inode(fs, child, &inode);\n \tif (err) {\n \t\tret = translate_error(fs, child, err);\n@@ -3055,7 +3075,7 @@ static void op_mkdir(fuse_req_t req, fuse_ino_t fino, const char *name,\n \t\tgoto out2;\n \t}\n \n-\tret = update_mtime(fs, parent, NULL);\n+\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \tif (ret)\n \t\tgoto out2;\n \n@@ -3081,7 +3101,7 @@ static void op_mkdir(fuse_req_t req, fuse_ino_t fino, const char *name,\n \tif (parent_sgid)\n \t\tinode.i_mode |= S_ISGID;\n \tinode.i_generation = ff->next_generation++;\n-\tinit_times(&inode);\n+\tfuse4fs_init_timestamps(ff, &inode);\n \n \terr = fuse4fs_write_inode(fs, child, &inode);\n \tif (err) {\n@@ -3432,7 +3452,7 @@ static int fuse4fs_remove_inode(struct fuse4fs *ff, ext2_ino_t ino)\n \t\tinode.i_links_count--;\n \t}\n \n-\tret = update_ctime(fs, ino, &inode);\n+\tret = fuse4fs_update_ctime(ff, ino, &inode);\n \tif (ret)\n \t\treturn ret;\n \n@@ -3504,7 +3524,7 @@ static int fuse4fs_unlink(struct fuse4fs *ff, ext2_ino_t parent,\n \t\tgoto out;\n \t}\n \n-\tret = update_mtime(fs, parent, NULL);\n+\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \tif (ret)\n \t\tgoto out;\n out:\n@@ -3638,7 +3658,7 @@ static int fuse4fs_rmdir(struct fuse4fs *ff, ext2_ino_t parent,\n \t\t\tgoto out;\n \t\t}\n \t\text2fs_dec_nlink(EXT2_INODE(&inode));\n-\t\tret = update_mtime(fs, rds.parent, &inode);\n+\t\tret = fuse4fs_update_mtime(ff, rds.parent, &inode);\n \t\tif (ret)\n \t\t\tgoto out;\n \t\terr = fuse4fs_write_inode(fs, rds.parent, &inode);\n@@ -3742,7 +3762,7 @@ static void op_symlink(fuse_req_t req, const char *target, fuse_ino_t fino,\n \t}\n \n \t/* Update parent dir's mtime */\n-\tret = update_mtime(fs, parent, NULL);\n+\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \tif (ret)\n \t\tgoto out2;\n \n@@ -3765,7 +3785,7 @@ static void op_symlink(fuse_req_t req, const char *target, fuse_ino_t fino,\n \tfuse4fs_set_uid(&inode, ctxt->uid);\n \tfuse4fs_set_gid(&inode, gid);\n \tinode.i_generation = ff->next_generation++;\n-\tinit_times(&inode);\n+\tfuse4fs_init_timestamps(ff, &inode);\n \n \terr = fuse4fs_write_inode(fs, child, &inode);\n \tif (err) {\n@@ -3996,11 +4016,11 @@ static void op_rename(fuse_req_t req, fuse_ino_t from_parent, const char *from,\n \t}\n \n \t/* Update timestamps */\n-\tret = update_ctime(fs, from_ino, NULL);\n+\tret = fuse4fs_update_ctime(ff, from_ino, NULL);\n \tif (ret)\n \t\tgoto out;\n \n-\tret = update_mtime(fs, to_dir_ino, NULL);\n+\tret = fuse4fs_update_mtime(ff, to_dir_ino, NULL);\n \tif (ret)\n \t\tgoto out;\n \n@@ -4079,7 +4099,7 @@ static void op_link(fuse_req_t req, fuse_ino_t child_fino,\n \t}\n \n \text2fs_inc_nlink(fs, EXT2_INODE(&inode));\n-\tret = update_ctime(fs, child, &inode);\n+\tret = fuse4fs_update_ctime(ff, child, &inode);\n \tif (ret)\n \t\tgoto out2;\n \n@@ -4096,7 +4116,7 @@ static void op_link(fuse_req_t req, fuse_ino_t child_fino,\n \t\tgoto out2;\n \t}\n \n-\tret = update_mtime(fs, parent, NULL);\n+\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \tif (ret)\n \t\tgoto out2;\n \n@@ -4332,7 +4352,7 @@ static int fuse4fs_truncate(struct fuse4fs *ff, ext2_ino_t ino, off_t new_size)\n \tif (err)\n \t\treturn translate_error(fs, ino, err);\n \n-\tret = update_mtime(fs, ino, NULL);\n+\tret = fuse4fs_update_mtime(ff, ino, NULL);\n \tif (ret)\n \t\treturn ret;\n \n@@ -4541,7 +4561,7 @@ static void op_read(fuse_req_t req, fuse_ino_t fino EXT2FS_ATTR((unused)),\n \t}\n \n \tif (fh->check_flags != X_OK && fuse4fs_is_writeable(ff)) {\n-\t\tret = update_atime(fs, fh->ino);\n+\t\tret = fuse4fs_update_atime(ff, fh->ino);\n \t\tif (ret)\n \t\t\tgoto out;\n \t}\n@@ -4615,7 +4635,7 @@ static void op_write(fuse_req_t req, fuse_ino_t fino EXT2FS_ATTR((unused)),\n \t\tgoto out;\n \t}\n \n-\tret = update_mtime(fs, fh->ino, NULL);\n+\tret = fuse4fs_update_mtime(ff, fh->ino, NULL);\n \tif (ret)\n \t\tgoto out;\n \n@@ -5062,7 +5082,7 @@ static void op_setxattr(fuse_req_t req, fuse_ino_t fino, const char *key,\n \t\tgoto out2;\n \t}\n \n-\tret = update_ctime(fs, ino, NULL);\n+\tret = fuse4fs_update_ctime(ff, ino, NULL);\n out2:\n \terr = ext2fs_xattrs_close(&h);\n \tif (!ret && err)\n@@ -5156,7 +5176,7 @@ static void op_removexattr(fuse_req_t req, fuse_ino_t fino, const char *key)\n \t\tgoto out2;\n \t}\n \n-\tret = update_ctime(fs, ino, NULL);\n+\tret = fuse4fs_update_ctime(ff, ino, NULL);\n out2:\n \terr = ext2fs_xattrs_close(&h);\n \tif (err && !ret)\n@@ -5303,7 +5323,7 @@ static void __op_readdir(fuse_req_t req, fuse_ino_t fino, size_t size,\n \t}\n \n \tif (fuse4fs_is_writeable(ff)) {\n-\t\tret = update_atime(i.fs, fh->ino);\n+\t\tret = fuse4fs_update_atime(i.ff, fh->ino);\n \t\tif (ret)\n \t\t\tgoto out;\n \t}\n@@ -5403,7 +5423,7 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name,\n \t\t\tgoto out2;\n \t\t}\n \n-\t\tret = update_mtime(fs, parent, NULL);\n+\t\tret = fuse4fs_update_mtime(ff, parent, NULL);\n \t\tif (ret)\n \t\t\tgoto out2;\n \t} else {\n@@ -5444,7 +5464,7 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name,\n \t}\n \n \tinode.i_generation = ff->next_generation++;\n-\tinit_times(&inode);\n+\tfuse4fs_init_timestamps(ff, &inode);\n \terr = fuse4fs_write_inode(fs, child, &inode);\n \tif (err) {\n \t\tret = translate_error(fs, child, err);\n@@ -5523,7 +5543,7 @@ static int fuse4fs_utimens(struct fuse4fs *ff, const struct fuse_ctx *ctxt,\n \tint ret = 0;\n \n \tif (to_set & (FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW))\n-\t\tget_now(&now);\n+\t\tfuse4fs_get_now(ff, &now);\n \n \tif (to_set & FUSE_SET_ATTR_ATIME_NOW) {\n \t\tatime = now;\n@@ -5661,7 +5681,7 @@ static void op_setattr(fuse_req_t req, fuse_ino_t fino, struct stat *attr,\n \t}\n \n \t/* Update ctime for any attribute change */\n-\tret = update_ctime(fs, ino, &inode);\n+\tret = fuse4fs_update_ctime(ff, ino, &inode);\n \tif (ret)\n \t\tgoto out;\n \n@@ -5743,7 +5763,7 @@ static int ioctl_setflags(struct fuse4fs *ff, const struct fuse_ctx *ctxt,\n \tif (ret)\n \t\treturn ret;\n \n-\tret = update_ctime(fs, fh->ino, &inode);\n+\tret = fuse4fs_update_ctime(ff, fh->ino, &inode);\n \tif (ret)\n \t\treturn ret;\n \n@@ -5796,7 +5816,7 @@ static int ioctl_setversion(struct fuse4fs *ff, const struct fuse_ctx *ctxt,\n \n \tinode.i_generation = *indata;\n \n-\tret = update_ctime(fs, fh->ino, &inode);\n+\tret = fuse4fs_update_ctime(ff, fh->ino, &inode);\n \tif (ret)\n \t\treturn ret;\n \n@@ -5932,7 +5952,7 @@ static int ioctl_fssetxattr(struct fuse4fs *ff, const struct fuse_ctx *ctxt,\n \tif (ext2fs_inode_includes(inode_size, i_projid))\n \t\tinode.i_projid = fsx->fsx_projid;\n \n-\tret = update_ctime(fs, fh->ino, &inode);\n+\tret = fuse4fs_update_ctime(ff, fh->ino, &inode);\n \tif (ret)\n \t\treturn ret;\n \n@@ -6228,7 +6248,7 @@ static int fuse4fs_allocate_range(struct fuse4fs *ff,\n \t\t}\n \t}\n \n-\terr = update_mtime(fs, fh->ino, &inode);\n+\terr = fuse4fs_update_mtime(ff, fh->ino, &inode);\n \tif (err)\n \t\treturn err;\n \n@@ -6401,7 +6421,7 @@ static int fuse4fs_punch_range(struct fuse4fs *ff,\n \t\t\treturn translate_error(fs, fh->ino, err);\n \t}\n \n-\terr = update_mtime(fs, fh->ino, &inode);\n+\terr = fuse4fs_update_mtime(ff, fh->ino, &inode);\n \tif (err)\n \t\treturn err;\n \n@@ -8739,7 +8759,7 @@ static int __translate_error(ext2_filsys fs, ext2_ino_t ino, errcode_t err,\n \t\t\terror_message(err), func, line);\n \n \t/* Make a note in the error log */\n-\tget_now(&now);\n+\tfuse4fs_get_now(ff, &now);\n \text2fs_set_tstamp(fs->super, s_last_error_time, now.tv_sec);\n \tfs->super->s_last_error_ino = ino;\n \tfs->super->s_last_error_line = line;\ndiff --git a/misc/fuse2fs.c b/misc/fuse2fs.c\nindex 935a66af66603e..458fd6e5bf6dd8 100644\n--- a/misc/fuse2fs.c\n+++ b/misc/fuse2fs.c\n@@ -841,8 +841,24 @@ static inline void fuse2fs_dump_extents(struct fuse2fs *ff, ext2_ino_t ino,\n \text2fs_extent_free(extents);\n }\n \n-static void get_now(struct timespec *now)\n+static void fuse2fs_get_now(struct fuse2fs *ff, struct timespec *now)\n {\n+#ifdef CLOCK_REALTIME_COARSE\n+\t/*\n+\t * In iomap mode, the kernel is responsible for maintaining timestamps\n+\t * because file writes don't upcall to fuse2fs.  The kernel's predicate\n+\t * for deciding if [cm]time should be updated bases its decisions off\n+\t * [cm]time being an exact match for the coarse clock (instead of\n+\t * checking that [cm]time < coarse_clock) which means that fuse2fs\n+\t * setting a fine-grained timestamp that is slightly ahead of the\n+\t * coarse clock can result in timestamps appearing to go backwards.\n+\t * generic/423 doesn't like seeing btime > ctime from statx, so we'll\n+\t * use the coarse clock in iomap mode.\n+\t */\n+\tif (fuse2fs_iomap_enabled(ff) &&\n+\t    !clock_gettime(CLOCK_REALTIME_COARSE, now))\n+\t\treturn;\n+#endif\n #ifdef CLOCK_REALTIME\n \tif (!clock_gettime(CLOCK_REALTIME, now))\n \t\treturn;\n@@ -870,7 +886,7 @@ static void fuse2fs_init_timestamps(struct fuse2fs *ff, ext2_ino_t ino,\n {\n \tstruct timespec now;\n \n-\tget_now(&now);\n+\tfuse2fs_get_now(ff, &now);\n \tEXT4_INODE_SET_XTIME(i_atime, &now, inode);\n \tEXT4_INODE_SET_XTIME(i_ctime, &now, inode);\n \tEXT4_INODE_SET_XTIME(i_mtime, &now, inode);\n@@ -889,7 +905,7 @@ static int fuse2fs_update_ctime(struct fuse2fs *ff, ext2_ino_t ino,\n \tstruct timespec now;\n \tstruct ext2_inode_large inode;\n \n-\tget_now(&now);\n+\tfuse2fs_get_now(ff, &now);\n \n \t/* If user already has a inode buffer, just update that */\n \tif (pinode) {\n@@ -935,7 +951,7 @@ static int fuse2fs_update_atime(struct fuse2fs *ff, ext2_ino_t ino)\n \tpinode = &inode;\n \tEXT4_INODE_GET_XTIME(i_atime, &atime, pinode);\n \tEXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);\n-\tget_now(&now);\n+\tfuse2fs_get_now(ff, &now);\n \n \tdatime = atime.tv_sec + ((double)atime.tv_nsec / NSEC_PER_SEC);\n \tdmtime = mtime.tv_sec + ((double)mtime.tv_nsec / NSEC_PER_SEC);\n@@ -970,7 +986,7 @@ static int fuse2fs_update_mtime(struct fuse2fs *ff, ext2_ino_t ino,\n \tstruct timespec now;\n \n \tif (pinode) {\n-\t\tget_now(&now);\n+\t\tfuse2fs_get_now(ff, &now);\n \t\tEXT4_INODE_SET_XTIME(i_mtime, &now, pinode);\n \t\tEXT4_INODE_SET_XTIME(i_ctime, &now, pinode);\n \t\tincrement_version(pinode);\n@@ -985,7 +1001,7 @@ static int fuse2fs_update_mtime(struct fuse2fs *ff, ext2_ino_t ino,\n \tif (err)\n \t\treturn translate_error(fs, ino, err);\n \n-\tget_now(&now);\n+\tfuse2fs_get_now(ff, &now);\n \tEXT4_INODE_SET_XTIME(i_mtime, &now, &inode);\n \tEXT4_INODE_SET_XTIME(i_ctime, &now, &inode);\n \tincrement_version(&inode);\n@@ -4987,9 +5003,9 @@ static int op_utimens(const char *path, const struct timespec ctv[2],\n \ttv[1] = ctv[1];\n #ifdef UTIME_NOW\n \tif (tv[0].tv_nsec == UTIME_NOW)\n-\t\tget_now(tv);\n+\t\tfuse2fs_get_now(ff, tv);\n \tif (tv[1].tv_nsec == UTIME_NOW)\n-\t\tget_now(tv + 1);\n+\t\tfuse2fs_get_now(ff, tv + 1);\n #endif /* UTIME_NOW */\n #ifdef UTIME_OMIT\n \tif (tv[0].tv_nsec != UTIME_OMIT)\n@@ -7747,7 +7763,7 @@ static int __translate_error(ext2_filsys fs, ext2_ino_t ino, errcode_t err,\n \t\t\terror_message(err), func, line);\n \n \t/* Make a note in the error log */\n-\tget_now(&now);\n+\tfuse2fs_get_now(ff, &now);\n \text2fs_set_tstamp(fs->super, s_last_error_time, now.tv_sec);\n \tfs->super->s_last_error_ino = ino;\n \tfs->super->s_last_error_line = line;\n","prefixes":["06/10"]}