Skip to content

RFC xfs: per-ag centric allocation alogrithms

Dave Chinner linux-xfs llvm 1 version In review

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 RFC Latest50 patches 13 repliesIn review

Patches in v1 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/50xfs: make last AG grow/shrink perag centricfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag.h fs/xfs/xfs_fsops.c +1 more+37 -411 reply
2/50xfs: kill xfs_ialloc_pagi_init()fs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc.h+16 -361 reply
3/50xfs: pass perag to xfs_ialloc_read_agi()fs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc.h +4 more+32 -361 reply
4/50xfs: kill xfs_alloc_pagf_init()fs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag_resv.c fs/xfs/libxfs/xfs_alloc.c +4 more+19 -411 reply
5/50xfs: pass perag to xfs_alloc_read_agf()fs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag_resv.c fs/xfs/libxfs/xfs_alloc.c +17 more+68 -811 reply
6/50xfs: pass perag to xfs_read_agifs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc.h fs/xfs/xfs_inode.c +1 more+40 -432 replies
7/50xfs: pass perag to xfs_read_agffs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h+14 -161 reply
8/50xfs: pass perag to xfs_alloc_get_freelistfs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_alloc_btree.c +2 more+13 -221 reply
9/50xfs: pass perag to xfs_alloc_put_freelistfs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_alloc_btree.c +2 more+10 -181 reply
10/50xfs: pass perag to xfs_alloc_read_agflfs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/scrub/agheader_repair.c +1 more+20 -191 reply
11/50xfs: Pre-calculate per-AG agbno geometryfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_alloc.c +14 more+115 -820 replies
12/50xfs: Pre-calculate per-AG agino geometryfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_ialloc.c +8 more+104 -790 replies
13/50xfs: replace xfs_ag_block_count() with perag accessesfs/xfs/libxfs/xfs_ialloc_btree.c fs/xfs/scrub/agheader_repair.c fs/xfs/scrub/repair.c+11 -130 replies
14/50xfs: make is_log_ag() a first class helperfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_ialloc.c +5 more+18 -170 replies
15/50xfs: active perag reference countingfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ag.h fs/xfs/scrub/bmap.c +6 more+107 -210 replies
16/50xfs: rework the perag trace points to be perag centricfs/xfs/libxfs/xfs_ag.c fs/xfs/xfs_icache.c fs/xfs/xfs_trace.h+22 -280 replies
17/50xfs: convert xfs_imap() to take a peragfs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc.h fs/xfs/scrub/common.c +2 more+32 -380 replies
18/50xfs: use active perag references for inode allocationfs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc.h+33 -340 replies
19/50xfs: inobt can use perags in many more places than it doesfs/xfs/libxfs/xfs_ag_resv.c fs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_ialloc_btree.c +4 more+47 -560 replies
20/50xfs: convert xfs_ialloc_next_ag() to an atomicfs/xfs/libxfs/xfs_ialloc.c fs/xfs/libxfs/xfs_sb.c fs/xfs/xfs_mount.h +1 more+4 -200 replies
21/50xfs: perags need atomic operational statefs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc_btree.c +10 more+101 -650 replies
22/50xfs: introduce xfs_for_each_perag_wrap()fs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_bmap.c fs/xfs/libxfs/xfs_ialloc.c+104 -490 replies
23/50xfs: rework xfs_alloc_vextent()fs/xfs/libxfs/xfs_alloc.c+255 -1430 replies
24/50xfs: use xfs_alloc_vextent_this_ag() in _iterate_ags()fs/xfs/libxfs/xfs_alloc.c+28 -290 replies
25/50xfs: combine __xfs_alloc_vextent_this_ag and xfs_alloc_ag_vextentfs/xfs/libxfs/xfs_alloc.c+35 -300 replies
26/50xfs: use xfs_alloc_vextent_this_ag() where appropriatefs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h +6 more+98 -630 replies
27/50xfs: factor xfs_bmap_btalloc()fs/xfs/libxfs/xfs_bmap.c+277 -1980 replies
28/50xfs: use xfs_alloc_vextent_first_ag() where appropriatefs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_bmap.c +1 more+28 -270 replies
29/50xfs: use xfs_alloc_vextent_start_bno() where appropriatefs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_bmap.c +1 more+59 -500 replies
30/50xfs: introduce xfs_alloc_vextent_near_bno()fs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_bmap.c +4 more+54 -700 replies
31/50xfs: introduce xfs_alloc_vextent_exact_bno()fs/xfs/libxfs/xfs_ag.c fs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h +3 more+56 -200 replies
32/50xfs: introduce xfs_alloc_vextent_prepare()fs/xfs/libxfs/xfs_alloc.c+86 -360 replies
33/50xfs: move allocation accounting to xfs_alloc_vextent_set_fsbno()fs/xfs/libxfs/xfs_alloc.c+62 -650 replies
34/50xfs: fold xfs_alloc_ag_vextent() into callersfs/xfs/libxfs/xfs_alloc.c fs/xfs/libxfs/xfs_alloc.h fs/xfs/libxfs/xfs_bmap.c +1 more+23 -1090 replies
35/50xfs: convert xfs_alloc_vextent_iterate_ags() to use perag walkerfs/xfs/libxfs/xfs_ag.h fs/xfs/libxfs/xfs_alloc.c+65 -540 replies
36/50xfs: convert trim to use for_each_perag_rangefs/xfs/xfs_discard.c+23 -270 replies
37/50xfs: factor out filestreams from xfs_bmap_btalloc_nullfbfs/xfs/libxfs/xfs_bmap.c+87 -640 replies
38/50xfs: get rid of notinit from xfs_bmap_longest_free_extentfs/xfs/libxfs/xfs_bmap.c+36 -480 replies
39/50xfs: use xfs_bmap_longest_free_extent() in filestreamsfs/xfs/libxfs/xfs_bmap.c fs/xfs/libxfs/xfs_bmap.h fs/xfs/xfs_filestream.c+11 -150 replies
40/50xfs: move xfs_bmap_btalloc_filestreams() to xfs_filestreams.cfs/xfs/libxfs/xfs_bmap.c fs/xfs/xfs_filestream.c fs/xfs/xfs_filestream.h+71 -790 replies
41/50xfs: merge filestream AG lookup into xfs_filestream_select_ag()fs/xfs/xfs_filestream.c+59 -810 replies
42/50xfs: merge new filestream AG selection into xfs_filestream_select_ag()fs/xfs/xfs_filestream.c+46 -740 replies
43/50xfs: remove xfs_filestream_select_ag() longest extent checkfs/xfs/xfs_filestream.c+3 -190 replies
44/50xfs: factor out MRU hit case in xfs_filestream_select_agfs/xfs/xfs_filestream.c+78 -490 replies
45/50xfs: track an active perag reference in filestreamsfs/xfs/xfs_filestream.c+43 -560 replies
46/50xfs: use for_each_perag_wrap in xfs_filestream_pick_agfs/xfs/xfs_filestream.c+41 -600 replies
47/50xfs: pass perag to filestreams tracingfs/xfs/xfs_filestream.c fs/xfs/xfs_filestream.h fs/xfs/xfs_trace.h+25 -420 replies
48/50xfs: return a referenced perag from filestreams allocatorfs/xfs/libxfs/xfs_bmap.c fs/xfs/xfs_filestream.c+66 -320 replies
49/50xfs: refactor the filestreams allocator pick functionsfs/xfs/xfs_filestream.c fs/xfs/xfs_trace.h+116 -1120 replies
50/50xfs: fix low space alloc deadlockfs/xfs/libxfs/xfs_alloc.c+20 -10 replies

