@@ -1636,13 +1636,13 @@ xrep_fallocate(
xfs_filblks_t len)
{
struct xfs_bmbt_irec map;
+ struct xfs_inode *ip = sc->tempip;
xfs_fileoff_t end = off + len;
int nmaps;
int error = 0;
- error = xrep_ino_dqattach(sc);
- if (error)
- return error;
+ ASSERT(sc->tempip != NULL);
+ ASSERT(!XFS_NOT_DQATTACHED(sc->mp, ip));
while (off < len) {
/*
@@ -1650,7 +1650,7 @@ xrep_fallocate(
* in ok shape.
*/
nmaps = 1;
- error = xfs_bmapi_read(sc->ip, off, end - off, &map, &nmaps,
+ error = xfs_bmapi_read(ip, off, end - off, &map, &nmaps,
XFS_DATA_FORK);
if (error)
break;
@@ -1672,15 +1672,21 @@ xrep_fallocate(
* allocated to it.
*/
nmaps = 1;
- error = xfs_bmapi_write(sc->tp, sc->ip, off, end - off,
+ error = xfs_bmapi_write(sc->tp, ip, off, end - off,
XFS_BMAPI_CONVERT | XFS_BMAPI_ZERO, 0, &map,
&nmaps);
if (error)
break;
- error = xfs_trans_roll_inode(&sc->tp, sc->ip);
+ /*
+ * Roll the transaction with the inode we're fixing and the
+ * temp inode, so that neither can pin the log.
+ */
+ xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
+ error = xfs_trans_roll_inode(&sc->tp, ip);
if (error)
break;
+ xfs_trans_ijoin(sc->tp, sc->ip, 0);
off += map.br_startblock;
}
@@ -1701,6 +1707,7 @@ xrep_set_file_contents(
{
struct list_head buffers_list;
struct xfs_mount *mp = sc->mp;
+ struct xfs_inode *ip = sc->tempip;
struct xfs_buf *bp;
xfs_rtblock_t off = 0;
loff_t pos = 0;
@@ -1744,12 +1751,19 @@ xrep_set_file_contents(
}
/* Set the new inode size, if needed. */
- if (sc->ip->i_d.di_size != isize) {
- sc->ip->i_d.di_size = isize;
- xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
+ if (ip->i_d.di_size != isize) {
+ ip->i_d.di_size = isize;
+ xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_CORE);
}
- return xfs_trans_roll_inode(&sc->tp, sc->ip);
+ /*
+ * Roll transaction, being careful to keep the tempfile and the
+ * metadata inode joined.
+ */
+ xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
+ error = xfs_trans_roll_inode(&sc->tp, ip);
+ xfs_trans_ijoin(sc->tp, sc->ip, 0);
+ return error;
out:
xfs_buf_delwri_cancel(&buffers_list);
return error;
@@ -20,6 +20,7 @@
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/btree.h"
+#include "scrub/repair.h"
/* Set us up with the realtime metadata locked. */
int
@@ -29,6 +30,17 @@ xchk_setup_rt(
{
int error;
+#ifdef CONFIG_XFS_ONLINE_REPAIR
+ if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
+ if (!xfs_sb_version_hasatomicswap(&sc->mp->m_sb))
+ return -EOPNOTSUPP;
+
+ error = xrep_create_tempfile(sc, S_IFREG);
+ if (error)
+ return error;
+ }
+#endif
+
error = xchk_setup_fs(sc, ip);
if (error)
return error;
@@ -18,6 +18,7 @@
#include "xfs_bmap.h"
#include "xfs_rmap.h"
#include "xfs_rtrmap_btree.h"
+#include "xfs_swapext.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
@@ -207,7 +208,29 @@ xrep_rtbitmap_get_buf(
xfs_fileoff_t off,
struct xfs_buf **bpp)
{
- return xfs_rtbuf_get(sc->mp, sc->tp, off, 0, bpp);
+ struct xfs_bmbt_irec map;
+ struct xfs_buf *bp;
+ struct xfs_mount *mp = sc->mp;
+ int nmap = 1;
+ int error;
+
+ error = xfs_bmapi_read(sc->tempip, off, 1, &map, &nmap,
+ XFS_DATA_FORK);
+ if (error)
+ return error;
+
+ if (nmap == 0 || !xfs_bmap_is_real_extent(&map))
+ return -EFSCORRUPTED;
+
+ error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
+ XFS_FSB_TO_DADDR(mp, map.br_startblock),
+ mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
+ if (error)
+ return error;
+
+ xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTBITMAP_BUF);
+ *bpp = bp;
+ return 0;
}
/* Repair the realtime bitmap. */
@@ -221,8 +244,12 @@ xrep_rtbitmap(
xfs_fileoff_t bmp_bytes;
int error;
- /* We require the realtime rmapbt to rebuild anything. */
- if (!xfs_sb_version_hasrtrmapbt(&sc->mp->m_sb))
+ /*
+ * We require the realtime rmapbt and atomic file updates to rebuild
+ * anything.
+ */
+ if (!xfs_sb_version_hasrtrmapbt(&sc->mp->m_sb) ||
+ !xfs_sb_version_hasatomicswap(&sc->mp->m_sb))
return -EOPNOTSUPP;
bmp_bytes = XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks);
@@ -240,8 +267,17 @@ xrep_rtbitmap(
if (error)
goto out;
+ /*
+ * Trylock the temporary file. We had better be the only ones holding
+ * onto this inode...
+ */
+ if (!xfs_ilock_nowait(sc->tempip, XFS_ILOCK_EXCL))
+ return -EAGAIN;
+ sc->temp_ilock_flags = XFS_ILOCK_EXCL;
+
/* Make sure we have space allocated for the entire bitmap file. */
xfs_trans_ijoin(sc->tp, sc->ip, 0);
+ xfs_trans_ijoin(sc->tp, sc->tempip, 0);
error = xrep_fallocate(sc, 0, sc->mp->m_sb.sb_rbmblocks);
if (error)
goto out;
@@ -249,6 +285,12 @@ xrep_rtbitmap(
/* Copy the bitmap file that we generated. */
error = xrep_set_file_contents(sc, xrep_rtbitmap_get_buf, rb.bmpfile,
bmp_bytes);
+ if (error)
+ goto out;
+
+ /* Now swap the extents. */
+ error = xfs_swapext_atomic(&sc->tp, sc->ip, sc->tempip, XFS_DATA_FORK,
+ 0, 0, sc->mp->m_sb.sb_rbmblocks, 0);
out:
fput(rb.bmpfile);
return error;
@@ -20,6 +20,7 @@
#include "scrub/common.h"
#include "scrub/trace.h"
#include "scrub/xfile.h"
+#include "scrub/repair.h"
/*
* Realtime Summary
@@ -61,6 +62,17 @@ xchk_setup_rtsummary(
struct xfs_mount *mp = sc->mp;
int error;
+#ifdef CONFIG_XFS_ONLINE_REPAIR
+ if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
+ if (!xfs_sb_version_hasatomicswap(&sc->mp->m_sb))
+ return -EOPNOTSUPP;
+
+ error = xrep_create_tempfile(sc, S_IFREG);
+ if (error)
+ return error;
+ }
+#endif
+
error = xchk_setup_fs(sc, ip);
if (error)
return error;
@@ -16,6 +16,7 @@
#include "xfs_inode.h"
#include "xfs_bit.h"
#include "xfs_bmap.h"
+#include "xfs_swapext.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
@@ -28,7 +29,29 @@ xrep_rtsum_get_buf(
xfs_fileoff_t off,
struct xfs_buf **bpp)
{
- return xfs_rtbuf_get(sc->mp, sc->tp, off, 1, bpp);
+ struct xfs_bmbt_irec map;
+ struct xfs_buf *bp;
+ struct xfs_mount *mp = sc->mp;
+ int nmap = 1;
+ int error;
+
+ error = xfs_bmapi_read(sc->tempip, off, 1, &map, &nmap,
+ XFS_DATA_FORK);
+ if (error)
+ return error;
+
+ if (nmap == 0 || !xfs_bmap_is_real_extent(&map))
+ return -EFSCORRUPTED;
+
+ error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
+ XFS_FSB_TO_DADDR(mp, map.br_startblock),
+ mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
+ if (error)
+ return error;
+
+ xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF);
+ *bpp = bp;
+ return 0;
}
/* Repair the realtime summary. */
@@ -38,18 +61,37 @@ xrep_rtsummary(
{
int error;
+ /* We require atomic file swap to be able to fix rt summaries. */
+ if (!xfs_sb_version_hasatomicswap(&sc->mp->m_sb))
+ return -EOPNOTSUPP;
+
/* Make sure any problems with the fork are fixed. */
error = xrep_metadata_inode_forks(sc);
if (error)
return error;
+ /*
+ * Trylock the temporary file. We had better be the only ones holding
+ * onto this inode...
+ */
+ if (!xfs_ilock_nowait(sc->tempip, XFS_ILOCK_EXCL))
+ return -EAGAIN;
+ sc->temp_ilock_flags = XFS_ILOCK_EXCL;
+
/* Make sure we have space allocated for the entire summary file. */
xfs_trans_ijoin(sc->tp, sc->ip, 0);
+ xfs_trans_ijoin(sc->tp, sc->tempip, 0);
error = xrep_fallocate(sc, 0, XFS_B_TO_FSB(sc->mp, sc->mp->m_rsumsize));
if (error)
return error;
/* Copy the rtsummary file that we generated. */
- return xrep_set_file_contents(sc, xrep_rtsum_get_buf, sc->xfile,
+ error = xrep_set_file_contents(sc, xrep_rtsum_get_buf, sc->xfile,
sc->mp->m_rsumsize);
+ if (error)
+ return error;
+
+ /* Now swap the extents. */
+ return xfs_swapext_atomic(&sc->tp, sc->ip, sc->tempip, XFS_DATA_FORK,
+ 0, 0, XFS_B_TO_FSB(sc->mp, sc->mp->m_rsumsize), 0);
}