File Index
Files and directories
Sign in
FILE

xfs_ag_resv.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/libxfs/xfs_ag_resv.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2016 Oracle.  All Rights Reserved.
  4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
  5 */
  6#include "xfs.h"
  7#include "xfs_fs.h"
  8#include "xfs_shared.h"
  9#include "xfs_format.h"
 10#include "xfs_log_format.h"
 11#include "xfs_trans_resv.h"
 12#include "xfs_mount.h"
 13#include "xfs_alloc.h"
 14#include "xfs_errortag.h"
 15#include "xfs_error.h"
 16#include "xfs_trace.h"
 17#include "xfs_trans.h"
 18#include "xfs_rmap_btree.h"
 19#include "xfs_btree.h"
 20#include "xfs_refcount_btree.h"
 21#include "xfs_ialloc_btree.h"
 22#include "xfs_ag.h"
 23#include "xfs_ag_resv.h"
 24
 25/*
 26 * Per-AG Block Reservations
 27 *
 28 * For some kinds of allocation group metadata structures, it is advantageous
 29 * to reserve a small number of blocks in each AG so that future expansions of
 30 * that data structure do not encounter ENOSPC because errors during a btree
 31 * split cause the filesystem to go offline.
 32 *
 33 * Prior to the introduction of reflink, this wasn't an issue because the free
 34 * space btrees maintain a reserve of space (the AGFL) to handle any expansion
 35 * that may be necessary; and allocations of other metadata (inodes, BMBT,
 36 * dir/attr) aren't restricted to a single AG.  However, with reflink it is
 37 * possible to allocate all the space in an AG, have subsequent reflink/CoW
 38 * activity expand the refcount btree, and discover that there's no space left
 39 * to handle that expansion.  Since we can calculate the maximum size of the
 40 * refcount btree, we can reserve space for it and avoid ENOSPC.
 41 *
 42 * Handling per-AG reservations consists of three changes to the allocator's
 43 * behavior:  First, because these reservations are always needed, we decrease
 44 * the ag_max_usable counter to reflect the size of the AG after the reserved
 45 * blocks are taken.  Second, the reservations must be reflected in the
 46 * fdblocks count to maintain proper accounting.  Third, each AG must maintain
 47 * its own reserved block counter so that we can calculate the amount of space
 48 * that must remain free to maintain the reservations.  Fourth, the "remaining
 49 * reserved blocks" count must be used when calculating the length of the
 50 * longest free extent in an AG and to clamp maxlen in the per-AG allocation
 51 * functions.  In other words, we maintain a virtual allocation via in-core
 52 * accounting tricks so that we don't have to clean up after a crash. :)
 53 *
 54 * Reserved blocks can be managed by passing one of the enum xfs_ag_resv_type
 55 * values via struct xfs_alloc_arg or directly to the xfs_free_extent
 56 * function.  It might seem a little funny to maintain a reservoir of blocks
 57 * to feed another reservoir, but the AGFL only holds enough blocks to get
 58 * through the next transaction.  The per-AG reservation is to ensure (we
 59 * hope) that each AG never runs out of blocks.  Each data structure wanting
 60 * to use the reservation system should update ask/used in xfs_ag_resv_init.
 61 */
 62
 63/*
 64 * Are we critically low on blocks?  For now we'll define that as the number
 65 * of blocks we can get our hands on being less than 10% of what we reserved
 66 * or less than some arbitrary number (maximum btree height).
 67 */
 68bool
 69xfs_ag_resv_critical(
 70	struct xfs_perag		*pag,
 71	enum xfs_ag_resv_type		type)
 72{
 73	struct xfs_mount		*mp = pag_mount(pag);
 74	xfs_extlen_t			avail;
 75	xfs_extlen_t			orig;
 76
 77	switch (type) {
 78	case XFS_AG_RESV_METADATA:
 79		avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved;
 80		orig = pag->pag_meta_resv.ar_asked;
 81		break;
 82	case XFS_AG_RESV_RMAPBT:
 83		avail = pag->pagf_freeblks + pag->pagf_flcount -
 84			pag->pag_meta_resv.ar_reserved;
 85		orig = pag->pag_rmapbt_resv.ar_asked;
 86		break;
 87	default:
 88		ASSERT(0);
 89		return false;
 90	}
 91
 92	trace_xfs_ag_resv_critical(pag, type, avail);
 93
 94	/* Critically low if less than 10% or max btree height remains. */
 95	return avail < orig / 10 || avail < mp->m_agbtree_maxlevels ||
 96		XFS_TEST_ERROR(mp, XFS_ERRTAG_AG_RESV_CRITICAL);
 97}
 98
 99/*
100 * How many blocks are reserved but not used, and therefore must not be
101 * allocated away?
102 */
103xfs_extlen_t
104xfs_ag_resv_needed(
105	struct xfs_perag		*pag,
106	enum xfs_ag_resv_type		type)
107{
108	xfs_extlen_t			len;
109
110	len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved;
111	switch (type) {
112	case XFS_AG_RESV_METADATA:
113	case XFS_AG_RESV_RMAPBT:
114		len -= xfs_perag_resv(pag, type)->ar_reserved;
115		break;
116	case XFS_AG_RESV_METAFILE:
117	case XFS_AG_RESV_NONE:
118		/* empty */
119		break;
120	default:
121		ASSERT(0);
122	}
123
124	trace_xfs_ag_resv_needed(pag, type, len);
125
126	return len;
127}
128
129/* Clean out a reservation */
130static void
131__xfs_ag_resv_free(
132	struct xfs_perag		*pag,
133	enum xfs_ag_resv_type		type)
134{
135	struct xfs_ag_resv		*resv;
136	xfs_extlen_t			oldresv;
137
138	trace_xfs_ag_resv_free(pag, type, 0);
139
140	resv = xfs_perag_resv(pag, type);
141	if (pag_agno(pag) == 0)
142		pag_mount(pag)->m_ag_max_usable += resv->ar_asked;
143	/*
144	 * RMAPBT blocks come from the AGFL and AGFL blocks are always
145	 * considered "free", so whatever was reserved at mount time must be
146	 * given back at umount.
147	 */
148	if (type == XFS_AG_RESV_RMAPBT)
149		oldresv = resv->ar_orig_reserved;
150	else
151		oldresv = resv->ar_reserved;
152	xfs_add_fdblocks(pag_mount(pag), oldresv);
153	resv->ar_reserved = 0;
154	resv->ar_asked = 0;
155	resv->ar_orig_reserved = 0;
156}
157
158/* Free a per-AG reservation. */
159void
160xfs_ag_resv_free(
161	struct xfs_perag		*pag)
162{
163	__xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
164	__xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
165}
166
167static int
168__xfs_ag_resv_init(
169	struct xfs_perag		*pag,
170	enum xfs_ag_resv_type		type,
171	xfs_extlen_t			ask,
172	xfs_extlen_t			used)
173{
174	struct xfs_mount		*mp = pag_mount(pag);
175	struct xfs_ag_resv		*resv;
176	int				error;
177	xfs_extlen_t			hidden_space;
178
179	if (used > ask)
180		ask = used;
181
182	switch (type) {
183	case XFS_AG_RESV_RMAPBT:
184		/*
185		 * Space taken by the rmapbt is not subtracted from fdblocks
186		 * because the rmapbt lives in the free space.  Here we must
187		 * subtract the entire reservation from fdblocks so that we
188		 * always have blocks available for rmapbt expansion.
189		 */
190		hidden_space = ask;
191		break;
192	case XFS_AG_RESV_METADATA:
193		/*
194		 * Space taken by all other metadata btrees are accounted
195		 * on-disk as used space.  We therefore only hide the space
196		 * that is reserved but not used by the trees.
197		 */
198		hidden_space = ask - used;
199		break;
200	default:
201		ASSERT(0);
202		return -EINVAL;
203	}
204
205	if (XFS_TEST_ERROR(mp, XFS_ERRTAG_AG_RESV_FAIL))
206		error = -ENOSPC;
207	else
208		error = xfs_dec_fdblocks(mp, hidden_space, true);
209	if (error) {
210		trace_xfs_ag_resv_init_error(pag, error, _RET_IP_);
211		xfs_warn(mp,
212"Per-AG reservation for AG %u failed.  Filesystem may run out of space.",
213				pag_agno(pag));
214		return error;
215	}
216
217	/*
218	 * Reduce the maximum per-AG allocation length by however much we're
219	 * trying to reserve for an AG.  Since this is a filesystem-wide
220	 * counter, we only make the adjustment for AG 0.  This assumes that
221	 * there aren't any AGs hungrier for per-AG reservation than AG 0.
222	 */
223	if (pag_agno(pag) == 0)
224		mp->m_ag_max_usable -= ask;
225
226	resv = xfs_perag_resv(pag, type);
227	resv->ar_asked = ask;
228	resv->ar_orig_reserved = hidden_space;
229	resv->ar_reserved = ask - used;
230
231	trace_xfs_ag_resv_init(pag, type, ask);
232	return 0;
233}
234
235/* Create a per-AG block reservation. */
236int
237xfs_ag_resv_init(
238	struct xfs_perag		*pag,
239	struct xfs_trans		*tp)
240{
241	struct xfs_mount		*mp = pag_mount(pag);
242	xfs_extlen_t			ask;
243	xfs_extlen_t			used;
244	int				error = 0, error2;
245	bool				has_resv = false;
246
247	/* Create the metadata reservation. */
248	if (pag->pag_meta_resv.ar_asked == 0) {
249		ask = used = 0;
250
251		error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used);
252		if (error)
253			goto out;
254
255		error = xfs_finobt_calc_reserves(pag, tp, &ask, &used);
256		if (error)
257			goto out;
258
259		error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
260				ask, used);
261		if (error) {
262			/*
263			 * Because we didn't have per-AG reservations when the
264			 * finobt feature was added we might not be able to
265			 * reserve all needed blocks.  Warn and fall back to the
266			 * old and potentially buggy code in that case, but
267			 * ensure we do have the reservation for the refcountbt.
268			 */
269			ask = used = 0;
270
271			mp->m_finobt_nores = true;
272
273			error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask,
274					&used);
275			if (error)
276				goto out;
277
278			error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
279					ask, used);
280			if (error)
281				goto out;
282		}
283		if (ask)
284			has_resv = true;
285	}
286
287	/* Create the RMAPBT metadata reservation */
288	if (pag->pag_rmapbt_resv.ar_asked == 0) {
289		ask = used = 0;
290
291		error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used);
292		if (error)
293			goto out;
294
295		error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used);
296		if (error)
297			goto out;
298		if (ask)
299			has_resv = true;
300	}
301
302out:
303	/*
304	 * Initialize the pagf if we have at least one active reservation on the
305	 * AG. This may have occurred already via reservation calculation, but
306	 * fall back to an explicit init to ensure the in-core allocbt usage
307	 * counters are initialized as soon as possible. This is important
308	 * because filesystems with large perag reservations are susceptible to
309	 * free space reservation problems that the allocbt counter is used to
310	 * address.
311	 */
312	if (has_resv) {
313		error2 = xfs_alloc_read_agf(pag, tp, 0, NULL);
314		if (error2)
315			return error2;
316
317		/*
318		 * If there isn't enough space in the AG to satisfy the
319		 * reservation, let the caller know that there wasn't enough
320		 * space.  Callers are responsible for deciding what to do
321		 * next, since (in theory) we can stumble along with
322		 * insufficient reservation if data blocks are being freed to
323		 * replenish the AG's free space.
324		 */
325		if (!error &&
326		    xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
327		    xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved >
328		    pag->pagf_freeblks + pag->pagf_flcount)
329			error = -ENOSPC;
330	}
331
332	return error;
333}
334
335/* Allocate a block from the reservation. */
336void
337xfs_ag_resv_alloc_extent(
338	struct xfs_perag		*pag,
339	enum xfs_ag_resv_type		type,
340	struct xfs_alloc_arg		*args)
341{
342	struct xfs_ag_resv		*resv;
343	xfs_extlen_t			len;
344	uint				field;
345
346	trace_xfs_ag_resv_alloc_extent(pag, type, args->len);
347
348	switch (type) {
349	case XFS_AG_RESV_AGFL:
350	case XFS_AG_RESV_METAFILE:
351		return;
352	case XFS_AG_RESV_METADATA:
353	case XFS_AG_RESV_RMAPBT:
354		resv = xfs_perag_resv(pag, type);
355		break;
356	default:
357		ASSERT(0);
358		fallthrough;
359	case XFS_AG_RESV_NONE:
360		field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS :
361				       XFS_TRANS_SB_FDBLOCKS;
362		xfs_trans_mod_sb(args->tp, field, -(int64_t)args->len);
363		return;
364	}
365
366	len = min_t(xfs_extlen_t, args->len, resv->ar_reserved);
367	resv->ar_reserved -= len;
368	if (type == XFS_AG_RESV_RMAPBT)
369		return;
370	/* Allocations of reserved blocks only need on-disk sb updates... */
371	xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len);
372	/* ...but non-reserved blocks need in-core and on-disk updates. */
373	if (args->len > len)
374		xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS,
375				-((int64_t)args->len - len));
376}
377
378/* Free a block to the reservation. */
379void
380xfs_ag_resv_free_extent(
381	struct xfs_perag		*pag,
382	enum xfs_ag_resv_type		type,
383	struct xfs_trans		*tp,
384	xfs_extlen_t			len)
385{
386	xfs_extlen_t			leftover;
387	struct xfs_ag_resv		*resv;
388
389	trace_xfs_ag_resv_free_extent(pag, type, len);
390
391	switch (type) {
392	case XFS_AG_RESV_AGFL:
393	case XFS_AG_RESV_METAFILE:
394		return;
395	case XFS_AG_RESV_METADATA:
396	case XFS_AG_RESV_RMAPBT:
397		resv = xfs_perag_resv(pag, type);
398		break;
399	default:
400		ASSERT(0);
401		fallthrough;
402	case XFS_AG_RESV_NONE:
403		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len);
404		fallthrough;
405	case XFS_AG_RESV_IGNORE:
406		return;
407	}
408
409	leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved);
410	resv->ar_reserved += leftover;
411	if (type == XFS_AG_RESV_RMAPBT)
412		return;
413	/* Freeing into the reserved pool only requires on-disk update... */
414	xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len);
415	/* ...but freeing beyond that requires in-core and on-disk update. */
416	if (len > leftover)
417		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover);
418}
~/ Read-only file preview.