Reviews trailers per patch

10 of 50 patches have a Reviewed-by or Acked-by.

PatchChristoph Hellwig
1/50R-b
2/50R-b
3/50R-b
4/50R-b
5/50R-b
6/50R-b R-b
7/50R-b
8/50R-b
9/50R-b
10/50R-b
11/50
12/50
13/50
14/50
15/50
16/50
17/50
18/50
19/50
20/50
21/50
22/50
23/50
24/50
25/50
26/50
27/50
28/50
29/50
30/50
31/50
32/50
33/50
34/50
35/50
36/50
37/50
38/50
39/50
40/50
41/50
42/50
43/50
44/50
45/50
46/50
47/50
48/50
49/50
50/50

Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes.

Read the v1 thread

Cover letter [RFC] [PATCH 00/50] xfs: per-ag centric allocation alogrithms

Hi folks,

This is "heads up" at this point so that people can see what is coming down the line and make early comments, not a request to consider these for merging soon. I may cherry pick some of the initial AGI/AGF cleanup patches patches for this cycle, but I'll send them separately if I do. The patch series is based on a 5.19-rc1 kernel.

This series continues the work towards making shrinking a filesystem possible. We need to be able to stop operations from taking place on AGs that need to be removed by a shrink, so before shrink can be implemented we need to have the infrastructure in place to prevent incursion into AGs that are going to be, or are in the process, of being removed from active duty.

The focus of this is making operations that depend on access to AGs use the perag to access and pin the AG in active use, thereby creating a barrier we can use to delay shrink until all active uses have been drained and new uses are prevented.

This series starts by driving the perag down into the AGI, AGF and AGFL access routines and unifies the perag structure initialisation with the high level AG header read functions. This largely replaces the xfs_mount/agno pair that is passed to all these functions with a perag, and in most places we already have a perag ready to pass in. There are a few places where perags need to be grabbed before reading the AG header buffers - some of these will need to be driven to higher layers to ensure we can run operations on AGs without getting stuck part way through waiting on a perag reference.

