New code for 5.17:

- Fix a minor locking inconsistency in readdir
  - Fix incorrect fs feature bit validation for secondary superblocks
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEUzaAxoMeQq6m2jMV+H93GTRKtOsFAmHfFFYACgkQ+H93GTRK
 tOvrQA//RnDMit4zLoPo3WeZTDjpv1CQkOXFgQSba+Owgz1RvGn5f29R4ICKW6Uy
 NfnPcq5AeNhysOAi0uZPl4EC6140QgMrD4aJjKY1JAc/BkeBVEN05NOUFfCuBXU/
 RMzL8nGD5zsN7fPIWVGS60iitou8IvoX8ky4dKx7XcsbFzbBMtnJIsUpfqVutY9u
 i+zub6sNRkstr4uBRk+1S8uAqHUAW+21YwfKqB6pgpCoO5BHu2e4eN01ohWvF8Ru
 0ujJ2j4YlfjYmtQypFk3rNgQoI0oXY6mYWZPKr7fYvhDpoKEodUvHRLIJEHqoD+y
 fX6Ey5XxpHmDxSJnWRC7Vznl56VEmMndUcWEq2ZqROp/r/zZp7StXyHLO7DR9nEs
 mp+55a4tcKhHa/KnjbqexAaN4a1NTpryMqjsPHP7VTNu5Dq8CK4kHtrcEVrKCZFq
 ExRFMfoUDxap6iJaxoKAz5CtZyJeuZO8bLCa7jq/2F91EWp+2aclxEU6VY5r6B2X
 dFlIY8XnZEfJxE3xnhH/aDs6IKWH4YmvgtwxNb+RIupyMTfJzpcysjV9NRER8fAv
 9rLfWNz+nx0efNyXle+h+vrzT/zXgyi/0PSjAQS9/xErTPRFAmXFefLl/0oMQSHC
 XFIVivcR0lxKpZhB5CIOfVj1Vu8VM52JvlXjHPU3ObqEbFDxtf4=
 =RYJ4
 -----END PGP SIGNATURE-----

Merge tag 'xfs-5.17-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Darrick Wong:
 "These are the last few obvious fixes that I found while stress testing
  online fsck for XFS prior to initiating a design review of the whole
  giant machinery.

   - Fix a minor locking inconsistency in readdir

   - Fix incorrect fs feature bit validation for secondary superblocks"

* tag 'xfs-5.17-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: fix online fsck handling of v5 feature bits on secondary supers
  xfs: take the ILOCK when readdir inspects directory mapping data
This commit is contained in:
Linus Torvalds 2022-01-15 07:47:40 +02:00
commit a33f5c380c
3 changed files with 72 additions and 46 deletions

View File

