Skip to content

Commit d2b6f8a

Browse files
committed
Merge tag 'xfs-5.13-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs updates from Darrick Wong: "The notable user-visible addition this cycle is ability to remove space from the last AG in a filesystem. This is the first of many changes needed for full-fledged support for shrinking a filesystem. Still needed are (a) the ability to reorganize files and metadata away from the end of the fs; (b) the ability to remove entire allocation groups; (c) shrink support for realtime volumes; and (d) thorough testing of (a-c). There are a number of performance improvements in this code drop: Dave streamlined various parts of the buffer logging code and reduced the cost of various debugging checks, and added the ability to pre-create the xattr structures while creating files. Brian eliminated transaction reservations that were being held across writeback (thus reducing livelock potential. Other random pieces: Pavel fixed the repetitve warnings about deprecated mount options, I fixed online fsck to behave itself when a readonly remount comes in during scrub, and refactored various other parts of that code, Christoph contributed a lot of refactoring this cycle. The xfs_icdinode structure has been absorbed into the (incore) xfs_inode structure, and the format and flags handling around xfs_inode_fork structures has been simplified. Chandan provided a number of fixes for extent count overflow related problems that have been shaken out by debugging knobs added during 5.12. Summary: - Various minor fixes in online scrub. - Prevent metadata files from being automatically inactivated. - Validate btree heights by the computed per-btree limits. - Don't warn about remounting with deprecated mount options. - Initialize attr forks at create time if we suspect we're going to need to store them. - Reduce memory reallocation workouts in the logging code. - Fix some theoretical math calculation errors in logged buffers that span multiple discontig memory ranges but contiguous ondisk regions. - Speedups in dirty buffer bitmap handling. - Make type verifier functions more inline-happy to reduce overhead. - Reduce debug overhead in directory checking code. - Many many typo fixes. - Begin to handle the permanent loss of the very end of a filesystem. - Fold struct xfs_icdinode into xfs_inode. - Deprecate the long defunct BMV_IF_NO_DMAPI_READ from the bmapx ioctl. - Remove a broken directory block format check from online scrub. - Fix a bug where we could produce an unnecessarily tall data fork btree when creating an attr fork. - Fix scrub and readonly remounts racing. - Fix a writeback ioend log deadlock problem by dropping the behavior where we could preallocate a setfilesize transaction. - Fix some bugs in the new extent count checking code. - Fix some bugs in the attr fork preallocation code. - Refactor if_flags out of the incore inode fork data structure" * tag 'xfs-5.13-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (77 commits) xfs: remove xfs_quiesce_attr declaration xfs: remove XFS_IFEXTENTS xfs: remove XFS_IFINLINE xfs: remove XFS_IFBROOT xfs: only look at the fork format in xfs_idestroy_fork xfs: simplify xfs_attr_remove_args xfs: rename and simplify xfs_bmap_one_block xfs: move the XFS_IFEXTENTS check into xfs_iread_extents xfs: drop unnecessary setfilesize helper xfs: drop unused ioend private merge and setfilesize code xfs: open code ioend needs workqueue helper xfs: drop submit side trans alloc for append ioends xfs: fix return of uninitialized value in variable error xfs: get rid of the ip parameter to xchk_setup_* xfs: fix scrub and remount-ro protection when running scrub xfs: move the check for post-EOF mappings into xfs_can_free_eofblocks xfs: move the xfs_can_free_eofblocks call under the IOLOCK xfs: precalculate default inode attribute offset xfs: default attr fork size does not handle device inodes xfs: inode fork allocation depends on XFS_IFEXTENT flag ...
2 parents f2c8083 + 76adf92 commit d2b6f8a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1459
-1303
lines changed

Documentation/admin-guide/xfs.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ and the short name of the data device. They all can be found in:
522522
================ ===========
523523
xfs_iwalk-$pid Inode scans of the entire filesystem. Currently limited to
524524
mount time quotacheck.
525-
xfs-blockgc Background garbage collection of disk space that have been
525+
xfs-gc Background garbage collection of disk space that have been
526526
speculatively allocated beyond EOF or for staging copy on
527527
write operations.
528528
================ ===========

fs/xfs/libxfs/xfs_ag.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include "xfs_ag.h"
2323
#include "xfs_ag_resv.h"
2424
#include "xfs_health.h"
25+
#include "xfs_error.h"
26+
#include "xfs_bmap.h"
27+
#include "xfs_defer.h"
28+
#include "xfs_log_format.h"
29+
#include "xfs_trans.h"
2530

