@@ -23,6 +23,7 @@
#include "xfs_trace.h"
#include "xfs_rtgroup.h"
#include "xfs_rtalloc.h"
+#include "xfs_rtrmap_btree.h"
/*
* Write new AG headers to disk. Non-transactional, but need to be
@@ -115,6 +116,13 @@ xfs_growfs_data_private(
xfs_buf_relse(bp);
}
+ /* Make sure the new fs size won't cause problems with the log. */
+ error = xfs_growfs_check_rtgeom(mp, nb, mp->m_sb.sb_rblocks,
+ mp->m_sb.sb_rextsize, mp->m_sb.sb_rextents,
+ mp->m_sb.sb_rbmblocks, mp->m_sb.sb_rextslog);
+ if (error)
+ return error;
+
nb_div = nb;
nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
nagcount = nb_div + (nb_mod != 0);
@@ -214,7 +222,11 @@ xfs_growfs_data_private(
error = xfs_fs_reserve_ag_blocks(mp);
if (error == -ENOSPC)
error = 0;
+
+ /* Compute new maxlevels for rt btrees. */
+ xfs_rtrmapbt_compute_maxlevels(mp);
}
+
return error;
out_trans_cancel:
@@ -1049,6 +1049,57 @@ xfs_growfs_rt_init_primary(
return 0;
}
+/*
+ * Check that changes to the realtime geometry won't affect the minimum
+ * log size, which would cause the fs to become unusable.
+ */
+int
+xfs_growfs_check_rtgeom(
+ const struct xfs_mount *mp,
+ xfs_rfsblock_t dblocks,
+ xfs_rfsblock_t rblocks,
+ xfs_agblock_t rextsize,
+ xfs_rtblock_t rextents,
+ xfs_extlen_t rbmblocks,
+ uint8_t rextslog)
+{
+ struct xfs_mount *fake_mp;
+ int min_logfsbs;
+
+ fake_mp = kmem_alloc(sizeof(struct xfs_mount), KM_MAYFAIL);
+ if (!fake_mp)
+ return -ENOMEM;
+
+ /*
+ * Create a dummy xfs_mount with the new rt geometry, and compute the
+ * new minimum log size. This ensures that the log is big enough to
+ * handle the larger transactions that we could start sending.
+ */
+ memcpy(fake_mp, mp, sizeof(struct xfs_mount));
+
+ fake_mp->m_sb.sb_dblocks = dblocks;
+ fake_mp->m_sb.sb_rblocks = rblocks;
+ fake_mp->m_sb.sb_rextents = rextents;
+ fake_mp->m_sb.sb_rextsize = rextsize;
+ fake_mp->m_sb.sb_rbmblocks = rbmblocks;
+ fake_mp->m_sb.sb_rextslog = rextslog;
+ if (rblocks > 0)
+ fake_mp->m_features |= XFS_FEAT_REALTIME;
+
+ xfs_rtrmapbt_compute_maxlevels(fake_mp);
+
+ xfs_trans_resv_calc(fake_mp, M_RES(fake_mp));
+ min_logfsbs = xfs_log_calc_minimum_size(fake_mp);
+ trace_xfs_growfs_check_rtgeom(mp, min_logfsbs);
+
+ kmem_free(fake_mp);
+
+ if (mp->m_sb.sb_logblocks < min_logfsbs)
+ return -ENOSPC;
+
+ return 0;
+}
+
/*
* Grow the realtime area of the filesystem.
*/
@@ -1139,6 +1190,12 @@ xfs_growfs_rt(
if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
return -EINVAL;
+ /* Make sure the new fs size won't cause problems with the log. */
+ error = xfs_growfs_check_rtgeom(mp, mp->m_sb.sb_dblocks, nrblocks,
+ in->extsize, nrextents, nrbmblocks, nrextslog);
+ if (error)
+ return error;
+
/* Allocate the new rt group structures */
if (xfs_has_rtgroups(mp)) {
/*
@@ -1313,8 +1370,12 @@ xfs_growfs_rt(
rtg->rtg_blockcount = xfs_rtgroup_block_count(mp,
rtg->rtg_rgno);
- /* Ensure the mount RT feature flag is now set. */
+ /*
+ * Ensure the mount RT feature flag is now set, and compute new
+ * maxlevels for rt btrees.
+ */
mp->m_features |= XFS_FEAT_REALTIME;
+ xfs_rtrmapbt_compute_maxlevels(mp);
}
if (error)
goto out_free;
@@ -84,6 +84,11 @@ xfs_growfs_rt(
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
int xfs_rtfile_convert_unwritten(struct xfs_inode *ip, loff_t pos,
uint64_t len);
+
+int xfs_growfs_check_rtgeom(const struct xfs_mount *mp, xfs_rfsblock_t dblocks,
+ xfs_rfsblock_t rblocks, xfs_agblock_t rextsize,
+ xfs_rtblock_t rextents, xfs_extlen_t rbmblocks,
+ uint8_t rextslog);
#else
# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (-ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (-ENOSYS)
@@ -107,6 +112,7 @@ xfs_rtmount_init(
# define xfs_rt_resv_free(mp) ((void)0)
# define xfs_rt_resv_init(mp) (0)
# define xfs_rtmount_dqattach(mp) (0)
+# define xfs_growfs_check_rtgeom(mp, d, r, rs, rx, rb, rl) (0)
#endif /* CONFIG_XFS_RT */
#endif /* __XFS_RTALLOC_H__ */
@@ -5196,6 +5196,27 @@ DEFINE_IMETA_RESV_EVENT(xfs_imeta_resv_free_extent);
DEFINE_IMETA_RESV_EVENT(xfs_imeta_resv_critical);
DEFINE_INODE_ERROR_EVENT(xfs_imeta_resv_init_error);
+#ifdef CONFIG_XFS_RT
+TRACE_EVENT(xfs_growfs_check_rtgeom,
+ TP_PROTO(const struct xfs_mount *mp, unsigned int min_logfsbs),
+ TP_ARGS(mp, min_logfsbs),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(unsigned int, logblocks)
+ __field(unsigned int, min_logfsbs)
+ ),
+ TP_fast_assign(
+ __entry->dev = mp->m_super->s_dev;
+ __entry->logblocks = mp->m_sb.sb_logblocks;
+ __entry->min_logfsbs = min_logfsbs;
+ ),
+ TP_printk("dev %d:%d logblocks %u min_logfsbs %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->logblocks,
+ __entry->min_logfsbs)
+);
+#endif /* CONFIG_XFS_RT */
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH