Skip to content

Commit 7e1b84b

Browse files
author
Darrick J. Wong
committed
xfs: hook live rmap operations during a repair operation
Hook the regular rmap code when an rmapbt repair operation is running so that we can unlock the AGF buffer to scan the filesystem and keep the in-memory btree up to date during the scan. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 4787fc8 commit 7e1b84b

12 files changed

Lines changed: 392 additions & 39 deletions

File tree

fs/xfs/libxfs/xfs_ag.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ xfs_initialize_perag(
417417
init_waitqueue_head(&pag->pag_active_wq);
418418
pag->pagb_count = 0;
419419
pag->pagb_tree = RB_ROOT;
420+
xfs_hooks_init(&pag->pag_rmap_update_hooks);
420421
#endif /* __KERNEL__ */
421422

422423
error = xfs_buf_cache_init(&pag->pag_bcache);

fs/xfs/libxfs/xfs_ag.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ struct xfs_perag {
120120
* inconsistencies.
121121
*/
122122
struct xfs_defer_drain pag_intents_drain;
123+
124+
/* Hook to feed rmapbt updates to an active online repair. */
125+
struct xfs_hooks pag_rmap_update_hooks;
123126
#endif /* __KERNEL__ */
124127
};
125128

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 121 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,86 @@ xfs_rmap_unmap(
821821
return error;
822822
}
823823

824+
#ifdef CONFIG_XFS_LIVE_HOOKS
825+
/*
826+
* Use a static key here to reduce the overhead of rmapbt live updates. If
827+
* the compiler supports jump labels, the static branch will be replaced by a
828+
* nop sled when there are no hook users. Online fsck is currently the only
829+
* caller, so this is a reasonable tradeoff.
830+
*
831+
* Note: Patching the kernel code requires taking the cpu hotplug lock. Other
832+
* parts of the kernel allocate memory with that lock held, which means that
833+
* XFS callers cannot hold any locks that might be used by memory reclaim or
834+
* writeback when calling the static_branch_{inc,dec} functions.
835+
*/
836+
DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_rmap_hooks_switch);
837+
838+
void
839+
xfs_rmap_hook_disable(void)
840+
{
841+
xfs_hooks_switch_off(&xfs_rmap_hooks_switch);
842+
}
843+
844+
void
845+
xfs_rmap_hook_enable(void)
846+
{
847+
xfs_hooks_switch_on(&xfs_rmap_hooks_switch);
848+
}
849+
850+
/* Call downstream hooks for a reverse mapping update. */
851+
static inline void
852+
xfs_rmap_update_hook(
853+
struct xfs_trans *tp,
854+
struct xfs_perag *pag,
855+
enum xfs_rmap_intent_type op,
856+
xfs_agblock_t startblock,
857+
xfs_extlen_t blockcount,
858+
bool unwritten,
859+
const struct xfs_owner_info *oinfo)
860+
{
861+
if (xfs_hooks_switched_on(&xfs_rmap_hooks_switch)) {
862+
struct xfs_rmap_update_params p = {
863+
.startblock = startblock,
864+
.blockcount = blockcount,
865+
.unwritten = unwritten,
866+
.oinfo = *oinfo, /* struct copy */
867+
};
868+
869+
if (pag)
870+
xfs_hooks_call(&pag->pag_rmap_update_hooks, op, &p);
871+
}
872+
}
873+
874+
/* Call the specified function during a reverse mapping update. */
875+
int
876+
xfs_rmap_hook_add(
877+
struct xfs_perag *pag,
878+
struct xfs_rmap_hook *hook)
879+
{
880+
return xfs_hooks_add(&pag->pag_rmap_update_hooks, &hook->rmap_hook);
881+
}
882+
883+
/* Stop calling the specified function during a reverse mapping update. */
884+
void
885+
xfs_rmap_hook_del(
886+
struct xfs_perag *pag,
887+
struct xfs_rmap_hook *hook)
888+
{
889+
xfs_hooks_del(&pag->pag_rmap_update_hooks, &hook->rmap_hook);
890+
}
891+
892+
/* Configure rmap update hook functions. */
893+
void
894+
xfs_rmap_hook_setup(
895+
struct xfs_rmap_hook *hook,
896+
notifier_fn_t mod_fn)
897+
{
898+
xfs_hook_setup(&hook->rmap_hook, mod_fn);
899+
}
900+
#else
901+
# define xfs_rmap_update_hook(t, p, o, s, b, u, oi) do { } while (0)
902+
#endif /* CONFIG_XFS_LIVE_HOOKS */
903+
824904
/*
825905
* Remove a reference to an extent in the rmap btree.
826906
*/
@@ -841,7 +921,7 @@ xfs_rmap_free(
841921
return 0;
842922

843923
cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
844-
924+
xfs_rmap_update_hook(tp, pag, XFS_RMAP_UNMAP, bno, len, false, oinfo);
845925
error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
846926

847927
xfs_btree_del_cursor(cur, error);
@@ -1093,6 +1173,7 @@ xfs_rmap_alloc(
10931173
return 0;
10941174

10951175
cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
1176+
xfs_rmap_update_hook(tp, pag, XFS_RMAP_MAP, bno, len, false, oinfo);
10961177
error = xfs_rmap_map(cur, bno, len, false, oinfo);
10971178

10981179
xfs_btree_del_cursor(cur, error);
@@ -2508,6 +2589,38 @@ xfs_rmap_finish_one_cleanup(
25082589
xfs_trans_brelse(tp, agbp);
25092590
}
25102591

2592+
/* Commit an rmap operation into the ondisk tree. */
2593+
int
2594+
__xfs_rmap_finish_intent(
2595+
struct xfs_btree_cur *rcur,
2596+
enum xfs_rmap_intent_type op,
2597+
xfs_agblock_t bno,
2598+
xfs_extlen_t len,
2599+
const struct xfs_owner_info *oinfo,
2600+
bool unwritten)
2601+
{
2602+
switch (op) {
2603+
case XFS_RMAP_ALLOC:
2604+
case XFS_RMAP_MAP:
2605+
return xfs_rmap_map(rcur, bno, len, unwritten, oinfo);
2606+
case XFS_RMAP_MAP_SHARED:
2607+
return xfs_rmap_map_shared(rcur, bno, len, unwritten, oinfo);
2608+
case XFS_RMAP_FREE:
2609+
case XFS_RMAP_UNMAP:
2610+
return xfs_rmap_unmap(rcur, bno, len, unwritten, oinfo);
2611+
case XFS_RMAP_UNMAP_SHARED:
2612+
return xfs_rmap_unmap_shared(rcur, bno, len, unwritten, oinfo);
2613+
case XFS_RMAP_CONVERT:
2614+
return xfs_rmap_convert(rcur, bno, len, !unwritten, oinfo);
2615+
case XFS_RMAP_CONVERT_SHARED:
2616+
return xfs_rmap_convert_shared(rcur, bno, len, !unwritten,
2617+
oinfo);
2618+
default:
2619+
ASSERT(0);
2620+
return -EFSCORRUPTED;
2621+
}
2622+
}
2623+
25112624
/*
25122625
* Process one of the deferred rmap operations. We pass back the
25132626
* btree cursor to maintain our lock on the rmapbt between calls.
@@ -2574,39 +2687,14 @@ xfs_rmap_finish_one(
25742687
unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
25752688
bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, ri->ri_bmap.br_startblock);
25762689

2577-
switch (ri->ri_type) {
2578-
case XFS_RMAP_ALLOC:
2579-
case XFS_RMAP_MAP:
2580-
error = xfs_rmap_map(rcur, bno, ri->ri_bmap.br_blockcount,
2581-
unwritten, &oinfo);
2582-
break;
2583-
case XFS_RMAP_MAP_SHARED:
2584-
error = xfs_rmap_map_shared(rcur, bno,
2585-
ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2586-
break;
2587-
case XFS_RMAP_FREE:
2588-
case XFS_RMAP_UNMAP:
2589-
error = xfs_rmap_unmap(rcur, bno, ri->ri_bmap.br_blockcount,
2590-
unwritten, &oinfo);
2591-
break;
2592-
case XFS_RMAP_UNMAP_SHARED:
2593-
error = xfs_rmap_unmap_shared(rcur, bno,
2594-
ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2595-
break;
2596-
case XFS_RMAP_CONVERT:
2597-
error = xfs_rmap_convert(rcur, bno, ri->ri_bmap.br_blockcount,
2598-
!unwritten, &oinfo);
2599-
break;
2600-
case XFS_RMAP_CONVERT_SHARED:
2601-
error = xfs_rmap_convert_shared(rcur, bno,
2602-
ri->ri_bmap.br_blockcount, !unwritten, &oinfo);
2603-
break;
2604-
default:
2605-
ASSERT(0);
2606-
error = -EFSCORRUPTED;
2607-
}
2690+
error = __xfs_rmap_finish_intent(rcur, ri->ri_type, bno,
2691+
ri->ri_bmap.br_blockcount, &oinfo, unwritten);
2692+
if (error)
2693+
return error;
26082694

2609-
return error;
2695+
xfs_rmap_update_hook(tp, ri->ri_pag, ri->ri_type, bno,
2696+
ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2697+
return 0;
26102698
}
26112699

26122700
/*

fs/xfs/libxfs/xfs_rmap.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp,
186186
struct xfs_btree_cur *rcur, int error);
187187
int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
188188
struct xfs_btree_cur **pcur);
189+
int __xfs_rmap_finish_intent(struct xfs_btree_cur *rcur,
190+
enum xfs_rmap_intent_type op, xfs_agblock_t bno,
191+
xfs_extlen_t len, const struct xfs_owner_info *oinfo,
192+
bool unwritten);
189193

190194
int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno,
191195
uint64_t owner, uint64_t offset, unsigned int flags,
@@ -235,4 +239,29 @@ extern struct kmem_cache *xfs_rmap_intent_cache;
235239
int __init xfs_rmap_intent_init_cache(void);
236240
void xfs_rmap_intent_destroy_cache(void);
237241

242+
/*
243+
* Parameters for tracking reverse mapping changes. The hook function arg
244+
* parameter is enum xfs_rmap_intent_type, and the rest is below.
245+
*/
246+
struct xfs_rmap_update_params {
247+
xfs_agblock_t startblock;
248+
xfs_extlen_t blockcount;
249+
struct xfs_owner_info oinfo;
250+
bool unwritten;
251+
};
252+
253+
#ifdef CONFIG_XFS_LIVE_HOOKS
254+
255+
struct xfs_rmap_hook {
256+
struct xfs_hook rmap_hook;
257+
};
258+
259+
void xfs_rmap_hook_disable(void);
260+
void xfs_rmap_hook_enable(void);
261+
262+
int xfs_rmap_hook_add(struct xfs_perag *pag, struct xfs_rmap_hook *hook);
263+
void xfs_rmap_hook_del(struct xfs_perag *pag, struct xfs_rmap_hook *hook);
264+
void xfs_rmap_hook_setup(struct xfs_rmap_hook *hook, notifier_fn_t mod_fn);
265+
#endif
266+
238267
#endif /* __XFS_RMAP_H__ */

fs/xfs/scrub/common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,9 @@ xchk_fsgates_enable(
13091309
if (scrub_fsgates & XCHK_FSGATES_DIRENTS)
13101310
xfs_dir_hook_enable();
13111311

1312+
if (scrub_fsgates & XCHK_FSGATES_RMAP)
1313+
xfs_rmap_hook_enable();
1314+
13121315
sc->flags |= scrub_fsgates;
13131316
}
13141317

fs/xfs/scrub/repair.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,3 +1165,39 @@ xrep_setup_xfbtree(
11651165

11661166
return xmbuf_alloc(sc->mp, descr, &sc->xmbtp);
11671167
}
1168+
1169+
/*
1170+
* Create a dummy transaction for use in a live update hook function. This
1171+
* function MUST NOT be called from regular repair code because the current
1172+
* process' transaction is saved via the cookie.
1173+
*/
1174+
int
1175+
xrep_trans_alloc_hook_dummy(
1176+
struct xfs_mount *mp,
1177+
void **cookiep,
1178+
struct xfs_trans **tpp)
1179+
{
1180+
int error;
1181+
1182+
*cookiep = current->journal_info;
1183+
current->journal_info = NULL;
1184+
1185+
error = xfs_trans_alloc_empty(mp, tpp);
1186+
if (!error)
1187+
return 0;
1188+
1189+
current->journal_info = *cookiep;
1190+
*cookiep = NULL;
1191+
return error;
1192+
}
1193+
1194+
/* Cancel a dummy transaction used by a live update hook function. */
1195+
void
1196+
xrep_trans_cancel_hook_dummy(
1197+
void **cookiep,
1198+
struct xfs_trans *tp)
1199+
{
1200+
xfs_trans_cancel(tp);
1201+
current->journal_info = *cookiep;
1202+
*cookiep = NULL;
1203+
}

fs/xfs/scrub/repair.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ int xrep_quotacheck(struct xfs_scrub *sc);
140140
int xrep_reinit_pagf(struct xfs_scrub *sc);
141141
int xrep_reinit_pagi(struct xfs_scrub *sc);
142142

143+
int xrep_trans_alloc_hook_dummy(struct xfs_mount *mp, void **cookiep,
144+
struct xfs_trans **tpp);
145+
void xrep_trans_cancel_hook_dummy(void **cookiep, struct xfs_trans *tp);
146+
143147
#else
144148

145149
#define xrep_ino_dqattach(sc) (0)

0 commit comments

Comments
 (0)