From patchwork Thu Dec 26 13:47:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yu Kuai X-Patchwork-Id: 11310511 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2F02914F6 for ; Thu, 26 Dec 2019 13:48:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 174E020740 for ; Thu, 26 Dec 2019 13:48:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726479AbfLZNsG (ORCPT ); Thu, 26 Dec 2019 08:48:06 -0500 Received: from szxga04-in.huawei.com ([45.249.212.190]:8623 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726475AbfLZNsG (ORCPT ); Thu, 26 Dec 2019 08:48:06 -0500 Received: from DGGEMS403-HUB.china.huawei.com (unknown [172.30.72.60]) by Forcepoint Email with ESMTP id DA9A0EDE30359A9F38C2; Thu, 26 Dec 2019 21:48:01 +0800 (CST) Received: from huawei.com (10.175.124.28) by DGGEMS403-HUB.china.huawei.com (10.3.19.203) with Microsoft SMTP Server id 14.3.439.0; Thu, 26 Dec 2019 21:47:55 +0800 From: yu kuai To: , , , , , CC: , , , , , Subject: [PATCH 1/2] xfs: introduce xfs_bmap_split_da_extent Date: Thu, 26 Dec 2019 21:47:20 +0800 Message-ID: <20191226134721.43797-2-yukuai3@huawei.com> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20191226134721.43797-1-yukuai3@huawei.com> References: <20191226134721.43797-1-yukuai3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.124.28] X-CFilter-Loop: Reflected Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org Add a new function xfs_bmap_split_da_extent to split a delalloc extent into two delalloc extents. Signed-off-by: yu kuai --- fs/xfs/libxfs/xfs_bmap.c | 26 ++++++++++++++++++++++++-- fs/xfs/libxfs/xfs_bmap.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 4c2e046fbfad..8247054c1e2b 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6117,7 +6117,7 @@ xfs_bmap_split_extent_at( /* * Convert to a btree if necessary. */ - if (xfs_bmap_needs_btree(ip, whichfork)) { + if (tp && xfs_bmap_needs_btree(ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); @@ -6132,7 +6132,7 @@ xfs_bmap_split_extent_at( xfs_btree_del_cursor(cur, error); } - if (logflags) + if (tp && logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } @@ -6165,6 +6165,28 @@ xfs_bmap_split_extent( return error; } +/* + * Splits a delalloc extent into two delalloc extents at split_fsb block + * such that it is the first block of the current_ext. Caller has to make + * sure split_fsb belong to a delalloc extent. + * If split_fsb is not the first block of the extent, caller need to sub + * the @ip->i_d.di_nextents to prevent crash in log recovery. + */ +int +xfs_bmap_split_da_extent( + struct xfs_inode *ip, + xfs_fileoff_t split_fsb) +{ + struct xfs_trans *tp = NULL; + int error; + + xfs_ilock(ip, XFS_ILOCK_EXCL); + error = xfs_bmap_split_extent_at(tp, ip, split_fsb); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return error; +} + /* Deferred mapping is only for real extents in the data fork. */ static bool xfs_bmap_is_update_needed( diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 14d25e0b7d9c..d8d969aa17ef 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -223,6 +223,7 @@ int xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, bool *done, xfs_fileoff_t stop_fsb); int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); +int xfs_bmap_split_da_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc, struct xfs_bmbt_irec *got, struct xfs_iext_cursor *cur, From patchwork Thu Dec 26 13:47:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yu Kuai X-Patchwork-Id: 11310513 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F809184C for ; Thu, 26 Dec 2019 13:48:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3847920828 for ; Thu, 26 Dec 2019 13:48:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726074AbfLZNsJ (ORCPT ); Thu, 26 Dec 2019 08:48:09 -0500 Received: from szxga05-in.huawei.com ([45.249.212.191]:8197 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726596AbfLZNsJ (ORCPT ); Thu, 26 Dec 2019 08:48:09 -0500 Received: from DGGEMS403-HUB.china.huawei.com (unknown [172.30.72.58]) by Forcepoint Email with ESMTP id E60EB48045FF6C5EA907; Thu, 26 Dec 2019 21:48:06 +0800 (CST) Received: from huawei.com (10.175.124.28) by DGGEMS403-HUB.china.huawei.com (10.3.19.203) with Microsoft SMTP Server id 14.3.439.0; Thu, 26 Dec 2019 21:47:56 +0800 From: yu kuai To: , , , , , CC: , , , , , Subject: [PATCH 2/2] xfs: fix stale data exposure problem when punch hole, collapse range or zero range across a delalloc extent Date: Thu, 26 Dec 2019 21:47:21 +0800 Message-ID: <20191226134721.43797-3-yukuai3@huawei.com> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20191226134721.43797-1-yukuai3@huawei.com> References: <20191226134721.43797-1-yukuai3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.124.28] X-CFilter-Loop: Reflected Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org In xfs_file_fallocate, when punch hole, zero range or collapse range is performed, xfs_fulsh_unmap_range() need to be called first. However, xfs_map_blocks will convert the whole extent to real, even if there are some blocks not related. Furthermore, the unrelated blocks will hold stale data since xfs_fulsh_unmap_range didn't flush the correspond dirty pages to disk. In this case, if user shutdown file system through xfsioctl with cmd 'XFS_IOC_GOINGDOWN' and arg 'XFS_FSOP_GOING_FLAGS_LOGFLUSH'. All the completed transactions will be flushed to disk, while dirty pages will never be flushed to disk. And after remount, the file will hold stale data. Fix the problem by spliting delalloc extent before xfs_flush_unmap_range is called. Signed-off-by: yu kuai Reported-by: kbuild test robot Reported-by: kernel test robot --- fs/xfs/xfs_file.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index c93250108952..5398102feec9 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -786,6 +786,50 @@ xfs_break_layouts( return error; } +int +try_split_da_extent( + struct xfs_inode *ip, + loff_t offset, + loff_t len) +{ + struct xfs_mount *mp = ip->i_mount; + xfs_fileoff_t start = XFS_B_TO_FSBT(mp, offset); + xfs_fileoff_t end = XFS_B_TO_FSBT(mp, offset + len - 1); + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); + struct xfs_iext_cursor cur; + struct xfs_bmbt_irec imap; + int error; + + /* + * if start belong to a delalloc extent and it's not the first block, + * split the extent at start. + */ + if (xfs_iext_lookup_extent(ip, ifp, start, &cur, &imap) && + imap.br_startblock != HOLESTARTBLOCK && + isnullstartblock(imap.br_startblock) && + start > imap.br_startoff) { + error = xfs_bmap_split_da_extent(ip, start); + if (error) + return error; + ip->i_d.di_nextents--; + } + + /* + * if end + 1 belong to a delalloc extent and it's not the first block, + * split the extent at end + 1. + */ + if (xfs_iext_lookup_extent(ip, ifp, end + 1, &cur, &imap) && + imap.br_startblock != HOLESTARTBLOCK && + isnullstartblock(imap.br_startblock) && + end + 1 > imap.br_startoff) { + error = xfs_bmap_split_da_extent(ip, end + 1); + if (error) + return error; + ip->i_d.di_nextents--; + } + + return 0; +} #define XFS_FALLOC_FL_SUPPORTED \ (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \ @@ -842,6 +886,9 @@ xfs_file_fallocate( */ if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE | FALLOC_FL_COLLAPSE_RANGE)) { + error = try_split_da_extent(ip, offset, len); + if (error) + goto out_unlock; error = xfs_flush_unmap_range(ip, offset, len); if (error) goto out_unlock;