diff mbox series

[15/58] xfs: ensure metadata directory paths exist before creating files

Message ID 170405010148.1809361.16643842176885546069.stgit@frogsfrogsfrogs (mailing list archive)
State Deferred, archived
Headers show
Series [01/58] xfs: don't use the incore struct xfs_sb for offsets into struct xfs_dsb | expand

Commit Message

Darrick J. Wong Dec. 31, 2023, 11:33 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Since xfs_imeta_create can create new metadata files arbitrarily deep in
the metadata directory tree, we must supply a function that can ensure
that all directories in a path exist, and call it before the quota
functions create the quota inodes.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/imeta_utils.c     |   69 ++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/imeta_utils.h     |    3 ++
 libxfs/libxfs_api_defs.h |    1 +
 mkfs/proto.c             |    8 +++++
 4 files changed, 81 insertions(+)
diff mbox series

Patch

diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c
index ce6000530d3..0186968ed3e 100644
--- a/libxfs/imeta_utils.c
+++ b/libxfs/imeta_utils.c
@@ -246,3 +246,72 @@  xfs_imeta_cancel_update(
 
 	xfs_imeta_teardown(upd, error);
 }
+
+/* Create a metadata for the last component of the path. */
+STATIC int
+xfs_imeta_mkdir(
+	struct xfs_mount		*mp,
+	const struct xfs_imeta_path	*path)
+{
+	struct xfs_imeta_update		upd;
+	struct xfs_inode		*ip = NULL;
+	int				error;
+
+	if (xfs_is_shutdown(mp))
+		return -EIO;
+
+	/* Allocate a transaction to create the last directory. */
+	error = xfs_imeta_start_create(mp, path, &upd);
+	if (error)
+		return error;
+
+	/* Create the subdirectory and take our reference. */
+	error = xfs_imeta_create(&upd, S_IFDIR, &ip);
+	if (error)
+		goto out_cancel;
+
+	error = xfs_imeta_commit_update(&upd);
+
+	/*
+	 * We don't pass the directory we just created to the caller, so finish
+	 * setting up the inode, then release the dir and the dquots.
+	 */
+	goto out_irele;
+
+out_cancel:
+	xfs_imeta_cancel_update(&upd, error);
+out_irele:
+	/* Have to finish setting up the inode to ensure it's deleted. */
+	if (ip)
+		xfs_irele(ip);
+	return error;
+}
+
+/*
+ * Make sure that every metadata directory path component exists and is a
+ * directory.
+ */
+int
+xfs_imeta_ensure_dirpath(
+	struct xfs_mount		*mp,
+	const struct xfs_imeta_path	*path)
+{
+	struct xfs_imeta_path		temp_path = {
+		.im_path		= path->im_path,
+		.im_depth		= 1,
+		.im_ftype		= XFS_DIR3_FT_DIR,
+	};
+	unsigned int			i;
+	int				error = 0;
+
+	if (!xfs_has_metadir(mp))
+		return 0;
+
+	for (i = 0; i < path->im_depth - 1; i++, temp_path.im_depth++) {
+		error = xfs_imeta_mkdir(mp, &temp_path);
+		if (error && error != -EEXIST)
+			return error;
+	}
+
+	return 0;
+}
diff --git a/libxfs/imeta_utils.h b/libxfs/imeta_utils.h
index a2afc0f37ac..8ab81149b05 100644
--- a/libxfs/imeta_utils.h
+++ b/libxfs/imeta_utils.h
@@ -18,6 +18,9 @@  int xfs_imeta_start_unlink(struct xfs_mount *mp,
 		const struct xfs_imeta_path *path,
 		struct xfs_inode *ip, struct xfs_imeta_update *upd);
 
+int xfs_imeta_ensure_dirpath(struct xfs_mount *mp,
+		const struct xfs_imeta_path *path);
+
 int xfs_imeta_commit_update(struct xfs_imeta_update *upd);
 void xfs_imeta_cancel_update(struct xfs_imeta_update *upd, int error);
 
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 90304da8983..e08be764a49 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -178,6 +178,7 @@ 
 #define xfs_imeta_commit_update		libxfs_imeta_commit_update
 #define xfs_imeta_create		libxfs_imeta_create
 #define xfs_imeta_create_space_res	libxfs_imeta_create_space_res
+#define xfs_imeta_ensure_dirpath	libxfs_imeta_ensure_dirpath
 #define xfs_imeta_iget			libxfs_imeta_iget
 #define xfs_imeta_irele			libxfs_imeta_irele
 #define xfs_imeta_link			libxfs_imeta_link
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 2eff1f32173..5e17ea420f4 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -754,6 +754,10 @@  rtbitmap_create(
 	struct xfs_inode	*rbmip;
 	int			error;
 
+	error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTBITMAP);
+	if (error)
+		fail(_("Realtime bitmap directory allocation failed"), error);
+
 	error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTBITMAP, &upd);
 	if (error)
 		res_failed(error);
@@ -783,6 +787,10 @@  rtsummary_create(
 	struct xfs_inode	*rsumip;
 	int			error;
 
+	error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTSUMMARY);
+	if (error)
+		fail(_("Realtime summary directory allocation failed"), error);
+
 	error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTSUMMARY, &upd);
 	if (error)
 		res_failed(error);