The next section of this patchset moves some of the AG geometry information from the xfs_mount to the xfs_perag, and starts converting code that requires geometry validation to use a perag instead of a mount and having to extract the AGNO from the object location. This also allows us to store the AG size in the perag and then we can stop having to compare the agno against sb_agcount to determine if the AG is the last AG and so has a runt size. This greatly simplifies some of the type validity checking we do and substantially reduces the CPU overhead of type validity checking. It also cuts over 1.2kB out of the binary size.

The series then starts converting the code to use active references. Active reference counts are used by high level code that needs to prevent the AG from being taken out from under it by a shrink operation. The high level code needs to be able to handle not getting an active reference gracefully, and the shrink code will need to wait for active references to drain before continuing.

Active references are implemented just as reference counts right now
- an active reference is taken at perag init during mount, and all other active references are dependent on the active reference count being greater than zero. This gives us an initial method of stopping new active references without needing other infrastructure; just drop the reference taken at filesystem mount time and when the refcount then falls to zero no new references can be taken.

In future, this will need to take into account AG control state (e.g. offline, no alloc, etc) as well as the reference count, but right now we can implement a basic barrier for shrink with just reference count manipulations. There are patches to convert the perag state to atomic opstate fields similar to the xfs_mount and xlog opstate fields in preparation for this.

The first target for active reference conversion is the for_each_perag*() iterators. This captures a lot of high level code that should skip offline AGs, and introduces the ability to differentiate between a lookup that didn't have an online AG and the end of the AG iteration range.

From there, the inode allocation AG selection is converted to active references, and the perag is driven deeper into the inode allocation and btree code to replace the xfs_mount. Most of the inode allocation code operates on a single AG once it is selected, hence it should pass the perag as the primary referenced object around for allocation, not the xfs_mount. There is a bit of churn here, but it emphasises that inode allocation is inherently an allocation group based operation.

Next the bmap/alloc interface undergoes a major untangling, reworking xfs_bmap_btalloc() into separate allocation operations for different contexts and failure handling behaviours. This then allows us to completely remove the xfs_alloc_vextent() layer via restructuring the xfs_alloc_vextent/xfs_alloc_ag_vextent() into a set of realtively simple helper function that describe the allocation that they are doing. e.g. xfs_alloc_vextent_exact_bno().

This allows the requirements for accessing AGs to be allocation context dependent. The allocations that require operation on a single AG generally can't tolerate failure after the allocation method and AG has been decided on, and hence the caller needs to manage the active references to ensure the allocation does not race with shrink removing the selected AG for the duration of the operation that requires access to that allocation group.

Other allocations iterate AGs and so the first AG is just a hint - these do not need to pin a perag first as they can tolerate not being able to access an AG by simply skipping over it. These require new perag iteration functions that can start at arbitrary AGs and wrap around at arbitrary AGs, hence a new set for for_each_perag_wrap*() helpers to do this.

Next is the rework of the filestreams allocator. This doesn't change any functionality, but gets rid of the unnecessary multi-pass selection algorithm when the selected AG is not available. It currently does a lookup pass which might iterate all AGs to select an AG, then checks if the AG is acceptible and if not does a "new AG" pass that is essentially identical to the lookup pass. Both of these scans also do the same "longest extent in AG" check before selecting an AG as is done after the AG is selected.

IOWs, the filestreams algorithm can be greatly simplified into a single new AG selection pass if the there is no current association or the currently associated AG doesn't have enough contiguous free space for the allocation to proceed. With this simplification of the filestreams allocator, it's then trivial to convert it to use for_each_ag_wrap() for the AG scan algorithm.

This actually passes auto group fstests with rmapbt=1 with only one regression - xfs/294 gets ENOSPC earlier and that makes unexpected output noise. The last patch in the series is needed to fix a AGF ABBA locking deadlock in g/476 - I only just worked this one out, and I strongly suspect that it's a pre-existing bug that leaves an AGF locked after failing to allocate anything from the AG.

This series currently ends at the xfs_bmap_btalloc ->allocator conversion. There still more to be done here before we can start disabling AGs for shrink:
- the bmapi layer needs to handle active AG references for exact and near allocation
- converting the allocation "firstblock" restrictions to hold an actively referenced perag, not a filesystem block address.
- inode cache lookups need to converted to active references
- audits needed to find and convert all the places that we use bp->b_pag instead of active references passed from high level code.
- addition of a "going offline" opstate and state machine to use for rejecting new active references as well as blocking shrink from making progress until all active references are gone
- ioctls for changing AG state from userspace
- audit of the freeing code to determine whether it can use passive references to allow freeing of blocks (which may require allocation!) whilst new allocations are prevented from being run on "going offline" AGs. This will allow userspace to stop new allocations in AGs to be shrunk before it starts emptying them and freeing the space that they have in use.

Cheers,

Dave.