mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
xfs: check rt bitmap file geometry more thoroughly
I forgot that the superblock tracks the number of blocks that are in the realtime bitmap, and that the rt bitmap file can have more blocks mapped to the data fork than sb_rbmblocks if growfsrt fails. So. Add to the rtbitmap scrubber an explicit check that sb_rextents and sb_rbmblocks are correct, then adjust the rtbitmap i_size checks to allow for the growfsrt failure case. Finally, flag post-eof blocks in the rtbitmap. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
dbbdbd0086
commit
41991cf298
@ -14,16 +14,30 @@
|
|||||||
#include "xfs_rtbitmap.h"
|
#include "xfs_rtbitmap.h"
|
||||||
#include "xfs_inode.h"
|
#include "xfs_inode.h"
|
||||||
#include "xfs_bmap.h"
|
#include "xfs_bmap.h"
|
||||||
|
#include "xfs_bit.h"
|
||||||
#include "scrub/scrub.h"
|
#include "scrub/scrub.h"
|
||||||
#include "scrub/common.h"
|
#include "scrub/common.h"
|
||||||
|
|
||||||
|
struct xchk_rtbitmap {
|
||||||
|
uint64_t rextents;
|
||||||
|
uint64_t rbmblocks;
|
||||||
|
unsigned int rextslog;
|
||||||
|
};
|
||||||
|
|
||||||
/* Set us up with the realtime metadata locked. */
|
/* Set us up with the realtime metadata locked. */
|
||||||
int
|
int
|
||||||
xchk_setup_rtbitmap(
|
xchk_setup_rtbitmap(
|
||||||
struct xfs_scrub *sc)
|
struct xfs_scrub *sc)
|
||||||
{
|
{
|
||||||
|
struct xfs_mount *mp = sc->mp;
|
||||||
|
struct xchk_rtbitmap *rtb;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
rtb = kzalloc(sizeof(struct xchk_rtbitmap), XCHK_GFP_FLAGS);
|
||||||
|
if (!rtb)
|
||||||
|
return -ENOMEM;
|
||||||
|
sc->buf = rtb;
|
||||||
|
|
||||||
error = xchk_trans_alloc(sc, 0);
|
error = xchk_trans_alloc(sc, 0);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
@ -37,6 +51,17 @@ xchk_setup_rtbitmap(
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
|
xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we've locked the rtbitmap, we can't race with growfsrt
|
||||||
|
* trying to expand the bitmap or change the size of the rt volume.
|
||||||
|
* Hence it is safe to compute and check the geometry values.
|
||||||
|
*/
|
||||||
|
if (mp->m_sb.sb_rblocks) {
|
||||||
|
rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
|
||||||
|
rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
|
||||||
|
rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,21 +92,30 @@ STATIC int
|
|||||||
xchk_rtbitmap_check_extents(
|
xchk_rtbitmap_check_extents(
|
||||||
struct xfs_scrub *sc)
|
struct xfs_scrub *sc)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = sc->mp;
|
|
||||||
struct xfs_bmbt_irec map;
|
struct xfs_bmbt_irec map;
|
||||||
xfs_rtblock_t off;
|
struct xfs_iext_cursor icur;
|
||||||
int nmap;
|
struct xfs_mount *mp = sc->mp;
|
||||||
|
struct xfs_inode *ip = sc->ip;
|
||||||
|
xfs_fileoff_t off = 0;
|
||||||
|
xfs_fileoff_t endoff;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
for (off = 0; off < mp->m_sb.sb_rbmblocks;) {
|
/* Mappings may not cross or lie beyond EOF. */
|
||||||
|
endoff = XFS_B_TO_FSB(mp, ip->i_disk_size);
|
||||||
|
if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) {
|
||||||
|
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (off < endoff) {
|
||||||
|
int nmap = 1;
|
||||||
|
|
||||||
if (xchk_should_terminate(sc, &error) ||
|
if (xchk_should_terminate(sc, &error) ||
|
||||||
(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
|
(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Make sure we have a written extent. */
|
/* Make sure we have a written extent. */
|
||||||
nmap = 1;
|
error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap,
|
||||||
error = xfs_bmapi_read(mp->m_rbmip, off,
|
|
||||||
mp->m_sb.sb_rbmblocks - off, &map, &nmap,
|
|
||||||
XFS_DATA_FORK);
|
XFS_DATA_FORK);
|
||||||
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
|
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
|
||||||
break;
|
break;
|
||||||
@ -102,12 +136,48 @@ int
|
|||||||
xchk_rtbitmap(
|
xchk_rtbitmap(
|
||||||
struct xfs_scrub *sc)
|
struct xfs_scrub *sc)
|
||||||
{
|
{
|
||||||
|
struct xfs_mount *mp = sc->mp;
|
||||||
|
struct xchk_rtbitmap *rtb = sc->buf;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Is the size of the rtbitmap correct? */
|
/* Is sb_rextents correct? */
|
||||||
if (sc->mp->m_rbmip->i_disk_size !=
|
if (mp->m_sb.sb_rextents != rtb->rextents) {
|
||||||
XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks)) {
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
xchk_ino_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is sb_rextslog correct? */
|
||||||
|
if (mp->m_sb.sb_rextslog != rtb->rextslog) {
|
||||||
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is sb_rbmblocks large enough to handle the current rt volume? In no
|
||||||
|
* case can we exceed 4bn bitmap blocks since the super field is a u32.
|
||||||
|
*/
|
||||||
|
if (rtb->rbmblocks > U32_MAX) {
|
||||||
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks) {
|
||||||
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The bitmap file length must be aligned to an fsblock. */
|
||||||
|
if (mp->m_rbmip->i_disk_size & mp->m_blockmask) {
|
||||||
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is the bitmap file itself large enough to handle the rt volume?
|
||||||
|
* growfsrt expands the bitmap file before updating sb_rextents, so the
|
||||||
|
* file can be larger than sb_rbmblocks.
|
||||||
|
*/
|
||||||
|
if (mp->m_rbmip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks)) {
|
||||||
|
xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +190,11 @@ xchk_rtbitmap(
|
|||||||
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
|
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtbitmap_rec, sc);
|
error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
|
||||||
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
|
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
|
||||||
goto out;
|
return error;
|
||||||
|
|
||||||
out:
|
return 0;
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* xref check that the extent is not free in the rtbitmap */
|
/* xref check that the extent is not free in the rtbitmap */
|
||||||
|
Loading…
Reference in New Issue
Block a user