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:
Коммит
a33f5c380c
|
@ -281,7 +281,7 @@ xchk_superblock(
|
||||||
features_mask = cpu_to_be32(XFS_SB_VERSION2_ATTR2BIT);
|
features_mask = cpu_to_be32(XFS_SB_VERSION2_ATTR2BIT);
|
||||||
if ((sb->sb_features2 & features_mask) !=
|
if ((sb->sb_features2 & features_mask) !=
|
||||||
(cpu_to_be32(mp->m_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)) {
|
if (!xfs_has_crc(mp)) {
|
||||||
/* all v5 fields must be zero */
|
/* all v5 fields must be zero */
|
||||||
|
@ -290,38 +290,37 @@ xchk_superblock(
|
||||||
offsetof(struct xfs_dsb, sb_features_compat)))
|
offsetof(struct xfs_dsb, sb_features_compat)))
|
||||||
xchk_block_set_corrupt(sc, bp);
|
xchk_block_set_corrupt(sc, bp);
|
||||||
} else {
|
} else {
|
||||||
/* Check compat flags; all are set at mkfs time. */
|
/* compat features must match */
|
||||||
features_mask = cpu_to_be32(XFS_SB_FEAT_COMPAT_UNKNOWN);
|
if (sb->sb_features_compat !=
|
||||||
if ((sb->sb_features_compat & features_mask) !=
|
cpu_to_be32(mp->m_sb.sb_features_compat))
|
||||||
(cpu_to_be32(mp->m_sb.sb_features_compat) & features_mask))
|
|
||||||
xchk_block_set_corrupt(sc, bp);
|
xchk_block_set_corrupt(sc, bp);
|
||||||
|
|
||||||
/* Check ro compat flags; all are set at mkfs time. */
|
/* ro compat features must match */
|
||||||
features_mask = cpu_to_be32(XFS_SB_FEAT_RO_COMPAT_UNKNOWN |
|
if (sb->sb_features_ro_compat !=
|
||||||
XFS_SB_FEAT_RO_COMPAT_FINOBT |
|
cpu_to_be32(mp->m_sb.sb_features_ro_compat))
|
||||||
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))
|
|
||||||
xchk_block_set_corrupt(sc, bp);
|
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 |
|
* NEEDSREPAIR is ignored on a secondary super, so we should
|
||||||
XFS_SB_FEAT_INCOMPAT_FTYPE |
|
* clear it when we find it, though it's not a corruption.
|
||||||
XFS_SB_FEAT_INCOMPAT_SPINODES |
|
*/
|
||||||
XFS_SB_FEAT_INCOMPAT_META_UUID);
|
features_mask = cpu_to_be32(XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);
|
||||||
if ((sb->sb_features_incompat & features_mask) !=
|
if ((cpu_to_be32(mp->m_sb.sb_features_incompat) ^
|
||||||
(cpu_to_be32(mp->m_sb.sb_features_incompat) &
|
sb->sb_features_incompat) & features_mask)
|
||||||
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);
|
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);
|
* log incompat features protect newer log record types from
|
||||||
if ((sb->sb_features_log_incompat & features_mask) !=
|
* older log recovery code. Log recovery doesn't check the
|
||||||
(cpu_to_be32(mp->m_sb.sb_features_log_incompat) &
|
* secondary supers, so we can clear these if needed.
|
||||||
features_mask))
|
*/
|
||||||
xchk_block_set_corrupt(sc, bp);
|
if (sb->sb_features_log_incompat)
|
||||||
|
xchk_block_set_preen(sc, bp);
|
||||||
|
|
||||||
/* Don't care about sb_crc */
|
/* Don't care about sb_crc */
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,18 @@ xrep_superblock(
|
||||||
xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
|
xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
|
||||||
xfs_sb_to_disk(bp->b_addr, &mp->m_sb);
|
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. */
|
/* Write this to disk. */
|
||||||
xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_SB_BUF);
|
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);
|
xfs_trans_log_buf(sc->tp, bp, 0, BBTOB(bp->b_length) - 1);
|
||||||
|
|
|
@ -138,7 +138,8 @@ xfs_dir2_sf_getdents(
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_dir2_block_getdents(
|
xfs_dir2_block_getdents(
|
||||||
struct xfs_da_args *args,
|
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_inode *dp = args->dp; /* incore directory inode */
|
||||||
struct xfs_buf *bp; /* buffer for block */
|
struct xfs_buf *bp; /* buffer for block */
|
||||||
|
@ -146,7 +147,6 @@ xfs_dir2_block_getdents(
|
||||||
int wantoff; /* starting block offset */
|
int wantoff; /* starting block offset */
|
||||||
xfs_off_t cook;
|
xfs_off_t cook;
|
||||||
struct xfs_da_geometry *geo = args->geo;
|
struct xfs_da_geometry *geo = args->geo;
|
||||||
int lock_mode;
|
|
||||||
unsigned int offset, next_offset;
|
unsigned int offset, next_offset;
|
||||||
unsigned int end;
|
unsigned int end;
|
||||||
|
|
||||||
|
@ -156,12 +156,13 @@ xfs_dir2_block_getdents(
|
||||||
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
|
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
lock_mode = xfs_ilock_data_map_shared(dp);
|
|
||||||
error = xfs_dir3_block_read(args->trans, dp, &bp);
|
error = xfs_dir3_block_read(args->trans, dp, &bp);
|
||||||
xfs_iunlock(dp, lock_mode);
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
xfs_iunlock(dp, *lock_mode);
|
||||||
|
*lock_mode = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract the byte offset we start at from the seek pointer.
|
* Extract the byte offset we start at from the seek pointer.
|
||||||
* We'll skip entries before this.
|
* We'll skip entries before this.
|
||||||
|
@ -344,7 +345,8 @@ STATIC int
|
||||||
xfs_dir2_leaf_getdents(
|
xfs_dir2_leaf_getdents(
|
||||||
struct xfs_da_args *args,
|
struct xfs_da_args *args,
|
||||||
struct dir_context *ctx,
|
struct dir_context *ctx,
|
||||||
size_t bufsize)
|
size_t bufsize,
|
||||||
|
unsigned int *lock_mode)
|
||||||
{
|
{
|
||||||
struct xfs_inode *dp = args->dp;
|
struct xfs_inode *dp = args->dp;
|
||||||
struct xfs_mount *mp = dp->i_mount;
|
struct xfs_mount *mp = dp->i_mount;
|
||||||
|
@ -356,7 +358,6 @@ xfs_dir2_leaf_getdents(
|
||||||
xfs_dir2_off_t curoff; /* current overall offset */
|
xfs_dir2_off_t curoff; /* current overall offset */
|
||||||
int length; /* temporary length value */
|
int length; /* temporary length value */
|
||||||
int byteoff; /* offset in current block */
|
int byteoff; /* offset in current block */
|
||||||
int lock_mode;
|
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
int error = 0; /* error return value */
|
int error = 0; /* error return value */
|
||||||
|
|
||||||
|
@ -390,13 +391,16 @@ xfs_dir2_leaf_getdents(
|
||||||
bp = NULL;
|
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,
|
error = xfs_dir2_leaf_readbuf(args, bufsize, &curoff,
|
||||||
&rablk, &bp);
|
&rablk, &bp);
|
||||||
xfs_iunlock(dp, lock_mode);
|
|
||||||
if (error || !bp)
|
if (error || !bp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
xfs_iunlock(dp, *lock_mode);
|
||||||
|
*lock_mode = 0;
|
||||||
|
|
||||||
xfs_dir3_data_check(dp, bp);
|
xfs_dir3_data_check(dp, bp);
|
||||||
/*
|
/*
|
||||||
* Find our position in the block.
|
* Find our position in the block.
|
||||||
|
@ -496,7 +500,7 @@ xfs_dir2_leaf_getdents(
|
||||||
*
|
*
|
||||||
* If supplied, the transaction collects locked dir buffers to avoid
|
* If supplied, the transaction collects locked dir buffers to avoid
|
||||||
* nested buffer deadlocks. This function does not dirty the
|
* 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.
|
* before calling this function.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -507,8 +511,9 @@ xfs_readdir(
|
||||||
size_t bufsize)
|
size_t bufsize)
|
||||||
{
|
{
|
||||||
struct xfs_da_args args = { NULL };
|
struct xfs_da_args args = { NULL };
|
||||||
int rval;
|
unsigned int lock_mode;
|
||||||
int v;
|
int isblock;
|
||||||
|
int error;
|
||||||
|
|
||||||
trace_xfs_readdir(dp);
|
trace_xfs_readdir(dp);
|
||||||
|
|
||||||
|
@ -516,6 +521,7 @@ xfs_readdir(
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
|
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);
|
XFS_STATS_INC(dp->i_mount, xs_dir_getdents);
|
||||||
|
|
||||||
args.dp = dp;
|
args.dp = dp;
|
||||||
|
@ -523,13 +529,22 @@ xfs_readdir(
|
||||||
args.trans = tp;
|
args.trans = tp;
|
||||||
|
|
||||||
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
|
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
|
||||||
rval = xfs_dir2_sf_getdents(&args, ctx);
|
return 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 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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче