Commit ae897e0b authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Darrick J. Wong
Browse files

xfs: support creating per-RTG files in growfs



To support adding new RT groups in growfs, we need to be able to create
the per-RT group files.  Add a new xfs_rtginode_create helper to create
a given per-RTG file.  Most of the code for that is shared, but the
details of the actual file are abstracted out using a new create method
in struct xfs_rtginode_ops.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
parent e3088ae2
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -1297,3 +1297,35 @@ xfs_rtfile_initialize_blocks(

	return 0;
}

int
xfs_rtbitmap_create(
	struct xfs_rtgroup	*rtg,
	struct xfs_inode	*ip,
	struct xfs_trans	*tp,
	bool			init)
{
	struct xfs_mount	*mp = rtg_mount(rtg);

	ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
	if (init && !xfs_has_rtgroups(mp)) {
		ip->i_diflags |= XFS_DIFLAG_NEWRTBM;
		inode_set_atime(VFS_I(ip), 0, 0);
	}
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	return 0;
}

int
xfs_rtsummary_create(
	struct xfs_rtgroup	*rtg,
	struct xfs_inode	*ip,
	struct xfs_trans	*tp,
	bool			init)
{
	struct xfs_mount	*mp = rtg_mount(rtg);

	ip->i_disk_size = mp->m_rsumblocks * mp->m_sb.sb_blocksize;
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	return 0;
}
+4 −0
Original line number Diff line number Diff line
@@ -315,6 +315,10 @@ xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
int xfs_rtfile_initialize_blocks(struct xfs_rtgroup *rtg,
		enum xfs_rtg_inodes type, xfs_fileoff_t offset_fsb,
		xfs_fileoff_t end_fsb, void *data);
int xfs_rtbitmap_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip,
		struct xfs_trans *tp, bool init);
int xfs_rtsummary_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip,
		struct xfs_trans *tp, bool init);

#else /* CONFIG_XFS_RT */
# define xfs_rtfree_extent(t,b,l)			(-ENOSYS)
+69 −0
Original line number Diff line number Diff line
@@ -272,16 +272,24 @@ struct xfs_rtginode_ops {

	/* Does the fs have this feature? */
	bool			(*enabled)(struct xfs_mount *mp);

	/* Create this rtgroup metadata inode and initialize it. */
	int			(*create)(struct xfs_rtgroup *rtg,
					  struct xfs_inode *ip,
					  struct xfs_trans *tp,
					  bool init);
};

static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = {
	[XFS_RTGI_BITMAP] = {
		.name		= "bitmap",
		.metafile_type	= XFS_METAFILE_RTBITMAP,
		.create		= xfs_rtbitmap_create,
	},
	[XFS_RTGI_SUMMARY] = {
		.name		= "summary",
		.metafile_type	= XFS_METAFILE_RTSUMMARY,
		.create		= xfs_rtsummary_create,
	},
};

@@ -389,6 +397,67 @@ xfs_rtginode_irele(
	*ipp = NULL;
}

/* Add a metadata inode for a realtime rmap btree. */
int
xfs_rtginode_create(
	struct xfs_rtgroup		*rtg,
	enum xfs_rtg_inodes		type,
	bool				init)
{
	const struct xfs_rtginode_ops	*ops = &xfs_rtginode_ops[type];
	struct xfs_mount		*mp = rtg_mount(rtg);
	struct xfs_metadir_update	upd = {
		.dp			= mp->m_rtdirip,
		.metafile_type		= ops->metafile_type,
	};
	int				error;

	if (!xfs_rtginode_enabled(rtg, type))
		return 0;

	if (!mp->m_rtdirip)
		return -EFSCORRUPTED;

	upd.path = xfs_rtginode_path(rtg_rgno(rtg), type);
	if (!upd.path)
		return -ENOMEM;

	error = xfs_metadir_start_create(&upd);
	if (error)
		goto out_path;

	error = xfs_metadir_create(&upd, S_IFREG);
	if (error)
		return error;

	xfs_rtginode_lockdep_setup(upd.ip, rtg_rgno(rtg), type);

	upd.ip->i_projid = rtg_rgno(rtg);
	error = ops->create(rtg, upd.ip, upd.tp, init);
	if (error)
		goto out_cancel;

	error = xfs_metadir_commit(&upd);
	if (error)
		goto out_path;

	kfree(upd.path);
	xfs_finish_inode_setup(upd.ip);
	rtg->rtg_inodes[type] = upd.ip;
	return 0;

out_cancel:
	xfs_metadir_cancel(&upd, error);
	/* Have to finish setting up the inode to ensure it's deleted. */
	if (upd.ip) {
		xfs_finish_inode_setup(upd.ip);
		xfs_irele(upd.ip);
	}
out_path:
	kfree(upd.path);
	return error;
}

/* Create the parent directory for all rtgroup inodes and load it. */
int
xfs_rtginode_mkdir_parent(
+2 −0
Original line number Diff line number Diff line
@@ -242,6 +242,8 @@ enum xfs_metafile_type xfs_rtginode_metafile_type(enum xfs_rtg_inodes type);
bool xfs_rtginode_enabled(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type);
int xfs_rtginode_load(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type,
		struct xfs_trans *tp);
int xfs_rtginode_create(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type,
		bool init);
void xfs_rtginode_irele(struct xfs_inode **ipp);

static inline const char *xfs_rtginode_path(xfs_rgnumber_t rgno,
+30 −0
Original line number Diff line number Diff line
@@ -711,6 +711,29 @@ xfs_growfs_rt_fixup_extsize(
	return error;
}

/* Ensure that the rtgroup metadata inode is loaded, creating it if neeeded. */
static int
xfs_rtginode_ensure(
	struct xfs_rtgroup	*rtg,
	enum xfs_rtg_inodes	type)
{
	struct xfs_trans	*tp;
	int			error;

	if (rtg->rtg_inodes[type])
		return 0;

	error = xfs_trans_alloc_empty(rtg_mount(rtg), &tp);
	if (error)
		return error;
	error = xfs_rtginode_load(rtg, type, tp);
	xfs_trans_cancel(tp);

	if (error != -ENOENT)
		return 0;
	return xfs_rtginode_create(rtg, type, true);
}

static int
xfs_growfs_rt_bmblock(
	struct xfs_rtgroup	*rtg,
@@ -927,12 +950,19 @@ xfs_growfs_rtg(
	xfs_extlen_t		bmblocks;
	xfs_fileoff_t		bmbno;
	struct xfs_rtgroup	*rtg;
	unsigned int		i;
	int			error;

	rtg = xfs_rtgroup_grab(mp, 0);
	if (!rtg)
		return -EINVAL;

	for (i = 0; i < XFS_RTGI_MAX; i++) {
		error = xfs_rtginode_ensure(rtg, i);
		if (error)
			goto out_rele;
	}

	error = xfs_growfs_rt_alloc_blocks(rtg, nrblocks, rextsize, &bmblocks);
	if (error)
		goto out_rele;