diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_ag_resv.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_ag_resv.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index d12feec486fb..c0cc9c823c9e 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c @@ -21,6 +21,7 @@ #include "xfs_ialloc_btree.h" #include "xfs_sb.h" #include "xfs_ag_resv.h" +#include "xfs_ag.h" /* * Per-AG Block Reservations @@ -75,6 +76,10 @@ xfs_ag_resv_critical( xfs_extlen_t btree_maxlevels; switch (type) { + case XFS_AG_RESV_RTMETADATA: + avail = percpu_counter_sum(&pag->pag_mount->m_fdblocks); + orig = pag->pag_mount->m_rtmeta_resv.ar_asked; + break; case XFS_AG_RESV_METADATA: avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved; orig = pag->pag_meta_resv.ar_asked; @@ -111,6 +116,7 @@ xfs_ag_resv_needed( len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved; switch (type) { + case XFS_AG_RESV_RTMETADATA: case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: len -= xfs_perag_resv(pag, type)->ar_reserved; @@ -177,6 +183,82 @@ xfs_ag_resv_free( return error; } +/* Clean out a rt reservation */ +int +xfs_rt_resv_free( + struct xfs_mount *mp) +{ + int error; + + trace_xfs_rt_resv_free(mp, 0); + + error = xfs_mod_fdblocks(mp, mp->m_rtmeta_resv.ar_reserved, true); + if (error) + return error; + + mp->m_rtmeta_resv.ar_reserved = 0; + mp->m_rtmeta_resv.ar_asked = 0; + mp->m_rtmeta_resv.ar_orig_reserved = 0; + return 0; +} + +static int +__xfs_rt_resv_init( + struct xfs_mount *mp, + xfs_filblks_t ask, + xfs_filblks_t used) +{ + xfs_filblks_t hidden_space; + int error; + + /* + * Space taken by all other metadata btrees are accounted on-disk as + * used space. We therefore only hide the space that is reserved but + * not used by the trees. + */ + if (used > ask) + ask = used; + hidden_space = ask - used; + + error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true); + if (error) { + trace_xfs_ag_resv_init_error(mp, NULLAGNUMBER, error, + _RET_IP_); + xfs_warn(mp, +"Space reservation for rt metadata failed. Filesystem may run out of space."); + return error; + } + + mp->m_rtmeta_resv.ar_asked = ask; + mp->m_rtmeta_resv.ar_orig_reserved = hidden_space; + mp->m_rtmeta_resv.ar_reserved = ask - used; + + trace_xfs_rt_resv_init(mp, ask); + return 0; +} + +/* Create a rt metadata block reservation. */ +int +xfs_rt_resv_init( + struct xfs_mount *mp, + struct xfs_trans *tp) +{ + xfs_filblks_t ask; + xfs_filblks_t used; + int error; + + /* Create the rt metadata reservation. */ + if (mp->m_rtmeta_resv.ar_asked == 0) { + ask = used = 0; + + error = __xfs_rt_resv_init(mp, ask, used); + if (error) + return error; + } + + return 0; +} + static int __xfs_ag_resv_init( struct xfs_perag *pag, @@ -202,6 +284,7 @@ __xfs_ag_resv_init( */ hidden_space = ask; break; + case XFS_AG_RESV_RTMETADATA: case XFS_AG_RESV_METADATA: /* * Space taken by all other metadata btrees are accounted @@ -335,6 +418,7 @@ xfs_ag_resv_alloc_extent( switch (type) { case XFS_AG_RESV_AGFL: return; + case XFS_AG_RESV_RTMETADATA: case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: resv = xfs_perag_resv(pag, type); @@ -377,6 +461,7 @@ xfs_ag_resv_free_extent( switch (type) { case XFS_AG_RESV_AGFL: return; + case XFS_AG_RESV_RTMETADATA: case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: resv = xfs_perag_resv(pag, type); |