@@ -906,18 +906,23 @@ struct xfs_swap_extent {
/* Clear the reflink flag from inode2 after the operation. */
#define XFS_SWAP_EXT_CLEAR_INO2_REFLINK (1ULL << 4)
+/* Try to convert inode2 from block to short format at the end, if possible. */
+#define XFS_SWAP_EXT_CVT_INO2_SF (1ULL << 5)
+
#define XFS_SWAP_EXT_FLAGS (XFS_SWAP_EXT_ATTR_FORK | \
XFS_SWAP_EXT_SET_SIZES | \
XFS_SWAP_EXT_SKIP_INO1_HOLES | \
XFS_SWAP_EXT_CLEAR_INO1_REFLINK | \
- XFS_SWAP_EXT_CLEAR_INO2_REFLINK)
+ XFS_SWAP_EXT_CLEAR_INO2_REFLINK | \
+ XFS_SWAP_EXT_CVT_INO2_SF)
#define XFS_SWAP_EXT_STRINGS \
{ XFS_SWAP_EXT_ATTR_FORK, "ATTRFORK" }, \
{ XFS_SWAP_EXT_SET_SIZES, "SETSIZES" }, \
{ XFS_SWAP_EXT_SKIP_INO1_HOLES, "SKIP_INO1_HOLES" }, \
{ XFS_SWAP_EXT_CLEAR_INO1_REFLINK, "CLEAR_INO1_REFLINK" }, \
- { XFS_SWAP_EXT_CLEAR_INO2_REFLINK, "CLEAR_INO2_REFLINK" }
+ { XFS_SWAP_EXT_CLEAR_INO2_REFLINK, "CLEAR_INO2_REFLINK" }, \
+ { XFS_SWAP_EXT_CVT_INO2_SF, "CVT_INO2_SF" }
/* This is the structure used to lay out an sxi log item in the log. */
struct xfs_sxi_log_format {
@@ -23,6 +23,10 @@
#include "xfs_error.h"
#include "xfs_errortag.h"
#include "xfs_health.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr_leaf.h"
+#include "xfs_attr.h"
struct kmem_cache *xfs_swapext_intent_cache;
@@ -121,7 +125,8 @@ static inline bool
sxi_has_postop_work(const struct xfs_swapext_intent *sxi)
{
return sxi->sxi_flags & (XFS_SWAP_EXT_CLEAR_INO1_REFLINK |
- XFS_SWAP_EXT_CLEAR_INO2_REFLINK);
+ XFS_SWAP_EXT_CLEAR_INO2_REFLINK |
+ XFS_SWAP_EXT_CVT_INO2_SF);
}
static inline void
@@ -350,6 +355,36 @@ xfs_swapext_exchange_mappings(
sxi_advance(sxi, irec1);
}
+/* Convert inode2's leaf attr fork back to shortform, if possible.. */
+STATIC int
+xfs_swapext_attr_to_sf(
+ struct xfs_trans *tp,
+ struct xfs_swapext_intent *sxi)
+{
+ struct xfs_da_args args = {
+ .dp = sxi->sxi_ip2,
+ .geo = tp->t_mountp->m_attr_geo,
+ .whichfork = XFS_ATTR_FORK,
+ .trans = tp,
+ };
+ struct xfs_buf *bp;
+ int forkoff;
+ int error;
+
+ if (!xfs_attr_is_leaf(sxi->sxi_ip2))
+ return 0;
+
+ error = xfs_attr3_leaf_read(tp, sxi->sxi_ip2, 0, &bp);
+ if (error)
+ return error;
+
+ forkoff = xfs_attr_shortform_allfit(bp, sxi->sxi_ip2);
+ if (forkoff == 0)
+ return 0;
+
+ return xfs_attr3_leaf_to_shortform(bp, &args, forkoff);
+}
+
static inline void
xfs_swapext_clear_reflink(
struct xfs_trans *tp,
@@ -367,6 +402,16 @@ xfs_swapext_do_postop_work(
struct xfs_trans *tp,
struct xfs_swapext_intent *sxi)
{
+ if (sxi->sxi_flags & XFS_SWAP_EXT_CVT_INO2_SF) {
+ int error = 0;
+
+ if (sxi->sxi_flags & XFS_SWAP_EXT_ATTR_FORK)
+ error = xfs_swapext_attr_to_sf(tp, sxi);
+ sxi->sxi_flags &= ~XFS_SWAP_EXT_CVT_INO2_SF;
+ if (error)
+ return error;
+ }
+
if (sxi->sxi_flags & XFS_SWAP_EXT_CLEAR_INO1_REFLINK) {
xfs_swapext_clear_reflink(tp, sxi->sxi_ip1);
sxi->sxi_flags &= ~XFS_SWAP_EXT_CLEAR_INO1_REFLINK;
@@ -794,6 +839,8 @@ xfs_swapext_init_intent(
if (req->req_flags & XFS_SWAP_REQ_SKIP_INO1_HOLES)
sxi->sxi_flags |= XFS_SWAP_EXT_SKIP_INO1_HOLES;
+ if (req->req_flags & XFS_SWAP_REQ_CVT_INO2_SF)
+ sxi->sxi_flags |= XFS_SWAP_EXT_CVT_INO2_SF;
if (req->req_flags & XFS_SWAP_REQ_LOGGED)
sxi->sxi_op_flags |= XFS_SWAP_EXT_OP_LOGGED;
@@ -1013,6 +1060,8 @@ xfs_swapext(
ASSERT(!(req->req_flags & ~XFS_SWAP_REQ_FLAGS));
if (req->req_flags & XFS_SWAP_REQ_SET_SIZES)
ASSERT(req->whichfork == XFS_DATA_FORK);
+ if (req->req_flags & XFS_SWAP_REQ_CVT_INO2_SF)
+ ASSERT(req->whichfork == XFS_ATTR_FORK);
if (req->blockcount == 0)
return;
@@ -126,16 +126,21 @@ struct xfs_swapext_req {
/* Files need to be upgraded to have large extent counts. */
#define XFS_SWAP_REQ_NREXT64 (1U << 3)
+/* Try to convert inode2's fork to local format, if possible. */
+#define XFS_SWAP_REQ_CVT_INO2_SF (1U << 4)
+
#define XFS_SWAP_REQ_FLAGS (XFS_SWAP_REQ_LOGGED | \
XFS_SWAP_REQ_SET_SIZES | \
XFS_SWAP_REQ_SKIP_INO1_HOLES | \
- XFS_SWAP_REQ_NREXT64)
+ XFS_SWAP_REQ_NREXT64 | \
+ XFS_SWAP_REQ_CVT_INO2_SF)
#define XFS_SWAP_REQ_STRINGS \
{ XFS_SWAP_REQ_LOGGED, "LOGGED" }, \
{ XFS_SWAP_REQ_SET_SIZES, "SETSIZES" }, \
{ XFS_SWAP_REQ_SKIP_INO1_HOLES, "SKIP_INO1_HOLES" }, \
- { XFS_SWAP_REQ_NREXT64, "NREXT64" }
+ { XFS_SWAP_REQ_NREXT64, "NREXT64" }, \
+ { XFS_SWAP_REQ_CVT_INO2_SF, "CVT_INO2_SF" }
unsigned int xfs_swapext_reflink_prep(const struct xfs_swapext_req *req);
void xfs_swapext_reflink_finish(struct xfs_trans *tp,