@@ -98,6 +98,7 @@ int libxfs_trans_reserve_more(struct xfs_trans *tp, uint blocks,
void xfs_defer_cancel(struct xfs_trans *);
struct xfs_buf *libxfs_trans_getsb(struct xfs_trans *);
+struct xfs_buf *libxfs_trans_getrtsb(struct xfs_trans *tp);
void libxfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
void libxfs_trans_log_inode (struct xfs_trans *, struct xfs_inode *,
@@ -263,6 +263,7 @@
#define xfs_trans_dirty_buf libxfs_trans_dirty_buf
#define xfs_trans_get_buf libxfs_trans_get_buf
#define xfs_trans_get_buf_map libxfs_trans_get_buf_map
+#define xfs_trans_getrtsb libxfs_trans_getrtsb
#define xfs_trans_getsb libxfs_trans_getsb
#define xfs_trans_ichgtime libxfs_trans_ichgtime
#define xfs_trans_ijoin libxfs_trans_ijoin
@@ -197,6 +197,7 @@ libxfs_buf_read(
int libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops);
struct xfs_buf *libxfs_getsb(struct xfs_mount *mp);
+struct xfs_buf *libxfs_getrtsb(struct xfs_mount *mp);
extern void libxfs_bcache_purge(struct xfs_mount *mp);
extern void libxfs_bcache_free(void);
extern void libxfs_bcache_flush(struct xfs_mount *mp);
@@ -164,6 +164,23 @@ libxfs_getsb(
return bp;
}
+struct xfs_buf *
+libxfs_getrtsb(
+ struct xfs_mount *mp)
+{
+ struct xfs_buf *bp;
+ int error;
+
+ if (!mp->m_rtdev_targp->bt_bdev)
+ return NULL;
+
+ error = libxfs_buf_read_uncached(mp->m_rtdev_targp, XFS_RTSB_DADDR,
+ XFS_FSB_TO_BB(mp, 1), 0, &bp, &xfs_rtsb_buf_ops);
+ if (error)
+ return NULL;
+ return bp;
+}
+
struct kmem_cache *xfs_buf_cache;
static struct cache_mru xfs_buf_freelist =
@@ -511,6 +511,35 @@ libxfs_trans_getsb(
return bp;
}
+struct xfs_buf *
+libxfs_trans_getrtsb(
+ struct xfs_trans *tp)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_buf *bp;
+ struct xfs_buf_log_item *bip;
+ int len = XFS_FSS_TO_BB(mp, 1);
+ DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len);
+
+ bp = xfs_trans_buf_item_match(tp, mp->m_rtdev, &map, 1);
+ if (bp != NULL) {
+ ASSERT(bp->b_transp == tp);
+ bip = bp->b_log_item;
+ ASSERT(bip != NULL);
+ bip->bli_recur++;
+ trace_xfs_trans_getsb_recur(bip);
+ return bp;
+ }
+
+ bp = libxfs_getrtsb(mp);
+ if (bp == NULL)
+ return NULL;
+
+ _libxfs_trans_bjoin(tp, bp, 1);
+ trace_xfs_trans_getsb(bp->b_log_item);
+ return bp;
+}
+
int
libxfs_trans_read_buf_map(
struct xfs_mount *mp,
@@ -305,3 +305,77 @@ const struct xfs_buf_ops xfs_rtsb_buf_ops = {
.verify_write = xfs_rtsb_write_verify,
.verify_struct = xfs_rtsb_verify,
};
+
+/* Update a realtime superblock from the primary fs super */
+void
+xfs_rtgroup_update_super(
+ struct xfs_buf *rtsb_bp,
+ const struct xfs_buf *sb_bp)
+{
+ const struct xfs_dsb *dsb = sb_bp->b_addr;
+ struct xfs_rtsb *rsb = rtsb_bp->b_addr;
+ const uuid_t *meta_uuid;
+
+ rsb->rsb_magicnum = cpu_to_be32(XFS_RTSB_MAGIC);
+ rsb->rsb_blocksize = dsb->sb_blocksize;
+ rsb->rsb_rblocks = dsb->sb_rblocks;
+
+ rsb->rsb_rextents = dsb->sb_rextents;
+ rsb->rsb_lsn = 0;
+
+ memcpy(&rsb->rsb_uuid, &dsb->sb_uuid, sizeof(rsb->rsb_uuid));
+
+ rsb->rsb_rgcount = dsb->sb_rgcount;
+ memcpy(&rsb->rsb_fname, &dsb->sb_fname, XFSLABEL_MAX);
+
+ rsb->rsb_rextsize = dsb->sb_rextsize;
+ rsb->rsb_rbmblocks = dsb->sb_rbmblocks;
+
+ rsb->rsb_rgblocks = dsb->sb_rgblocks;
+ rsb->rsb_blocklog = dsb->sb_blocklog;
+ rsb->rsb_sectlog = dsb->sb_sectlog;
+ rsb->rsb_rextslog = dsb->sb_rextslog;
+ rsb->rsb_pad = 0;
+ rsb->rsb_pad2 = 0;
+
+ /*
+ * The metadata uuid is the fs uuid if the metauuid feature is not
+ * enabled.
+ */
+ if (dsb->sb_features_incompat &
+ cpu_to_be32(XFS_SB_FEAT_INCOMPAT_META_UUID))
+ meta_uuid = &dsb->sb_meta_uuid;
+ else
+ meta_uuid = &dsb->sb_uuid;
+ memcpy(&rsb->rsb_meta_uuid, meta_uuid, sizeof(rsb->rsb_meta_uuid));
+}
+
+/*
+ * Update the primary realtime superblock from a filesystem superblock and
+ * log it to the given transaction.
+ */
+void
+xfs_rtgroup_log_super(
+ struct xfs_trans *tp,
+ const struct xfs_buf *sb_bp)
+{
+ struct xfs_buf *rtsb_bp;
+
+ if (!xfs_has_rtgroups(tp->t_mountp))
+ return;
+
+ rtsb_bp = xfs_trans_getrtsb(tp);
+ if (!rtsb_bp) {
+ /*
+ * It's possible for the rtgroups feature to be enabled but
+ * there is no incore rt superblock buffer if the rt geometry
+ * was specified at mkfs time but the rt section has not yet
+ * been attached. In this case, rblocks must be zero.
+ */
+ ASSERT(tp->t_mountp->m_sb.sb_rblocks == 0);
+ return;
+ }
+
+ xfs_rtgroup_update_super(rtsb_bp, sb_bp);
+ xfs_trans_ordered_buf(tp, rtsb_bp);
+}
@@ -197,8 +197,14 @@ xfs_daddr_to_rgbno(
#ifdef CONFIG_XFS_RT
xfs_rgblock_t xfs_rtgroup_block_count(struct xfs_mount *mp,
xfs_rgnumber_t rgno);
+
+void xfs_rtgroup_update_super(struct xfs_buf *rtsb_bp,
+ const struct xfs_buf *sb_bp);
+void xfs_rtgroup_log_super(struct xfs_trans *tp, const struct xfs_buf *sb_bp);
#else
# define xfs_rtgroup_block_count(mp, rgno) (0)
+# define xfs_rtgroup_update_super(bp, sb_bp) ((void)0)
+# define xfs_rtgroup_log_super(tp, sb_bp) ((void)0)
#endif /* CONFIG_XFS_RT */
#endif /* __LIBXFS_RTGROUP_H */
@@ -24,6 +24,7 @@
#include "xfs_health.h"
#include "xfs_ag.h"
#include "xfs_swapext.h"
+#include "xfs_rtgroup.h"
/*
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1098,6 +1099,8 @@ xfs_log_sb(
xfs_sb_to_disk(bp->b_addr, &mp->m_sb);
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsb) - 1);
+
+ xfs_rtgroup_log_super(tp, bp);
}
/*
@@ -1214,6 +1217,7 @@ xfs_sync_sb_buf(
{
struct xfs_trans *tp;
struct xfs_buf *bp;
+ struct xfs_buf *rtsb_bp = NULL;
int error;
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, 0, &tp);
@@ -1223,6 +1227,11 @@ xfs_sync_sb_buf(
bp = xfs_trans_getsb(tp);
xfs_log_sb(tp);
xfs_trans_bhold(tp, bp);
+ if (xfs_has_rtgroups(mp)) {
+ rtsb_bp = xfs_trans_getrtsb(tp);
+ if (rtsb_bp)
+ xfs_trans_bhold(tp, rtsb_bp);
+ }
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp);
if (error)
@@ -1231,7 +1240,11 @@ xfs_sync_sb_buf(
* write out the sb buffer to get the changes to disk
*/
error = xfs_bwrite(bp);
+ if (!error && rtsb_bp)
+ error = xfs_bwrite(rtsb_bp);
out:
+ if (rtsb_bp)
+ xfs_buf_relse(rtsb_bp);
xfs_buf_relse(bp);
return error;
}