diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_ag_resv.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_ag_resv.c | 70 |
1 files changed, 55 insertions, 15 deletions
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index d346d42c54d1..33db69be4832 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "xfs_rmap_btree.h" | 39 | #include "xfs_rmap_btree.h" |
40 | #include "xfs_btree.h" | 40 | #include "xfs_btree.h" |
41 | #include "xfs_refcount_btree.h" | 41 | #include "xfs_refcount_btree.h" |
42 | #include "xfs_ialloc_btree.h" | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * Per-AG Block Reservations | 45 | * Per-AG Block Reservations |
@@ -200,22 +201,30 @@ __xfs_ag_resv_init( | |||
200 | struct xfs_mount *mp = pag->pag_mount; | 201 | struct xfs_mount *mp = pag->pag_mount; |
201 | struct xfs_ag_resv *resv; | 202 | struct xfs_ag_resv *resv; |
202 | int error; | 203 | int error; |
204 | xfs_extlen_t reserved; | ||
203 | 205 | ||
204 | resv = xfs_perag_resv(pag, type); | ||
205 | if (used > ask) | 206 | if (used > ask) |
206 | ask = used; | 207 | ask = used; |
207 | resv->ar_asked = ask; | 208 | reserved = ask - used; |
208 | resv->ar_reserved = resv->ar_orig_reserved = ask - used; | ||
209 | mp->m_ag_max_usable -= ask; | ||
210 | 209 | ||
211 | trace_xfs_ag_resv_init(pag, type, ask); | 210 | error = xfs_mod_fdblocks(mp, -(int64_t)reserved, true); |
212 | 211 | if (error) { | |
213 | error = xfs_mod_fdblocks(mp, -(int64_t)resv->ar_reserved, true); | ||
214 | if (error) | ||
215 | trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno, | 212 | trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno, |
216 | error, _RET_IP_); | 213 | error, _RET_IP_); |
214 | xfs_warn(mp, | ||
215 | "Per-AG reservation for AG %u failed. Filesystem may run out of space.", | ||
216 | pag->pag_agno); | ||
217 | return error; | ||
218 | } | ||
217 | 219 | ||
218 | return error; | 220 | mp->m_ag_max_usable -= ask; |
221 | |||
222 | resv = xfs_perag_resv(pag, type); | ||
223 | resv->ar_asked = ask; | ||
224 | resv->ar_reserved = resv->ar_orig_reserved = reserved; | ||
225 | |||
226 | trace_xfs_ag_resv_init(pag, type, ask); | ||
227 | return 0; | ||
219 | } | 228 | } |
220 | 229 | ||
221 | /* Create a per-AG block reservation. */ | 230 | /* Create a per-AG block reservation. */ |
@@ -223,6 +232,8 @@ int | |||
223 | xfs_ag_resv_init( | 232 | xfs_ag_resv_init( |
224 | struct xfs_perag *pag) | 233 | struct xfs_perag *pag) |
225 | { | 234 | { |
235 | struct xfs_mount *mp = pag->pag_mount; | ||
236 | xfs_agnumber_t agno = pag->pag_agno; | ||
226 | xfs_extlen_t ask; | 237 | xfs_extlen_t ask; |
227 | xfs_extlen_t used; | 238 | xfs_extlen_t used; |
228 | int error = 0; | 239 | int error = 0; |
@@ -231,23 +242,45 @@ xfs_ag_resv_init( | |||
231 | if (pag->pag_meta_resv.ar_asked == 0) { | 242 | if (pag->pag_meta_resv.ar_asked == 0) { |
232 | ask = used = 0; | 243 | ask = used = 0; |
233 | 244 | ||
234 | error = xfs_refcountbt_calc_reserves(pag->pag_mount, | 245 | error = xfs_refcountbt_calc_reserves(mp, agno, &ask, &used); |
235 | pag->pag_agno, &ask, &used); | ||
236 | if (error) | 246 | if (error) |
237 | goto out; | 247 | goto out; |
238 | 248 | ||
239 | error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, | 249 | error = xfs_finobt_calc_reserves(mp, agno, &ask, &used); |
240 | ask, used); | ||
241 | if (error) | 250 | if (error) |
242 | goto out; | 251 | goto out; |
252 | |||
253 | error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, | ||
254 | ask, used); | ||
255 | if (error) { | ||
256 | /* | ||
257 | * Because we didn't have per-AG reservations when the | ||
258 | * finobt feature was added we might not be able to | ||
259 | * reserve all needed blocks. Warn and fall back to the | ||
260 | * old and potentially buggy code in that case, but | ||
261 | * ensure we do have the reservation for the refcountbt. | ||
262 | */ | ||
263 | ask = used = 0; | ||
264 | |||
265 | mp->m_inotbt_nores = true; | ||
266 | |||
267 | error = xfs_refcountbt_calc_reserves(mp, agno, &ask, | ||
268 | &used); | ||
269 | if (error) | ||
270 | goto out; | ||
271 | |||
272 | error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, | ||
273 | ask, used); | ||
274 | if (error) | ||
275 | goto out; | ||
276 | } | ||
243 | } | 277 | } |
244 | 278 | ||
245 | /* Create the AGFL metadata reservation */ | 279 | /* Create the AGFL metadata reservation */ |
246 | if (pag->pag_agfl_resv.ar_asked == 0) { | 280 | if (pag->pag_agfl_resv.ar_asked == 0) { |
247 | ask = used = 0; | 281 | ask = used = 0; |
248 | 282 | ||
249 | error = xfs_rmapbt_calc_reserves(pag->pag_mount, pag->pag_agno, | 283 | error = xfs_rmapbt_calc_reserves(mp, agno, &ask, &used); |
250 | &ask, &used); | ||
251 | if (error) | 284 | if (error) |
252 | goto out; | 285 | goto out; |
253 | 286 | ||
@@ -256,9 +289,16 @@ xfs_ag_resv_init( | |||
256 | goto out; | 289 | goto out; |
257 | } | 290 | } |
258 | 291 | ||
292 | #ifdef DEBUG | ||
293 | /* need to read in the AGF for the ASSERT below to work */ | ||
294 | error = xfs_alloc_pagf_init(pag->pag_mount, NULL, pag->pag_agno, 0); | ||
295 | if (error) | ||
296 | return error; | ||
297 | |||
259 | ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + | 298 | ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + |
260 | xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <= | 299 | xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <= |
261 | pag->pagf_freeblks + pag->pagf_flcount); | 300 | pag->pagf_freeblks + pag->pagf_flcount); |
301 | #endif | ||
262 | out: | 302 | out: |
263 | return error; | 303 | return error; |
264 | } | 304 | } |