1
2
3
4
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_sb.h"
23#include "xfs_ag_resv.h"
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68bool
69xfs_ag_resv_critical(
70 struct xfs_perag *pag,
71 enum xfs_ag_resv_type type)
72{
73 xfs_extlen_t avail;
74 xfs_extlen_t orig;
75
76 switch (type) {
77 case XFS_AG_RESV_METADATA:
78 avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved;
79 orig = pag->pag_meta_resv.ar_asked;
80 break;
81 case XFS_AG_RESV_RMAPBT:
82 avail = pag->pagf_freeblks + pag->pagf_flcount -
83 pag->pag_meta_resv.ar_reserved;
84 orig = pag->pag_rmapbt_resv.ar_asked;
85 break;
86 default:
87 ASSERT(0);
88 return false;
89 }
90
91 trace_xfs_ag_resv_critical(pag, type, avail);
92
93
94 return XFS_TEST_ERROR(avail < orig / 10 || avail < XFS_BTREE_MAXLEVELS,
95 pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL);
96}
97
98
99
100
101
102xfs_extlen_t
103xfs_ag_resv_needed(
104 struct xfs_perag *pag,
105 enum xfs_ag_resv_type type)
106{
107 xfs_extlen_t len;
108
109 len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved;
110 switch (type) {
111 case XFS_AG_RESV_METADATA:
112 case XFS_AG_RESV_RMAPBT:
113 len -= xfs_perag_resv(pag, type)->ar_reserved;
114 break;
115 case XFS_AG_RESV_NONE:
116
117 break;
118 default:
119 ASSERT(0);
120 }
121
122 trace_xfs_ag_resv_needed(pag, type, len);
123
124 return len;
125}
126
127
128static int
129__xfs_ag_resv_free(
130 struct xfs_perag *pag,
131 enum xfs_ag_resv_type type)
132{
133 struct xfs_ag_resv *resv;
134 xfs_extlen_t oldresv;
135 int error;
136
137 trace_xfs_ag_resv_free(pag, type, 0);
138
139 resv = xfs_perag_resv(pag, type);
140 if (pag->pag_agno == 0)
141 pag->pag_mount->m_ag_max_usable += resv->ar_asked;
142
143
144
145
146
147 if (type == XFS_AG_RESV_RMAPBT)
148 oldresv = resv->ar_orig_reserved;
149 else
150 oldresv = resv->ar_reserved;
151 error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true);
152 resv->ar_reserved = 0;
153 resv->ar_asked = 0;
154 resv->ar_orig_reserved = 0;
155
156 if (error)
157 trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno,
158 error, _RET_IP_);
159 return error;
160}
161
162
163int
164xfs_ag_resv_free(
165 struct xfs_perag *pag)
166{
167 int error;
168 int err2;
169
170 error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
171 err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
172 if (err2 && !error)
173 error = err2;
174 return error;
175}
176
177static int
178__xfs_ag_resv_init(
179 struct xfs_perag *pag,
180 enum xfs_ag_resv_type type,
181 xfs_extlen_t ask,
182 xfs_extlen_t used)
183{
184 struct xfs_mount *mp = pag->pag_mount;
185 struct xfs_ag_resv *resv;
186 int error;
187 xfs_extlen_t hidden_space;
188
189 if (used > ask)
190 ask = used;
191
192 switch (type) {
193 case XFS_AG_RESV_RMAPBT:
194
195
196
197
198
199
200 hidden_space = ask;
201 break;
202 case XFS_AG_RESV_METADATA:
203
204
205
206
207
208 hidden_space = ask - used;
209 break;
210 default:
211 ASSERT(0);
212 return -EINVAL;
213 }
214 error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true);
215 if (error) {
216 trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno,
217 error, _RET_IP_);
218 xfs_warn(mp,
219"Per-AG reservation for AG %u failed. Filesystem may run out of space.",
220 pag->pag_agno);
221 return error;
222 }
223
224
225
226
227
228
229
230 if (pag->pag_agno == 0)
231 mp->m_ag_max_usable -= ask;
232
233 resv = xfs_perag_resv(pag, type);
234 resv->ar_asked = ask;
235 resv->ar_orig_reserved = hidden_space;
236 resv->ar_reserved = ask - used;
237
238 trace_xfs_ag_resv_init(pag, type, ask);
239 return 0;
240}
241
242
243int
244xfs_ag_resv_init(
245 struct xfs_perag *pag,
246 struct xfs_trans *tp)
247{
248 struct xfs_mount *mp = pag->pag_mount;
249 xfs_agnumber_t agno = pag->pag_agno;
250 xfs_extlen_t ask;
251 xfs_extlen_t used;
252 int error = 0, error2;
253 bool has_resv = false;
254
255
256 if (pag->pag_meta_resv.ar_asked == 0) {
257 ask = used = 0;
258
259 error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used);
260 if (error)
261 goto out;
262
263 error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used);
264 if (error)
265 goto out;
266
267 error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
268 ask, used);
269 if (error) {
270
271
272
273
274
275
276
277 ask = used = 0;
278
279 mp->m_finobt_nores = true;
280
281 error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask,
282 &used);
283 if (error)
284 goto out;
285
286 error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
287 ask, used);
288 if (error)
289 goto out;
290 }
291 if (ask)
292 has_resv = true;
293 }
294
295
296 if (pag->pag_rmapbt_resv.ar_asked == 0) {
297 ask = used = 0;
298
299 error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used);
300 if (error)
301 goto out;
302
303 error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used);
304 if (error)
305 goto out;
306 if (ask)
307 has_resv = true;
308 }
309
310out:
311
312
313
314
315
316
317
318
319
320 if (has_resv) {
321 error2 = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, 0);
322 if (error2)
323 return error2;
324 ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
325 xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <=
326 pag->pagf_freeblks + pag->pagf_flcount);
327 }
328 return error;
329}
330
331
332void
333xfs_ag_resv_alloc_extent(
334 struct xfs_perag *pag,
335 enum xfs_ag_resv_type type,
336 struct xfs_alloc_arg *args)
337{
338 struct xfs_ag_resv *resv;
339 xfs_extlen_t len;
340 uint field;
341
342 trace_xfs_ag_resv_alloc_extent(pag, type, args->len);
343
344 switch (type) {
345 case XFS_AG_RESV_AGFL:
346 return;
347 case XFS_AG_RESV_METADATA:
348 case XFS_AG_RESV_RMAPBT:
349 resv = xfs_perag_resv(pag, type);
350 break;
351 default:
352 ASSERT(0);
353
354 case XFS_AG_RESV_NONE:
355 field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS :
356 XFS_TRANS_SB_FDBLOCKS;
357 xfs_trans_mod_sb(args->tp, field, -(int64_t)args->len);
358 return;
359 }
360
361 len = min_t(xfs_extlen_t, args->len, resv->ar_reserved);
362 resv->ar_reserved -= len;
363 if (type == XFS_AG_RESV_RMAPBT)
364 return;
365
366 xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len);
367
368 if (args->len > len)
369 xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS,
370 -((int64_t)args->len - len));
371}
372
373
374void
375xfs_ag_resv_free_extent(
376 struct xfs_perag *pag,
377 enum xfs_ag_resv_type type,
378 struct xfs_trans *tp,
379 xfs_extlen_t len)
380{
381 xfs_extlen_t leftover;
382 struct xfs_ag_resv *resv;
383
384 trace_xfs_ag_resv_free_extent(pag, type, len);
385
386 switch (type) {
387 case XFS_AG_RESV_AGFL:
388 return;
389 case XFS_AG_RESV_METADATA:
390 case XFS_AG_RESV_RMAPBT:
391 resv = xfs_perag_resv(pag, type);
392 break;
393 default:
394 ASSERT(0);
395
396 case XFS_AG_RESV_NONE:
397 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len);
398 return;
399 }
400
401 leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved);
402 resv->ar_reserved += leftover;
403 if (type == XFS_AG_RESV_RMAPBT)
404 return;
405
406 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len);
407
408 if (len > leftover)
409 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover);
410}
411