2631
static int
2732
xfs_get_aghdr_buf(
@@ -485,6 +490,116 @@ xfs_ag_init_headers(
485490
return error;
486491
}
487492

493+
int
494+
xfs_ag_shrink_space(
495+
struct xfs_mount *mp,
496+
struct xfs_trans **tpp,
497+
xfs_agnumber_t agno,
498+
xfs_extlen_t delta)
499+
{
500+
struct xfs_alloc_arg args = {
501+
.tp = *tpp,
502+
.mp = mp,
503+
.type = XFS_ALLOCTYPE_THIS_BNO,
504+
.minlen = delta,
505+
.maxlen = delta,
506+
.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE,
507+
.resv = XFS_AG_RESV_NONE,
508+
.prod = 1
509+
};
510+
struct xfs_buf *agibp, *agfbp;
511+
struct xfs_agi *agi;
512+
struct xfs_agf *agf;
513+
int error, err2;
514+
515+
ASSERT(agno == mp->m_sb.sb_agcount - 1);
516+
error = xfs_ialloc_read_agi(mp, *tpp, agno, &agibp);
517+
if (error)
518+
return error;
519+
520+
agi = agibp->b_addr;
521+
522+
error = xfs_alloc_read_agf(mp, *tpp, agno, 0, &agfbp);
523+
if (error)
524+
return error;
525+
526+
agf = agfbp->b_addr;
527+
/* some extra paranoid checks before we shrink the ag */
528+
if (XFS_IS_CORRUPT(mp, agf->agf_length != agi->agi_length))
529+
return -EFSCORRUPTED;
530+
if (delta >= agi->agi_length)
531+
return -EINVAL;
532+
533+
args.fsbno = XFS_AGB_TO_FSB(mp, agno,
534+
be32_to_cpu(agi->agi_length) - delta);
535+
536+
/*
537+
* Disable perag reservations so it doesn't cause the allocation request
538+
* to fail. We'll reestablish reservation before we return.
539+
*/
540+
error = xfs_ag_resv_free(agibp->b_pag);
541+
if (error)
542+
return error;
543+
544+
/* internal log shouldn't also show up in the free space btrees */
545+
error = xfs_alloc_vextent(&args);
546+
if (!error && args.agbno == NULLAGBLOCK)
547+
error = -ENOSPC;
548+
549+
if (error) {
550+
/*
551+
* if extent allocation fails, need to roll the transaction to
552+
* ensure that the AGFL fixup has been committed anyway.
553+
*/
554+
xfs_trans_bhold(*tpp, agfbp);
555+
err2 = xfs_trans_roll(tpp);
556+
if (err2)
557+
return err2;
558+
xfs_trans_bjoin(*tpp, agfbp);
559+
goto resv_init_out;
560+
}
561+
562+
/*
563+
* if successfully deleted from freespace btrees, need to confirm
564+
* per-AG reservation works as expected.
565+
*/
566+
be32_add_cpu(&agi->agi_length, -delta);
567+
be32_add_cpu(&agf->agf_length, -delta);
568+
569+
err2 = xfs_ag_resv_init(agibp->b_pag, *tpp);
570+
if (err2) {
571+
be32_add_cpu(&agi->agi_length, delta);
572+
be32_add_cpu(&agf->agf_length, delta);
573+
if (err2 != -ENOSPC)
574+
goto resv_err;
575+
576+
__xfs_bmap_add_free(*tpp, args.fsbno, delta, NULL, true);
577+
578+
/*
579+
* Roll the transaction before trying to re-init the per-ag
580+
* reservation. The new transaction is clean so it will cancel
581+
* without any side effects.
582+
*/
583+
error = xfs_defer_finish(tpp);
584+
if (error)
585+
return error;
586+
587+
error = -ENOSPC;
588+
goto resv_init_out;
589+
}
590+
xfs_ialloc_log_agi(*tpp, agibp, XFS_AGI_LENGTH);
591+
xfs_alloc_log_agf(*tpp, agfbp, XFS_AGF_LENGTH);
592+
return 0;
593+
resv_init_out:
594+
err2 = xfs_ag_resv_init(agibp->b_pag, *tpp);
595+
if (!err2)
596+
return error;
597+
resv_err:
598+
xfs_warn(mp, "Error %d reserving per-AG metadata reserve pool.", err2);
599+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
600+
return err2;
601+
}
602+
488603
/*
489604
* Extent the AG indicated by the @id by the length passed in
490605
*/

fs/xfs/libxfs/xfs_ag.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ struct aghdr_init_data {
2424
};
2525

2626
int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id);
27+
int xfs_ag_shrink_space(struct xfs_mount *mp, struct xfs_trans **tpp,
28+
xfs_agnumber_t agno, xfs_extlen_t delta);
2729
int xfs_ag_extend_space(struct xfs_mount *mp, struct xfs_trans *tp,
2830
struct aghdr_init_data *id, xfs_extlen_t len);
2931
int xfs_ag_get_geometry(struct xfs_mount *mp, xfs_agnumber_t agno,

fs/xfs/libxfs/xfs_ag_resv.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,11 @@ __xfs_ag_resv_init(
211211
ASSERT(0);
212212
return -EINVAL;
213213
}
214-
error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true);
214+
215+
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_AG_RESV_FAIL))
216+
error = -ENOSPC;
217+
else
218+
error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true);
215219
if (error) {
216220
trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno,
217221
error, _RET_IP_);

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2906,13 +2906,13 @@ xfs_agf_verify(
29062906

29072907
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
29082908
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) < 1 ||
2909-
be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
2910-
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
2909+
be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > mp->m_ag_maxlevels ||
2910+
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > mp->m_ag_maxlevels)
29112911
return __this_address;
29122912

