From patchwork Sat Oct 22 07:19:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Greg KH X-Patchwork-Id: 7309 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:4242:0:0:0:0:0 with SMTP id s2csp1093358wrr; Sat, 22 Oct 2022 00:57:00 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7qgG2UOLWD1y3yDUpKA+4MukczHjR3oo2mFhKJN+mICSsK8xbdsvf9Uglah9s0Tlrb0plI X-Received: by 2002:a05:6a00:1707:b0:566:15a1:8b07 with SMTP id h7-20020a056a00170700b0056615a18b07mr23072566pfc.34.1666425409181; Sat, 22 Oct 2022 00:56:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1666425409; cv=none; d=google.com; s=arc-20160816; b=0winf/ZwVysJYi/JDIH8KeiKDnyA32e+4uCIPlKRSfBdABExWumc3tt6kCATNR5RtI F8jNejAcYstgbymiMV3E9OKzrlNDZT7yjM8JeKH2waLMgRuYE5SwHCt8LpC4H/TLE8qG nbpQYSG8NxkimpCbnAUktn4aKypYGdX/f45Isn0cQ7MWJ0BtLLEeTNjDij6d94M5sEj/ wVZewPA1cjHsFSDVUe0WiD3QoM73Z6KT5wv8LRMkpfjVe3AqTWE/qNn3SvN7pyKB1TDl hasBhp4nP7Eb6Cx0jmOWSS/I9oYGxqi/XpJIMEvOk1oENnmW6B244xoL84qBNR8HkDPB xfqg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=FgCpfSP1CKvVI9oR6vVQ5YrNl4WjCu7l6RxGcmvU4XI=; b=DpzJczAyOCzO/BRarNWsMzBLz7LnuZGW/tgsEN41TarAioMyEIw3WkbtNT0S/iW13S LJODPzmk8O2JYgL//laoVMOhnDC5d/ii9QCHoBbtfWHMAzPFvvje6E9sjO5DPDNmhEoL egk7bRhaw/cBD9d82yLjO97m1IjK+netD7jn35aNOa+zPS4F+Ke56J7AnbSPnKhI/Umo pZvQv7ax3x8eTqjYEAdq7AWXYszRU3SJaTMC/X1izoiRwaC9VIPFaqnrAZLgl0SYvQaH NRy4sd9KfFpYYnQKkqcy0Tqax5Akbgg0tAvynWd0F/uvfPhnroGPnYNuHeIhgK46XPlT yYcQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=sj7cu+Rv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v16-20020a631510000000b004386a1ebe70si27467985pgl.43.2022.10.22.00.56.37; Sat, 22 Oct 2022 00:56:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=sj7cu+Rv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232258AbiJVH4Q (ORCPT + 99 others); Sat, 22 Oct 2022 03:56:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42382 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231666AbiJVHwj (ORCPT ); Sat, 22 Oct 2022 03:52:39 -0400 Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5246486811; Sat, 22 Oct 2022 00:46:41 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id 3B7CECE2CA4; Sat, 22 Oct 2022 07:38:51 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A83CC433D6; Sat, 22 Oct 2022 07:38:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1666424329; bh=KFZDHCr5VatjNoLsuJLsKBNtpw+3u3h/VovKkhXL+MA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sj7cu+RvEtRHEp/h8bEULRdAfn0p/V3DsmRCBQQxRoWIPwtWlUeYSW5cU5xfFmfad jko4ORfOD5DxT7p7fr2WqpMTijqRk+tEJwySNk/P0YV4NPF3jrzcytzTZm/BPHO9LF IPqqwI+RKQrG2uoElCLW9dz5w4JsYogLlnSRgVb4= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dave Chinner , Christoph Hellwig , stable@kernel.org, Lukas Czerner , Jan Kara , Theodore Tso Subject: [PATCH 5.19 106/717] fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE Date: Sat, 22 Oct 2022 09:19:45 +0200 Message-Id: <20221022072434.191098893@linuxfoundation.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221022072415.034382448@linuxfoundation.org> References: <20221022072415.034382448@linuxfoundation.org> User-Agent: quilt/0.67 MIME-Version: 1.0 X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1747373689935920546?= X-GMAIL-MSGID: =?utf-8?q?1747373689935920546?= From: Lukas Czerner commit cbfecb927f429a6fa613d74b998496bd71e4438a upstream. Currently the I_DIRTY_TIME will never get set if the inode already has I_DIRTY_INODE with assumption that it supersedes I_DIRTY_TIME. That's true, however ext4 will only update the on-disk inode in ->dirty_inode(), not on actual writeback. As a result if the inode already has I_DIRTY_INODE state by the time we get to __mark_inode_dirty() only with I_DIRTY_TIME, the time was already filled into on-disk inode and will not get updated until the next I_DIRTY_INODE update, which might never come if we crash or get a power failure. The problem can be reproduced on ext4 by running xfstest generic/622 with -o iversion mount option. Fix it by allowing I_DIRTY_TIME to be set even if the inode already has I_DIRTY_INODE. Also make sure that the case is properly handled in writeback_single_inode() as well. Additionally changes in xfs_fs_dirty_inode() was made to accommodate for I_DIRTY_TIME in flag. Thanks Jan Kara for suggestions on how to make this work properly. Cc: Dave Chinner Cc: Christoph Hellwig Cc: stable@kernel.org Signed-off-by: Lukas Czerner Suggested-by: Jan Kara Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/20220825100657.44217-1-lczerner@redhat.com Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/vfs.rst | 3 +++ fs/fs-writeback.c | 37 +++++++++++++++++++++++++------------ fs/xfs/xfs_super.c | 10 ++++++++-- include/linux/fs.h | 9 +++++---- 4 files changed, 41 insertions(+), 18 deletions(-) --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -274,6 +274,9 @@ or bottom half). This is specifically for the inode itself being marked dirty, not its data. If the update needs to be persisted by fdatasync(), then I_DIRTY_DATASYNC will be set in the flags argument. + I_DIRTY_TIME will be set in the flags in case lazytime is enabled + and struct inode has times updated since the last ->dirty_inode + call. ``write_inode`` this method is called when the VFS needs to write an inode to --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1718,9 +1718,14 @@ static int writeback_single_inode(struct */ if (!(inode->i_state & I_DIRTY_ALL)) inode_cgwb_move_to_attached(inode, wb); - else if (!(inode->i_state & I_SYNC_QUEUED) && - (inode->i_state & I_DIRTY)) - redirty_tail_locked(inode, wb); + else if (!(inode->i_state & I_SYNC_QUEUED)) { + if ((inode->i_state & I_DIRTY)) + redirty_tail_locked(inode, wb); + else if (inode->i_state & I_DIRTY_TIME) { + inode->dirtied_when = jiffies; + inode_io_list_move_locked(inode, wb, &wb->b_dirty_time); + } + } spin_unlock(&wb->list_lock); inode_sync_complete(inode); @@ -2370,6 +2375,20 @@ void __mark_inode_dirty(struct inode *in if (flags & I_DIRTY_INODE) { /* + * Inode timestamp update will piggback on this dirtying. + * We tell ->dirty_inode callback that timestamps need to + * be updated by setting I_DIRTY_TIME in flags. + */ + if (inode->i_state & I_DIRTY_TIME) { + spin_lock(&inode->i_lock); + if (inode->i_state & I_DIRTY_TIME) { + inode->i_state &= ~I_DIRTY_TIME; + flags |= I_DIRTY_TIME; + } + spin_unlock(&inode->i_lock); + } + + /* * Notify the filesystem about the inode being dirtied, so that * (if needed) it can update on-disk fields and journal the * inode. This is only needed when the inode itself is being @@ -2378,7 +2397,8 @@ void __mark_inode_dirty(struct inode *in */ trace_writeback_dirty_inode_start(inode, flags); if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode(inode, flags & I_DIRTY_INODE); + sb->s_op->dirty_inode(inode, + flags & (I_DIRTY_INODE | I_DIRTY_TIME)); trace_writeback_dirty_inode(inode, flags); /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ @@ -2399,21 +2419,15 @@ void __mark_inode_dirty(struct inode *in */ smp_mb(); - if (((inode->i_state & flags) == flags) || - (dirtytime && (inode->i_state & I_DIRTY_INODE))) + if ((inode->i_state & flags) == flags) return; spin_lock(&inode->i_lock); - if (dirtytime && (inode->i_state & I_DIRTY_INODE)) - goto out_unlock_inode; if ((inode->i_state & flags) != flags) { const int was_dirty = inode->i_state & I_DIRTY; inode_attach_wb(inode, NULL); - /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ - if (flags & I_DIRTY_INODE) - inode->i_state &= ~I_DIRTY_TIME; inode->i_state |= flags; /* @@ -2486,7 +2500,6 @@ void __mark_inode_dirty(struct inode *in out_unlock: if (wb) spin_unlock(&wb->list_lock); -out_unlock_inode: spin_unlock(&inode->i_lock); } EXPORT_SYMBOL(__mark_inode_dirty); --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -650,7 +650,7 @@ xfs_fs_destroy_inode( static void xfs_fs_dirty_inode( struct inode *inode, - int flag) + int flags) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; @@ -658,7 +658,13 @@ xfs_fs_dirty_inode( if (!(inode->i_sb->s_flags & SB_LAZYTIME)) return; - if (flag != I_DIRTY_SYNC || !(inode->i_state & I_DIRTY_TIME)) + + /* + * Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC) + * and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed + * in flags possibly together with I_DIRTY_SYNC. + */ + if ((flags & ~I_DIRTY_TIME) != I_DIRTY_SYNC || !(flags & I_DIRTY_TIME)) return; if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp)) --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2241,13 +2241,14 @@ static inline void kiocb_clone(struct ki * don't have to write inode on fdatasync() when only * e.g. the timestamps have changed. * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. - * I_DIRTY_TIME The inode itself only has dirty timestamps, and the + * I_DIRTY_TIME The inode itself has dirty timestamps, and the * lazytime mount option is enabled. We keep track of this * separately from I_DIRTY_SYNC in order to implement * lazytime. This gets cleared if I_DIRTY_INODE - * (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. I.e. - * either I_DIRTY_TIME *or* I_DIRTY_INODE can be set in - * i_state, but not both. I_DIRTY_PAGES may still be set. + * (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. But + * I_DIRTY_TIME can still be set if I_DIRTY_SYNC is already + * in place because writeback might already be in progress + * and we don't want to lose the time update * I_NEW Serves as both a mutex and completion notification. * New inodes set I_NEW. If two processes both create * the same inode, one of them will release its inode and