Skip to content

Commit c0927a7

Browse files
committed
Merge tag 'xfs-6.3-merge-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull moar xfs updates from Darrick Wong: "This contains a fix for a deadlock in the allocator. It continues the slow march towards being able to offline AGs, and it refactors the interface to the xfs allocator to be less indirection happy. Summary: - Fix a deadlock in the free space allocator due to the AG-walking algorithm forgetting to follow AG-order locking rules - Make the inode allocator prefer existing free inodes instead of failing to allocate new inode chunks when free space is low - Set minleft correctly when setting allocator parameters for bmap changes - Fix uninitialized variable access in the getfsmap code - Make a distinction between active and passive per-AG structure references. For now, active references are taken to perform some work in an AG on behalf of a high level operation; passive references are used by lower level code to finish operations started by other threads. Eventually this will become part of online shrink - Split out all the different allocator strategies into separate functions to move us away from design antipattern of filling out a huge structure for various differentish things and issuing a single function multiplexing call - Various cleanups in the filestreams allocator code, which we might very well want to deprecate instead of continuing - Fix a bug with the agi rotor code that was introduced earlier in this series" * tag 'xfs-6.3-merge-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (44 commits) xfs: restore old agirotor behavior xfs: fix uninitialized variable access xfs: refactor the filestreams allocator pick functions xfs: return a referenced perag from filestreams allocator xfs: pass perag to filestreams tracing xfs: use for_each_perag_wrap in xfs_filestream_pick_ag xfs: track an active perag reference in filestreams xfs: factor out MRU hit case in xfs_filestream_select_ag xfs: remove xfs_filestream_select_ag() longest extent check xfs: merge new filestream AG selection into xfs_filestream_select_ag() xfs: merge filestream AG lookup into xfs_filestream_select_ag() xfs: move xfs_bmap_btalloc_filestreams() to xfs_filestreams.c xfs: use xfs_bmap_longest_free_extent() in filestreams xfs: get rid of notinit from xfs_bmap_longest_free_extent xfs: factor out filestreams from xfs_bmap_btalloc_nullfb xfs: convert trim to use for_each_perag_range xfs: convert xfs_alloc_vextent_iterate_ags() to use perag walker xfs: move the minimum agno checks into xfs_alloc_vextent_check_args xfs: fold xfs_alloc_ag_vextent() into callers xfs: move allocation accounting to xfs_alloc_vextent_set_fsbno() ...
2 parents 1899946 + 6e2985c commit c0927a7

36 files changed

+1536
-1243
lines changed

fs/xfs/libxfs/xfs_ag.c

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,15 @@ xfs_perag_get(
4444
xfs_agnumber_t agno)
4545
{
4646
struct xfs_perag *pag;
47-
int ref = 0;
4847

4948
rcu_read_lock();
5049
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
5150
if (pag) {
51+
trace_xfs_perag_get(pag, _RET_IP_);
5252
ASSERT(atomic_read(&pag->pag_ref) >= 0);
53-
ref = atomic_inc_return(&pag->pag_ref);
53+
atomic_inc(&pag->pag_ref);
5454
}
5555
rcu_read_unlock();
56-
trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
5756
return pag;
5857
}
5958

