#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_rtgroup.h"
+#include "xfs_bmap_util.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
return -EFSCORRUPTED;
}
-#define REPLACE_LEFT_SIDE (1U << 0)
-#define REPLACE_RIGHT_SIDE (1U << 1)
-
-/*
- * Given a CoW fork mapping @got and a replacement mapping @rep, map the space
- * described by @rep into the cow fork, pushing aside @got as necessary. @icur
- * must point to iext tree leaf containing @got.
- */
-static inline void
-xrep_cow_replace_mapping(
- struct xfs_inode *ip,
- struct xfs_iext_cursor *icur,
- struct xfs_bmbt_irec *got,
- struct xfs_bmbt_irec *rep)
-{
- struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_COW_FORK);
- xfs_fileoff_t rep_endoff =
- rep->br_startoff + rep->br_blockcount;
- xfs_fileoff_t got_endoff =
- got->br_startoff + got->br_blockcount;
- uint32_t state = BMAP_COWFORK;
-
- ASSERT(rep->br_blockcount > 0);
- ASSERT(!isnullstartblock(got->br_startblock));
- ASSERT(got->br_startoff <= rep->br_startoff);
- ASSERT(got_endoff >= rep_endoff);
-
- trace_xrep_cow_replace_mapping(ip, got, rep);
-
- if (got->br_startoff == rep->br_startoff)
- state |= BMAP_LEFT_FILLING;
- if (got_endoff == rep_endoff)
- state |= BMAP_RIGHT_FILLING;
-
- switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) {
- case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
- /*
- * Replacement matches the whole mapping, update the record.
- */
- xfs_iext_update_extent(ip, state, icur, rep);
- break;
- case BMAP_LEFT_FILLING:
- /*
- * Replace the first part of the mapping: Update the cursor
- * position with the new mapping, then add a record with the
- * tail of the old mapping.
- */
- got->br_startoff = rep_endoff;
- got->br_blockcount -= rep->br_blockcount;
- got->br_startblock += rep->br_blockcount;
-
- xfs_iext_update_extent(ip, state, icur, rep);
- xfs_iext_next(ifp, icur);
- xfs_iext_insert(ip, icur, got, state);
- break;
- case BMAP_RIGHT_FILLING:
- /*
- * Replacing the last part of the mapping. Shorten the current
- * mapping then add a record with the new mapping.
- */
- got->br_blockcount -= rep->br_blockcount;
-
- xfs_iext_update_extent(ip, state, icur, got);
- xfs_iext_next(ifp, icur);
- xfs_iext_insert(ip, icur, rep, state);
- break;
- case 0:
- /*
- * Replacing the middle of the extent. Shorten the current
- * mapping, add a new record with the new mapping, and add a
- * second new record with the tail of the old mapping.
- */
- got->br_blockcount = rep->br_startoff - got->br_startoff;
-
- struct xfs_bmbt_irec new = {
- .br_startoff = rep_endoff,
- .br_blockcount = got_endoff - rep_endoff,
- .br_state = got->br_state,
- .br_startblock = got->br_startblock +
- rep->br_blockcount +
- got->br_blockcount,
- };
-
- xfs_iext_update_extent(ip, state, icur, got);
- xfs_iext_next(ifp, icur);
- xfs_iext_insert(ip, icur, rep, state);
- xfs_iext_next(ifp, icur);
- xfs_iext_insert(ip, icur, &new, state);
- break;
- }
-}
-
/*
* Replace the unwritten CoW staging extent backing the given file range with a
* new space extent that isn't as problematic.
* Replace the old mapping with the new one, and commit the metadata
* changes made so far.
*/
- xrep_cow_replace_mapping(sc->ip, &icur, &got, &rep);
+ xfs_bmap_replace_cow_mapping(sc->ip, &icur, &got, &rep);
xfs_inode_set_cowblocks_tag(sc->ip);
error = xfs_defer_finish(&sc->tp);
__entry->blockcount)
);
-TRACE_EVENT(xrep_cow_replace_mapping,
- TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *got,
- const struct xfs_bmbt_irec *rep),
- TP_ARGS(ip, got, rep),
- TP_STRUCT__entry(
- __field(dev_t, dev)
- __field(xfs_ino_t, ino)
- __field(xfs_fsblock_t, startblock)
- __field(xfs_fileoff_t, startoff)
- __field(xfs_filblks_t, blockcount)
- __field(xfs_exntst_t, state)
- __field(xfs_fileoff_t, new_startoff)
- __field(xfs_fsblock_t, new_startblock)
- __field(xfs_extlen_t, new_blockcount)
- __field(xfs_exntst_t, new_state)
- ),
- TP_fast_assign(
- __entry->dev = ip->i_mount->m_super->s_dev;
- __entry->ino = I_INO(ip);
- __entry->startoff = got->br_startoff;
- __entry->startblock = got->br_startblock;
- __entry->blockcount = got->br_blockcount;
- __entry->state = got->br_state;
- __entry->new_startoff = rep->br_startoff;
- __entry->new_startblock = rep->br_startblock;
- __entry->new_blockcount = rep->br_blockcount;
- __entry->new_state = rep->br_state;
- ),
- TP_printk("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startoff 0x%llx new_startblock 0x%llx new_fsbcount 0x%x new_state 0x%x",
- MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->ino,
- __entry->startoff,
- __entry->startblock,
- __entry->blockcount,
- __entry->state,
- __entry->new_startoff,
- __entry->new_startblock,
- __entry->new_blockcount,
- __entry->new_state)
-);
-
TRACE_EVENT(xrep_cow_free_staging,
TP_PROTO(const struct xfs_perag *pag, xfs_agblock_t agbno,
xfs_extlen_t blockcount),
xfs_trans_cancel(tp);
goto out_unlock_ilock;
}
+
+/*
+ * Given a CoW fork mapping @got and a replacement mapping @rep, map the space
+ * described by @rep into the cow fork, pushing aside @got as necessary. @icur
+ * must point to iext tree leaf containing @got.
+ */
+void
+xfs_bmap_replace_cow_mapping(
+ struct xfs_inode *ip,
+ struct xfs_iext_cursor *icur,
+ struct xfs_bmbt_irec *got,
+ struct xfs_bmbt_irec *rep)
+{
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_COW_FORK);
+ xfs_fileoff_t rep_endoff =
+ rep->br_startoff + rep->br_blockcount;
+ xfs_fileoff_t got_endoff =
+ got->br_startoff + got->br_blockcount;
+ uint32_t state = BMAP_COWFORK;
+
+ ASSERT(rep->br_blockcount > 0);
+ ASSERT(!isnullstartblock(got->br_startblock));
+ ASSERT(got->br_startoff <= rep->br_startoff);
+ ASSERT(got_endoff >= rep_endoff);
+
+ trace_xfs_bmap_replace_cow_mapping(ip, got, rep);
+
+ if (got->br_startoff == rep->br_startoff)
+ state |= BMAP_LEFT_FILLING;
+ if (got_endoff == rep_endoff)
+ state |= BMAP_RIGHT_FILLING;
+
+ switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) {
+ case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
+ /*
+ * Replacement matches the whole mapping, update the record.
+ */
+ xfs_iext_update_extent(ip, state, icur, rep);
+ break;
+ case BMAP_LEFT_FILLING:
+ /*
+ * Replace the first part of the mapping: Update the cursor
+ * position with the new mapping, then add a record with the
+ * tail of the old mapping.
+ */
+ got->br_startoff = rep_endoff;
+ got->br_blockcount -= rep->br_blockcount;
+ got->br_startblock += rep->br_blockcount;
+
+ xfs_iext_update_extent(ip, state, icur, rep);
+ xfs_iext_next(ifp, icur);
+ xfs_iext_insert(ip, icur, got, state);
+ break;
+ case BMAP_RIGHT_FILLING:
+ /*
+ * Replacing the last part of the mapping. Shorten the current
+ * mapping then add a record with the new mapping.
+ */
+ got->br_blockcount -= rep->br_blockcount;
+
+ xfs_iext_update_extent(ip, state, icur, got);
+ xfs_iext_next(ifp, icur);
+ xfs_iext_insert(ip, icur, rep, state);
+ break;
+ case 0:
+ /*
+ * Replacing the middle of the extent. Shorten the current
+ * mapping, add a new record with the new mapping, and add a
+ * second new record with the tail of the old mapping.
+ */
+ got->br_blockcount = rep->br_startoff - got->br_startoff;
+
+ struct xfs_bmbt_irec new = {
+ .br_startoff = rep_endoff,
+ .br_blockcount = got_endoff - rep_endoff,
+ .br_state = got->br_state,
+ .br_startblock = got->br_startblock +
+ rep->br_blockcount +
+ got->br_blockcount,
+ };
+
+ xfs_iext_update_extent(ip, state, icur, got);
+ xfs_iext_next(ifp, icur);
+ xfs_iext_insert(ip, icur, rep, state);
+ xfs_iext_next(ifp, icur);
+ xfs_iext_insert(ip, icur, &new, state);
+ break;
+ }
+}
int xfs_flush_unmap_range(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t len);
+void xfs_bmap_replace_cow_mapping(struct xfs_inode *ip,
+ struct xfs_iext_cursor *icur, struct xfs_bmbt_irec *got,
+ struct xfs_bmbt_irec *rep);
+
#endif /* __XFS_BMAP_UTIL_H__ */
__entry->error)
);
+TRACE_EVENT(xfs_bmap_replace_cow_mapping,
+ TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *got,
+ const struct xfs_bmbt_irec *rep),
+ TP_ARGS(ip, got, rep),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(xfs_fsblock_t, startblock)
+ __field(xfs_fileoff_t, startoff)
+ __field(xfs_filblks_t, blockcount)
+ __field(xfs_exntst_t, state)
+ __field(xfs_fileoff_t, new_startoff)
+ __field(xfs_fsblock_t, new_startblock)
+ __field(xfs_extlen_t, new_blockcount)
+ __field(xfs_exntst_t, new_state)
+ ),
+ TP_fast_assign(
+ __entry->dev = ip->i_mount->m_super->s_dev;
+ __entry->ino = I_INO(ip);
+ __entry->startoff = got->br_startoff;
+ __entry->startblock = got->br_startblock;
+ __entry->blockcount = got->br_blockcount;
+ __entry->state = got->br_state;
+ __entry->new_startoff = rep->br_startoff;
+ __entry->new_startblock = rep->br_startblock;
+ __entry->new_blockcount = rep->br_blockcount;
+ __entry->new_state = rep->br_state;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startoff 0x%llx new_startblock 0x%llx new_fsbcount 0x%x new_state 0x%x",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->startoff,
+ __entry->startblock,
+ __entry->blockcount,
+ __entry->state,
+ __entry->new_startoff,
+ __entry->new_startblock,
+ __entry->new_blockcount,
+ __entry->new_state)
+);
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH