From: Darrick J. Wong <djwong@xxxxxxxxxx> Create a xfs_iget_meta function for metadata inodes to ensure that we always check that the inobt thinks a metadata inode is in use. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- libxfs/init.c | 4 ++-- libxfs/inode.c | 36 ++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 2 ++ libxfs/xfs_imeta.h | 5 +++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/libxfs/init.c b/libxfs/init.c index c199aeea45e..c0f148e75a2 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -883,9 +883,9 @@ void libxfs_rtmount_destroy(xfs_mount_t *mp) { if (mp->m_rsumip) - libxfs_irele(mp->m_rsumip); + libxfs_imeta_irele(mp->m_rsumip); if (mp->m_rbmip) - libxfs_irele(mp->m_rbmip); + libxfs_imeta_irele(mp->m_rbmip); mp->m_rsumip = mp->m_rbmip = NULL; } diff --git a/libxfs/inode.c b/libxfs/inode.c index 47c9b9d6bd7..560b127ee9d 100644 --- a/libxfs/inode.c +++ b/libxfs/inode.c @@ -225,6 +225,35 @@ libxfs_iget( return error; } +/* + * Get a metadata inode. The ftype must match exactly. Caller must supply + * a transaction (even if empty) to avoid livelocking if the inobt has a cycle. + */ +int +libxfs_imeta_iget( + struct xfs_trans *tp, + xfs_ino_t ino, + unsigned char ftype, + struct xfs_inode **ipp) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_inode *ip; + int error; + + error = libxfs_iget(mp, tp, ino, XFS_IGET_UNTRUSTED, &ip); + if (error) + return error; + + if (ftype == XFS_DIR3_FT_UNKNOWN || + xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype) { + libxfs_irele(ip); + return -EFSCORRUPTED; + } + + *ipp = ip; + return 0; +} + static void libxfs_idestroy( struct xfs_inode *ip) @@ -258,6 +287,13 @@ libxfs_irele( } } +void +libxfs_imeta_irele( + struct xfs_inode *ip) +{ + libxfs_irele(ip); +} + static inline void inode_fsgid_set(struct inode *inode, struct mnt_idmap *idmap) { diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 167617771d8..873995f265c 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -177,6 +177,8 @@ #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_iget libxfs_imeta_iget +#define xfs_imeta_irele libxfs_imeta_irele #define xfs_imeta_link libxfs_imeta_link #define xfs_imeta_link_space_res libxfs_imeta_link_space_res #define xfs_imeta_lookup libxfs_imeta_lookup diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index 7b3da865c09..0a4361bda1c 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -47,4 +47,9 @@ unsigned int xfs_imeta_create_space_res(struct xfs_mount *mp); unsigned int xfs_imeta_link_space_res(struct xfs_mount *mp); unsigned int xfs_imeta_unlink_space_res(struct xfs_mount *mp); +/* Must be implemented by the libxfs client */ +int xfs_imeta_iget(struct xfs_trans *tp, xfs_ino_t ino, unsigned char ftype, + struct xfs_inode **ipp); +void xfs_imeta_irele(struct xfs_inode *ip); + #endif /* __XFS_IMETA_H__ */