summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_swapext.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_swapext.c')
-rw-r--r--fs/xfs/libxfs/xfs_swapext.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_swapext.c b/fs/xfs/libxfs/xfs_swapext.c
index c80932f62913..186d20dc2f15 100644
--- a/fs/xfs/libxfs/xfs_swapext.c
+++ b/fs/xfs/libxfs/xfs_swapext.c
@@ -25,6 +25,7 @@
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_attr_leaf.h"
+#include "xfs_dir2_priv.h"
/* Information to help us reset reflink flag / CoW fork state after a swap. */
@@ -231,6 +232,37 @@ xfs_swapext_attr_to_shortform2(
#define XFS_SWAP_EXTENT_POST_PROCESSING (XFS_SWAP_EXTENT_INO2_SHORTFORM)
+/* Convert inode2's block dir fork back to shortform, if possible.. */
+STATIC int
+xfs_swapext_dir_to_shortform2(
+ struct xfs_trans *tp,
+ struct xfs_swapext_intent *sxi)
+{
+ struct xfs_da_args args = {
+ .dp = sxi->sxi_ip2,
+ .geo = tp->t_mountp->m_dir_geo,
+ .whichfork = XFS_DATA_FORK,
+ .trans = tp,
+ };
+ struct xfs_dir2_sf_hdr sfh;
+ struct xfs_buf *bp;
+ int size;
+ int error;
+
+ if (!xfs_bmap_one_block(sxi->sxi_ip2, XFS_DATA_FORK))
+ return 0;
+
+ error = xfs_dir3_block_read(tp, sxi->sxi_ip2, &bp);
+ if (error)
+ return error;
+
+ size = xfs_dir2_block_sfsize(sxi->sxi_ip2, bp->b_addr, &sfh);
+ if (size > XFS_IFORK_DSIZE(sxi->sxi_ip2))
+ return 0;
+
+ return xfs_dir2_block_to_sf(&args, bp, size, &sfh);
+}
+
/* Do we have more work to do to finish this operation? */
bool
xfs_swapext_has_more_work(
@@ -261,6 +293,8 @@ xfs_swapext_finish_one(
if (sxi->sxi_flags & XFS_SWAP_EXTENT_INO2_SHORTFORM) {
if (sxi->sxi_flags & XFS_SWAP_EXTENT_ATTR_FORK)
error = xfs_swapext_attr_to_shortform2(tp, sxi);
+ else if (S_ISDIR(VFS_I(sxi->sxi_ip2)->i_mode))
+ error = xfs_swapext_dir_to_shortform2(tp, sxi);
sxi->sxi_flags &= ~XFS_SWAP_EXTENT_INO2_SHORTFORM;
return error;
}