29132913
if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&
29142914
(be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) < 1 ||
2915-
be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS))
2915+
be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > mp->m_rmap_maxlevels))
29162916
return __this_address;
29172917

29182918
if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&
@@ -2939,7 +2939,7 @@ xfs_agf_verify(
29392939

29402940
if (xfs_sb_version_hasreflink(&mp->m_sb) &&
29412941
(be32_to_cpu(agf->agf_refcount_level) < 1 ||
2942-
be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS))
2942+
be32_to_cpu(agf->agf_refcount_level) > mp->m_refc_maxlevels))
29432943
return __this_address;
29442944

29452945
return NULL;

fs/xfs/libxfs/xfs_attr.c

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,26 @@ xfs_inode_hasattr(
7070
return 1;
7171
}
7272

73+
/*
74+
* Returns true if the there is exactly only block in the attr fork, in which
75+
* case the attribute fork consists of a single leaf block entry.
76+
*/
77+
bool
78+
xfs_attr_is_leaf(
79+
struct xfs_inode *ip)
80+
{
81+
struct xfs_ifork *ifp = ip->i_afp;
82+
struct xfs_iext_cursor icur;
83+
struct xfs_bmbt_irec imap;
84+
85+
if (ifp->if_nextents != 1 || ifp->if_format != XFS_DINODE_FMT_EXTENTS)
86+
return false;
87+
88+
xfs_iext_first(ifp, &icur);
89+
xfs_iext_get_extent(ifp, &icur, &imap);
90+
return imap.br_startoff == 0 && imap.br_blockcount == 1;
91+
}
92+
7393
/*========================================================================
7494
* Overall external interface routines.
7595
*========================================================================*/
@@ -89,7 +109,7 @@ xfs_attr_get_ilocked(
89109

90110
if (args->dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL)
91111
return xfs_attr_shortform_getvalue(args);
92-
if (xfs_bmap_one_block(args->dp, XFS_ATTR_FORK))
112+
if (xfs_attr_is_leaf(args->dp))
93113
return xfs_attr_leaf_get(args);
94114
return xfs_attr_node_get(args);
95115
}
@@ -293,7 +313,7 @@ xfs_attr_set_args(
293313
return error;
294314
}
295315

296-
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
316+
if (xfs_attr_is_leaf(dp)) {
297317
error = xfs_attr_leaf_addname(args);
298318
if (error != -ENOSPC)
299319
return error;
@@ -342,12 +362,10 @@ xfs_has_attr(
342362
if (!xfs_inode_hasattr(dp))
343363
return -ENOATTR;
344364

345-
if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) {
346-
ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
365+
if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL)
347366
return xfs_attr_sf_findname(args, NULL, NULL);
348-
}
349367

350-
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
368+
if (xfs_attr_is_leaf(dp)) {
351369
error = xfs_attr_leaf_hasname(args, &bp);
352370

353371
if (bp)
@@ -366,21 +384,14 @@ int
366384
xfs_attr_remove_args(
367385
struct xfs_da_args *args)
368386
{
369-
struct xfs_inode *dp = args->dp;
370-
int error;
371-
372-
if (!xfs_inode_hasattr(dp)) {
373-
error = -ENOATTR;
374-
} else if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) {
375-
ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
376-
error = xfs_attr_shortform_remove(args);
377-
} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
378-
error = xfs_attr_leaf_removename(args);
379-
} else {
380-
error = xfs_attr_node_removename(args);
381-
}
387+
if (!xfs_inode_hasattr(args->dp))
388+
return -ENOATTR;
382389

383-
return error;
390+
if (args->dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL)
391+
return xfs_attr_shortform_remove(args);
392+
if (xfs_attr_is_leaf(args->dp))
393+
return xfs_attr_leaf_removename(args);
394+
return xfs_attr_node_removename(args);
384395
}
385396

386397
/*
@@ -928,6 +939,7 @@ xfs_attr_node_addname(
928939
* Search to see if name already exists, and get back a pointer
929940
* to where it should go.
930941
*/
942+
error = 0;
931943
retval = xfs_attr_node_hasname(args, &state);
932944
if (retval != -ENOATTR && retval != -EEXIST)
933945
goto out;
@@ -1282,7 +1294,7 @@ xfs_attr_node_removename(
12821294
/*
12831295
* If the result is small enough, push it all into the inode.
12841296
*/
1285-
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
1297+
if (xfs_attr_is_leaf(dp))
12861298
error = xfs_attr_node_shrink(args, state);
12871299

12881300
out:

fs/xfs/libxfs/xfs_attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ int xfs_attr_inactive(struct xfs_inode *dp);
8585
int xfs_attr_list_ilocked(struct xfs_attr_list_context *);
8686
int xfs_attr_list(struct xfs_attr_list_context *);
8787
int xfs_inode_hasattr(struct xfs_inode *ip);
88+
bool xfs_attr_is_leaf(struct xfs_inode *ip);
8889
int xfs_attr_get_ilocked(struct xfs_da_args *args);
8990
int xfs_attr_get(struct xfs_da_args *args);
9091
int xfs_attr_set(struct xfs_da_args *args);

0 commit comments

Comments
 (0)