Skip to content

Commit a8b3be2

Browse files
committed
Merge tag 'xfs-6.12-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Carlos Maiolino: - Fix recovery of allocator ops after a growfs - Do not fail repairs on metadata files with no attr fork * tag 'xfs-6.12-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: update the pag for the last AG at recovery time xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag xfs: error out when a superblock buffer update reduces the agcount xfs: update the file system geometry after recoverying superblock buffers xfs: merge the perag freeing helpers xfs: pass the exact range to initialize to xfs_initialize_perag xfs: don't fail repairs on metadata files with no attr fork
2 parents 850925a + 4a201dc commit a8b3be2

File tree

7 files changed

+122
-78
lines changed

7 files changed

+122
-78
lines changed

fs/xfs/libxfs/xfs_ag.c

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,20 @@ xfs_initialize_perag_data(
185185
}
186186

187187
/*
188-
* Free up the per-ag resources associated with the mount structure.
188+
* Free up the per-ag resources within the specified AG range.
189189
*/
190190
void
191-
xfs_free_perag(
192-
struct xfs_mount *mp)
191+
xfs_free_perag_range(
192+
struct xfs_mount *mp,
193+
xfs_agnumber_t first_agno,
194+
xfs_agnumber_t end_agno)
195+
193196
{
194-
struct xfs_perag *pag;
195197
xfs_agnumber_t agno;
196198

197-
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
198-
pag = xa_erase(&mp->m_perags, agno);
199+
for (agno = first_agno; agno < end_agno; agno++) {
200+
struct xfs_perag *pag = xa_erase(&mp->m_perags, agno);
201+
199202
ASSERT(pag);
200203
XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
201204
xfs_defer_drain_free(&pag->pag_intents_drain);
@@ -270,54 +273,37 @@ xfs_agino_range(
270273
return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
271274
}
272275

273-
/*
274-
* Free perag within the specified AG range, it is only used to free unused
275-
* perags under the error handling path.
276-
*/
277-
void
278-
xfs_free_unused_perag_range(
276+
int
277+
xfs_update_last_ag_size(
279278
struct xfs_mount *mp,
280-
xfs_agnumber_t agstart,
281-
xfs_agnumber_t agend)
279+
xfs_agnumber_t prev_agcount)
282280
{
283-
struct xfs_perag *pag;
284-
xfs_agnumber_t index;
281+
struct xfs_perag *pag = xfs_perag_grab(mp, prev_agcount - 1);
285282

286-
for (index = agstart; index < agend; index++) {
287-
pag = xa_erase(&mp->m_perags, index);
288-
if (!pag)
289-
break;
290-
xfs_buf_cache_destroy(&pag->pag_bcache);
291-
xfs_defer_drain_free(&pag->pag_intents_drain);
292-
kfree(pag);
293-
}
283+
if (!pag)
284+
return -EFSCORRUPTED;
285+
pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1,
286+
mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks);
287+
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
288+
&pag->agino_max);
289+
xfs_perag_rele(pag);
290+
return 0;
294291
}
295292

