xfs: allow internal RT devices for zoned mode

Allow creating an RT subvolume on the same device as the main data
device.  This is mostly used for SMR HDDs where the conventional zones
are used for the data device and the sequential write required zones
for the zoned RT section.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
This commit is contained in:
Christoph Hellwig 2024-11-17 08:53:10 +01:00
parent 2167eaabe2
commit bdc03eb5f9
8 changed files with 34 additions and 9 deletions

View file

@ -107,9 +107,11 @@ xfs_gbno_to_daddr(
xfs_agblock_t gbno) xfs_agblock_t gbno)
{ {
struct xfs_mount *mp = xg->xg_mount; struct xfs_mount *mp = xg->xg_mount;
uint32_t blocks = mp->m_groups[xg->xg_type].blocks; struct xfs_groups *g = &mp->m_groups[xg->xg_type];
xfs_fsblock_t fsbno;
return XFS_FSB_TO_BB(mp, (xfs_fsblock_t)xg->xg_gno * blocks + gbno); fsbno = (xfs_fsblock_t)xg->xg_gno * g->blocks + gbno;
return XFS_FSB_TO_BB(mp, g->start_fsb + fsbno);
} }
static inline uint32_t static inline uint32_t

View file

@ -230,7 +230,8 @@ xfs_rtb_to_daddr(
xfs_rgnumber_t rgno = xfs_rtb_to_rgno(mp, rtbno); xfs_rgnumber_t rgno = xfs_rtb_to_rgno(mp, rtbno);
uint64_t start_bno = (xfs_rtblock_t)rgno * g->blocks; uint64_t start_bno = (xfs_rtblock_t)rgno * g->blocks;
return XFS_FSB_TO_BB(mp, start_bno + (rtbno & g->blkmask)); return XFS_FSB_TO_BB(mp,
g->start_fsb + start_bno + (rtbno & g->blkmask));
} }
static inline xfs_rtblock_t static inline xfs_rtblock_t
@ -238,10 +239,11 @@ xfs_daddr_to_rtb(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_daddr_t daddr) xfs_daddr_t daddr)
{ {
xfs_rfsblock_t bno = XFS_BB_TO_FSBT(mp, daddr); struct xfs_groups *g = &mp->m_groups[XG_TYPE_RTG];
xfs_rfsblock_t bno;
bno = XFS_BB_TO_FSBT(mp, daddr) - g->start_fsb;
if (xfs_has_rtgroups(mp)) { if (xfs_has_rtgroups(mp)) {
struct xfs_groups *g = &mp->m_groups[XG_TYPE_RTG];
xfs_rgnumber_t rgno; xfs_rgnumber_t rgno;
uint32_t rgbno; uint32_t rgbno;

View file

@ -1204,6 +1204,7 @@ xfs_sb_mount_rextsize(
rgs->blocks = sbp->sb_rgextents * sbp->sb_rextsize; rgs->blocks = sbp->sb_rgextents * sbp->sb_rextsize;
rgs->blklog = mp->m_sb.sb_rgblklog; rgs->blklog = mp->m_sb.sb_rgblklog;
rgs->blkmask = xfs_mask32lo(mp->m_sb.sb_rgblklog); rgs->blkmask = xfs_mask32lo(mp->m_sb.sb_rgblklog);
rgs->start_fsb = mp->m_sb.sb_rtstart;
} else { } else {
rgs->blocks = 0; rgs->blocks = 0;
rgs->blklog = 0; rgs->blklog = 0;

View file

@ -150,7 +150,7 @@ xfs_file_fsync(
* ensure newly written file data make it to disk before logging the new * ensure newly written file data make it to disk before logging the new
* inode size in case of an extending write. * inode size in case of an extending write.
*/ */
if (XFS_IS_REALTIME_INODE(ip)) if (XFS_IS_REALTIME_INODE(ip) && mp->m_rtdev_targp != mp->m_ddev_targp)
error = blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev); error = blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
else if (mp->m_logdev_targp != mp->m_ddev_targp) else if (mp->m_logdev_targp != mp->m_ddev_targp)
error = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev); error = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);

View file

@ -308,6 +308,10 @@ xfs_growfs_data(
if (!mutex_trylock(&mp->m_growlock)) if (!mutex_trylock(&mp->m_growlock))
return -EWOULDBLOCK; return -EWOULDBLOCK;
/* we can't grow the data section when an internal RT section exists */
if (in->newblocks != mp->m_sb.sb_dblocks && mp->m_sb.sb_rtstart)
return -EINVAL;
/* update imaxpct separately to the physical grow of the filesystem */ /* update imaxpct separately to the physical grow of the filesystem */
if (in->imaxpct != mp->m_sb.sb_imax_pct) { if (in->imaxpct != mp->m_sb.sb_imax_pct) {
error = xfs_growfs_imaxpct(mp, in->imaxpct); error = xfs_growfs_imaxpct(mp, in->imaxpct);

View file

@ -103,6 +103,13 @@ struct xfs_groups {
* rtgroup, so this mask must be 64-bit. * rtgroup, so this mask must be 64-bit.
*/ */
uint64_t blkmask; uint64_t blkmask;
/*
* Start of the first group in the device. This is used to support a
* RT device following the data device on the same block device for
* SMR hard drives.
*/
xfs_fsblock_t start_fsb;
}; };
struct xfs_freecounter { struct xfs_freecounter {

View file

@ -1266,7 +1266,8 @@ xfs_rt_check_size(
return -EFBIG; return -EFBIG;
} }
error = xfs_buf_read_uncached(mp->m_rtdev_targp, daddr, error = xfs_buf_read_uncached(mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart) + daddr,
XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL); XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
if (error) if (error)
xfs_warn(mp, "cannot read last RT device sector (%lld)", xfs_warn(mp, "cannot read last RT device sector (%lld)",

View file

@ -533,7 +533,15 @@ xfs_setup_devices(
if (error) if (error)
return error; return error;
} }
if (mp->m_rtdev_targp) {
if (mp->m_sb.sb_rtstart) {
if (mp->m_rtdev_targp) {
xfs_warn(mp,
"can't use internal and external rtdev at the same time");
return -EINVAL;
}
mp->m_rtdev_targp = mp->m_ddev_targp;
} else if (mp->m_rtname) {
error = xfs_setsize_buftarg(mp->m_rtdev_targp, error = xfs_setsize_buftarg(mp->m_rtdev_targp,
mp->m_sb.sb_sectsize); mp->m_sb.sb_sectsize);
if (error) if (error)
@ -757,7 +765,7 @@ xfs_mount_free(
{ {
if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
xfs_free_buftarg(mp->m_logdev_targp); xfs_free_buftarg(mp->m_logdev_targp);
if (mp->m_rtdev_targp) if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp)
xfs_free_buftarg(mp->m_rtdev_targp); xfs_free_buftarg(mp->m_rtdev_targp);
if (mp->m_ddev_targp) if (mp->m_ddev_targp)
xfs_free_buftarg(mp->m_ddev_targp); xfs_free_buftarg(mp->m_ddev_targp);