Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+122 -78
+28 -47
fs/xfs/libxfs/xfs_ag.c
··· 185 185 } 186 186 187 187 /* 188 - * Free up the per-ag resources associated with the mount structure. 188 + * Free up the per-ag resources within the specified AG range. 189 189 */ 190 190 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 + 193 196 { 194 - struct xfs_perag *pag; 195 197 xfs_agnumber_t agno; 196 198 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 + 199 202 ASSERT(pag); 200 203 XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0); 201 204 xfs_defer_drain_free(&pag->pag_intents_drain); ··· 273 270 return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last); 274 271 } 275 272 276 - /* 277 - * Free perag within the specified AG range, it is only used to free unused 278 - * perags under the error handling path. 279 - */ 280 - void 281 - xfs_free_unused_perag_range( 273 + int 274 + xfs_update_last_ag_size( 282 275 struct xfs_mount *mp, 283 - xfs_agnumber_t agstart, 284 - xfs_agnumber_t agend) 276 + xfs_agnumber_t prev_agcount) 285 277 { 286 - struct xfs_perag *pag; 287 - xfs_agnumber_t index; 278 + struct xfs_perag *pag = xfs_perag_grab(mp, prev_agcount - 1); 288 279 289 - for (index = agstart; index < agend; index++) { 290 - pag = xa_erase(&mp->m_perags, index); 291 - if (!pag) 292 - break; 293 - xfs_buf_cache_destroy(&pag->pag_bcache); 294 - xfs_defer_drain_free(&pag->pag_intents_drain); 295 - kfree(pag); 296 - } 280 + if (!pag) 281 + return -EFSCORRUPTED; 282 + pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1, 283 + mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks); 284 + __xfs_agino_range(mp, pag->block_count, &pag->agino_min, 285 + &pag->agino_max); 286 + xfs_perag_rele(pag); 287 + return 0; 297 288 } 298 289 299 290 int 300 291 xfs_initialize_perag( 301 292 struct xfs_mount *mp, 302 - xfs_agnumber_t agcount, 293 + xfs_agnumber_t old_agcount, 294 + xfs_agnumber_t new_agcount, 303 295 xfs_rfsblock_t dblocks, 304 296 xfs_agnumber_t *maxagi) 305 297 { 306 298 struct xfs_perag *pag; 307 299 xfs_agnumber_t index; 308 - xfs_agnumber_t first_initialised = NULLAGNUMBER; 309 300 int error; 310 301 311 - /* 312 - * Walk the current per-ag tree so we don't try to initialise AGs 313 - * that already exist (growfs case). Allocate and insert all the 314 - * AGs we don't find ready for initialisation. 315 - */ 316 - for (index = 0; index < agcount; index++) { 317 - pag = xfs_perag_get(mp, index); 318 - if (pag) { 319 - xfs_perag_put(pag); 320 - continue; 321 - } 322 - 323 - pag = kzalloc(sizeof(*pag), GFP_KERNEL | __GFP_RETRY_MAYFAIL); 302 + for (index = old_agcount; index < new_agcount; index++) { 303 + pag = kzalloc(sizeof(*pag), GFP_KERNEL); 324 304 if (!pag) { 325 305 error = -ENOMEM; 326 306 goto out_unwind_new_pags; ··· 339 353 /* Active ref owned by mount indicates AG is online. */ 340 354 atomic_set(&pag->pag_active_ref, 1); 341 355 342 - /* first new pag is fully initialized */ 343 - if (first_initialised == NULLAGNUMBER) 344 - first_initialised = index; 345 - 346 356 /* 347 357 * Pre-calculated geometry 348 358 */ 349 - pag->block_count = __xfs_ag_block_count(mp, index, agcount, 359 + pag->block_count = __xfs_ag_block_count(mp, index, new_agcount, 350 360 dblocks); 351 361 pag->min_block = XFS_AGFL_BLOCK(mp); 352 362 __xfs_agino_range(mp, pag->block_count, &pag->agino_min, 353 363 &pag->agino_max); 354 364 } 355 365 356 - index = xfs_set_inode_alloc(mp, agcount); 366 + index = xfs_set_inode_alloc(mp, new_agcount); 357 367 358 368 if (maxagi) 359 369 *maxagi = index; ··· 363 381 out_free_pag: 364 382 kfree(pag); 365 383 out_unwind_new_pags: 366 - /* unwind any prior newly initialized pags */ 367 - xfs_free_unused_perag_range(mp, first_initialised, agcount); 384 + xfs_free_perag_range(mp, old_agcount, index); 368 385 return error; 369 386 } 370 387
+6 -5
fs/xfs/libxfs/xfs_ag.h
··· 144 144 __XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES) 145 145 __XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET) 146 146 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); 151 152 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); 153 154 154 155 /* Passive AG references */ 155 156 struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
+5 -3
fs/xfs/scrub/repair.c
··· 1084 1084 return error; 1085 1085 1086 1086 /* 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 + } 1090 1092 1091 1093 /* Clear the reflink flag since metadata never shares. */ 1092 1094 if (xfs_is_reflink_inode(sc->ip)) {
+70
fs/xfs/xfs_buf_item_recover.c
··· 22 22 #include "xfs_inode.h" 23 23 #include "xfs_dir2.h" 24 24 #include "xfs_quota.h" 25 + #include "xfs_alloc.h" 26 + #include "xfs_ag.h" 27 + #include "xfs_sb.h" 25 28 26 29 /* 27 30 * This is the number of entries in the l_buf_cancel_table used during ··· 688 685 } 689 686 690 687 /* 688 + * Update the in-memory superblock and perag structures from the primary SB 689 + * buffer. 690 + * 691 + * This is required because transactions running after growfs may require the 692 + * updated values to be set in a previous fully commit transaction. 693 + */ 694 + static int 695 + xlog_recover_do_primary_sb_buffer( 696 + struct xfs_mount *mp, 697 + struct xlog_recover_item *item, 698 + struct xfs_buf *bp, 699 + struct xfs_buf_log_format *buf_f, 700 + xfs_lsn_t current_lsn) 701 + { 702 + struct xfs_dsb *dsb = bp->b_addr; 703 + xfs_agnumber_t orig_agcount = mp->m_sb.sb_agcount; 704 + int error; 705 + 706 + xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn); 707 + 708 + if (orig_agcount == 0) { 709 + xfs_alert(mp, "Trying to grow file system without AGs"); 710 + return -EFSCORRUPTED; 711 + } 712 + 713 + /* 714 + * Update the in-core super block from the freshly recovered on-disk one. 715 + */ 716 + xfs_sb_from_disk(&mp->m_sb, dsb); 717 + 718 + if (mp->m_sb.sb_agcount < orig_agcount) { 719 + xfs_alert(mp, "Shrinking AG count in log recovery not supported"); 720 + return -EFSCORRUPTED; 721 + } 722 + 723 + /* 724 + * Growfs can also grow the last existing AG. In this case we also need 725 + * to update the length in the in-core perag structure and values 726 + * depending on it. 727 + */ 728 + error = xfs_update_last_ag_size(mp, orig_agcount); 729 + if (error) 730 + return error; 731 + 732 + /* 733 + * Initialize the new perags, and also update various block and inode 734 + * allocator setting based off the number of AGs or total blocks. 735 + * Because of the latter this also needs to happen if the agcount did 736 + * not change. 737 + */ 738 + error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount, 739 + mp->m_sb.sb_dblocks, &mp->m_maxagi); 740 + if (error) { 741 + xfs_warn(mp, "Failed recovery per-ag init: %d", error); 742 + return error; 743 + } 744 + mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); 745 + return 0; 746 + } 747 + 748 + /* 691 749 * V5 filesystems know the age of the buffer on disk being recovered. We can 692 750 * have newer objects on disk than we are replaying, and so for these cases we 693 751 * don't want to replay the current change as that will make the buffer contents ··· 1030 966 1031 967 dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); 1032 968 if (!dirty) 969 + goto out_release; 970 + } else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) && 971 + xfs_buf_daddr(bp) == 0) { 972 + error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f, 973 + current_lsn); 974 + if (error) 1033 975 goto out_release; 1034 976 } else { 1035 977 xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+9 -11
fs/xfs/xfs_fsops.c
··· 87 87 struct xfs_mount *mp, /* mount point for filesystem */ 88 88 struct xfs_growfs_data *in) /* growfs data input struct */ 89 89 { 90 + xfs_agnumber_t oagcount = mp->m_sb.sb_agcount; 90 91 struct xfs_buf *bp; 91 92 int error; 92 93 xfs_agnumber_t nagcount; ··· 95 94 xfs_rfsblock_t nb, nb_div, nb_mod; 96 95 int64_t delta; 97 96 bool lastag_extended = false; 98 - xfs_agnumber_t oagcount; 99 97 struct xfs_trans *tp; 100 98 struct aghdr_init_data id = {}; 101 99 struct xfs_perag *last_pag; ··· 138 138 if (delta == 0) 139 139 return 0; 140 140 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) 149 143 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; 151 149 152 150 if (delta > 0) 153 151 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, ··· 229 231 xfs_trans_cancel(tp); 230 232 out_free_unused_perag: 231 233 if (nagcount > oagcount) 232 - xfs_free_unused_perag_range(mp, oagcount, nagcount); 234 + xfs_free_perag_range(mp, oagcount, nagcount); 233 235 return error; 234 236 } 235 237
-7
fs/xfs/xfs_log_recover.c
··· 3393 3393 /* re-initialise in-core superblock and geometry structures */ 3394 3394 mp->m_features |= xfs_sb_version_to_features(sbp); 3395 3395 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); 3403 3396 3404 3397 /* Normal transactions can now occur */ 3405 3398 clear_bit(XLOG_ACTIVE_RECOVERY, &log->l_opstate);
+4 -5
fs/xfs/xfs_mount.c
··· 810 810 /* 811 811 * Allocate and initialize the per-ag data. 812 812 */ 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); 815 815 if (error) { 816 816 xfs_warn(mp, "Failed per-ag init: %d", error); 817 817 goto out_free_dir; ··· 1048 1048 xfs_buftarg_drain(mp->m_logdev_targp); 1049 1049 xfs_buftarg_drain(mp->m_ddev_targp); 1050 1050 out_free_perag: 1051 - xfs_free_perag(mp); 1051 + xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount); 1052 1052 out_free_dir: 1053 1053 xfs_da_unmount(mp); 1054 1054 out_remove_uuid: ··· 1129 1129 xfs_errortag_clearall(mp); 1130 1130 #endif 1131 1131 shrinker_free(mp->m_inodegc_shrinker); 1132 - xfs_free_perag(mp); 1133 - 1132 + xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount); 1134 1133 xfs_errortag_del(mp); 1135 1134 xfs_error_sysfs_del(mp); 1136 1135 xchk_stats_unregister(mp->m_scrub_stats);