@@ -68,7 +67,6 @@ xfs_perag_get_tag(
6867
{
6968
struct xfs_perag *pag;
7069
int found;
71-
int ref;
7270

7371
rcu_read_lock();
7472
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
@@ -77,21 +75,78 @@ xfs_perag_get_tag(
7775
rcu_read_unlock();
7876
return NULL;
7977
}
80-
ref = atomic_inc_return(&pag->pag_ref);
78+
trace_xfs_perag_get_tag(pag, _RET_IP_);
79+
atomic_inc(&pag->pag_ref);
8180
rcu_read_unlock();
82-
trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
8381
return pag;
8482
}
8583

8684
void
8785
xfs_perag_put(
8886
struct xfs_perag *pag)
8987
{
90-
int ref;
91-
88+
trace_xfs_perag_put(pag, _RET_IP_);
9289
ASSERT(atomic_read(&pag->pag_ref) > 0);
93-
ref = atomic_dec_return(&pag->pag_ref);
94-
trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
90+
atomic_dec(&pag->pag_ref);
91+
}
92+
93+
/*
94+
* Active references for perag structures. This is for short term access to the
95+
* per ag structures for walking trees or accessing state. If an AG is being
96+
* shrunk or is offline, then this will fail to find that AG and return NULL
97+
* instead.
98+
*/
99+
struct xfs_perag *
100+
xfs_perag_grab(
101+
struct xfs_mount *mp,
102+
xfs_agnumber_t agno)
103+
{
104+
struct xfs_perag *pag;
105+
106+
rcu_read_lock();
107+
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
108+
if (pag) {
109+
trace_xfs_perag_grab(pag, _RET_IP_);
110+
if (!atomic_inc_not_zero(&pag->pag_active_ref))
111+
pag = NULL;
112+
}
113+
rcu_read_unlock();
114+
return pag;
115+
}
116+
117+
/*
118+
* search from @first to find the next perag with the given tag set.
119+
*/
120+
struct xfs_perag *
121+
xfs_perag_grab_tag(
122+
struct xfs_mount *mp,
123+
xfs_agnumber_t first,
124+
int tag)
125+
{
126+
struct xfs_perag *pag;
127+
int found;
128+
129+
rcu_read_lock();
130+
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
131+
(void **)&pag, first, 1, tag);
132+
if (found <= 0) {
133+
rcu_read_unlock();
134+
return NULL;
135+
}
136+
trace_xfs_perag_grab_tag(pag, _RET_IP_);
137+
if (!atomic_inc_not_zero(&pag->pag_active_ref))
138+
pag = NULL;
139+
rcu_read_unlock();
140+
return pag;
141+
}
142+
143+
void
144+
xfs_perag_rele(
145+
struct xfs_perag *pag)
146+
{
147+
trace_xfs_perag_rele(pag, _RET_IP_);
148+
if (atomic_dec_and_test(&pag->pag_active_ref))
149+
wake_up(&pag->pag_active_wq);
95150
}
96151

