mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
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:
commit
a33f5c380c
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user