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 | } |
