@@ -95,6 +95,7 @@ struct iomap;
#include "xfs_btree_mem.h"
#include "xfs_parent.h"
#include "xfs_ag_resv.h"
+#include "xfs_metafile.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -210,6 +210,11 @@ static inline struct timespec64 inode_set_ctime_current(struct inode *inode)
return now;
}
+static inline bool inode_wrong_type(const struct inode *inode, umode_t mode)
+{
+ return (inode->i_mode ^ mode) & S_IFMT;
+}
+
typedef struct xfs_inode {
struct cache_node i_node;
struct xfs_mount *i_mount; /* fs mount struct ptr */
@@ -55,6 +55,7 @@ HFILES = \
xfs_inode_buf.h \
xfs_inode_fork.h \
xfs_inode_util.h \
+ xfs_metafile.h \
xfs_parent.h \
xfs_quota_defs.h \
xfs_refcount.h \
@@ -205,6 +205,61 @@ libxfs_iget(
return error;
}
+/*
+ * Get a metadata inode.
+ *
+ * The metafile type must match the file mode exactly.
+ */
+int
+libxfs_trans_metafile_iget(
+ struct xfs_trans *tp,
+ xfs_ino_t ino,
+ enum xfs_metafile_type metafile_type,
+ struct xfs_inode **ipp)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_inode *ip;
+ umode_t mode;
+ int error;
+
+ error = libxfs_iget(mp, tp, ino, 0, &ip);
+ if (error)
+ return error;
+
+ if (metafile_type == XFS_METAFILE_DIR)
+ mode = S_IFDIR;
+ else
+ mode = S_IFREG;
+ if (inode_wrong_type(VFS_I(ip), mode))
+ goto bad_rele;
+
+ *ipp = ip;
+ return 0;
+bad_rele:
+ libxfs_irele(ip);
+ return -EFSCORRUPTED;
+}
+
+/* Grab a metadata file if the caller doesn't already have a transaction. */
+int
+libxfs_metafile_iget(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ enum xfs_metafile_type metafile_type,
+ struct xfs_inode **ipp)
+{
+ struct xfs_trans *tp;
+ int error;
+
+ error = libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ return error;
+
+ error = libxfs_trans_metafile_iget(tp, ino, metafile_type, ipp);
+ libxfs_trans_cancel(tp);
+ return error;
+}
+
static void
libxfs_idestroy(
struct xfs_inode *ip)
@@ -184,6 +184,7 @@
#define xfs_iext_next libxfs_iext_next
#define xfs_ifork_zap_attr libxfs_ifork_zap_attr
#define xfs_imap_to_bp libxfs_imap_to_bp
+
#define xfs_initialize_perag libxfs_initialize_perag
#define xfs_initialize_perag_data libxfs_initialize_perag_data
#define xfs_init_local_fork libxfs_init_local_fork
@@ -208,8 +209,12 @@
#define xfs_log_calc_minimum_size libxfs_log_calc_minimum_size
#define xfs_log_get_max_trans_res libxfs_log_get_max_trans_res
#define xfs_log_sb libxfs_log_sb
+
+#define xfs_metafile_iget libxfs_metafile_iget
+#define xfs_trans_metafile_iget libxfs_trans_metafile_iget
#define xfs_mode_to_ftype libxfs_mode_to_ftype
#define xfs_mkdir_space_res libxfs_mkdir_space_res
+
#define xfs_parent_addname libxfs_parent_addname
#define xfs_parent_finish libxfs_parent_finish
#define xfs_parent_hashval libxfs_parent_hashval
new file mode 100644
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2018-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_METAFILE_H__
+#define __XFS_METAFILE_H__
+
+/* Code specific to kernel/userspace; must be provided externally. */
+
+int xfs_trans_metafile_iget(struct xfs_trans *tp, xfs_ino_t ino,
+ enum xfs_metafile_type metafile_type, struct xfs_inode **ipp);
+int xfs_metafile_iget(struct xfs_mount *mp, xfs_ino_t ino,
+ enum xfs_metafile_type metafile_type, struct xfs_inode **ipp);
+
+#endif /* __XFS_METAFILE_H__ */