|
@@ -39,6 +39,7 @@
|
|
|
#include "xfs_rmap_btree.h"
|
|
|
#include "xfs_btree.h"
|
|
|
#include "xfs_refcount_btree.h"
|
|
|
+#include "xfs_ialloc_btree.h"
|
|
|
|
|
|
/*
|
|
|
* Per-AG Block Reservations
|
|
@@ -200,22 +201,30 @@ __xfs_ag_resv_init(
|
|
|
struct xfs_mount *mp = pag->pag_mount;
|
|
|
struct xfs_ag_resv *resv;
|
|
|
int error;
|
|
|
+ xfs_extlen_t reserved;
|
|
|
|
|
|
- resv = xfs_perag_resv(pag, type);
|
|
|
if (used > ask)
|
|
|
ask = used;
|
|
|
- resv->ar_asked = ask;
|
|
|
- resv->ar_reserved = resv->ar_orig_reserved = ask - used;
|
|
|
- mp->m_ag_max_usable -= ask;
|
|
|
+ reserved = ask - used;
|
|
|
|
|
|
- trace_xfs_ag_resv_init(pag, type, ask);
|
|
|
-
|
|
|
- error = xfs_mod_fdblocks(mp, -(int64_t)resv->ar_reserved, true);
|
|
|
- if (error)
|
|
|
+ error = xfs_mod_fdblocks(mp, -(int64_t)reserved, true);
|
|
|
+ if (error) {
|
|
|
trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno,
|
|
|
error, _RET_IP_);
|
|
|
+ xfs_warn(mp,
|
|
|
+"Per-AG reservation for AG %u failed. Filesystem may run out of space.",
|
|
|
+ pag->pag_agno);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
|
|
|
- return error;
|
|
|
+ mp->m_ag_max_usable -= ask;
|
|
|
+
|
|
|
+ resv = xfs_perag_resv(pag, type);
|
|
|
+ resv->ar_asked = ask;
|
|
|
+ resv->ar_reserved = resv->ar_orig_reserved = reserved;
|
|
|
+
|
|
|
+ trace_xfs_ag_resv_init(pag, type, ask);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* Create a per-AG block reservation. */
|
|
@@ -223,6 +232,8 @@ int
|
|
|
xfs_ag_resv_init(
|
|
|
struct xfs_perag *pag)
|
|
|
{
|
|
|
+ struct xfs_mount *mp = pag->pag_mount;
|
|
|
+ xfs_agnumber_t agno = pag->pag_agno;
|
|
|
xfs_extlen_t ask;
|
|
|
xfs_extlen_t used;
|
|
|
int error = 0;
|
|
@@ -231,23 +242,45 @@ xfs_ag_resv_init(
|
|
|
if (pag->pag_meta_resv.ar_asked == 0) {
|
|
|
ask = used = 0;
|
|
|
|
|
|
- error = xfs_refcountbt_calc_reserves(pag->pag_mount,
|
|
|
- pag->pag_agno, &ask, &used);
|
|
|
+ error = xfs_refcountbt_calc_reserves(mp, agno, &ask, &used);
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
|
- error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
|
|
|
- ask, used);
|
|
|
+ error = xfs_finobt_calc_reserves(mp, agno, &ask, &used);
|
|
|
if (error)
|
|
|
goto out;
|
|
|
+
|
|
|
+ error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
|
|
|
+ ask, used);
|
|
|
+ if (error) {
|
|
|
+ /*
|
|
|
+ * Because we didn't have per-AG reservations when the
|
|
|
+ * finobt feature was added we might not be able to
|
|
|
+ * reserve all needed blocks. Warn and fall back to the
|
|
|
+ * old and potentially buggy code in that case, but
|
|
|
+ * ensure we do have the reservation for the refcountbt.
|
|
|
+ */
|
|
|
+ ask = used = 0;
|
|
|
+
|
|
|
+ mp->m_inotbt_nores = true;
|
|
|
+
|
|
|
+ error = xfs_refcountbt_calc_reserves(mp, agno, &ask,
|
|
|
+ &used);
|
|
|
+ if (error)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
|
|
|
+ ask, used);
|
|
|
+ if (error)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Create the AGFL metadata reservation */
|
|
|
if (pag->pag_agfl_resv.ar_asked == 0) {
|
|
|
ask = used = 0;
|
|
|
|
|
|
- error = xfs_rmapbt_calc_reserves(pag->pag_mount, pag->pag_agno,
|
|
|
- &ask, &used);
|
|
|
+ error = xfs_rmapbt_calc_reserves(mp, agno, &ask, &used);
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
@@ -256,9 +289,16 @@ xfs_ag_resv_init(
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+#ifdef DEBUG
|
|
|
+ /* need to read in the AGF for the ASSERT below to work */
|
|
|
+ error = xfs_alloc_pagf_init(pag->pag_mount, NULL, pag->pag_agno, 0);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
|
|
|
xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <=
|
|
|
pag->pagf_freeblks + pag->pagf_flcount);
|
|
|
+#endif
|
|
|
out:
|
|
|
return error;
|
|
|
}
|