@ -281,7 +281,7 @@ xchk_superblock(
features_mask = cpu_to_be32(XFS_SB_VERSION2_ATTR2BIT);
if ((sb->sb_features2 & features_mask) !=
(cpu_to_be32(mp->m_sb.sb_features2) & features_mask))
xchk_block_set_corrupt(sc, bp);
xchk_block_set_preen(sc, bp);
if (!xfs_has_crc(mp)) {
/* all v5 fields must be zero */
@ -290,38 +290,37 @@ xchk_superblock(
offsetof(struct xfs_dsb, sb_features_compat)))
xchk_block_set_corrupt(sc, bp);
} else {
/* Check compat flags; all are set at mkfs time. */
features_mask = cpu_to_be32(XFS_SB_FEAT_COMPAT_UNKNOWN);
if ((sb->sb_features_compat & features_mask) !=
(cpu_to_be32(mp->m_sb.sb_features_compat) & features_mask))
/* compat features must match */
if (sb->sb_features_compat !=
cpu_to_be32(mp->m_sb.sb_features_compat))
xchk_block_set_corrupt(sc, bp);
/* Check ro compat flags; all are set at mkfs time. */
features_mask = cpu_to_be32(XFS_SB_FEAT_RO_COMPAT_UNKNOWN |
XFS_SB_FEAT_RO_COMPAT_FINOBT |
XFS_SB_FEAT_RO_COMPAT_RMAPBT |
XFS_SB_FEAT_RO_COMPAT_REFLINK);
if ((sb->sb_features_ro_compat & features_mask) !=
(cpu_to_be32(mp->m_sb.sb_features_ro_compat) &
features_mask))
/* ro compat features must match */
if (sb->sb_features_ro_compat !=
cpu_to_be32(mp->m_sb.sb_features_ro_compat))
xchk_block_set_corrupt(sc, bp);
/* Check incompat flags; all are set at mkfs time. */
features_mask = cpu_to_be32(XFS_SB_FEAT_INCOMPAT_UNKNOWN |
XFS_SB_FEAT_INCOMPAT_FTYPE |
XFS_SB_FEAT_INCOMPAT_SPINODES |
XFS_SB_FEAT_INCOMPAT_META_UUID);
if ((sb->sb_features_incompat & features_mask) !=
(cpu_to_be32(mp->m_sb.sb_features_incompat) &
features_mask))
/*
* NEEDSREPAIR is ignored on a secondary super, so we should
* clear it when we find it, though it's not a corruption.
*/
features_mask = cpu_to_be32(XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);
if ((cpu_to_be32(mp->m_sb.sb_features_incompat) ^
sb->sb_features_incompat) & features_mask)
xchk_block_set_preen(sc, bp);
/* all other incompat features must match */
if ((cpu_to_be32(mp->m_sb.sb_features_incompat) ^
sb->sb_features_incompat) & ~features_mask)
xchk_block_set_corrupt(sc, bp);
/* Check log incompat flags; all are set at mkfs time. */
features_mask = cpu_to_be32(XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN);
if ((sb->sb_features_log_incompat & features_mask) !=
(cpu_to_be32(mp->m_sb.sb_features_log_incompat) &
features_mask))
xchk_block_set_corrupt(sc, bp);
/*
* log incompat features protect newer log record types from
* older log recovery code. Log recovery doesn't check the
* secondary supers, so we can clear these if needed.
*/
if (sb->sb_features_log_incompat)
xchk_block_set_preen(sc, bp);
/* Don't care about sb_crc */

View File

@ -52,6 +52,18 @@ xrep_superblock(
xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
xfs_sb_to_disk(bp->b_addr, &mp->m_sb);
/*
* Don't write out a secondary super with NEEDSREPAIR or log incompat
* features set, since both are ignored when set on a secondary.
*/
if (xfs_has_crc(mp)) {
struct xfs_dsb *sb = bp->b_addr;
sb->sb_features_incompat &=
~cpu_to_be32(XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);
sb->sb_features_log_incompat = 0;
}
/* Write this to disk. */
xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_SB_BUF);
xfs_trans_log_buf(sc->tp, bp, 0, BBTOB(bp->b_length) - 1);

View File

@ -138,7 +138,8 @@ xfs_dir2_sf_getdents(
STATIC int
xfs_dir2_block_getdents(
struct xfs_da_args *args,
struct dir_context *ctx)
struct dir_context *ctx,
unsigned int *lock_mode)
{
struct xfs_inode *dp = args->dp; /* incore directory inode */
struct xfs_buf *bp; /* buffer for block */
@ -146,7 +147,6 @@ xfs_dir2_block_getdents(
int wantoff; /* starting block offset */
xfs_off_t cook;
struct xfs_da_geometry *geo = args->geo;
int lock_mode;
unsigned int offset, next_offset;
unsigned int end;
@ -156,12 +156,13 @@ xfs_dir2_block_getdents(
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
return 0;
lock_mode = xfs_ilock_data_map_shared(dp);
error = xfs_dir3_block_read(args->trans, dp, &bp);
xfs_iunlock(dp, lock_mode);
if (error)
return error;
xfs_iunlock(dp, *lock_mode);
*lock_mode = 0;
/*
* Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this.
@ -344,7 +345,8 @@ STATIC int
xfs_dir2_leaf_getdents(
struct xfs_da_args *args,
struct dir_context *ctx,
size_t bufsize)
size_t bufsize,
unsigned int *lock_mode)
{
struct xfs_inode *dp = args->dp;
struct xfs_mount *mp = dp->i_mount;
@ -356,7 +358,6 @@ xfs_dir2_leaf_getdents(
xfs_dir2_off_t curoff; /* current overall offset */
int length; /* temporary length value */
int byteoff; /* offset in current block */
int lock_mode;
unsigned int offset = 0;
int error = 0; /* error return value */
@ -390,13 +391,16 @@ xfs_dir2_leaf_getdents(
bp = NULL;
}
lock_mode = xfs_ilock_data_map_shared(dp);
if (*lock_mode == 0)
*lock_mode = xfs_ilock_data_map_shared(dp);
error = xfs_dir2_leaf_readbuf(args, bufsize, &curoff,
&rablk, &bp);
xfs_iunlock(dp, lock_mode);
if (error || !bp)
break;
xfs_iunlock(dp, *lock_mode);
*lock_mode = 0;
xfs_dir3_data_check(dp, bp);
/*
* Find our position in the block.
@ -496,7 +500,7 @@ xfs_dir2_leaf_getdents(
*
* If supplied, the transaction collects locked dir buffers to avoid
* nested buffer deadlocks. This function does not dirty the
* transaction. The caller should ensure that the inode is locked
* transaction. The caller must hold the IOLOCK (shared or exclusive)
* before calling this function.
*/
int
@ -507,8 +511,9 @@ xfs_readdir(
size_t bufsize)
{
struct xfs_da_args args = { NULL };
int rval;
int v;
unsigned int lock_mode;
int isblock;
int error;
trace_xfs_readdir(dp);
@ -516,6 +521,7 @@ xfs_readdir(
return -EIO;
ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
ASSERT(xfs_isilocked(dp, XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
XFS_STATS_INC(dp->i_mount, xs_dir_getdents);
args.dp = dp;
@ -523,13 +529,22 @@ xfs_readdir(
args.trans = tp;
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_getdents(&args, ctx);
else if ((rval = xfs_dir2_isblock(&args, &v)))
;
else if (v)
rval = xfs_dir2_block_getdents(&args, ctx);
else
rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize);
return xfs_dir2_sf_getdents(&args, ctx);
return rval;
lock_mode = xfs_ilock_data_map_shared(dp);
error = xfs_dir2_isblock(&args, &isblock);
if (error)
goto out_unlock;
if (isblock) {
error = xfs_dir2_block_getdents(&args, ctx, &lock_mode);
goto out_unlock;
}
error = xfs_dir2_leaf_getdents(&args, ctx, bufsize, &lock_mode);
out_unlock:
if (lock_mode)
xfs_iunlock(dp, lock_mode);
return error;
}