97152
/*
@@ -196,6 +251,10 @@ xfs_free_perag(
196251
cancel_delayed_work_sync(&pag->pag_blockgc_work);
197252
xfs_buf_hash_destroy(pag);
198253

254+
/* drop the mount's active reference */
255+
xfs_perag_rele(pag);
256+
XFS_IS_CORRUPT(pag->pag_mount,
257+
atomic_read(&pag->pag_active_ref) != 0);
199258
call_rcu(&pag->rcu_head, __xfs_free_perag);
200259
}
201260
}
@@ -314,6 +373,7 @@ xfs_initialize_perag(
314373
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
315374
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
316375
init_waitqueue_head(&pag->pagb_wait);
376+
init_waitqueue_head(&pag->pag_active_wq);
317377
pag->pagb_count = 0;
318378
pag->pagb_tree = RB_ROOT;
319379
#endif /* __KERNEL__ */
@@ -322,6 +382,9 @@ xfs_initialize_perag(
322382
if (error)
323383
goto out_remove_pag;
324384

385+
/* Active ref owned by mount indicates AG is online. */
386+
atomic_set(&pag->pag_active_ref, 1);
387+
325388
/* first new pag is fully initialized */
326389
if (first_initialised == NULLAGNUMBER)
327390
first_initialised = index;
@@ -824,7 +887,7 @@ xfs_ag_shrink_space(
824887
struct xfs_alloc_arg args = {
825888
.tp = *tpp,
826889
.mp = mp,
827-
.type = XFS_ALLOCTYPE_THIS_BNO,
890+
.pag = pag,
828891
.minlen = delta,
829892
.maxlen = delta,
830893
.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE,
@@ -856,14 +919,11 @@ xfs_ag_shrink_space(
856919
if (delta >= aglen)
857920
return -EINVAL;
858921

859-
args.fsbno = XFS_AGB_TO_FSB(mp, pag->pag_agno, aglen - delta);
860-
861922
/*
862923
* Make sure that the last inode cluster cannot overlap with the new
863924
* end of the AG, even if it's sparse.
864925
*/
865-
error = xfs_ialloc_check_shrink(*tpp, pag->pag_agno, agibp,
866-
aglen - delta);
926+
error = xfs_ialloc_check_shrink(pag, *tpp, agibp, aglen - delta);
867927
if (error)
868928
return error;
869929

@@ -876,7 +936,8 @@ xfs_ag_shrink_space(
876936
return error;
877937

878938
/* internal log shouldn't also show up in the free space btrees */
879-
error = xfs_alloc_vextent(&args);
939+
error = xfs_alloc_vextent_exact_bno(&args,
940+
XFS_AGB_TO_FSB(mp, pag->pag_agno, aglen - delta));
880941
if (!error && args.agbno == NULLAGBLOCK)
881942
error = -ENOSPC;
882943

fs/xfs/libxfs/xfs_ag.h

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@ struct xfs_ag_resv {
3232
struct xfs_perag {
3333
struct xfs_mount *pag_mount; /* owner filesystem */
3434
xfs_agnumber_t pag_agno; /* AG this structure belongs to */
35-
atomic_t pag_ref; /* perag reference count */
36-
char pagf_init; /* this agf's entry is initialized */
37-
char pagi_init; /* this agi's entry is initialized */
38-
char pagf_metadata; /* the agf is preferred to be metadata */
39-
char pagi_inodeok; /* The agi is ok for inodes */
35+
atomic_t pag_ref; /* passive reference count */
36+
atomic_t pag_active_ref; /* active reference count */
37+
wait_queue_head_t pag_active_wq;/* woken active_ref falls to zero */
38+
unsigned long pag_opstate;
4039
uint8_t pagf_levels[XFS_BTNUM_AGF];
4140
/* # of levels in bno & cnt btree */
42-
bool pagf_agflreset; /* agfl requires reset before use */
4341
uint32_t pagf_flcount; /* count of blocks in freelist */
4442
xfs_extlen_t pagf_freeblks; /* total free blocks */
4543
xfs_extlen_t pagf_longest; /* longest free space */
@@ -106,16 +104,44 @@ struct xfs_perag {
106104
#endif /* __KERNEL__ */
107105
};
108106

107+
/*
108+
* Per-AG operational state. These are atomic flag bits.
109+
*/
110+
#define XFS_AGSTATE_AGF_INIT 0
111+
#define XFS_AGSTATE_AGI_INIT 1
112+
#define XFS_AGSTATE_PREFERS_METADATA 2
113+
#define XFS_AGSTATE_ALLOWS_INODES 3
114+
#define XFS_AGSTATE_AGFL_NEEDS_RESET 4
115+
116+
#define __XFS_AG_OPSTATE(name, NAME) \
117+
static inline bool xfs_perag_ ## name (struct xfs_perag *pag) \
118+
{ \
119+
return test_bit(XFS_AGSTATE_ ## NAME, &pag->pag_opstate); \
120+
}
121+
122+
__XFS_AG_OPSTATE(initialised_agf, AGF_INIT)
123+
__XFS_AG_OPSTATE(initialised_agi, AGI_INIT)
124+
__XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
125+
__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
126+
__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
127+
109128
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
110129
xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
111130
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
112131
void xfs_free_perag(struct xfs_mount *mp);
113132

133+
/* Passive AG references */
114134
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
115135
struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
116136
unsigned int tag);
117137
void xfs_perag_put(struct xfs_perag *pag);
118138

139+
/* Active AG references */
140+
struct xfs_perag *xfs_perag_grab(struct xfs_mount *, xfs_agnumber_t);
141+
struct xfs_perag *xfs_perag_grab_tag(struct xfs_mount *, xfs_agnumber_t,
142+
int tag);
143+
void xfs_perag_rele(struct xfs_perag *pag);
144+
119145
/*
120146
* Per-ag geometry infomation and validation
121147
*/
@@ -193,31 +219,86 @@ xfs_perag_next(
193219
struct xfs_mount *mp = pag->pag_mount;
194220

195221
*agno = pag->pag_agno + 1;
196-
xfs_perag_put(pag);
197-
if (*agno > end_agno)
198-
return NULL;
199-
return xfs_perag_get(mp, *agno);
222+
xfs_perag_rele(pag);
223+
while (*agno <= end_agno) {
224+
pag = xfs_perag_grab(mp, *agno);
225+
if (pag)
226+
return pag;
227+
(*agno)++;
228+
}
229+
return NULL;
200230
}
201231

202232
#define for_each_perag_range(mp, agno, end_agno, pag) \
203-
for ((pag) = xfs_perag_get((mp), (agno)); \
233+
for ((pag) = xfs_perag_grab((mp), (agno)); \
204234
(pag) != NULL; \
205235
(pag) = xfs_perag_next((pag), &(agno), (end_agno)))
206236

207237
#define for_each_perag_from(mp, agno, pag) \
208238
for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, (pag))
209239

210-
211240
#define for_each_perag(mp, agno, pag) \
212241
(agno) = 0; \
213242
for_each_perag_from((mp), (agno), (pag))
214243

215244
#define for_each_perag_tag(mp, agno, pag, tag) \
216-
for ((agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
245+
for ((agno) = 0, (pag) = xfs_perag_grab_tag((mp), 0, (tag)); \
217246
(pag) != NULL; \
218247
(agno) = (pag)->pag_agno + 1, \
219-
xfs_perag_put(pag), \
220-
(pag) = xfs_perag_get_tag((mp), (agno), (tag)))
248+
xfs_perag_rele(pag), \
249+
(pag) = xfs_perag_grab_tag((mp), (agno), (tag)))
250+
251+
static inline struct xfs_perag *
252+
xfs_perag_next_wrap(
253+
struct xfs_perag *pag,
254+
xfs_agnumber_t *agno,
255+
xfs_agnumber_t stop_agno,
256+
xfs_agnumber_t restart_agno,
257+
xfs_agnumber_t wrap_agno)
258+
{
259+
struct xfs_mount *mp = pag->pag_mount;
260+
261+
*agno = pag->pag_agno + 1;
262+
xfs_perag_rele(pag);
263+
while (*agno != stop_agno) {
264+
if (*agno >= wrap_agno) {
265+
if (restart_agno >= stop_agno)
266+
break;
267+
*agno = restart_agno;
268+
}
269+
270+
pag = xfs_perag_grab(mp, *agno);
271+
if (pag)
272+
return pag;
273+
(*agno)++;
274+
}
275+
return NULL;
276+
}
277+
278+
/*
279+
* Iterate all AGs from start_agno through wrap_agno, then restart_agno through
280+
* (start_agno - 1).
281+
*/
282+
#define for_each_perag_wrap_range(mp, start_agno, restart_agno, wrap_agno, agno, pag) \
283+
for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), (agno)); \
284+
(pag) != NULL; \
285+
(pag) = xfs_perag_next_wrap((pag), &(agno), (start_agno), \
286+
(restart_agno), (wrap_agno)))
287+
/*
288+
* Iterate all AGs from start_agno through wrap_agno, then 0 through
289+
* (start_agno - 1).
290+
*/
291+
#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) \
292+
for_each_perag_wrap_range((mp), (start_agno), 0, (wrap_agno), (agno), (pag))
293+
294+
/*
295+
* Iterate all AGs from start_agno through to the end of the filesystem, then 0
296+
* through (start_agno - 1).
297+
*/
298+
#define for_each_perag_wrap(mp, start_agno, agno, pag) \
299+
for_each_perag_wrap_at((mp), (start_agno), (mp)->m_sb.sb_agcount, \
300+
(agno), (pag))
301+
221302

222303
struct aghdr_init_data {
223304
/* per ag data */

fs/xfs/libxfs/xfs_ag_resv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ xfs_ag_resv_init(
264264
if (error)
265265
goto out;
266266

267-
error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used);
267+
error = xfs_finobt_calc_reserves(pag, tp, &ask, &used);
268268
if (error)
269269
goto out;
270270

0 commit comments

Comments
 (0)