From 3945ae03d822aa47584dd502ac024ae1e1eb9e2d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 24 Nov 2020 11:45:54 -0800 Subject: [PATCH 01/40] xfs: move kernel-specific superblock validation out of libxfs A couple of the superblock validation checks apply only to the kernel, so move them to xfs_fc_fill_super before we add the needsrepair "feature", which will prevent the kernel (but not xfsprogs) from mounting the filesystem. This also reduces the diff between kernel and userspace libxfs. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Eric Sandeen --- fs/xfs/libxfs/xfs_sb.c | 27 --------------------------- fs/xfs/xfs_super.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 5aeafa59ed27..05359690aaed 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -382,17 +382,6 @@ xfs_validate_sb_common( return -EFSCORRUPTED; } - /* - * Until this is fixed only page-sized or smaller data blocks work. - */ - if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { - xfs_warn(mp, - "File system with blocksize %d bytes. " - "Only pagesize (%ld) or less will currently work.", - sbp->sb_blocksize, PAGE_SIZE); - return -ENOSYS; - } - /* * Currently only very few inode sizes are supported. */ @@ -408,22 +397,6 @@ xfs_validate_sb_common( return -ENOSYS; } - if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || - xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { - xfs_warn(mp, - "file system too large to be mounted on this system."); - return -EFBIG; - } - - /* - * Don't touch the filesystem if a user tool thinks it owns the primary - * superblock. mkfs doesn't clear the flag from secondary supers, so - * we don't check them at all. - */ - if (XFS_BUF_ADDR(bp) == XFS_SB_DADDR && sbp->sb_inprogress) { - xfs_warn(mp, "Offline file system operation in progress!"); - return -EFSCORRUPTED; - } return 0; } diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e3e229e52512..599566c1a3b4 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1467,6 +1467,38 @@ xfs_fc_fill_super( #endif } + /* + * Don't touch the filesystem if a user tool thinks it owns the primary + * superblock. mkfs doesn't clear the flag from secondary supers, so + * we don't check them at all. + */ + if (mp->m_sb.sb_inprogress) { + xfs_warn(mp, "Offline file system operation in progress!"); + error = -EFSCORRUPTED; + goto out_free_sb; + } + + /* + * Until this is fixed only page-sized or smaller data blocks work. + */ + if (mp->m_sb.sb_blocksize > PAGE_SIZE) { + xfs_warn(mp, + "File system with blocksize %d bytes. " + "Only pagesize (%ld) or less will currently work.", + mp->m_sb.sb_blocksize, PAGE_SIZE); + error = -ENOSYS; + goto out_free_sb; + } + + /* Ensure this filesystem fits in the page cache limits */ + if (xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_dblocks) || + xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_rblocks)) { + xfs_warn(mp, + "file system too large to be mounted on this system."); + error = -EFBIG; + goto out_free_sb; + } + /* * XFS block mappings use 54 bits to store the logical block offset. * This should suffice to handle the maximum file size that the VFS From 80c720b8eb1c7800133c5ae1686353d33564b773 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 24 Nov 2020 11:45:55 -0800 Subject: [PATCH 02/40] xfs: define a new "needrepair" feature Define an incompat feature flag to indicate that the filesystem needs to be repaired. While libxfs will recognize this feature, the kernel will refuse to mount if the feature flag is set, and only xfs_repair will be able to clear the flag. The goal here is to force the admin to run xfs_repair to completion after upgrading the filesystem, or if we otherwise detect anomalies. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Dave Chinner Reviewed-by: Eric Sandeen --- fs/xfs/libxfs/xfs_format.h | 7 +++++++ fs/xfs/xfs_super.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index dd764da08f6f..5d8ba609ac0b 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -468,6 +468,7 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ +#define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ @@ -584,6 +585,12 @@ static inline bool xfs_sb_version_hasinobtcounts(struct xfs_sb *sbp) (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_INOBTCNT); } +static inline bool xfs_sb_version_needsrepair(struct xfs_sb *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && + (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR); +} + /* * end of superblock version macros */ diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 599566c1a3b4..36002f460d7c 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1467,6 +1467,13 @@ xfs_fc_fill_super( #endif } + /* Filesystem claims it needs repair, so refuse the mount. */ + if (xfs_sb_version_needsrepair(&mp->m_sb)) { + xfs_warn(mp, "Filesystem needs repair. Please run xfs_repair."); + error = -EFSCORRUPTED; + goto out_free_sb; + } + /* * Don't touch the filesystem if a user tool thinks it owns the primary * superblock. mkfs doesn't clear the flag from secondary supers, so From 96f65bad7c31557c28468ba8c1896c7dd7a6bbfa Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 24 Nov 2020 11:45:55 -0800 Subject: [PATCH 03/40] xfs: enable the needsrepair feature Make it so that libxfs recognizes the needsrepair feature. Note that the kernel will still refuse to mount these. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Eric Sandeen Reviewed-by: Dave Chinner --- fs/xfs/libxfs/xfs_format.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 5d8ba609ac0b..f64eed3ccfed 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -473,7 +473,8 @@ xfs_sb_has_ro_compat_feature( (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ XFS_SB_FEAT_INCOMPAT_META_UUID| \ - XFS_SB_FEAT_INCOMPAT_BIGTIME) + XFS_SB_FEAT_INCOMPAT_BIGTIME| \ + XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool From bc525cf455dac810d28f9edd379805dc249bc5a9 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:35 -0800 Subject: [PATCH 04/40] xfs: hoist recovered bmap intent checks out of xfs_bui_item_recover When we recover a bmap intent from the log, we need to validate its contents before we try to replay them. Hoist the checking code into a separate function in preparation to refactor this code to use validation helpers. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_bmap_item.c | 74 +++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 9e16a4d0f97c..9be61feca65b 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -417,6 +417,49 @@ const struct xfs_defer_op_type xfs_bmap_update_defer_type = { .cancel_item = xfs_bmap_update_cancel_item, }; +/* Is this recovered BUI ok? */ +static inline bool +xfs_bui_validate( + struct xfs_mount *mp, + struct xfs_bui_log_item *buip) +{ + struct xfs_map_extent *bmap; + xfs_fsblock_t startblock_fsb; + xfs_fsblock_t inode_fsb; + + /* Only one mapping operation per BUI... */ + if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) + return false; + + bmap = &buip->bui_format.bui_extents[0]; + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, bmap->me_startblock)); + inode_fsb = XFS_BB_TO_FSB(mp, XFS_FSB_TO_DADDR(mp, + XFS_INO_TO_FSB(mp, bmap->me_owner))); + + if (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS) + return false; + + switch (bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK) { + case XFS_BMAP_MAP: + case XFS_BMAP_UNMAP: + break; + default: + return false; + } + + if (startblock_fsb == 0 || + bmap->me_len == 0 || + inode_fsb == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || + bmap->me_len >= mp->m_sb.sb_agblocks || + inode_fsb >= mp->m_sb.sb_dblocks || + (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS)) + return false; + + return true; +} + /* * Process a bmap update intent item that was recovered from the log. * We need to update some inode's bmbt. @@ -433,47 +476,24 @@ xfs_bui_item_recover( struct xfs_mount *mp = lip->li_mountp; struct xfs_map_extent *bmap; struct xfs_bud_log_item *budp; - xfs_fsblock_t startblock_fsb; - xfs_fsblock_t inode_fsb; xfs_filblks_t count; xfs_exntst_t state; unsigned int bui_type; int whichfork; int error = 0; - /* Only one mapping operation per BUI... */ - if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) + if (!xfs_bui_validate(mp, buip)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &buip->bui_format, sizeof(buip->bui_format)); return -EFSCORRUPTED; + } - /* - * First check the validity of the extent described by the - * BUI. If anything is bad, then toss the BUI. - */ bmap = &buip->bui_format.bui_extents[0]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, bmap->me_startblock)); - inode_fsb = XFS_BB_TO_FSB(mp, XFS_FSB_TO_DADDR(mp, - XFS_INO_TO_FSB(mp, bmap->me_owner))); state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? XFS_EXT_UNWRITTEN : XFS_EXT_NORM; whichfork = (bmap->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; bui_type = bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; - switch (bui_type) { - case XFS_BMAP_MAP: - case XFS_BMAP_UNMAP: - break; - default: - return -EFSCORRUPTED; - } - if (startblock_fsb == 0 || - bmap->me_len == 0 || - inode_fsb == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - bmap->me_len >= mp->m_sb.sb_agblocks || - inode_fsb >= mp->m_sb.sb_dblocks || - (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS)) - return -EFSCORRUPTED; /* Grab the inode. */ error = xfs_iget(mp, NULL, bmap->me_owner, 0, 0, &ip); From 67d8679bd3913d2c4ec5f32ade778881b93af766 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:36 -0800 Subject: [PATCH 05/40] xfs: improve the code that checks recovered bmap intent items The code that validates recovered bmap intent items is kind of a mess -- it doesn't use the standard xfs type validators, and it doesn't check for things that it should. Fix the validator function to use the standard validation helpers and look for more types of obvious errors. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_bmap_item.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 9be61feca65b..a21a9f71c0c0 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -424,18 +424,12 @@ xfs_bui_validate( struct xfs_bui_log_item *buip) { struct xfs_map_extent *bmap; - xfs_fsblock_t startblock_fsb; - xfs_fsblock_t inode_fsb; /* Only one mapping operation per BUI... */ if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) return false; bmap = &buip->bui_format.bui_extents[0]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, bmap->me_startblock)); - inode_fsb = XFS_BB_TO_FSB(mp, XFS_FSB_TO_DADDR(mp, - XFS_INO_TO_FSB(mp, bmap->me_owner))); if (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS) return false; @@ -448,13 +442,19 @@ xfs_bui_validate( return false; } - if (startblock_fsb == 0 || - bmap->me_len == 0 || - inode_fsb == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - bmap->me_len >= mp->m_sb.sb_agblocks || - inode_fsb >= mp->m_sb.sb_dblocks || - (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS)) + if (!xfs_verify_ino(mp, bmap->me_owner)) + return false; + + if (bmap->me_startoff + bmap->me_len <= bmap->me_startoff) + return false; + + if (bmap->me_startblock + bmap->me_len <= bmap->me_startblock) + return false; + + if (!xfs_verify_fsbno(mp, bmap->me_startblock)) + return false; + + if (!xfs_verify_fsbno(mp, bmap->me_startblock + bmap->me_len - 1)) return false; return true; From dda7ba65bf03b6f3a7502b9f85c2524a5ae5aa2e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:36 -0800 Subject: [PATCH 06/40] xfs: hoist recovered rmap intent checks out of xfs_rui_item_recover When we recover a rmap intent from the log, we need to validate its contents before we try to replay them. Hoist the checking code into a separate function in preparation to refactor this code to use validation helpers. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_rmap_item.c | 67 ++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 7adc996ca6e3..19d2dc285ed6 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -460,6 +460,42 @@ const struct xfs_defer_op_type xfs_rmap_update_defer_type = { .cancel_item = xfs_rmap_update_cancel_item, }; +/* Is this recovered RUI ok? */ +static inline bool +xfs_rui_validate_map( + struct xfs_mount *mp, + struct xfs_map_extent *rmap) +{ + xfs_fsblock_t startblock_fsb; + bool op_ok; + + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, rmap->me_startblock)); + switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { + case XFS_RMAP_EXTENT_MAP: + case XFS_RMAP_EXTENT_MAP_SHARED: + case XFS_RMAP_EXTENT_UNMAP: + case XFS_RMAP_EXTENT_UNMAP_SHARED: + case XFS_RMAP_EXTENT_CONVERT: + case XFS_RMAP_EXTENT_CONVERT_SHARED: + case XFS_RMAP_EXTENT_ALLOC: + case XFS_RMAP_EXTENT_FREE: + op_ok = true; + break; + default: + op_ok = false; + break; + } + if (!op_ok || startblock_fsb == 0 || + rmap->me_len == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || + rmap->me_len >= mp->m_sb.sb_agblocks || + (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS)) + return false; + + return true; +} + /* * Process an rmap update intent item that was recovered from the log. * We need to update the rmapbt. @@ -475,10 +511,8 @@ xfs_rui_item_recover( struct xfs_trans *tp; struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_mountp; - xfs_fsblock_t startblock_fsb; enum xfs_rmap_intent_type type; xfs_exntst_t state; - bool op_ok; int i; int whichfork; int error = 0; @@ -489,30 +523,13 @@ xfs_rui_item_recover( * just toss the RUI. */ for (i = 0; i < ruip->rui_format.rui_nextents; i++) { - rmap = &ruip->rui_format.rui_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, rmap->me_startblock)); - switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { - case XFS_RMAP_EXTENT_MAP: - case XFS_RMAP_EXTENT_MAP_SHARED: - case XFS_RMAP_EXTENT_UNMAP: - case XFS_RMAP_EXTENT_UNMAP_SHARED: - case XFS_RMAP_EXTENT_CONVERT: - case XFS_RMAP_EXTENT_CONVERT_SHARED: - case XFS_RMAP_EXTENT_ALLOC: - case XFS_RMAP_EXTENT_FREE: - op_ok = true; - break; - default: - op_ok = false; - break; - } - if (!op_ok || startblock_fsb == 0 || - rmap->me_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - rmap->me_len >= mp->m_sb.sb_agblocks || - (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS)) + if (!xfs_rui_validate_map(mp, + &ruip->rui_format.rui_extents[i])) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &ruip->rui_format, + sizeof(ruip->rui_format)); return -EFSCORRUPTED; + } } error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, From c447ad62dc906f4b5f788e8ff20c1768ab2eab2c Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:37 -0800 Subject: [PATCH 07/40] xfs: improve the code that checks recovered rmap intent items The code that validates recovered rmap intent items is kind of a mess -- it doesn't use the standard xfs type validators, and it doesn't check for things that it should. Fix the validator function to use the standard validation helpers and look for more types of obvious errors. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster --- fs/xfs/xfs_rmap_item.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 19d2dc285ed6..6f3250a22093 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -466,11 +466,9 @@ xfs_rui_validate_map( struct xfs_mount *mp, struct xfs_map_extent *rmap) { - xfs_fsblock_t startblock_fsb; - bool op_ok; + if (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS) + return false; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, rmap->me_startblock)); switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { case XFS_RMAP_EXTENT_MAP: case XFS_RMAP_EXTENT_MAP_SHARED: @@ -480,17 +478,25 @@ xfs_rui_validate_map( case XFS_RMAP_EXTENT_CONVERT_SHARED: case XFS_RMAP_EXTENT_ALLOC: case XFS_RMAP_EXTENT_FREE: - op_ok = true; break; default: - op_ok = false; - break; + return false; } - if (!op_ok || startblock_fsb == 0 || - rmap->me_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - rmap->me_len >= mp->m_sb.sb_agblocks || - (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS)) + + if (!XFS_RMAP_NON_INODE_OWNER(rmap->me_owner) && + !xfs_verify_ino(mp, rmap->me_owner)) + return false; + + if (rmap->me_startoff + rmap->me_len <= rmap->me_startoff) + return false; + + if (rmap->me_startblock + rmap->me_len <= rmap->me_startblock) + return false; + + if (!xfs_verify_fsbno(mp, rmap->me_startblock)) + return false; + + if (!xfs_verify_fsbno(mp, rmap->me_startblock + rmap->me_len - 1)) return false; return true; From ed64f8343aafa62e762c74dfb400f640b6fa6c15 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:37 -0800 Subject: [PATCH 08/40] xfs: hoist recovered refcount intent checks out of xfs_cui_item_recover When we recover a refcount intent from the log, we need to validate its contents before we try to replay them. Hoist the checking code into a separate function in preparation to refactor this code to use validation helpers. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_refcount_item.c | 59 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 7529eb63ce94..e19f96c9b93a 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -417,6 +417,38 @@ const struct xfs_defer_op_type xfs_refcount_update_defer_type = { .cancel_item = xfs_refcount_update_cancel_item, }; +/* Is this recovered CUI ok? */ +static inline bool +xfs_cui_validate_phys( + struct xfs_mount *mp, + struct xfs_phys_extent *refc) +{ + xfs_fsblock_t startblock_fsb; + bool op_ok; + + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, refc->pe_startblock)); + switch (refc->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK) { + case XFS_REFCOUNT_INCREASE: + case XFS_REFCOUNT_DECREASE: + case XFS_REFCOUNT_ALLOC_COW: + case XFS_REFCOUNT_FREE_COW: + op_ok = true; + break; + default: + op_ok = false; + break; + } + if (!op_ok || startblock_fsb == 0 || + refc->pe_len == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || + refc->pe_len >= mp->m_sb.sb_agblocks || + (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS)) + return false; + + return true; +} + /* * Process a refcount update intent item that was recovered from the log. * We need to update the refcountbt. @@ -433,11 +465,9 @@ xfs_cui_item_recover( struct xfs_trans *tp; struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_mountp; - xfs_fsblock_t startblock_fsb; xfs_fsblock_t new_fsb; xfs_extlen_t new_len; unsigned int refc_type; - bool op_ok; bool requeue_only = false; enum xfs_refcount_intent_type type; int i; @@ -449,26 +479,13 @@ xfs_cui_item_recover( * just toss the CUI. */ for (i = 0; i < cuip->cui_format.cui_nextents; i++) { - refc = &cuip->cui_format.cui_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, refc->pe_startblock)); - switch (refc->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK) { - case XFS_REFCOUNT_INCREASE: - case XFS_REFCOUNT_DECREASE: - case XFS_REFCOUNT_ALLOC_COW: - case XFS_REFCOUNT_FREE_COW: - op_ok = true; - break; - default: - op_ok = false; - break; - } - if (!op_ok || startblock_fsb == 0 || - refc->pe_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - refc->pe_len >= mp->m_sb.sb_agblocks || - (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS)) + if (!xfs_cui_validate_phys(mp, + &cuip->cui_format.cui_extents[i])) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &cuip->cui_format, + sizeof(cuip->cui_format)); return -EFSCORRUPTED; + } } /* From 0d79781a1aa6a6a567e63294012eee2384f406f2 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:37 -0800 Subject: [PATCH 09/40] xfs: improve the code that checks recovered refcount intent items The code that validates recovered refcount intent items is kind of a mess -- it doesn't use the standard xfs type validators, and it doesn't check for things that it should. Fix the validator function to use the standard validation helpers and look for more types of obvious errors. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_refcount_item.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index e19f96c9b93a..c24f2da0f795 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -423,27 +423,26 @@ xfs_cui_validate_phys( struct xfs_mount *mp, struct xfs_phys_extent *refc) { - xfs_fsblock_t startblock_fsb; - bool op_ok; + if (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS) + return false; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, refc->pe_startblock)); switch (refc->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK) { case XFS_REFCOUNT_INCREASE: case XFS_REFCOUNT_DECREASE: case XFS_REFCOUNT_ALLOC_COW: case XFS_REFCOUNT_FREE_COW: - op_ok = true; break; default: - op_ok = false; - break; + return false; } - if (!op_ok || startblock_fsb == 0 || - refc->pe_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - refc->pe_len >= mp->m_sb.sb_agblocks || - (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS)) + + if (refc->pe_startblock + refc->pe_len <= refc->pe_startblock) + return false; + + if (!xfs_verify_fsbno(mp, refc->pe_startblock)) + return false; + + if (!xfs_verify_fsbno(mp, refc->pe_startblock + refc->pe_len - 1)) return false; return true; From 3c15df3de0e2bcc4390aa95c60fd12edb7f12bdd Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:38 -0800 Subject: [PATCH 10/40] xfs: hoist recovered extent-free intent checks out of xfs_efi_item_recover When we recover a extent-free intent from the log, we need to validate its contents before we try to replay them. Hoist the checking code into a separate function in preparation to refactor this code to use validation helpers. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_extfree_item.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 6c11bfc3d452..f86c8a7c9c4e 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -578,6 +578,25 @@ const struct xfs_defer_op_type xfs_agfl_free_defer_type = { .cancel_item = xfs_extent_free_cancel_item, }; +/* Is this recovered EFI ok? */ +static inline bool +xfs_efi_validate_ext( + struct xfs_mount *mp, + struct xfs_extent *extp) +{ + xfs_fsblock_t startblock_fsb; + + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, extp->ext_start)); + if (startblock_fsb == 0 || + extp->ext_len == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || + extp->ext_len >= mp->m_sb.sb_agblocks) + return false; + + return true; +} + /* * Process an extent free intent item that was recovered from * the log. We need to free the extents that it describes. @@ -592,7 +611,6 @@ xfs_efi_item_recover( struct xfs_efd_log_item *efdp; struct xfs_trans *tp; struct xfs_extent *extp; - xfs_fsblock_t startblock_fsb; int i; int error = 0; @@ -602,14 +620,13 @@ xfs_efi_item_recover( * just toss the EFI. */ for (i = 0; i < efip->efi_format.efi_nextents; i++) { - extp = &efip->efi_format.efi_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, extp->ext_start)); - if (startblock_fsb == 0 || - extp->ext_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - extp->ext_len >= mp->m_sb.sb_agblocks) + if (!xfs_efi_validate_ext(mp, + &efip->efi_format.efi_extents[i])) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &efip->efi_format, + sizeof(efip->efi_format)); return -EFSCORRUPTED; + } } error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); From 7396c7fbe07e3c33b578bd9d36e48d42d2acdeb2 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:38 -0800 Subject: [PATCH 11/40] xfs: improve the code that checks recovered extent-free intent items The code that validates recovered extent-free intent items is kind of a mess -- it doesn't use the standard xfs type validators, and it doesn't check for things that it should. Fix the validator function to use the standard validation helpers and look for more types of obvious errors. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_extfree_item.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index f86c8a7c9c4e..bfdfbd192a38 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -584,14 +584,13 @@ xfs_efi_validate_ext( struct xfs_mount *mp, struct xfs_extent *extp) { - xfs_fsblock_t startblock_fsb; + if (extp->ext_start + extp->ext_len <= extp->ext_start) + return false; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, extp->ext_start)); - if (startblock_fsb == 0 || - extp->ext_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - extp->ext_len >= mp->m_sb.sb_agblocks) + if (!xfs_verify_fsbno(mp, extp->ext_start)) + return false; + + if (!xfs_verify_fsbno(mp, extp->ext_start + extp->ext_len - 1)) return false; return true; From da5de110296c329461bb7b1caa2d993648db324f Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:39 -0800 Subject: [PATCH 12/40] xfs: validate feature support when recovering rmap/refcount intents The rmap, and refcount log intent items were added to support the rmap and reflink features. Because these features come with changes to the ondisk format, the log items aren't tied to a log incompat flag. However, the log recovery routines don't actually check for those feature flags. The kernel has no business replayng an intent item for a feature that isn't enabled, so check that as part of recovered log item validation. (Note that kernels pre-dating rmap and reflink already fail log recovery on the unknown log item type code.) Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster --- fs/xfs/xfs_refcount_item.c | 3 +++ fs/xfs/xfs_rmap_item.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index c24f2da0f795..937d482c9be4 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -423,6 +423,9 @@ xfs_cui_validate_phys( struct xfs_mount *mp, struct xfs_phys_extent *refc) { + if (!xfs_sb_version_hasreflink(&mp->m_sb)) + return false; + if (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS) return false; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 6f3250a22093..9b84017184d9 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -466,6 +466,9 @@ xfs_rui_validate_map( struct xfs_mount *mp, struct xfs_map_extent *rmap) { + if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) + return false; + if (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS) return false; From 6337032689fa51462d47eb456e5867cb0efa33eb Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 29 Nov 2020 16:33:39 -0800 Subject: [PATCH 13/40] xfs: trace log intent item recovery failures Add a trace point so that we can capture when a recovered log intent item fails to recover. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_log_recover.c | 5 ++++- fs/xfs/xfs_trace.h | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 87886b7f77da..1152c4b3ba96 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2559,8 +2559,11 @@ xlog_recover_process_intents( spin_unlock(&ailp->ail_lock); error = lip->li_ops->iop_recover(lip, &capture_list); spin_lock(&ailp->ail_lock); - if (error) + if (error) { + trace_xlog_intent_recovery_failed(log->l_mp, error, + lip->li_ops->iop_recover); break; + } } xfs_trans_ail_cursor_done(&cur); diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 86951652d3ed..5a263ae3d4f0 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -103,6 +103,24 @@ DEFINE_ATTR_LIST_EVENT(xfs_attr_list_notfound); DEFINE_ATTR_LIST_EVENT(xfs_attr_leaf_list); DEFINE_ATTR_LIST_EVENT(xfs_attr_node_list); +TRACE_EVENT(xlog_intent_recovery_failed, + TP_PROTO(struct xfs_mount *mp, int error, void *function), + TP_ARGS(mp, error, function), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(int, error) + __field(void *, function) + ), + TP_fast_assign( + __entry->dev = mp->m_super->s_dev; + __entry->error = error; + __entry->function = function; + ), + TP_printk("dev %d:%d error %d function %pS", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->error, __entry->function) +); + DECLARE_EVENT_CLASS(xfs_perag_class, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, unsigned long caller_ip), From acf104c2331c1ba2a667e65dd36139d1555b1432 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 2 Dec 2020 12:25:43 -0800 Subject: [PATCH 14/40] xfs: detect overflows in bmbt records Detect file block mappings with a blockcount that's either so large that integer overflows occur or are zero, because neither are valid in the filesystem. Worse yet, attempting directory modifications causes the iext code to trip over the bmbt key handling and takes the filesystem down. We can fix most of this by preventing the bad metadata from entering the incore structures in the first place. Found by setting blockcount=0 in a directory data fork mapping and watching the fireworks. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_bmap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index d9a692484eae..de9c27ef68d8 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6229,6 +6229,11 @@ xfs_bmap_validate_extent( xfs_fsblock_t endfsb; bool isrt; + if (irec->br_startblock + irec->br_blockcount <= irec->br_startblock) + return __this_address; + if (irec->br_startoff + irec->br_blockcount <= irec->br_startoff) + return __this_address; + isrt = XFS_IS_REALTIME_INODE(ip); endfsb = irec->br_startblock + irec->br_blockcount - 1; if (isrt && whichfork == XFS_DATA_FORK) { From da531cc46ef16301b1bc5bc74acbaacc628904f5 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 2 Dec 2020 12:25:44 -0800 Subject: [PATCH 15/40] xfs: fix parent pointer scrubber bailing out on unallocated inodes xfs_iget can return -ENOENT for a file that the inobt thinks is allocated but has zeroed mode. This currently causes scrub to exit with an operational error instead of flagging this as a corruption. The end result is that scrub mistakenly reports the ENOENT to the user instead of "directory parent pointer corrupt" like we do for EINVAL. Fixes: 5927268f5a04 ("xfs: flag inode corruption if parent ptr doesn't get us a real inode") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/scrub/parent.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index 855aa8bcab64..66c35f6dfc24 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -164,13 +164,13 @@ xchk_parent_validate( * can't use DONTCACHE here because DONTCACHE inodes can trigger * immediate inactive cleanup of the inode. * - * If _iget returns -EINVAL then the parent inode number is garbage - * and the directory is corrupt. If the _iget returns -EFSCORRUPTED - * or -EFSBADCRC then the parent is corrupt which is a cross - * referencing error. Any other error is an operational error. + * If _iget returns -EINVAL or -ENOENT then the parent inode number is + * garbage and the directory is corrupt. If the _iget returns + * -EFSCORRUPTED or -EFSBADCRC then the parent is corrupt which is a + * cross referencing error. Any other error is an operational error. */ error = xfs_iget(mp, sc->tp, dnum, XFS_IGET_UNTRUSTED, 0, &dp); - if (error == -EINVAL) { + if (error == -EINVAL || error == -ENOENT) { error = -EFSCORRUPTED; xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error); goto out; From 4b80ac64450f169bae364df631d233d66070a06e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 2 Dec 2020 12:25:44 -0800 Subject: [PATCH 16/40] xfs: scrub should mark a directory corrupt if any entries cannot be iget'd It's possible that xfs_iget can return EINVAL for inodes that the inobt thinks are free, or ENOENT for inodes that look free. If this is the case, mark the directory corrupt immediately when we check ftype. Note that we already check the ftype of the '.' and '..' entries, so we can skip the iget part since we already know the inode type for '.' and we have a separate parent pointer scrubber for '..'. Fixes: a5c46e5e8912 ("xfs: scrub directory metadata") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/scrub/dir.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index b045e95c2ea7..178b3455a170 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -66,8 +66,18 @@ xchk_dir_check_ftype( * eofblocks cleanup (which allocates what would be a nested * transaction), we can't use DONTCACHE here because DONTCACHE * inodes can trigger immediate inactive cleanup of the inode. + * + * If _iget returns -EINVAL or -ENOENT then the child inode number is + * garbage and the directory is corrupt. If the _iget returns + * -EFSCORRUPTED or -EFSBADCRC then the child is corrupt which is a + * cross referencing error. Any other error is an operational error. */ error = xfs_iget(mp, sdc->sc->tp, inum, 0, 0, &ip); + if (error == -EINVAL || error == -ENOENT) { + error = -EFSCORRUPTED; + xchk_fblock_process_error(sdc->sc, XFS_DATA_FORK, 0, &error); + goto out; + } if (!xchk_fblock_xref_process_error(sdc->sc, XFS_DATA_FORK, offset, &error)) goto out; @@ -105,6 +115,7 @@ xchk_dir_actor( struct xfs_name xname; xfs_ino_t lookup_ino; xfs_dablk_t offset; + bool checked_ftype = false; int error = 0; sdc = container_of(dir_iter, struct xchk_dir_ctx, dir_iter); @@ -133,6 +144,7 @@ xchk_dir_actor( if (xfs_sb_version_hasftype(&mp->m_sb) && type != DT_DIR) xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); + checked_ftype = true; if (ino != ip->i_ino) xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); @@ -144,6 +156,7 @@ xchk_dir_actor( if (xfs_sb_version_hasftype(&mp->m_sb) && type != DT_DIR) xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); + checked_ftype = true; if (ip->i_ino == mp->m_sb.sb_rootino && ino != ip->i_ino) xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); @@ -167,9 +180,11 @@ xchk_dir_actor( } /* Verify the file type. This function absorbs error codes. */ - error = xchk_dir_check_ftype(sdc, offset, lookup_ino, type); - if (error) - goto out; + if (!checked_ftype) { + error = xchk_dir_check_ftype(sdc, offset, lookup_ino, type); + if (error) + goto out; + } out: /* * A negative error code returned here is supposed to cause the From 67457eb0d225521a0e81327aef808cd0f9075880 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 4 Dec 2020 13:20:00 -0800 Subject: [PATCH 17/40] xfs: refactor data device extent validation Refactor all the open-coded validation of non-static data device extents into a single helper. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Brian Foster --- fs/xfs/libxfs/xfs_bmap.c | 8 ++------ fs/xfs/libxfs/xfs_types.c | 23 +++++++++++++++++++++++ fs/xfs/libxfs/xfs_types.h | 2 ++ fs/xfs/scrub/bmap.c | 5 +---- fs/xfs/xfs_bmap_item.c | 11 +---------- fs/xfs/xfs_extfree_item.c | 11 +---------- fs/xfs/xfs_refcount_item.c | 11 +---------- fs/xfs/xfs_rmap_item.c | 11 +---------- 8 files changed, 32 insertions(+), 50 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index de9c27ef68d8..7f1b6ad570a9 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6242,12 +6242,8 @@ xfs_bmap_validate_extent( if (!xfs_verify_rtbno(mp, endfsb)) return __this_address; } else { - if (!xfs_verify_fsbno(mp, irec->br_startblock)) - return __this_address; - if (!xfs_verify_fsbno(mp, endfsb)) - return __this_address; - if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) != - XFS_FSB_TO_AGNO(mp, endfsb)) + if (!xfs_verify_fsbext(mp, irec->br_startblock, + irec->br_blockcount)) return __this_address; } if (irec->br_state != XFS_EXT_NORM && whichfork != XFS_DATA_FORK) diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c index 4f595546a639..b74866dbea94 100644 --- a/fs/xfs/libxfs/xfs_types.c +++ b/fs/xfs/libxfs/xfs_types.c @@ -61,6 +61,29 @@ xfs_verify_fsbno( return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno)); } +/* + * Verify that a data device extent is fully contained inside the filesystem, + * does not cross an AG boundary, and does not point at static metadata. + */ +bool +xfs_verify_fsbext( + struct xfs_mount *mp, + xfs_fsblock_t fsbno, + xfs_fsblock_t len) +{ + if (fsbno + len <= fsbno) + return false; + + if (!xfs_verify_fsbno(mp, fsbno)) + return false; + + if (!xfs_verify_fsbno(mp, fsbno + len - 1)) + return false; + + return XFS_FSB_TO_AGNO(mp, fsbno) == + XFS_FSB_TO_AGNO(mp, fsbno + len - 1); +} + /* Calculate the first and last possible inode number in an AG. */ void xfs_agino_range( diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h index 397d94775440..7feaaac25b3d 100644 --- a/fs/xfs/libxfs/xfs_types.h +++ b/fs/xfs/libxfs/xfs_types.h @@ -184,6 +184,8 @@ xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno); bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno, + xfs_fsblock_t len); void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t *first, xfs_agino_t *last); diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index fed56d213a3f..3e2ba7875059 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -359,10 +359,7 @@ xchk_bmap_iextent( xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff); if (!info->is_rt && - (!xfs_verify_fsbno(mp, irec->br_startblock) || - !xfs_verify_fsbno(mp, end) || - XFS_FSB_TO_AGNO(mp, irec->br_startblock) != - XFS_FSB_TO_AGNO(mp, end))) + !xfs_verify_fsbext(mp, irec->br_startblock, irec->br_blockcount)) xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff); diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index a21a9f71c0c0..659bde22c505 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -448,16 +448,7 @@ xfs_bui_validate( if (bmap->me_startoff + bmap->me_len <= bmap->me_startoff) return false; - if (bmap->me_startblock + bmap->me_len <= bmap->me_startblock) - return false; - - if (!xfs_verify_fsbno(mp, bmap->me_startblock)) - return false; - - if (!xfs_verify_fsbno(mp, bmap->me_startblock + bmap->me_len - 1)) - return false; - - return true; + return xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len); } /* diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index bfdfbd192a38..93223ebb3372 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -584,16 +584,7 @@ xfs_efi_validate_ext( struct xfs_mount *mp, struct xfs_extent *extp) { - if (extp->ext_start + extp->ext_len <= extp->ext_start) - return false; - - if (!xfs_verify_fsbno(mp, extp->ext_start)) - return false; - - if (!xfs_verify_fsbno(mp, extp->ext_start + extp->ext_len - 1)) - return false; - - return true; + return xfs_verify_fsbext(mp, extp->ext_start, extp->ext_len); } /* diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 937d482c9be4..07ebccbbf4df 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -439,16 +439,7 @@ xfs_cui_validate_phys( return false; } - if (refc->pe_startblock + refc->pe_len <= refc->pe_startblock) - return false; - - if (!xfs_verify_fsbno(mp, refc->pe_startblock)) - return false; - - if (!xfs_verify_fsbno(mp, refc->pe_startblock + refc->pe_len - 1)) - return false; - - return true; + return xfs_verify_fsbext(mp, refc->pe_startblock, refc->pe_len); } /* diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 9b84017184d9..4fa875237422 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -493,16 +493,7 @@ xfs_rui_validate_map( if (rmap->me_startoff + rmap->me_len <= rmap->me_startoff) return false; - if (rmap->me_startblock + rmap->me_len <= rmap->me_startblock) - return false; - - if (!xfs_verify_fsbno(mp, rmap->me_startblock)) - return false; - - if (!xfs_verify_fsbno(mp, rmap->me_startblock + rmap->me_len - 1)) - return false; - - return true; + return xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len); } /* From 18695ad4251462b33787b7e375dbda57c1969c8f Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 4 Dec 2020 13:24:22 -0800 Subject: [PATCH 18/40] xfs: refactor realtime volume extent validation Refactor all the open-coded validation of realtime device extents into a single helper. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 13 +++---------- fs/xfs/libxfs/xfs_types.c | 16 ++++++++++++++++ fs/xfs/libxfs/xfs_types.h | 2 ++ fs/xfs/scrub/bmap.c | 8 +------- fs/xfs/scrub/rtbitmap.c | 4 +--- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 7f1b6ad570a9..7bcf498ef6b2 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6226,20 +6226,13 @@ xfs_bmap_validate_extent( struct xfs_bmbt_irec *irec) { struct xfs_mount *mp = ip->i_mount; - xfs_fsblock_t endfsb; - bool isrt; - if (irec->br_startblock + irec->br_blockcount <= irec->br_startblock) - return __this_address; if (irec->br_startoff + irec->br_blockcount <= irec->br_startoff) return __this_address; - isrt = XFS_IS_REALTIME_INODE(ip); - endfsb = irec->br_startblock + irec->br_blockcount - 1; - if (isrt && whichfork == XFS_DATA_FORK) { - if (!xfs_verify_rtbno(mp, irec->br_startblock)) - return __this_address; - if (!xfs_verify_rtbno(mp, endfsb)) + if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) { + if (!xfs_verify_rtext(mp, irec->br_startblock, + irec->br_blockcount)) return __this_address; } else { if (!xfs_verify_fsbext(mp, irec->br_startblock, diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c index b74866dbea94..7b310eb296b7 100644 --- a/fs/xfs/libxfs/xfs_types.c +++ b/fs/xfs/libxfs/xfs_types.c @@ -198,6 +198,22 @@ xfs_verify_rtbno( return rtbno < mp->m_sb.sb_rblocks; } +/* Verify that a realtime device extent is fully contained inside the volume. */ +bool +xfs_verify_rtext( + struct xfs_mount *mp, + xfs_rtblock_t rtbno, + xfs_rtblock_t len) +{ + if (rtbno + len <= rtbno) + return false; + + if (!xfs_verify_rtbno(mp, rtbno)) + return false; + + return xfs_verify_rtbno(mp, rtbno + len - 1); +} + /* Calculate the range of valid icount values. */ void xfs_icount_range( diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h index 7feaaac25b3d..18e83ce46568 100644 --- a/fs/xfs/libxfs/xfs_types.h +++ b/fs/xfs/libxfs/xfs_types.h @@ -197,6 +197,8 @@ bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); +bool xfs_verify_rtext(struct xfs_mount *mp, xfs_rtblock_t rtbno, + xfs_rtblock_t len); bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount); bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off); void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min, diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index 3e2ba7875059..cce8ac7d3973 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -319,7 +319,6 @@ xchk_bmap_iextent( struct xfs_bmbt_irec *irec) { struct xfs_mount *mp = info->sc->mp; - xfs_filblks_t end; int error = 0; /* @@ -349,13 +348,8 @@ xchk_bmap_iextent( if (irec->br_blockcount > MAXEXTLEN) xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff); - if (irec->br_startblock + irec->br_blockcount <= irec->br_startblock) - xchk_fblock_set_corrupt(info->sc, info->whichfork, - irec->br_startoff); - end = irec->br_startblock + irec->br_blockcount - 1; if (info->is_rt && - (!xfs_verify_rtbno(mp, irec->br_startblock) || - !xfs_verify_rtbno(mp, end))) + !xfs_verify_rtext(mp, irec->br_startblock, irec->br_blockcount)) xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff); if (!info->is_rt && diff --git a/fs/xfs/scrub/rtbitmap.c b/fs/xfs/scrub/rtbitmap.c index 76e4ffe0315b..d409ca592178 100644 --- a/fs/xfs/scrub/rtbitmap.c +++ b/fs/xfs/scrub/rtbitmap.c @@ -52,9 +52,7 @@ xchk_rtbitmap_rec( startblock = rec->ar_startext * tp->t_mountp->m_sb.sb_rextsize; blockcount = rec->ar_extcount * tp->t_mountp->m_sb.sb_rextsize; - if (startblock + blockcount <= startblock || - !xfs_verify_rtbno(sc->mp, startblock) || - !xfs_verify_rtbno(sc->mp, startblock + blockcount - 1)) + if (!xfs_verify_rtext(sc->mp, startblock, blockcount)) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); return 0; } From 33005fd0a537501111fc97ec330b721388c6b451 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 4 Dec 2020 13:28:35 -0800 Subject: [PATCH 19/40] xfs: refactor file range validation Refactor all the open-coded validation of file block ranges into a single helper, and teach the bmap scrubber to check the ranges. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_bmap.c | 2 +- fs/xfs/libxfs/xfs_types.c | 25 +++++++++++++++++++++++++ fs/xfs/libxfs/xfs_types.h | 3 +++ fs/xfs/scrub/bmap.c | 4 ++++ fs/xfs/xfs_bmap_item.c | 2 +- fs/xfs/xfs_inode.c | 2 +- fs/xfs/xfs_rmap_item.c | 2 +- fs/xfs/xfs_super.c | 2 +- 8 files changed, 37 insertions(+), 5 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 7bcf498ef6b2..dcf56bcafb8f 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6227,7 +6227,7 @@ xfs_bmap_validate_extent( { struct xfs_mount *mp = ip->i_mount; - if (irec->br_startoff + irec->br_blockcount <= irec->br_startoff) + if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount)) return __this_address; if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) { diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c index 7b310eb296b7..b254fbeaaa50 100644 --- a/fs/xfs/libxfs/xfs_types.c +++ b/fs/xfs/libxfs/xfs_types.c @@ -258,3 +258,28 @@ xfs_verify_dablk( return dabno <= max_dablk; } + +/* Check that a file block offset does not exceed the maximum. */ +bool +xfs_verify_fileoff( + struct xfs_mount *mp, + xfs_fileoff_t off) +{ + return off <= XFS_MAX_FILEOFF; +} + +/* Check that a range of file block offsets do not exceed the maximum. */ +bool +xfs_verify_fileext( + struct xfs_mount *mp, + xfs_fileoff_t off, + xfs_fileoff_t len) +{ + if (off + len <= off) + return false; + + if (!xfs_verify_fileoff(mp, off)) + return false; + + return xfs_verify_fileoff(mp, off + len - 1); +} diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h index 18e83ce46568..064bd6e8c922 100644 --- a/fs/xfs/libxfs/xfs_types.h +++ b/fs/xfs/libxfs/xfs_types.h @@ -203,5 +203,8 @@ bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount); bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off); void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min, unsigned long long *max); +bool xfs_verify_fileoff(struct xfs_mount *mp, xfs_fileoff_t off); +bool xfs_verify_fileext(struct xfs_mount *mp, xfs_fileoff_t off, + xfs_fileoff_t len); #endif /* __XFS_TYPES_H__ */ diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index cce8ac7d3973..bce4421acdb9 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -329,6 +329,10 @@ xchk_bmap_iextent( xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff); + if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount)) + xchk_fblock_set_corrupt(info->sc, info->whichfork, + irec->br_startoff); + xchk_bmap_dirattr_extent(ip, info, irec); /* There should never be a "hole" extent in either extent list. */ diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 659bde22c505..93e4d8ae6e92 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -445,7 +445,7 @@ xfs_bui_validate( if (!xfs_verify_ino(mp, bmap->me_owner)) return false; - if (bmap->me_startoff + bmap->me_len <= bmap->me_startoff) + if (!xfs_verify_fileext(mp, bmap->me_startoff, bmap->me_len)) return false; return xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 2bfbcf28b1bd..004fce3646ae 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1521,7 +1521,7 @@ xfs_itruncate_extents_flags( * the page cache can't scale that far. */ first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); - if (first_unmap_block >= XFS_MAX_FILEOFF) { + if (!xfs_verify_fileoff(mp, first_unmap_block)) { WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF); return 0; } diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 4fa875237422..49cebd68b672 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -490,7 +490,7 @@ xfs_rui_validate_map( !xfs_verify_ino(mp, rmap->me_owner)) return false; - if (rmap->me_startoff + rmap->me_len <= rmap->me_startoff) + if (!xfs_verify_fileext(mp, rmap->me_startoff, rmap->me_len)) return false; return xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 36002f460d7c..e1668491cee7 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1517,7 +1517,7 @@ xfs_fc_fill_super( * Avoid integer overflow by comparing the maximum bmbt offset to the * maximum pagecache offset in units of fs blocks. */ - if (XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE) > XFS_MAX_FILEOFF) { + if (!xfs_verify_fileoff(mp, XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE))) { xfs_warn(mp, "MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!", XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE), From 1e5c39dfd3a4630f382581b967c027f4cff7569d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 4 Dec 2020 15:59:39 -0800 Subject: [PATCH 20/40] xfs: rename xfs_fc_* back to xfs_fs_* Get rid of this one-off namespace since we're done converting things to fscontext now. Suggested-by: Dave Chinner Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Brian Foster --- fs/xfs/xfs_super.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e1668491cee7..315630e03509 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1159,7 +1159,7 @@ suffix_kstrtoint( * NOTE: mp->m_super is NULL here! */ static int -xfs_fc_parse_param( +xfs_fs_parse_param( struct fs_context *fc, struct fs_parameter *param) { @@ -1317,7 +1317,7 @@ xfs_fc_parse_param( } static int -xfs_fc_validate_params( +xfs_fs_validate_params( struct xfs_mount *mp) { /* @@ -1386,7 +1386,7 @@ xfs_fc_validate_params( } static int -xfs_fc_fill_super( +xfs_fs_fill_super( struct super_block *sb, struct fs_context *fc) { @@ -1396,7 +1396,7 @@ xfs_fc_fill_super( mp->m_super = sb; - error = xfs_fc_validate_params(mp); + error = xfs_fs_validate_params(mp); if (error) goto out_free_names; @@ -1660,10 +1660,10 @@ xfs_fc_fill_super( } static int -xfs_fc_get_tree( +xfs_fs_get_tree( struct fs_context *fc) { - return get_tree_bdev(fc, xfs_fc_fill_super); + return get_tree_bdev(fc, xfs_fs_fill_super); } static int @@ -1782,7 +1782,7 @@ xfs_remount_ro( * silently ignore all options that we can't actually change. */ static int -xfs_fc_reconfigure( +xfs_fs_reconfigure( struct fs_context *fc) { struct xfs_mount *mp = XFS_M(fc->root->d_sb); @@ -1795,7 +1795,7 @@ xfs_fc_reconfigure( if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) fc->sb_flags |= SB_I_VERSION; - error = xfs_fc_validate_params(new_mp); + error = xfs_fs_validate_params(new_mp); if (error) return error; @@ -1832,7 +1832,7 @@ xfs_fc_reconfigure( return 0; } -static void xfs_fc_free( +static void xfs_fs_free( struct fs_context *fc) { struct xfs_mount *mp = fc->s_fs_info; @@ -1848,10 +1848,10 @@ static void xfs_fc_free( } static const struct fs_context_operations xfs_context_ops = { - .parse_param = xfs_fc_parse_param, - .get_tree = xfs_fc_get_tree, - .reconfigure = xfs_fc_reconfigure, - .free = xfs_fc_free, + .parse_param = xfs_fs_parse_param, + .get_tree = xfs_fs_get_tree, + .reconfigure = xfs_fs_reconfigure, + .free = xfs_fs_free, }; static int xfs_init_fs_context( From a9382fa9a9ffb136bb274cfaefe64b1ac5dbb867 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:41:21 -0800 Subject: [PATCH 21/40] xfs: delete duplicated tp->t_dqinfo null check and allocation The function xfs_trans_mod_dquot_byino() wraps around xfs_trans_mod_dquot() to account for quotas, and also there is the function call chain xfs_trans_reserve_quota_bydquots -> xfs_trans_dqresv -> xfs_trans_mod_dquot, both of them do the duplicated null check and allocation. Thus we can delete the duplicated operation from them. Signed-off-by: Kaixu Xia Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_trans_dquot.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c index fe45b0c3970c..67f1e275b34d 100644 --- a/fs/xfs/xfs_trans_dquot.c +++ b/fs/xfs/xfs_trans_dquot.c @@ -143,9 +143,6 @@ xfs_trans_mod_dquot_byino( xfs_is_quota_inode(&mp->m_sb, ip->i_ino)) return; - if (tp->t_dqinfo == NULL) - xfs_trans_alloc_dqinfo(tp); - if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) @@ -698,7 +695,6 @@ xfs_trans_dqresv( * because we don't have the luxury of a transaction envelope then. */ if (tp) { - ASSERT(tp->t_dqinfo); ASSERT(flags & XFS_QMOPT_RESBLK_MASK); if (nblks != 0) xfs_trans_mod_dquot(tp, dqp, @@ -752,9 +748,6 @@ xfs_trans_reserve_quota_bydquots( if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp)) return 0; - if (tp && tp->t_dqinfo == NULL) - xfs_trans_alloc_dqinfo(tp); - ASSERT(flags & XFS_QMOPT_RESBLK_MASK); if (udqp) { From 04a58620a17cb14fa20c6e536e03eb27f9af6bc9 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:41:21 -0800 Subject: [PATCH 22/40] xfs: check tp->t_dqinfo value instead of the XFS_TRANS_DQ_DIRTY flag Nowadays the only things that the XFS_TRANS_DQ_DIRTY flag seems to do are indicates the tp->t_dqinfo->dqs[XFS_QM_TRANS_{USR,GRP,PRJ}] values changed and check in xfs_trans_apply_dquot_deltas() and the unreserve variant xfs_trans_unreserve_and_mod_dquots(). Actually, we also can use the tp->t_dqinfo value instead of the XFS_TRANS_DQ_DIRTY flag, that is to say, we allocate the new tp->t_dqinfo only when the qtrx values changed, so the tp->t_dqinfo value isn't NULL equals the XFS_TRANS_DQ_DIRTY flag is set, we only need to check if tp->t_dqinfo == NULL in xfs_trans_apply_dquot_deltas() and its unreserve variant to determine whether lock all of the dquots and join them to the transaction. Signed-off-by: Kaixu Xia Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_shared.h | 1 - fs/xfs/xfs_inode.c | 8 +------- fs/xfs/xfs_trans_dquot.c | 13 ++----------- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h index c795ae47b3c9..8c61a461bf7b 100644 --- a/fs/xfs/libxfs/xfs_shared.h +++ b/fs/xfs/libxfs/xfs_shared.h @@ -62,7 +62,6 @@ void xfs_log_get_max_trans_res(struct xfs_mount *mp, #define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ #define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ #define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ -#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ #define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ #define XFS_TRANS_NO_WRITECOUNT 0x40 /* do not elevate SB writecount */ #define XFS_TRANS_RES_FDBLKS 0x80 /* reserve newly freed blocks */ diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 004fce3646ae..034fe0adae05 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -959,7 +959,6 @@ xfs_dir_ialloc( xfs_buf_t *ialloc_context = NULL; int code; void *dqinfo; - uint tflags; tp = *tpp; ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); @@ -1018,12 +1017,9 @@ xfs_dir_ialloc( * and attach it to the next transaction. */ dqinfo = NULL; - tflags = 0; if (tp->t_dqinfo) { dqinfo = (void *)tp->t_dqinfo; tp->t_dqinfo = NULL; - tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY; - tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY); } code = xfs_trans_roll(&tp); @@ -1031,10 +1027,8 @@ xfs_dir_ialloc( /* * Re-attach the quota info that we detached from prev trx. */ - if (dqinfo) { + if (dqinfo) tp->t_dqinfo = dqinfo; - tp->t_flags |= tflags; - } if (code) { xfs_buf_relse(ialloc_context); diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c index 67f1e275b34d..0ebfd7930382 100644 --- a/fs/xfs/xfs_trans_dquot.c +++ b/fs/xfs/xfs_trans_dquot.c @@ -84,13 +84,6 @@ xfs_trans_dup_dqinfo( xfs_trans_alloc_dqinfo(ntp); - /* - * Because the quota blk reservation is carried forward, - * it is also necessary to carry forward the DQ_DIRTY flag. - */ - if (otp->t_flags & XFS_TRANS_DQ_DIRTY) - ntp->t_flags |= XFS_TRANS_DQ_DIRTY; - for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) { oqa = otp->t_dqinfo->dqs[j]; nqa = ntp->t_dqinfo->dqs[j]; @@ -270,8 +263,6 @@ xfs_trans_mod_dquot( if (delta) trace_xfs_trans_mod_dquot_after(qtrx); - - tp->t_flags |= XFS_TRANS_DQ_DIRTY; } @@ -348,7 +339,7 @@ xfs_trans_apply_dquot_deltas( int64_t totalbdelta; int64_t totalrtbdelta; - if (!(tp->t_flags & XFS_TRANS_DQ_DIRTY)) + if (!tp->t_dqinfo) return; ASSERT(tp->t_dqinfo); @@ -490,7 +481,7 @@ xfs_trans_unreserve_and_mod_dquots( struct xfs_dqtrx *qtrx, *qa; bool locked; - if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY)) + if (!tp->t_dqinfo) return; for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) { From b3b29cd1069c56fbfdd63e650372530f2e26e911 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:41:22 -0800 Subject: [PATCH 23/40] xfs: directly return if the delta equal to zero The xfs_trans_mod_dquot() function will allocate new tp->t_dqinfo if it is NULL and make the changes in the tp->t_dqinfo->dqs[XFS_QM_TRANS _{USR,GRP,PRJ}]. Nowadays seems none of the callers want to join the dquots to the transaction and push them to device when the delta is zero. Actually, most of time the caller would check the delta and go on only when the delta value is not zero, so we should bail out when it is zero. Signed-off-by: Kaixu Xia Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_trans_dquot.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c index 0ebfd7930382..28b8ac701919 100644 --- a/fs/xfs/xfs_trans_dquot.c +++ b/fs/xfs/xfs_trans_dquot.c @@ -194,6 +194,9 @@ xfs_trans_mod_dquot( ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp)); qtrx = NULL; + if (!delta) + return; + if (tp->t_dqinfo == NULL) xfs_trans_alloc_dqinfo(tp); /* @@ -205,10 +208,8 @@ xfs_trans_mod_dquot( if (qtrx->qt_dquot == NULL) qtrx->qt_dquot = dqp; - if (delta) { - trace_xfs_trans_mod_dquot_before(qtrx); - trace_xfs_trans_mod_dquot(tp, dqp, field, delta); - } + trace_xfs_trans_mod_dquot_before(qtrx); + trace_xfs_trans_mod_dquot(tp, dqp, field, delta); switch (field) { /* regular disk blk reservation */ @@ -261,8 +262,7 @@ xfs_trans_mod_dquot( ASSERT(0); } - if (delta) - trace_xfs_trans_mod_dquot_after(qtrx); + trace_xfs_trans_mod_dquot_after(qtrx); } @@ -687,14 +687,9 @@ xfs_trans_dqresv( */ if (tp) { ASSERT(flags & XFS_QMOPT_RESBLK_MASK); - if (nblks != 0) - xfs_trans_mod_dquot(tp, dqp, - flags & XFS_QMOPT_RESBLK_MASK, - nblks); - if (ninos != 0) - xfs_trans_mod_dquot(tp, dqp, - XFS_TRANS_DQ_RES_INOS, - ninos); + xfs_trans_mod_dquot(tp, dqp, flags & XFS_QMOPT_RESBLK_MASK, + nblks); + xfs_trans_mod_dquot(tp, dqp, XFS_TRANS_DQ_RES_INOS, ninos); } ASSERT(dqp->q_blk.reserved >= dqp->q_blk.count); ASSERT(dqp->q_rtb.reserved >= dqp->q_rtb.count); From 88269b880a8ea38cf607e684906f3b00acd5b56b Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:43:19 -0800 Subject: [PATCH 24/40] xfs: remove unnecessary null check in xfs_generic_create The function posix_acl_release() test the passed-in argument and move on only when it is non-null, so maybe the null check in xfs_generic_create is unnecessary. Signed-off-by: Kaixu Xia Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_iops.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 1414ab79eacf..d1ecf7669fc8 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -206,10 +206,8 @@ xfs_generic_create( xfs_finish_inode_setup(ip); out_free_acl: - if (default_acl) - posix_acl_release(default_acl); - if (acl) - posix_acl_release(acl); + posix_acl_release(default_acl); + posix_acl_release(acl); return error; out_cleanup_inode: From afbd914776db9c035dbe2afa6badb9955ae52492 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:44:19 -0800 Subject: [PATCH 25/40] xfs: remove the unused XFS_B_FSB_OFFSET macro There are no callers of the XFS_B_FSB_OFFSET macro, so remove it. Signed-off-by: Kaixu Xia Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_format.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index f64eed3ccfed..630388b72dbe 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -633,7 +633,6 @@ xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino) #define XFS_B_TO_FSB(mp,b) \ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) #define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) -#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) /* * Allocation group header From 237d7887ae723af7d978e8b9a385fdff416f357b Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Thu, 3 Dec 2020 16:46:50 -0800 Subject: [PATCH 26/40] xfs: show the proper user quota options The quota option 'usrquota' should be shown if both the XFS_UQUOTA_ACCT and XFS_UQUOTA_ENFD flags are set. The option 'uqnoenforce' should be shown when only the XFS_UQUOTA_ACCT flag is set. The current code logic seems wrong, Fix it and show proper options. Signed-off-by: Kaixu Xia Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_super.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 315630e03509..813be879a5e5 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -199,10 +199,12 @@ xfs_fs_show_options( seq_printf(m, ",swidth=%d", (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); - if (mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD)) - seq_puts(m, ",usrquota"); - else if (mp->m_qflags & XFS_UQUOTA_ACCT) - seq_puts(m, ",uqnoenforce"); + if (mp->m_qflags & XFS_UQUOTA_ACCT) { + if (mp->m_qflags & XFS_UQUOTA_ENFD) + seq_puts(m, ",usrquota"); + else + seq_puts(m, ",uqnoenforce"); + } if (mp->m_qflags & XFS_PQUOTA_ACCT) { if (mp->m_qflags & XFS_PQUOTA_ENFD) From 7bc1fea9d36c78e783ce7d4ad28ad129ebcce435 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Thu, 3 Dec 2020 16:42:01 -0800 Subject: [PATCH 27/40] xfs: introduce xfs_validate_stripe_geometry() Introduce a common helper to consolidate stripe validation process. Also make kernel code xfs_validate_sb_common() use it first. Signed-off-by: Gao Xiang Reviewed-by: Brian Foster Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_sb.c | 77 ++++++++++++++++++++++++++++++++++++------ fs/xfs/libxfs/xfs_sb.h | 3 ++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 05359690aaed..bbda117e5d85 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -360,21 +360,18 @@ xfs_validate_sb_common( } } - if (sbp->sb_unit) { - if (!xfs_sb_version_hasdalign(sbp) || - sbp->sb_unit > sbp->sb_width || - (sbp->sb_width % sbp->sb_unit) != 0) { - xfs_notice(mp, "SB stripe unit sanity check failed"); - return -EFSCORRUPTED; - } - } else if (xfs_sb_version_hasdalign(sbp)) { + /* + * Either (sb_unit and !hasdalign) or (!sb_unit and hasdalign) + * would imply the image is corrupted. + */ + if (!!sbp->sb_unit ^ xfs_sb_version_hasdalign(sbp)) { xfs_notice(mp, "SB stripe alignment sanity check failed"); return -EFSCORRUPTED; - } else if (sbp->sb_width) { - xfs_notice(mp, "SB stripe width sanity check failed"); - return -EFSCORRUPTED; } + if (!xfs_validate_stripe_geometry(mp, XFS_FSB_TO_B(mp, sbp->sb_unit), + XFS_FSB_TO_B(mp, sbp->sb_width), 0, false)) + return -EFSCORRUPTED; if (xfs_sb_version_hascrc(&mp->m_sb) && sbp->sb_blocksize < XFS_MIN_CRC_BLOCKSIZE) { @@ -1206,3 +1203,61 @@ xfs_sb_get_secondary( *bpp = bp; return 0; } + +/* + * sunit, swidth, sectorsize(optional with 0) should be all in bytes, + * so users won't be confused by values in error messages. + */ +bool +xfs_validate_stripe_geometry( + struct xfs_mount *mp, + __s64 sunit, + __s64 swidth, + int sectorsize, + bool silent) +{ + if (swidth > INT_MAX) { + if (!silent) + xfs_notice(mp, +"stripe width (%lld) is too large", swidth); + return false; + } + + if (sunit > swidth) { + if (!silent) + xfs_notice(mp, +"stripe unit (%lld) is larger than the stripe width (%lld)", sunit, swidth); + return false; + } + + if (sectorsize && (int)sunit % sectorsize) { + if (!silent) + xfs_notice(mp, +"stripe unit (%lld) must be a multiple of the sector size (%d)", + sunit, sectorsize); + return false; + } + + if (sunit && !swidth) { + if (!silent) + xfs_notice(mp, +"invalid stripe unit (%lld) and stripe width of 0", sunit); + return false; + } + + if (!sunit && swidth) { + if (!silent) + xfs_notice(mp, +"invalid stripe width (%lld) and stripe unit of 0", swidth); + return false; + } + + if (sunit && (int)swidth % (int)sunit) { + if (!silent) + xfs_notice(mp, +"stripe width (%lld) must be a multiple of the stripe unit (%lld)", + swidth, sunit); + return false; + } + return true; +} diff --git a/fs/xfs/libxfs/xfs_sb.h b/fs/xfs/libxfs/xfs_sb.h index 92465a9a5162..f79f9dc632b6 100644 --- a/fs/xfs/libxfs/xfs_sb.h +++ b/fs/xfs/libxfs/xfs_sb.h @@ -42,4 +42,7 @@ extern int xfs_sb_get_secondary(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); +extern bool xfs_validate_stripe_geometry(struct xfs_mount *mp, + __s64 sunit, __s64 swidth, int sectorsize, bool silent); + #endif /* __XFS_SB_H__ */ From 2e984badbcc0f1cf284441c566ca4309fe59ac05 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Dec 2020 13:38:42 -0800 Subject: [PATCH 28/40] xfs: remove unneeded return value check for *init_cursor() Since *init_cursor() can always return a valid cursor, the NULL check in caller is unneeded. So clean them up. This also keeps the behavior consistent with other callers. Signed-off-by: Joseph Qi Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_bmap_btree.c | 2 -- fs/xfs/libxfs/xfs_ialloc_btree.c | 5 ----- fs/xfs/libxfs/xfs_refcount.c | 9 --------- fs/xfs/libxfs/xfs_rmap.c | 9 --------- fs/xfs/scrub/agheader_repair.c | 2 -- fs/xfs/scrub/bmap.c | 5 ----- fs/xfs/scrub/common.c | 14 -------------- 7 files changed, 46 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index ecec604e6e4d..976659190d27 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -639,8 +639,6 @@ xfs_bmbt_change_owner( ASSERT(XFS_IFORK_PTR(ip, whichfork)->if_format == XFS_DINODE_FMT_BTREE); cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork); - if (!cur) - return -ENOMEM; cur->bc_ino.flags |= XFS_BTCUR_BMBT_INVALID_OWNER; error = xfs_btree_change_owner(cur, new_owner, buffer_list); diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c index cc919a2ee870..4c5831646bd9 100644 --- a/fs/xfs/libxfs/xfs_ialloc_btree.c +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c @@ -672,11 +672,6 @@ xfs_inobt_cur( return error; cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which); - if (!cur) { - xfs_trans_brelse(tp, *agi_bpp); - *agi_bpp = NULL; - return -ENOMEM; - } *curpp = cur; return 0; } diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 2076627243b0..2037b9f23069 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c @@ -1179,10 +1179,6 @@ xfs_refcount_finish_one( return error; rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); - if (!rcur) { - error = -ENOMEM; - goto out_cur; - } rcur->bc_ag.refc.nr_ops = nr_ops; rcur->bc_ag.refc.shape_changes = shape_changes; } @@ -1217,11 +1213,6 @@ xfs_refcount_finish_one( trace_xfs_refcount_finish_one_leftover(mp, agno, type, bno, blockcount, new_agbno, *new_len); return error; - -out_cur: - xfs_trans_brelse(tp, agbp); - - return error; } /* diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index 2668ebe02865..10e0cf9949a2 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c @@ -2404,10 +2404,6 @@ xfs_rmap_finish_one( return -EFSCORRUPTED; rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); - if (!rcur) { - error = -ENOMEM; - goto out_cur; - } } *pcur = rcur; @@ -2446,11 +2442,6 @@ xfs_rmap_finish_one( error = -EFSCORRUPTED; } return error; - -out_cur: - xfs_trans_brelse(tp, agbp); - - return error; } /* diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c index 401f71579ce6..23690f824ffa 100644 --- a/fs/xfs/scrub/agheader_repair.c +++ b/fs/xfs/scrub/agheader_repair.c @@ -829,8 +829,6 @@ xrep_agi_calc_from_btrees( cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno, XFS_BTNUM_FINO); - if (error) - goto err; error = xfs_btree_count_blocks(cur, &blocks); if (error) goto err; diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index bce4421acdb9..33559c3a4bc3 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -558,10 +558,6 @@ xchk_bmap_check_ag_rmaps( return error; cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno); - if (!cur) { - error = -ENOMEM; - goto out_agf; - } sbcri.sc = sc; sbcri.whichfork = whichfork; @@ -570,7 +566,6 @@ xchk_bmap_check_ag_rmaps( error = 0; xfs_btree_del_cursor(cur, error); -out_agf: xfs_trans_brelse(sc->tp, agf); return error; } diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c index 18876056e5e0..8ea6d4aa3f55 100644 --- a/fs/xfs/scrub/common.c +++ b/fs/xfs/scrub/common.c @@ -466,8 +466,6 @@ xchk_ag_btcur_init( /* Set up a bnobt cursor for cross-referencing. */ sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, agno, XFS_BTNUM_BNO); - if (!sa->bno_cur) - goto err; } if (sa->agf_bp && @@ -475,8 +473,6 @@ xchk_ag_btcur_init( /* Set up a cntbt cursor for cross-referencing. */ sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, agno, XFS_BTNUM_CNT); - if (!sa->cnt_cur) - goto err; } /* Set up a inobt cursor for cross-referencing. */ @@ -484,8 +480,6 @@ xchk_ag_btcur_init( xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) { sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp, agno, XFS_BTNUM_INO); - if (!sa->ino_cur) - goto err; } /* Set up a finobt cursor for cross-referencing. */ @@ -493,8 +487,6 @@ xchk_ag_btcur_init( xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) { sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp, agno, XFS_BTNUM_FINO); - if (!sa->fino_cur) - goto err; } /* Set up a rmapbt cursor for cross-referencing. */ @@ -502,8 +494,6 @@ xchk_ag_btcur_init( xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) { sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp, agno); - if (!sa->rmap_cur) - goto err; } /* Set up a refcountbt cursor for cross-referencing. */ @@ -511,13 +501,9 @@ xchk_ag_btcur_init( xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) { sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp, sa->agf_bp, agno); - if (!sa->refc_cur) - goto err; } return 0; -err: - return -ENOMEM; } /* Release the AG header context and btree cursors. */ From a5336d6bb2d02d0e9d4d3c8be04b80b8b68d56c8 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 7 Dec 2020 10:41:46 -0800 Subject: [PATCH 29/40] xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks In commit 27c14b5daa82 we started tracking the last inode seen during an inode walk to avoid infinite loops if a corrupt inobt record happens to have a lower ir_startino than the record preceeding it. Unfortunately, the assertion trips over the case where there are completely empty inobt records (which can happen quite easily on 64k page filesystems) because we advance the tracking cursor without actually putting the empty record into the processing buffer. Fix the assert to allow for this case. Reported-by: zlang@redhat.com Fixes: 27c14b5daa82 ("xfs: ensure inobt record walks always make forward progress") Signed-off-by: Darrick J. Wong Reviewed-by: Zorro Lang Reviewed-by: Dave Chinner --- fs/xfs/xfs_iwalk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c index 2a45138831e3..eae3aff9bc97 100644 --- a/fs/xfs/xfs_iwalk.c +++ b/fs/xfs/xfs_iwalk.c @@ -363,7 +363,7 @@ xfs_iwalk_run_callbacks( /* Delete cursor but remember the last record we cached... */ xfs_iwalk_del_inobt(tp, curpp, agi_bpp, 0); irec = &iwag->recs[iwag->nr_recs - 1]; - ASSERT(next_agino == irec->ir_startino + XFS_INODES_PER_CHUNK); + ASSERT(next_agino >= irec->ir_startino + XFS_INODES_PER_CHUNK); error = xfs_iwalk_ag_recs(iwag); if (error) From 207ddc0ef4f413ab1f4e0c1fcab2226425dec293 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 8 Dec 2020 18:59:12 -0800 Subject: [PATCH 30/40] xfs: don't catch dax+reflink inodes as corruption in verifier We don't yet support dax on reflinked files, but that is in the works. Further, having the flag set does not automatically mean that the inode is actually "in the CPU direct access state," which depends on several other conditions in addition to the flag being set. As such, we should not catch this as corruption in the verifier - simply not actually enabling S_DAX on reflinked files is enough for now. Fixes: 4f435ebe7d04 ("xfs: don't mix reflink and DAX mode for now") Signed-off-by: Eric Sandeen Reviewed-by: Christoph Hellwig [darrick: fix the scrubber too] Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_inode_buf.c | 4 ---- fs/xfs/scrub/inode.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index c667c63f2cb0..4d7410e49db4 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -547,10 +547,6 @@ xfs_dinode_verify( if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & XFS_DIFLAG_REALTIME)) return __this_address; - /* don't let reflink and dax mix */ - if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags2 & XFS_DIFLAG2_DAX)) - return __this_address; - /* COW extent size hint validation */ fa = xfs_inode_validate_cowextsize(mp, be32_to_cpu(dip->di_cowextsize), mode, flags, flags2); diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c index bb25ff1b770d..faf65eb5bd31 100644 --- a/fs/xfs/scrub/inode.c +++ b/fs/xfs/scrub/inode.c @@ -185,10 +185,6 @@ xchk_inode_flags2( if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK)) goto bad; - /* dax and reflink make no sense, currently */ - if ((flags2 & XFS_DIFLAG2_DAX) && (flags2 & XFS_DIFLAG2_REFLINK)) - goto bad; - /* no bigtime iflag without the bigtime feature */ if (xfs_dinode_has_bigtime(dip) && !xfs_sb_version_hasbigtime(&mp->m_sb)) From 15574ebbff260a70d344cfb924a8daf3c47dc303 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 9 Dec 2020 10:02:05 -0800 Subject: [PATCH 31/40] xfs: convert noroom, okalloc in xfs_dialloc() to bool Boolean is preferred for such use. Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_ialloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 974e71bc4a3a..45cf7e55f5ee 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1716,11 +1716,11 @@ xfs_dialloc( xfs_agnumber_t agno; int error; int ialloced; - int noroom = 0; + bool noroom = false; xfs_agnumber_t start_agno; struct xfs_perag *pag; struct xfs_ino_geometry *igeo = M_IGEO(mp); - int okalloc = 1; + bool okalloc = true; if (*IO_agbp) { /* @@ -1753,8 +1753,8 @@ xfs_dialloc( if (igeo->maxicount && percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos > igeo->maxicount) { - noroom = 1; - okalloc = 0; + noroom = true; + okalloc = false; } /* From aececc9f8dec92a25c84a3378021636ce58d72dc Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 9 Dec 2020 10:02:17 -0800 Subject: [PATCH 32/40] xfs: introduce xfs_dialloc_roll() Introduce a helper to make the on-disk inode allocation rolling logic clearer in preparation of the following cleanup. Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_ialloc.c | 35 +++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_ialloc.h | 5 +++++ fs/xfs/xfs_inode.c | 31 +------------------------------ 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 45cf7e55f5ee..3ae83f6998dc 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1682,6 +1682,41 @@ xfs_dialloc_ag( return error; } +int +xfs_dialloc_roll( + struct xfs_trans **tpp, + struct xfs_buf *agibp) +{ + struct xfs_trans *tp = *tpp; + struct xfs_dquot_acct *dqinfo; + int error; + + /* + * Hold to on to the agibp across the commit so no other allocation can + * come in and take the free inodes we just allocated for our caller. + */ + xfs_trans_bhold(tp, agibp); + + /* + * We want the quota changes to be associated with the next transaction, + * NOT this one. So, detach the dqinfo from this and attach it to the + * next transaction. + */ + dqinfo = tp->t_dqinfo; + tp->t_dqinfo = NULL; + + error = xfs_trans_roll(&tp); + + /* Re-attach the quota info that we detached from prev trx. */ + tp->t_dqinfo = dqinfo; + + *tpp = tp; + if (error) + return error; + xfs_trans_bjoin(tp, agibp); + return 0; +} + /* * Allocate an inode on disk. * diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h index 72b3468b97b1..bd6e0db9e23c 100644 --- a/fs/xfs/libxfs/xfs_ialloc.h +++ b/fs/xfs/libxfs/xfs_ialloc.h @@ -32,6 +32,11 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog); } +int +xfs_dialloc_roll( + struct xfs_trans **tpp, + struct xfs_buf *agibp); + /* * Allocate an inode on disk. * Mode is used to tell whether the new inode will need space, and whether diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 034fe0adae05..6329b049570b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -958,7 +958,6 @@ xfs_dir_ialloc( xfs_inode_t *ip; xfs_buf_t *ialloc_context = NULL; int code; - void *dqinfo; tp = *tpp; ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); @@ -1002,41 +1001,13 @@ xfs_dir_ialloc( * to succeed the second time. */ if (ialloc_context) { - /* - * Normally, xfs_trans_commit releases all the locks. - * We call bhold to hang on to the ialloc_context across - * the commit. Holding this buffer prevents any other - * processes from doing any allocations in this - * allocation group. - */ - xfs_trans_bhold(tp, ialloc_context); - - /* - * We want the quota changes to be associated with the next - * transaction, NOT this one. So, detach the dqinfo from this - * and attach it to the next transaction. - */ - dqinfo = NULL; - if (tp->t_dqinfo) { - dqinfo = (void *)tp->t_dqinfo; - tp->t_dqinfo = NULL; - } - - code = xfs_trans_roll(&tp); - - /* - * Re-attach the quota info that we detached from prev trx. - */ - if (dqinfo) - tp->t_dqinfo = dqinfo; - + code = xfs_dialloc_roll(&tp, ialloc_context); if (code) { xfs_buf_relse(ialloc_context); *tpp = tp; *ipp = NULL; return code; } - xfs_trans_bjoin(tp, ialloc_context); /* * Call ialloc again. Since we've locked out all From 1abcf261016e12246e1f0d2dada9c5c851a9ceb7 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 9 Dec 2020 10:05:15 -0800 Subject: [PATCH 33/40] xfs: move on-disk inode allocation out of xfs_ialloc() So xfs_ialloc() will only address in-core inode allocation then, Also, rename xfs_ialloc() to xfs_dir_ialloc_init() in order to keep everything in xfs_inode.c under the same namespace. Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_inode.c | 211 +++++++++++++++------------------------------ fs/xfs/xfs_inode.h | 6 +- fs/xfs/xfs_qm.c | 26 +++--- 3 files changed, 84 insertions(+), 159 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 6329b049570b..bc1027ce0d1f 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -761,68 +761,26 @@ xfs_inode_inherit_flags2( } /* - * Allocate an inode on disk and return a copy of its in-core version. - * The in-core inode is locked exclusively. Set mode, nlink, and rdev - * appropriately within the inode. The uid and gid for the inode are - * set according to the contents of the given cred structure. - * - * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() - * has a free inode available, call xfs_iget() to obtain the in-core - * version of the allocated inode. Finally, fill in the inode and - * log its initial contents. In this case, ialloc_context would be - * set to NULL. - * - * If xfs_dialloc() does not have an available inode, it will replenish - * its supply by doing an allocation. Since we can only do one - * allocation within a transaction without deadlocks, we must commit - * the current transaction before returning the inode itself. - * In this case, therefore, we will set ialloc_context and return. - * The caller should then commit the current transaction, start a new - * transaction, and call xfs_ialloc() again to actually get the inode. - * - * To ensure that some other process does not grab the inode that - * was allocated during the first call to xfs_ialloc(), this routine - * also returns the [locked] bp pointing to the head of the freelist - * as ialloc_context. The caller should hold this buffer across - * the commit and pass it back into this routine on the second call. - * - * If we are allocating quota inodes, we do not have a parent inode - * to attach to or associate with (i.e. pip == NULL) because they - * are not linked into the directory structure - they are attached - * directly to the superblock - and so have no parent. + * Initialise a newly allocated inode and return the in-core inode to the + * caller locked exclusively. */ static int -xfs_ialloc( - xfs_trans_t *tp, - xfs_inode_t *pip, - umode_t mode, - xfs_nlink_t nlink, - dev_t rdev, - prid_t prid, - xfs_buf_t **ialloc_context, - xfs_inode_t **ipp) +xfs_init_new_inode( + struct xfs_trans *tp, + struct xfs_inode *pip, + xfs_ino_t ino, + umode_t mode, + xfs_nlink_t nlink, + dev_t rdev, + prid_t prid, + struct xfs_inode **ipp) { - struct xfs_mount *mp = tp->t_mountp; - xfs_ino_t ino; - xfs_inode_t *ip; - uint flags; - int error; - struct timespec64 tv; - struct inode *inode; - - /* - * Call the space management code to pick - * the on-disk inode to be allocated. - */ - error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, - ialloc_context, &ino); - if (error) - return error; - if (*ialloc_context || ino == NULLFSINO) { - *ipp = NULL; - return 0; - } - ASSERT(*ialloc_context == NULL); + struct xfs_mount *mp = tp->t_mountp; + struct xfs_inode *ip; + unsigned int flags; + int error; + struct timespec64 tv; + struct inode *inode; /* * Protect against obviously corrupt allocation btree records. Later @@ -837,14 +795,13 @@ xfs_ialloc( } /* - * Get the in-core inode with the lock held exclusively. - * This is because we're setting fields here we need - * to prevent others from looking at until we're done. + * Get the in-core inode with the lock held exclusively to prevent + * others from looking at until we're done. */ - error = xfs_iget(mp, tp, ino, XFS_IGET_CREATE, - XFS_ILOCK_EXCL, &ip); + error = xfs_iget(mp, tp, ino, XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip); if (error) return error; + ASSERT(ip != NULL); inode = VFS_I(ip); inode->i_mode = mode; @@ -932,108 +889,76 @@ xfs_ialloc( } /* - * Allocates a new inode from disk and return a pointer to the - * incore copy. This routine will internally commit the current - * transaction and allocate a new one if the Space Manager needed - * to do an allocation to replenish the inode free-list. - * - * This routine is designed to be called from xfs_create and - * xfs_create_dir. + * Allocates a new inode from disk and return a pointer to the incore copy. This + * routine will internally commit the current transaction and allocate a new one + * if we needed to allocate more on-disk free inodes to perform the requested + * operation. * + * If we are allocating quota inodes, we do not have a parent inode to attach to + * or associate with (i.e. dp == NULL) because they are not linked into the + * directory structure - they are attached directly to the superblock - and so + * have no parent. */ int xfs_dir_ialloc( - xfs_trans_t **tpp, /* input: current transaction; - output: may be a new transaction. */ - xfs_inode_t *dp, /* directory within whose allocate - the inode. */ - umode_t mode, - xfs_nlink_t nlink, - dev_t rdev, - prid_t prid, /* project id */ - xfs_inode_t **ipp) /* pointer to inode; it will be - locked. */ + struct xfs_trans **tpp, + struct xfs_inode *dp, + umode_t mode, + xfs_nlink_t nlink, + dev_t rdev, + prid_t prid, + struct xfs_inode **ipp) { - xfs_trans_t *tp; - xfs_inode_t *ip; - xfs_buf_t *ialloc_context = NULL; - int code; + struct xfs_buf *ialloc_context = NULL; + xfs_ino_t parent_ino = dp ? dp->i_ino : 0; + xfs_ino_t ino; + int error; - tp = *tpp; - ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES); /* - * xfs_ialloc will return a pointer to an incore inode if - * the Space Manager has an available inode on the free - * list. Otherwise, it will do an allocation and replenish - * the freelist. Since we can only do one allocation per - * transaction without deadlocks, we will need to commit the - * current transaction and start a new one. We will then - * need to call xfs_ialloc again to get the inode. - * - * If xfs_ialloc did an allocation to replenish the freelist, - * it returns the bp containing the head of the freelist as - * ialloc_context. We will hold a lock on it across the - * transaction commit so that no other process can steal - * the inode(s) that we've just allocated. + * Call the space management code to pick the on-disk inode to be + * allocated and replenish the freelist. Since we can only do one + * allocation per transaction without deadlocks, we will need to + * commit the current transaction and start a new one. + * If xfs_dialloc did an allocation to replenish the freelist, it + * returns the bp containing the head of the freelist as + * ialloc_context. We will hold a lock on it across the transaction + * commit so that no other process can steal the inode(s) that we've + * just allocated. */ - code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context, - &ip); - - /* - * Return an error if we were unable to allocate a new inode. - * This should only happen if we run out of space on disk or - * encounter a disk error. - */ - if (code) { - *ipp = NULL; - return code; - } - if (!ialloc_context && !ip) { - *ipp = NULL; - return -ENOSPC; - } + error = xfs_dialloc(*tpp, parent_ino, mode, &ialloc_context, &ino); + if (error) + return error; /* * If the AGI buffer is non-NULL, then we were unable to get an * inode in one operation. We need to commit the current - * transaction and call xfs_ialloc() again. It is guaranteed + * transaction and call xfs_dialloc() again. It is guaranteed * to succeed the second time. */ if (ialloc_context) { - code = xfs_dialloc_roll(&tp, ialloc_context); - if (code) { + error = xfs_dialloc_roll(tpp, ialloc_context); + if (error) { xfs_buf_relse(ialloc_context); - *tpp = tp; - *ipp = NULL; - return code; + return error; } - /* - * Call ialloc again. Since we've locked out all - * other allocations in this allocation group, - * this call should always succeed. + * Call dialloc again. Since we've locked out all other + * allocations in this allocation group, this call should + * always succeed. */ - code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, - &ialloc_context, &ip); - - /* - * If we get an error at this point, return to the caller - * so that the current transaction can be aborted. - */ - if (code) { - *tpp = tp; - *ipp = NULL; - return code; - } - ASSERT(!ialloc_context && ip); - + error = xfs_dialloc(*tpp, parent_ino, mode, &ialloc_context, + &ino); + if (error) + return error; + ASSERT(!ialloc_context); } - *ipp = ip; - *tpp = tp; + if (ino == NULLFSINO) + return -ENOSPC; - return 0; + return xfs_init_new_inode(*tpp, dp, ino, mode, nlink, rdev, prid, ipp); } /* diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 751a3d1d7d84..eca333f5f715 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -407,9 +407,9 @@ void xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode, xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip); xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip); -int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t, - xfs_nlink_t, dev_t, prid_t, - struct xfs_inode **); +int xfs_dir_ialloc(struct xfs_trans **tpp, struct xfs_inode *dp, umode_t mode, + xfs_nlink_t nlink, dev_t dev, prid_t prid, + struct xfs_inode **ipp); static inline int xfs_itruncate_extents( diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index b2a9abee8b2b..c134eb4aeaa8 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -737,15 +737,15 @@ xfs_qm_destroy_quotainfo( */ STATIC int xfs_qm_qino_alloc( - xfs_mount_t *mp, - xfs_inode_t **ip, - uint flags) + struct xfs_mount *mp, + struct xfs_inode **ipp, + unsigned int flags) { - xfs_trans_t *tp; - int error; - bool need_alloc = true; + struct xfs_trans *tp; + int error; + bool need_alloc = true; - *ip = NULL; + *ipp = NULL; /* * With superblock that doesn't have separate pquotino, we * share an inode between gquota and pquota. If the on-disk @@ -771,7 +771,7 @@ xfs_qm_qino_alloc( return -EFSCORRUPTED; } if (ino != NULLFSINO) { - error = xfs_iget(mp, NULL, ino, 0, 0, ip); + error = xfs_iget(mp, NULL, ino, 0, 0, ipp); if (error) return error; mp->m_sb.sb_gquotino = NULLFSINO; @@ -787,7 +787,7 @@ xfs_qm_qino_alloc( return error; if (need_alloc) { - error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip); + error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ipp); if (error) { xfs_trans_cancel(tp); return error; @@ -812,11 +812,11 @@ xfs_qm_qino_alloc( mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT; } if (flags & XFS_QMOPT_UQUOTA) - mp->m_sb.sb_uquotino = (*ip)->i_ino; + mp->m_sb.sb_uquotino = (*ipp)->i_ino; else if (flags & XFS_QMOPT_GQUOTA) - mp->m_sb.sb_gquotino = (*ip)->i_ino; + mp->m_sb.sb_gquotino = (*ipp)->i_ino; else - mp->m_sb.sb_pquotino = (*ip)->i_ino; + mp->m_sb.sb_pquotino = (*ipp)->i_ino; spin_unlock(&mp->m_sb_lock); xfs_log_sb(tp); @@ -826,7 +826,7 @@ xfs_qm_qino_alloc( xfs_alert(mp, "%s failed (error %d)!", __func__, error); } if (need_alloc) - xfs_finish_inode_setup(*ip); + xfs_finish_inode_setup(*ipp); return error; } From f3bf6e0f1196c69a7b0412521596cd1cc7622a82 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 9 Dec 2020 10:05:16 -0800 Subject: [PATCH 34/40] xfs: move xfs_dialloc_roll() into xfs_dialloc() Get rid of the confusing ialloc_context and failure handling around xfs_dialloc() by moving xfs_dialloc_roll() into xfs_dialloc(). Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_ialloc.c | 59 +++++++++++++------------------------- fs/xfs/libxfs/xfs_ialloc.h | 21 +------------- fs/xfs/xfs_inode.c | 36 ++--------------------- 3 files changed, 23 insertions(+), 93 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 3ae83f6998dc..cf1cc9b40e1b 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1682,7 +1682,7 @@ xfs_dialloc_ag( return error; } -int +static int xfs_dialloc_roll( struct xfs_trans **tpp, struct xfs_buf *agibp) @@ -1723,30 +1723,18 @@ xfs_dialloc_roll( * Mode is used to tell whether the new inode will need space, and whether it * is a directory. * - * This function is designed to be called twice if it has to do an allocation - * to make more free inodes. On the first call, *IO_agbp should be set to NULL. - * If an inode is available without having to performn an allocation, an inode - * number is returned. In this case, *IO_agbp is set to NULL. If an allocation - * needs to be done, xfs_dialloc returns the current AGI buffer in *IO_agbp. - * The caller should then commit the current transaction, allocate a - * new transaction, and call xfs_dialloc() again, passing in the previous value - * of *IO_agbp. IO_agbp should be held across the transactions. Since the AGI - * buffer is locked across the two calls, the second call is guaranteed to have - * a free inode available. - * * Once we successfully pick an inode its number is returned and the on-disk * data structures are updated. The inode itself is not read in, since doing so * would break ordering constraints with xfs_reclaim. */ int xfs_dialloc( - struct xfs_trans *tp, + struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode, - struct xfs_buf **IO_agbp, xfs_ino_t *inop) { - struct xfs_mount *mp = tp->t_mountp; + struct xfs_mount *mp = (*tpp)->t_mountp; struct xfs_buf *agbp; xfs_agnumber_t agno; int error; @@ -1757,21 +1745,11 @@ xfs_dialloc( struct xfs_ino_geometry *igeo = M_IGEO(mp); bool okalloc = true; - if (*IO_agbp) { - /* - * If the caller passes in a pointer to the AGI buffer, - * continue where we left off before. In this case, we - * know that the allocation group has free inodes. - */ - agbp = *IO_agbp; - goto out_alloc; - } - /* * We do not have an agbp, so select an initial allocation * group for inode allocation. */ - start_agno = xfs_ialloc_ag_select(tp, parent, mode); + start_agno = xfs_ialloc_ag_select(*tpp, parent, mode); if (start_agno == NULLAGNUMBER) { *inop = NULLFSINO; return 0; @@ -1806,7 +1784,7 @@ xfs_dialloc( } if (!pag->pagi_init) { - error = xfs_ialloc_pagi_init(mp, tp, agno); + error = xfs_ialloc_pagi_init(mp, *tpp, agno); if (error) goto out_error; } @@ -1821,7 +1799,7 @@ xfs_dialloc( * Then read in the AGI buffer and recheck with the AGI buffer * lock held. */ - error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + error = xfs_ialloc_read_agi(mp, *tpp, agno, &agbp); if (error) goto out_error; @@ -1834,9 +1812,9 @@ xfs_dialloc( goto nextag_relse_buffer; - error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); + error = xfs_ialloc_ag_alloc(*tpp, agbp, &ialloced); if (error) { - xfs_trans_brelse(tp, agbp); + xfs_trans_brelse(*tpp, agbp); if (error != -ENOSPC) goto out_error; @@ -1848,21 +1826,25 @@ xfs_dialloc( if (ialloced) { /* - * We successfully allocated some inodes, return - * the current context to the caller so that it - * can commit the current transaction and call - * us again where we left off. + * We successfully allocated space for an inode cluster + * in this AG. Roll the transaction so that we can + * allocate one of the new inodes. */ ASSERT(pag->pagi_freecount > 0); xfs_perag_put(pag); - *IO_agbp = agbp; + error = xfs_dialloc_roll(tpp, agbp); + if (error) { + xfs_buf_relse(agbp); + return error; + } + *inop = NULLFSINO; - return 0; + goto out_alloc; } nextag_relse_buffer: - xfs_trans_brelse(tp, agbp); + xfs_trans_brelse(*tpp, agbp); nextag: xfs_perag_put(pag); if (++agno == mp->m_sb.sb_agcount) @@ -1874,8 +1856,7 @@ xfs_dialloc( } out_alloc: - *IO_agbp = NULL; - return xfs_dialloc_ag(tp, agbp, parent, inop); + return xfs_dialloc_ag(*tpp, agbp, parent, inop); out_error: xfs_perag_put(pag); return error; diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h index bd6e0db9e23c..13810ffe4af9 100644 --- a/fs/xfs/libxfs/xfs_ialloc.h +++ b/fs/xfs/libxfs/xfs_ialloc.h @@ -32,39 +32,20 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog); } -int -xfs_dialloc_roll( - struct xfs_trans **tpp, - struct xfs_buf *agibp); - /* * Allocate an inode on disk. * Mode is used to tell whether the new inode will need space, and whether * it is a directory. * - * To work within the constraint of one allocation per transaction, - * xfs_dialloc() is designed to be called twice if it has to do an - * allocation to make more free inodes. If an inode is - * available without an allocation, agbp would be set to the current - * agbp and alloc_done set to false. - * If an allocation needed to be done, agbp would be set to the - * inode header of the allocation group and alloc_done set to true. - * The caller should then commit the current transaction and allocate a new - * transaction. xfs_dialloc() should then be called again with - * the agbp value returned from the previous call. - * * Once we successfully pick an inode its number is returned and the * on-disk data structures are updated. The inode itself is not read * in, since doing so would break ordering constraints with xfs_reclaim. - * - * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. */ int /* error */ xfs_dialloc( - struct xfs_trans *tp, /* transaction pointer */ + struct xfs_trans **tpp, /* double pointer of transaction */ xfs_ino_t parent, /* parent inode (directory) */ umode_t mode, /* mode bits for new inode */ - struct xfs_buf **agbp, /* buf for a.g. inode header */ xfs_ino_t *inop); /* inode number allocated */ /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bc1027ce0d1f..3c4e7edec1f6 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -909,7 +909,6 @@ xfs_dir_ialloc( prid_t prid, struct xfs_inode **ipp) { - struct xfs_buf *ialloc_context = NULL; xfs_ino_t parent_ino = dp ? dp->i_ino : 0; xfs_ino_t ino; int error; @@ -918,43 +917,12 @@ xfs_dir_ialloc( /* * Call the space management code to pick the on-disk inode to be - * allocated and replenish the freelist. Since we can only do one - * allocation per transaction without deadlocks, we will need to - * commit the current transaction and start a new one. - * If xfs_dialloc did an allocation to replenish the freelist, it - * returns the bp containing the head of the freelist as - * ialloc_context. We will hold a lock on it across the transaction - * commit so that no other process can steal the inode(s) that we've - * just allocated. + * allocated. */ - error = xfs_dialloc(*tpp, parent_ino, mode, &ialloc_context, &ino); + error = xfs_dialloc(tpp, parent_ino, mode, &ino); if (error) return error; - /* - * If the AGI buffer is non-NULL, then we were unable to get an - * inode in one operation. We need to commit the current - * transaction and call xfs_dialloc() again. It is guaranteed - * to succeed the second time. - */ - if (ialloc_context) { - error = xfs_dialloc_roll(tpp, ialloc_context); - if (error) { - xfs_buf_relse(ialloc_context); - return error; - } - /* - * Call dialloc again. Since we've locked out all other - * allocations in this allocation group, this call should - * always succeed. - */ - error = xfs_dialloc(*tpp, parent_ino, mode, &ialloc_context, - &ino); - if (error) - return error; - ASSERT(!ialloc_context); - } - if (ino == NULLFSINO) return -ENOSPC; From 8d822dc38ad781b1bfa5c03227da80dbd87e9959 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 9 Dec 2020 10:05:16 -0800 Subject: [PATCH 35/40] xfs: spilt xfs_dialloc() into 2 functions This patch explicitly separates free inode chunk allocation and inode allocation into two individual high level operations. Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_ialloc.c | 54 +++++++++++++++++--------------------- fs/xfs/libxfs/xfs_ialloc.h | 20 ++++++++++---- fs/xfs/xfs_inode.c | 11 ++++++-- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index cf1cc9b40e1b..4c45d0bb17ba 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1570,7 +1570,7 @@ xfs_dialloc_ag_update_inobt( * The caller selected an AG for us, and made sure that free inodes are * available. */ -STATIC int +int xfs_dialloc_ag( struct xfs_trans *tp, struct xfs_buf *agbp, @@ -1718,21 +1718,22 @@ xfs_dialloc_roll( } /* - * Allocate an inode on disk. + * Select and prepare an AG for inode allocation. * - * Mode is used to tell whether the new inode will need space, and whether it - * is a directory. + * Mode is used to tell whether the new inode is a directory and hence where to + * locate it. * - * Once we successfully pick an inode its number is returned and the on-disk - * data structures are updated. The inode itself is not read in, since doing so - * would break ordering constraints with xfs_reclaim. + * This function will ensure that the selected AG has free inodes available to + * allocate from. The selected AGI will be returned locked to the caller, and it + * will allocate more free inodes if required. If no free inodes are found or + * can be allocated, no AGI will be returned. */ int -xfs_dialloc( +xfs_dialloc_select_ag( struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode, - xfs_ino_t *inop) + struct xfs_buf **IO_agbp) { struct xfs_mount *mp = (*tpp)->t_mountp; struct xfs_buf *agbp; @@ -1745,15 +1746,15 @@ xfs_dialloc( struct xfs_ino_geometry *igeo = M_IGEO(mp); bool okalloc = true; + *IO_agbp = NULL; + /* * We do not have an agbp, so select an initial allocation * group for inode allocation. */ start_agno = xfs_ialloc_ag_select(*tpp, parent, mode); - if (start_agno == NULLAGNUMBER) { - *inop = NULLFSINO; + if (start_agno == NULLAGNUMBER) return 0; - } /* * If we have already hit the ceiling of inode blocks then clear @@ -1786,7 +1787,7 @@ xfs_dialloc( if (!pag->pagi_init) { error = xfs_ialloc_pagi_init(mp, *tpp, agno); if (error) - goto out_error; + break; } /* @@ -1801,11 +1802,11 @@ xfs_dialloc( */ error = xfs_ialloc_read_agi(mp, *tpp, agno, &agbp); if (error) - goto out_error; + break; if (pag->pagi_freecount) { xfs_perag_put(pag); - goto out_alloc; + goto found_ag; } if (!okalloc) @@ -1816,12 +1817,9 @@ xfs_dialloc( if (error) { xfs_trans_brelse(*tpp, agbp); - if (error != -ENOSPC) - goto out_error; - - xfs_perag_put(pag); - *inop = NULLFSINO; - return 0; + if (error == -ENOSPC) + error = 0; + break; } if (ialloced) { @@ -1838,9 +1836,7 @@ xfs_dialloc( xfs_buf_relse(agbp); return error; } - - *inop = NULLFSINO; - goto out_alloc; + goto found_ag; } nextag_relse_buffer: @@ -1849,17 +1845,15 @@ xfs_dialloc( xfs_perag_put(pag); if (++agno == mp->m_sb.sb_agcount) agno = 0; - if (agno == start_agno) { - *inop = NULLFSINO; + if (agno == start_agno) return noroom ? -ENOSPC : 0; - } } -out_alloc: - return xfs_dialloc_ag(*tpp, agbp, parent, inop); -out_error: xfs_perag_put(pag); return error; +found_ag: + *IO_agbp = agbp; + return 0; } /* diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h index 13810ffe4af9..3511086a7ae1 100644 --- a/fs/xfs/libxfs/xfs_ialloc.h +++ b/fs/xfs/libxfs/xfs_ialloc.h @@ -37,16 +37,26 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) * Mode is used to tell whether the new inode will need space, and whether * it is a directory. * - * Once we successfully pick an inode its number is returned and the - * on-disk data structures are updated. The inode itself is not read - * in, since doing so would break ordering constraints with xfs_reclaim. + * There are two phases to inode allocation: selecting an AG and ensuring + * that it contains free inodes, followed by allocating one of the free + * inodes. xfs_dialloc_select_ag() does the former and returns a locked AGI + * to the caller, ensuring that followup call to xfs_dialloc_ag() will + * have free inodes to allocate from. xfs_dialloc_ag() will return the inode + * number of the free inode we allocated. */ int /* error */ -xfs_dialloc( +xfs_dialloc_select_ag( struct xfs_trans **tpp, /* double pointer of transaction */ xfs_ino_t parent, /* parent inode (directory) */ umode_t mode, /* mode bits for new inode */ - xfs_ino_t *inop); /* inode number allocated */ + struct xfs_buf **IO_agbp); + +int +xfs_dialloc_ag( + struct xfs_trans *tp, + struct xfs_buf *agbp, + xfs_ino_t parent, + xfs_ino_t *inop); /* * Free disk inode. Carefully avoids touching the incore inode, all diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 3c4e7edec1f6..b7352bc4c815 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -909,6 +909,7 @@ xfs_dir_ialloc( prid_t prid, struct xfs_inode **ipp) { + struct xfs_buf *agibp; xfs_ino_t parent_ino = dp ? dp->i_ino : 0; xfs_ino_t ino; int error; @@ -919,13 +920,19 @@ xfs_dir_ialloc( * Call the space management code to pick the on-disk inode to be * allocated. */ - error = xfs_dialloc(tpp, parent_ino, mode, &ino); + error = xfs_dialloc_select_ag(tpp, parent_ino, mode, &agibp); if (error) return error; - if (ino == NULLFSINO) + if (!agibp) return -ENOSPC; + /* Allocate an inode from the selected AG */ + error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino); + if (error) + return error; + ASSERT(ino != NULLFSINO); + return xfs_init_new_inode(*tpp, dp, ino, mode, nlink, rdev, prid, ipp); } From 3937493c502566d90a74c3439ebdb663d9380cc3 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 9 Dec 2020 10:05:17 -0800 Subject: [PATCH 36/40] xfs: kill ialloced in xfs_dialloc() It's enough to just use return code, and get rid of an argument. Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Gao Xiang Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_ialloc.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 4c45d0bb17ba..d58607cda477 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -607,13 +607,13 @@ xfs_inobt_insert_sprec( /* * Allocate new inodes in the allocation group specified by agbp. - * Return 0 for success, else error code. + * Returns 0 if inodes were allocated in this AG; 1 if there was no space + * in this AG; or the usual negative error code. */ STATIC int xfs_ialloc_ag_alloc( struct xfs_trans *tp, - struct xfs_buf *agbp, - int *alloc) + struct xfs_buf *agbp) { struct xfs_agi *agi; struct xfs_alloc_arg args; @@ -795,10 +795,9 @@ xfs_ialloc_ag_alloc( allocmask = (1 << (newlen / XFS_INODES_PER_HOLEMASK_BIT)) - 1; } - if (args.fsbno == NULLFSBLOCK) { - *alloc = 0; - return 0; - } + if (args.fsbno == NULLFSBLOCK) + return 1; + ASSERT(args.len == args.minlen); /* @@ -903,7 +902,6 @@ xfs_ialloc_ag_alloc( */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); - *alloc = 1; return 0; } @@ -1739,7 +1737,6 @@ xfs_dialloc_select_ag( struct xfs_buf *agbp; xfs_agnumber_t agno; int error; - int ialloced; bool noroom = false; xfs_agnumber_t start_agno; struct xfs_perag *pag; @@ -1812,9 +1809,8 @@ xfs_dialloc_select_ag( if (!okalloc) goto nextag_relse_buffer; - - error = xfs_ialloc_ag_alloc(*tpp, agbp, &ialloced); - if (error) { + error = xfs_ialloc_ag_alloc(*tpp, agbp); + if (error < 0) { xfs_trans_brelse(*tpp, agbp); if (error == -ENOSPC) @@ -1822,7 +1818,7 @@ xfs_dialloc_select_ag( break; } - if (ialloced) { + if (error == 0) { /* * We successfully allocated space for an inode cluster * in this AG. Roll the transaction so that we can From 26f88363ec78473ab61d29bcbb962c74ae0f1b1a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 10 Dec 2020 20:00:38 -0800 Subject: [PATCH 37/40] xfs: remove xfs_vn_setattr_nonsize Merge xfs_vn_setattr_nonsize into the only caller. Signed-off-by: Christoph Hellwig Reviewed-by: Gao Xiang Reviewed-by: Brian Foster Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_iops.c | 26 +++++++------------------- fs/xfs/xfs_iops.h | 1 - 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index d1ecf7669fc8..a0644da67321 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -824,22 +824,6 @@ xfs_setattr_nonsize( return error; } -int -xfs_vn_setattr_nonsize( - struct dentry *dentry, - struct iattr *iattr) -{ - struct xfs_inode *ip = XFS_I(d_inode(dentry)); - int error; - - trace_xfs_setattr(ip); - - error = xfs_vn_change_ok(dentry, iattr); - if (error) - return error; - return xfs_setattr_nonsize(ip, iattr, 0); -} - /* * Truncate file. Must have write permission and not be a directory. * @@ -1067,11 +1051,11 @@ xfs_vn_setattr( struct dentry *dentry, struct iattr *iattr) { + struct inode *inode = d_inode(dentry); + struct xfs_inode *ip = XFS_I(inode); int error; if (iattr->ia_valid & ATTR_SIZE) { - struct inode *inode = d_inode(dentry); - struct xfs_inode *ip = XFS_I(inode); uint iolock; xfs_ilock(ip, XFS_MMAPLOCK_EXCL); @@ -1086,7 +1070,11 @@ xfs_vn_setattr( error = xfs_vn_setattr_size(dentry, iattr); xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); } else { - error = xfs_vn_setattr_nonsize(dentry, iattr); + trace_xfs_setattr(ip); + + error = xfs_vn_change_ok(dentry, iattr); + if (!error) + error = xfs_setattr_nonsize(ip, iattr, 0); } return error; diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h index 4d24ff309f59..a91e2d1b47b4 100644 --- a/fs/xfs/xfs_iops.h +++ b/fs/xfs/xfs_iops.h @@ -21,7 +21,6 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size); extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr); extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags); -extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap); extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap); #endif /* __XFS_IOPS_H__ */ From 5d24ec4c7d3c4520b1baec4443ad47b5ae796570 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 10 Dec 2020 20:00:39 -0800 Subject: [PATCH 38/40] xfs: open code updating i_mode in xfs_set_acl Rather than going through the big and hairy xfs_setattr_nonsize function, just open code a transactional i_mode and i_ctime update. This allows to mark xfs_setattr_nonsize and remove the flags argument to it. Signed-off-by: Christoph Hellwig Reviewed-by: Gao Xiang Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_acl.c | 40 ++++++++++++++++++++++------------------ fs/xfs/xfs_iops.c | 11 +++++------ fs/xfs/xfs_iops.h | 7 ------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index c544951a0c07..779cb73b3d00 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -16,6 +16,7 @@ #include "xfs_acl.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" +#include "xfs_trans.h" #include @@ -212,21 +213,28 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) } static int -xfs_set_mode(struct inode *inode, umode_t mode) +xfs_acl_set_mode( + struct inode *inode, + umode_t mode) { - int error = 0; + struct xfs_inode *ip = XFS_I(inode); + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + int error; - if (mode != inode->i_mode) { - struct iattr iattr; + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); + if (error) + return error; - iattr.ia_valid = ATTR_MODE | ATTR_CTIME; - iattr.ia_mode = mode; - iattr.ia_ctime = current_time(inode); + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + inode->i_mode = mode; + inode->i_ctime = current_time(inode); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL); - } - - return error; + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(tp); + return xfs_trans_commit(tp); } int @@ -251,18 +259,14 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) } set_acl: - error = __xfs_set_acl(inode, acl, type); - if (error) - return error; - /* * We set the mode after successfully updating the ACL xattr because the * xattr update can fail at ENOSPC and we don't want to change the mode * if the ACL update hasn't been applied. */ - if (set_mode) - error = xfs_set_mode(inode, mode); - + error = __xfs_set_acl(inode, acl, type); + if (!error && set_mode && mode != inode->i_mode) + error = xfs_acl_set_mode(inode, mode); return error; } diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index a0644da67321..67c8dc9de8aa 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -646,11 +646,10 @@ xfs_vn_change_ok( * Caution: The caller of this function is responsible for calling * setattr_prepare() or otherwise verifying the change is fine. */ -int +static int xfs_setattr_nonsize( struct xfs_inode *ip, - struct iattr *iattr, - int flags) + struct iattr *iattr) { xfs_mount_t *mp = ip->i_mount; struct inode *inode = VFS_I(ip); @@ -807,7 +806,7 @@ xfs_setattr_nonsize( * to attr_set. No previous user of the generic * Posix ACL code seems to care about this issue either. */ - if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { + if (mask & ATTR_MODE) { error = posix_acl_chmod(inode, inode->i_mode); if (error) return error; @@ -863,7 +862,7 @@ xfs_setattr_size( * Use the regular setattr path to update the timestamps. */ iattr->ia_valid &= ~ATTR_SIZE; - return xfs_setattr_nonsize(ip, iattr, 0); + return xfs_setattr_nonsize(ip, iattr); } /* @@ -1074,7 +1073,7 @@ xfs_vn_setattr( error = xfs_vn_change_ok(dentry, iattr); if (!error) - error = xfs_setattr_nonsize(ip, iattr, 0); + error = xfs_setattr_nonsize(ip, iattr); } return error; diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h index a91e2d1b47b4..99ca745c1071 100644 --- a/fs/xfs/xfs_iops.h +++ b/fs/xfs/xfs_iops.h @@ -13,14 +13,7 @@ extern const struct file_operations xfs_dir_file_operations; extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size); -/* - * Internal setattr interfaces. - */ -#define XFS_ATTR_NOACL 0x01 /* Don't call posix_acl_chmod */ - extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr); -extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, - int flags); extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap); #endif /* __XFS_IOPS_H__ */ From 1189686e5440041057f8cc21a7c1d13bb6642cb9 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 11 Dec 2020 11:36:23 -0800 Subject: [PATCH 39/40] fs/xfs: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Reviewed-by: Brian Foster Reviewed-by: Eric Sandeen Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_btree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 2d25bab68764..51dbff9b0908 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -4070,7 +4070,7 @@ xfs_btree_delrec( * surviving block, and log it. */ xfs_btree_set_numrecs(left, lrecs + rrecs); - xfs_btree_get_sibling(cur, right, &cptr, XFS_BB_RIGHTSIB), + xfs_btree_get_sibling(cur, right, &cptr, XFS_BB_RIGHTSIB); xfs_btree_set_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); From e82226138b20d4f638426413e83c6b5db532c6a2 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 16 Dec 2020 16:07:34 -0800 Subject: [PATCH 40/40] xfs: remove xfs_buf_t typedef Prepare for kernel xfs_buf alignment by getting rid of the xfs_buf_t typedef from userspace. [darrick: This patch is a port of a userspace patch removing the xfs_buf_t typedef in preparation to make the userspace xfs_buf code behave more like its kernel counterpart.] Signed-off-by: Dave Chinner Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner --- fs/xfs/libxfs/xfs_alloc.c | 16 ++++++++-------- fs/xfs/libxfs/xfs_bmap.c | 6 +++--- fs/xfs/libxfs/xfs_btree.c | 10 +++++----- fs/xfs/libxfs/xfs_ialloc.c | 4 ++-- fs/xfs/libxfs/xfs_rtbitmap.c | 22 +++++++++++----------- fs/xfs/xfs_buf.c | 24 ++++++++++++------------ fs/xfs/xfs_buf.h | 14 +++++++------- fs/xfs/xfs_buf_item.c | 4 ++-- fs/xfs/xfs_fsops.c | 2 +- fs/xfs/xfs_log_recover.c | 8 ++++---- fs/xfs/xfs_rtalloc.c | 20 ++++++++++---------- fs/xfs/xfs_rtalloc.h | 4 ++-- fs/xfs/xfs_symlink.c | 4 ++-- fs/xfs/xfs_trans.c | 2 +- fs/xfs/xfs_trans_buf.c | 16 ++++++++-------- 15 files changed, 78 insertions(+), 78 deletions(-) diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 15640015be9d..7cb9f064ac64 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -690,9 +690,9 @@ xfs_alloc_read_agfl( xfs_mount_t *mp, /* mount point structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ - xfs_buf_t **bpp) /* buffer for the ag free block array */ + struct xfs_buf **bpp) /* buffer for the ag free block array */ { - xfs_buf_t *bp; /* return value */ + struct xfs_buf *bp; /* return value */ int error; ASSERT(agno != NULLAGNUMBER); @@ -2647,12 +2647,12 @@ xfs_alloc_fix_freelist( int /* error */ xfs_alloc_get_freelist( xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *agbp, /* buffer containing the agf structure */ + struct xfs_buf *agbp, /* buffer containing the agf structure */ xfs_agblock_t *bnop, /* block address retrieved from freelist */ int btreeblk) /* destination is a AGF btree */ { struct xfs_agf *agf = agbp->b_addr; - xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ + struct xfs_buf *agflbp;/* buffer for a.g. freelist structure */ xfs_agblock_t bno; /* block number returned */ __be32 *agfl_bno; int error; @@ -2711,7 +2711,7 @@ xfs_alloc_get_freelist( void xfs_alloc_log_agf( xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *bp, /* buffer for a.g. freelist header */ + struct xfs_buf *bp, /* buffer for a.g. freelist header */ int fields) /* mask of fields to be logged (XFS_AGF_...) */ { int first; /* first byte offset */ @@ -2757,7 +2757,7 @@ xfs_alloc_pagf_init( xfs_agnumber_t agno, /* allocation group number */ int flags) /* XFS_ALLOC_FLAGS_... */ { - xfs_buf_t *bp; + struct xfs_buf *bp; int error; error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp); @@ -2772,8 +2772,8 @@ xfs_alloc_pagf_init( int /* error */ xfs_alloc_put_freelist( xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *agbp, /* buffer for a.g. freelist header */ - xfs_buf_t *agflbp,/* buffer for a.g. free block array */ + struct xfs_buf *agbp, /* buffer for a.g. freelist header */ + struct xfs_buf *agflbp,/* buffer for a.g. free block array */ xfs_agblock_t bno, /* block being freed */ int btreeblk) /* block came from a AGF btree */ { diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index dcf56bcafb8f..bc446418e227 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -321,7 +321,7 @@ xfs_bmap_check_leaf_extents( struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_block *block; /* current btree block */ xfs_fsblock_t bno; /* block # of "block" */ - xfs_buf_t *bp; /* buffer for "block" */ + struct xfs_buf *bp; /* buffer for "block" */ int error; /* error return value */ xfs_extnum_t i=0, j; /* index into the extents list */ int level; /* btree level, for checking */ @@ -592,7 +592,7 @@ xfs_bmap_btree_to_extents( struct xfs_btree_block *rblock = ifp->if_broot; struct xfs_btree_block *cblock;/* child btree block */ xfs_fsblock_t cbno; /* child block number */ - xfs_buf_t *cbp; /* child block's buffer */ + struct xfs_buf *cbp; /* child block's buffer */ int error; /* error return value */ __be64 *pp; /* ptr to block address */ struct xfs_owner_info oinfo; @@ -830,7 +830,7 @@ xfs_bmap_local_to_extents( int flags; /* logging flags returned */ struct xfs_ifork *ifp; /* inode fork pointer */ xfs_alloc_arg_t args; /* allocation arguments */ - xfs_buf_t *bp; /* buffer for extent block */ + struct xfs_buf *bp; /* buffer for extent block */ struct xfs_bmbt_irec rec; struct xfs_iext_cursor icur; diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 51dbff9b0908..c4d7a9241dc3 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -397,7 +397,7 @@ xfs_btree_dup_cursor( xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t **ncur) /* output cursor */ { - xfs_buf_t *bp; /* btree block's buffer pointer */ + struct xfs_buf *bp; /* btree block's buffer pointer */ int error; /* error return value */ int i; /* level number of btree block */ xfs_mount_t *mp; /* mount structure for filesystem */ @@ -701,7 +701,7 @@ xfs_btree_firstrec( int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ - xfs_buf_t *bp; /* buffer containing block */ + struct xfs_buf *bp; /* buffer containing block */ /* * Get the block pointer for this level. @@ -731,7 +731,7 @@ xfs_btree_lastrec( int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ - xfs_buf_t *bp; /* buffer containing block */ + struct xfs_buf *bp; /* buffer containing block */ /* * Get the block pointer for this level. @@ -993,7 +993,7 @@ STATIC void xfs_btree_setbuf( xfs_btree_cur_t *cur, /* btree cursor */ int lev, /* level in btree */ - xfs_buf_t *bp) /* new buffer to set */ + struct xfs_buf *bp) /* new buffer to set */ { struct xfs_btree_block *b; /* btree block */ @@ -1636,7 +1636,7 @@ xfs_btree_decrement( int *stat) /* success/failure */ { struct xfs_btree_block *block; - xfs_buf_t *bp; + struct xfs_buf *bp; int error; /* error return value */ int lev; union xfs_btree_ptr ptr; diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index d58607cda477..69b228fce81a 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -2459,7 +2459,7 @@ xfs_imap( void xfs_ialloc_log_agi( xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *bp, /* allocation group header buffer */ + struct xfs_buf *bp, /* allocation group header buffer */ int fields) /* bitmask of fields to log */ { int first; /* first byte number */ @@ -2680,7 +2680,7 @@ xfs_ialloc_pagi_init( xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno) /* allocation group number */ { - xfs_buf_t *bp = NULL; + struct xfs_buf *bp = NULL; int error; error = xfs_ialloc_read_agi(mp, tp, agno, &bp); diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c index 6c1aba16113c..fe3a49575ff3 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.c +++ b/fs/xfs/libxfs/xfs_rtbitmap.c @@ -56,9 +56,9 @@ xfs_rtbuf_get( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t block, /* block number in bitmap or summary */ int issum, /* is summary not bitmap */ - xfs_buf_t **bpp) /* output: buffer for the block */ + struct xfs_buf **bpp) /* output: buffer for the block */ { - xfs_buf_t *bp; /* block buffer, result */ + struct xfs_buf *bp; /* block buffer, result */ xfs_inode_t *ip; /* bitmap or summary inode */ xfs_bmbt_irec_t map; int nmap = 1; @@ -101,7 +101,7 @@ xfs_rtfind_back( xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ - xfs_buf_t *bp; /* buf for the block */ + struct xfs_buf *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t firstbit; /* first useful bit in the word */ @@ -276,7 +276,7 @@ xfs_rtfind_forw( xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ - xfs_buf_t *bp; /* buf for the block */ + struct xfs_buf *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ @@ -447,11 +447,11 @@ xfs_rtmodify_summary_int( int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_suminfo_t *sum) /* out: summary info for this block */ { - xfs_buf_t *bp; /* buffer for the summary block */ + struct xfs_buf *bp; /* buffer for the summary block */ int error; /* error value */ xfs_fsblock_t sb; /* summary fsblock */ int so; /* index into the summary file */ @@ -517,7 +517,7 @@ xfs_rtmodify_summary( int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { return xfs_rtmodify_summary_int(mp, tp, log, bbno, @@ -539,7 +539,7 @@ xfs_rtmodify_range( xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ - xfs_buf_t *bp; /* buf for the block */ + struct xfs_buf *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtword_t *first; /* first used word in the buffer */ @@ -690,7 +690,7 @@ xfs_rtfree_range( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to free */ xfs_extlen_t len, /* length to free */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { xfs_rtblock_t end; /* end of the freed extent */ @@ -773,7 +773,7 @@ xfs_rtcheck_range( xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ - xfs_buf_t *bp; /* buf for the block */ + struct xfs_buf *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ @@ -969,7 +969,7 @@ xfs_rtfree_extent( int error; /* error value */ xfs_mount_t *mp; /* file system mount structure */ xfs_fsblock_t sb; /* summary file block number */ - xfs_buf_t *sumbp = NULL; /* summary file block buffer */ + struct xfs_buf *sumbp = NULL; /* summary file block buffer */ mp = tp->t_mountp; diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 4e4cf91f4f9f..f8400bbd6473 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -278,7 +278,7 @@ _xfs_buf_alloc( */ STATIC int _xfs_buf_get_pages( - xfs_buf_t *bp, + struct xfs_buf *bp, int page_count) { /* Make sure that we have a page list */ @@ -302,7 +302,7 @@ _xfs_buf_get_pages( */ STATIC void _xfs_buf_free_pages( - xfs_buf_t *bp) + struct xfs_buf *bp) { if (bp->b_pages != bp->b_page_array) { kmem_free(bp->b_pages); @@ -319,7 +319,7 @@ _xfs_buf_free_pages( */ static void xfs_buf_free( - xfs_buf_t *bp) + struct xfs_buf *bp) { trace_xfs_buf_free(bp, _RET_IP_); @@ -352,7 +352,7 @@ xfs_buf_free( */ STATIC int xfs_buf_allocate_memory( - xfs_buf_t *bp, + struct xfs_buf *bp, uint flags) { size_t size; @@ -463,7 +463,7 @@ xfs_buf_allocate_memory( */ STATIC int _xfs_buf_map_pages( - xfs_buf_t *bp, + struct xfs_buf *bp, uint flags) { ASSERT(bp->b_flags & _XBF_PAGES); @@ -590,7 +590,7 @@ xfs_buf_find( struct xfs_buf **found_bp) { struct xfs_perag *pag; - xfs_buf_t *bp; + struct xfs_buf *bp; struct xfs_buf_map cmap = { .bm_bn = map[0].bm_bn }; xfs_daddr_t eofs; int i; @@ -762,7 +762,7 @@ xfs_buf_get_map( int _xfs_buf_read( - xfs_buf_t *bp, + struct xfs_buf *bp, xfs_buf_flags_t flags) { ASSERT(!(flags & XBF_WRITE)); @@ -1005,7 +1005,7 @@ xfs_buf_get_uncached( */ void xfs_buf_hold( - xfs_buf_t *bp) + struct xfs_buf *bp) { trace_xfs_buf_hold(bp, _RET_IP_); atomic_inc(&bp->b_hold); @@ -1017,7 +1017,7 @@ xfs_buf_hold( */ void xfs_buf_rele( - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_perag *pag = bp->b_pag; bool release; @@ -1161,7 +1161,7 @@ xfs_buf_unlock( STATIC void xfs_buf_wait_unpin( - xfs_buf_t *bp) + struct xfs_buf *bp) { DECLARE_WAITQUEUE (wait, current); @@ -1373,7 +1373,7 @@ xfs_buf_ioend_work( struct work_struct *work) { struct xfs_buf *bp = - container_of(work, xfs_buf_t, b_ioend_work); + container_of(work, struct xfs_buf, b_ioend_work); xfs_buf_ioend(bp); } @@ -1388,7 +1388,7 @@ xfs_buf_ioend_async( void __xfs_buf_ioerror( - xfs_buf_t *bp, + struct xfs_buf *bp, int error, xfs_failaddr_t failaddr) { diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index bfd2907e7bc4..5d91a31298a4 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -124,7 +124,7 @@ struct xfs_buf_ops { xfs_failaddr_t (*verify_struct)(struct xfs_buf *bp); }; -typedef struct xfs_buf { +struct xfs_buf { /* * first cacheline holds all the fields needed for an uncontended cache * hit to be fully processed. The semaphore straddles the cacheline @@ -190,7 +190,7 @@ typedef struct xfs_buf { int b_last_error; const struct xfs_buf_ops *b_ops; -} xfs_buf_t; +}; /* Finding and Reading Buffers */ struct xfs_buf *xfs_buf_incore(struct xfs_buftarg *target, @@ -253,16 +253,16 @@ int _xfs_buf_read(struct xfs_buf *bp, xfs_buf_flags_t flags); void xfs_buf_hold(struct xfs_buf *bp); /* Releasing Buffers */ -extern void xfs_buf_rele(xfs_buf_t *); +extern void xfs_buf_rele(struct xfs_buf *); /* Locking and Unlocking Buffers */ -extern int xfs_buf_trylock(xfs_buf_t *); -extern void xfs_buf_lock(xfs_buf_t *); -extern void xfs_buf_unlock(xfs_buf_t *); +extern int xfs_buf_trylock(struct xfs_buf *); +extern void xfs_buf_lock(struct xfs_buf *); +extern void xfs_buf_unlock(struct xfs_buf *); #define xfs_buf_islocked(bp) \ ((bp)->b_sema.count <= 0) -static inline void xfs_buf_relse(xfs_buf_t *bp) +static inline void xfs_buf_relse(struct xfs_buf *bp) { xfs_buf_unlock(bp); xfs_buf_rele(bp); diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 0356f2e340a1..dc0be2a639cc 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -412,7 +412,7 @@ xfs_buf_item_unpin( int remove) { struct xfs_buf_log_item *bip = BUF_ITEM(lip); - xfs_buf_t *bp = bip->bli_buf; + struct xfs_buf *bp = bip->bli_buf; int stale = bip->bli_flags & XFS_BLI_STALE; int freed; @@ -942,7 +942,7 @@ xfs_buf_item_free( */ void xfs_buf_item_relse( - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index ef1d5bb88b93..5870db855e8b 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -28,7 +28,7 @@ xfs_growfs_data_private( xfs_mount_t *mp, /* mount point for filesystem */ xfs_growfs_data_t *in) /* growfs data input struct */ { - xfs_buf_t *bp; + struct xfs_buf *bp; int error; xfs_agnumber_t nagcount; xfs_agnumber_t nagimax = 0; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 1152c4b3ba96..97f31308de03 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2631,7 +2631,7 @@ xlog_recover_clear_agi_bucket( { xfs_trans_t *tp; xfs_agi_t *agi; - xfs_buf_t *agibp; + struct xfs_buf *agibp; int offset; int error; @@ -2749,7 +2749,7 @@ xlog_recover_process_iunlinks( xfs_mount_t *mp; xfs_agnumber_t agno; xfs_agi_t *agi; - xfs_buf_t *agibp; + struct xfs_buf *agibp; xfs_agino_t agino; int bucket; int error; @@ -3501,8 +3501,8 @@ xlog_recover_check_summary( struct xlog *log) { xfs_mount_t *mp; - xfs_buf_t *agfbp; - xfs_buf_t *agibp; + struct xfs_buf *agfbp; + struct xfs_buf *agibp; xfs_agnumber_t agno; uint64_t freeblks; uint64_t itotal; diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index ede1baf31413..b4999fb01ff7 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -32,7 +32,7 @@ xfs_rtget_summary( xfs_trans_t *tp, /* transaction pointer */ int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_suminfo_t *sum) /* out: summary info for this block */ { @@ -50,7 +50,7 @@ xfs_rtany_summary( int low, /* low log2 extent size */ int high, /* high log2 extent size */ xfs_rtblock_t bbno, /* bitmap block number */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ int *stat) /* out: any good extents here? */ { @@ -104,7 +104,7 @@ xfs_rtcopy_summary( xfs_trans_t *tp) /* transaction pointer */ { xfs_rtblock_t bbno; /* bitmap block number */ - xfs_buf_t *bp; /* summary buffer */ + struct xfs_buf *bp; /* summary buffer */ int error; /* error return value */ int log; /* summary level number (log length) */ xfs_suminfo_t sum; /* summary data */ @@ -144,7 +144,7 @@ xfs_rtallocate_range( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* start block to allocate */ xfs_extlen_t len, /* length to allocate */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { xfs_rtblock_t end; /* end of the allocated extent */ @@ -226,7 +226,7 @@ xfs_rtallocate_extent_block( xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ xfs_rtblock_t *nextp, /* out: next block to try */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */ @@ -345,7 +345,7 @@ xfs_rtallocate_extent_exact( xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */ @@ -424,7 +424,7 @@ xfs_rtallocate_extent_near( xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */ @@ -626,7 +626,7 @@ xfs_rtallocate_extent_size( xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ - xfs_buf_t **rbpp, /* in/out: summary block buffer */ + struct xfs_buf **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */ @@ -900,7 +900,7 @@ xfs_growfs_rt( xfs_growfs_rt_t *in) /* growfs rt input struct */ { xfs_rtblock_t bmbno; /* bitmap block number */ - xfs_buf_t *bp; /* temporary buffer */ + struct xfs_buf *bp; /* temporary buffer */ int error; /* error return value */ xfs_mount_t *nmp; /* new (fake) mount structure */ xfs_rfsblock_t nrblocks; /* new number of realtime blocks */ @@ -1151,7 +1151,7 @@ xfs_rtallocate_extent( int error; /* error value */ xfs_rtblock_t r; /* result allocated block */ xfs_fsblock_t sb; /* summary file block number */ - xfs_buf_t *sumbp; /* summary file block buffer */ + struct xfs_buf *sumbp; /* summary file block buffer */ ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL)); ASSERT(minlen > 0 && minlen <= maxlen); diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h index 93e77b221355..ed885620589c 100644 --- a/fs/xfs/xfs_rtalloc.h +++ b/fs/xfs/xfs_rtalloc.h @@ -115,10 +115,10 @@ int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, int val); int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp, int log, xfs_rtblock_t bbno, int delta, - xfs_buf_t **rbpp, xfs_fsblock_t *rsb, + struct xfs_buf **rbpp, xfs_fsblock_t *rsb, xfs_suminfo_t *sum); int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log, - xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp, + xfs_rtblock_t bbno, int delta, struct xfs_buf **rbpp, xfs_fsblock_t *rsb); int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 8e88a7ca387e..1f43fd7f3209 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -154,7 +154,7 @@ xfs_symlink( const char *cur_chunk; int byte_cnt; int n; - xfs_buf_t *bp; + struct xfs_buf *bp; prid_t prid; struct xfs_dquot *udqp = NULL; struct xfs_dquot *gdqp = NULL; @@ -365,7 +365,7 @@ STATIC int xfs_inactive_symlink_rmt( struct xfs_inode *ip) { - xfs_buf_t *bp; + struct xfs_buf *bp; int done; int error; int i; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index c94e71f741b6..e72730f85af1 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -465,7 +465,7 @@ xfs_trans_apply_sb_deltas( xfs_trans_t *tp) { xfs_dsb_t *sbp; - xfs_buf_t *bp; + struct xfs_buf *bp; int whole = 0; bp = xfs_trans_getsb(tp); diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 42d63b830cb9..9aced0a00003 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -121,7 +121,7 @@ xfs_trans_get_buf_map( xfs_buf_flags_t flags, struct xfs_buf **bpp) { - xfs_buf_t *bp; + struct xfs_buf *bp; struct xfs_buf_log_item *bip; int error; @@ -401,7 +401,7 @@ xfs_trans_brelse( void xfs_trans_bhold( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; @@ -422,7 +422,7 @@ xfs_trans_bhold( void xfs_trans_bhold_release( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; @@ -538,7 +538,7 @@ xfs_trans_log_buf( void xfs_trans_binval( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; int i; @@ -593,7 +593,7 @@ xfs_trans_binval( void xfs_trans_inode_buf( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; @@ -618,7 +618,7 @@ xfs_trans_inode_buf( void xfs_trans_stale_inode_buf( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; @@ -643,7 +643,7 @@ xfs_trans_stale_inode_buf( void xfs_trans_inode_alloc_buf( xfs_trans_t *tp, - xfs_buf_t *bp) + struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; @@ -737,7 +737,7 @@ xfs_trans_buf_copy_type( void xfs_trans_dquot_buf( xfs_trans_t *tp, - xfs_buf_t *bp, + struct xfs_buf *bp, uint type) { struct xfs_buf_log_item *bip = bp->b_log_item;