296293
int
297294
xfs_initialize_perag(
298295
struct xfs_mount *mp,
299-
xfs_agnumber_t agcount,
296+
xfs_agnumber_t old_agcount,
297+
xfs_agnumber_t new_agcount,
300298
xfs_rfsblock_t dblocks,
301299
xfs_agnumber_t *maxagi)
302300
{
303301
struct xfs_perag *pag;
304302
xfs_agnumber_t index;
305-
xfs_agnumber_t first_initialised = NULLAGNUMBER;
306303
int error;
307304

308-
/*
309-
* Walk the current per-ag tree so we don't try to initialise AGs
310-
* that already exist (growfs case). Allocate and insert all the
311-
* AGs we don't find ready for initialisation.
312-
*/
313-
for (index = 0; index < agcount; index++) {
314-
pag = xfs_perag_get(mp, index);
315-
if (pag) {
316-
xfs_perag_put(pag);
317-
continue;
318-
}
319-
320-
pag = kzalloc(sizeof(*pag), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
305+
for (index = old_agcount; index < new_agcount; index++) {
306+
pag = kzalloc(sizeof(*pag), GFP_KERNEL);
321307
if (!pag) {
322308
error = -ENOMEM;
323309
goto out_unwind_new_pags;
@@ -353,21 +339,17 @@ xfs_initialize_perag(
353339
/* Active ref owned by mount indicates AG is online. */
354340
atomic_set(&pag->pag_active_ref, 1);
355341

356-
/* first new pag is fully initialized */
357-
if (first_initialised == NULLAGNUMBER)
358-
first_initialised = index;
359-
360342
/*
361343
* Pre-calculated geometry
362344
*/
363-
pag->block_count = __xfs_ag_block_count(mp, index, agcount,
345+
pag->block_count = __xfs_ag_block_count(mp, index, new_agcount,
364346
dblocks);
365347
pag->min_block = XFS_AGFL_BLOCK(mp);
366348
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
367349
&pag->agino_max);
368350
}
369351

370-
index = xfs_set_inode_alloc(mp, agcount);
352+
index = xfs_set_inode_alloc(mp, new_agcount);
371353

372354
if (maxagi)
373355
*maxagi = index;
@@ -381,8 +363,7 @@ xfs_initialize_perag(
381363
out_free_pag:
382364
kfree(pag);
383365
out_unwind_new_pags:
384-
/* unwind any prior newly initialized pags */
385-
xfs_free_unused_perag_range(mp, first_initialised, agcount);
366+
xfs_free_perag_range(mp, old_agcount, index);
386367
return error;
387368
}
388369

fs/xfs/libxfs/xfs_ag.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,13 @@ __XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
144144
__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
145145
__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
146146

147-
void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
148-
xfs_agnumber_t agend);
149-
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
150-
xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
147+
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
148+
xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
149+
xfs_agnumber_t *maxagi);
150+
void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
151+
xfs_agnumber_t end_agno);
151152
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
152-
void xfs_free_perag(struct xfs_mount *mp);
153+
int xfs_update_last_ag_size(struct xfs_mount *mp, xfs_agnumber_t prev_agcount);
153154

154155
/* Passive AG references */
155156
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);

fs/xfs/scrub/repair.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,11 @@ xrep_metadata_inode_forks(
10841084
return error;
10851085

10861086
/* Make sure the attr fork looks ok before we delete it. */
1087-
error = xrep_metadata_inode_subtype(sc, XFS_SCRUB_TYPE_BMBTA);
1088-
if (error)
1089-
return error;
1087+
if (xfs_inode_hasattr(sc->ip)) {
1088+
error = xrep_metadata_inode_subtype(sc, XFS_SCRUB_TYPE_BMBTA);
1089+
if (error)
1090+
return error;
1091+
}
10901092

10911093
/* Clear the reflink flag since metadata never shares. */
10921094
if (xfs_is_reflink_inode(sc->ip)) {

fs/xfs/xfs_buf_item_recover.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "xfs_inode.h"
2323
#include "xfs_dir2.h"
2424
#include "xfs_quota.h"
25+
#include "xfs_alloc.h"
26+
#include "xfs_ag.h"
27+
#include "xfs_sb.h"
2528

2629
/*
2730
* This is the number of entries in the l_buf_cancel_table used during
@@ -684,6 +687,67 @@ xlog_recover_do_inode_buffer(
684687
return 0;
685688
}
686689

690+
/*
691+
* Update the in-memory superblock and perag structures from the primary SB
692+
* buffer.
693+
*
694+
* This is required because transactions running after growfs may require the
695+
* updated values to be set in a previous fully commit transaction.
696+
*/
697+
static int
698+
xlog_recover_do_primary_sb_buffer(
699+
struct xfs_mount *mp,
700+
struct xlog_recover_item *item,
701+
struct xfs_buf *bp,
702+
struct xfs_buf_log_format *buf_f,
703+
xfs_lsn_t current_lsn)
704+
{
705+
struct xfs_dsb *dsb = bp->b_addr;
706+
xfs_agnumber_t orig_agcount = mp->m_sb.sb_agcount;
707+
int error;
708+
709+
xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
710+
711+
if (orig_agcount == 0) {
712+
xfs_alert(mp, "Trying to grow file system without AGs");
713+
return -EFSCORRUPTED;
714+
}
715+
716+
/*
717+
* Update the in-core super block from the freshly recovered on-disk one.
718+
*/
719+
xfs_sb_from_disk(&mp->m_sb, dsb);
720+
721+
if (mp->m_sb.sb_agcount < orig_agcount) {
722+
xfs_alert(mp, "Shrinking AG count in log recovery not supported");
723+
return -EFSCORRUPTED;
724+
}
725+
726+
/*
727+
* Growfs can also grow the last existing AG. In this case we also need
728+
* to update the length in the in-core perag structure and values
729+
* depending on it.
730+
*/
731+
error = xfs_update_last_ag_size(mp, orig_agcount);
732+
if (error)
733+
return error;
734+
735+
/*
736+
* Initialize the new perags, and also update various block and inode
737+
* allocator setting based off the number of AGs or total blocks.
738+
* Because of the latter this also needs to happen if the agcount did
739+
* not change.
740+
*/
741+
error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount,
742+
mp->m_sb.sb_dblocks, &mp->m_maxagi);
743+
if (error) {
744+
xfs_warn(mp, "Failed recovery per-ag init: %d", error);
745+
return error;
746+
}
747+
mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
748+
return 0;
749+
}
750+
687751
/*
688752
* V5 filesystems know the age of the buffer on disk being recovered. We can
689753
* have newer objects on disk than we are replaying, and so for these cases we
@@ -967,6 +1031,12 @@ xlog_recover_buf_commit_pass2(
9671031
dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
9681032
if (!dirty)
9691033
goto out_release;
1034+
} else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) &&
1035+
xfs_buf_daddr(bp) == 0) {
1036+
error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
1037+
current_lsn);
1038+
if (error)
1039+
goto out_release;
9701040
} else {
9711041
xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
9721042
}

fs/xfs/xfs_fsops.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,14 @@ xfs_growfs_data_private(
8787
struct xfs_mount *mp, /* mount point for filesystem */
8888
struct xfs_growfs_data *in) /* growfs data input struct */
8989
{
90+
xfs_agnumber_t oagcount = mp->m_sb.sb_agcount;
9091
struct xfs_buf *bp;
9192
int error;
9293
xfs_agnumber_t nagcount;
9394
xfs_agnumber_t nagimax = 0;
9495
xfs_rfsblock_t nb, nb_div, nb_mod;
9596
int64_t delta;
9697
bool lastag_extended = false;
97-
xfs_agnumber_t oagcount;
9898
struct xfs_trans *tp;
9999
struct aghdr_init_data id = {};
100100
struct xfs_perag *last_pag;
@@ -138,16 +138,14 @@ xfs_growfs_data_private(
138138
if (delta == 0)
139139
return 0;
140140

141-
oagcount = mp->m_sb.sb_agcount;
142-
/* allocate the new per-ag structures */
143-
if (nagcount > oagcount) {
144-
error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
145-
if (error)
146-
return error;
147-
} else if (nagcount < oagcount) {
148-
/* TODO: shrinking the entire AGs hasn't yet completed */
141+
/* TODO: shrinking the entire AGs hasn't yet completed */
142+
if (nagcount < oagcount)
149143
return -EINVAL;
150-
}
144+
145+
/* allocate the new per-ag structures */
146+
error = xfs_initialize_perag(mp, oagcount, nagcount, nb, &nagimax);
147+
if (error)
148+
return error;
151149

152150
if (delta > 0)
153151
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
@@ -231,7 +229,7 @@ xfs_growfs_data_private(
231229
xfs_trans_cancel(tp);
232230
out_free_unused_perag:
233231
if (nagcount > oagcount)
234-
xfs_free_unused_perag_range(mp, oagcount, nagcount);
232+
xfs_free_perag_range(mp, oagcount, nagcount);
235233
return error;
236234
}
237235

fs/xfs/xfs_log_recover.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3393,13 +3393,6 @@ xlog_do_recover(
33933393
/* re-initialise in-core superblock and geometry structures */
33943394
mp->m_features |= xfs_sb_version_to_features(sbp);
33953395
xfs_reinit_percpu_counters(mp);
3396-
error = xfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
3397-
&mp->m_maxagi);
3398-
if (error) {
3399-
xfs_warn(mp, "Failed post-recovery per-ag init: %d", error);
3400-
return error;
3401-
}
3402-
mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
34033396

34043397
/* Normal transactions can now occur */
34053398
clear_bit(XLOG_ACTIVE_RECOVERY, &log->l_opstate);

fs/xfs/xfs_mount.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -810,8 +810,8 @@ xfs_mountfs(
810810
/*
811811
* Allocate and initialize the per-ag data.
812812
*/
813-
error = xfs_initialize_perag(mp, sbp->sb_agcount, mp->m_sb.sb_dblocks,
814-
&mp->m_maxagi);
813+
error = xfs_initialize_perag(mp, 0, sbp->sb_agcount,
814+
mp->m_sb.sb_dblocks, &mp->m_maxagi);
815815
if (error) {
816816
xfs_warn(mp, "Failed per-ag init: %d", error);
817817
goto out_free_dir;
@@ -1048,7 +1048,7 @@ xfs_mountfs(
10481048
xfs_buftarg_drain(mp->m_logdev_targp);
10491049
xfs_buftarg_drain(mp->m_ddev_targp);
10501050
out_free_perag:
1051-
xfs_free_perag(mp);
1051+
xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount);
10521052
out_free_dir:
10531053
xfs_da_unmount(mp);
10541054
out_remove_uuid:
@@ -1129,8 +1129,7 @@ xfs_unmountfs(
11291129
xfs_errortag_clearall(mp);
11301130
#endif
11311131
shrinker_free(mp->m_inodegc_shrinker);
1132-
xfs_free_perag(mp);
1133-
1132+
xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount);
11341133
xfs_errortag_del(mp);
11351134
xfs_error_sysfs_del(mp);
11361135
xchk_stats_unregister(mp->m_scrub_stats);

0 commit comments

Comments
 (0)