root/fs/xfs/libxfs/xfs_exchmaps.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <djwong@kernel.org>
 */
#ifndef __XFS_EXCHMAPS_H__
#define __XFS_EXCHMAPS_H__

/* In-core deferred operation info about a file mapping exchange request. */
struct xfs_exchmaps_intent {
        /* List of other incore deferred work. */
        struct list_head        xmi_list;

        /* Inodes participating in the operation. */
        struct xfs_inode        *xmi_ip1;
        struct xfs_inode        *xmi_ip2;

        /* File offset range information. */
        xfs_fileoff_t           xmi_startoff1;
        xfs_fileoff_t           xmi_startoff2;
        xfs_filblks_t           xmi_blockcount;

        /* Set these file sizes after the operation, unless negative. */
        xfs_fsize_t             xmi_isize1;
        xfs_fsize_t             xmi_isize2;

        uint64_t                xmi_flags;      /* XFS_EXCHMAPS_* flags */
};

/* Try to convert inode2 from block to short format at the end, if possible. */
#define __XFS_EXCHMAPS_INO2_SHORTFORM   (1ULL << 63)

#define XFS_EXCHMAPS_INTERNAL_FLAGS     (__XFS_EXCHMAPS_INO2_SHORTFORM)

/* flags that can be passed to xfs_exchmaps_{estimate,mappings} */
#define XFS_EXCHMAPS_PARAMS             (XFS_EXCHMAPS_ATTR_FORK | \
                                         XFS_EXCHMAPS_SET_SIZES | \
                                         XFS_EXCHMAPS_INO1_WRITTEN)

static inline int
xfs_exchmaps_whichfork(const struct xfs_exchmaps_intent *xmi)
{
        if (xmi->xmi_flags & XFS_EXCHMAPS_ATTR_FORK)
                return XFS_ATTR_FORK;
        return XFS_DATA_FORK;
}

/* Parameters for a mapping exchange request. */
struct xfs_exchmaps_req {
        /* Inodes participating in the operation. */
        struct xfs_inode        *ip1;
        struct xfs_inode        *ip2;

        /* File offset range information. */
        xfs_fileoff_t           startoff1;
        xfs_fileoff_t           startoff2;
        xfs_filblks_t           blockcount;

        /* XFS_EXCHMAPS_* operation flags */
        uint64_t                flags;

        /*
         * Fields below this line are filled out by xfs_exchmaps_estimate;
         * callers should initialize this part of the struct to zero.
         */

        /*
         * Data device blocks to be moved out of ip1, and free space needed to
         * handle the bmbt changes.
         */
        xfs_filblks_t           ip1_bcount;

        /*
         * Data device blocks to be moved out of ip2, and free space needed to
         * handle the bmbt changes.
         */
        xfs_filblks_t           ip2_bcount;

        /* rt blocks to be moved out of ip1. */
        xfs_filblks_t           ip1_rtbcount;

        /* rt blocks to be moved out of ip2. */
        xfs_filblks_t           ip2_rtbcount;

        /* Free space needed to handle the bmbt changes */
        unsigned long long      resblks;

        /* Number of exchanges needed to complete the operation */
        unsigned long long      nr_exchanges;
};

static inline int
xfs_exchmaps_reqfork(const struct xfs_exchmaps_req *req)
{
        if (req->flags & XFS_EXCHMAPS_ATTR_FORK)
                return XFS_ATTR_FORK;
        return XFS_DATA_FORK;
}

int xfs_exchmaps_estimate_overhead(struct xfs_exchmaps_req *req);
int xfs_exchmaps_estimate(struct xfs_exchmaps_req *req);

extern struct kmem_cache        *xfs_exchmaps_intent_cache;

int __init xfs_exchmaps_intent_init_cache(void);
void xfs_exchmaps_intent_destroy_cache(void);

struct xfs_exchmaps_intent *xfs_exchmaps_init_intent(
                const struct xfs_exchmaps_req *req);
void xfs_exchmaps_ensure_reflink(struct xfs_trans *tp,
                const struct xfs_exchmaps_intent *xmi);
void xfs_exchmaps_upgrade_extent_counts(struct xfs_trans *tp,
                const struct xfs_exchmaps_intent *xmi);

int xfs_exchmaps_finish_one(struct xfs_trans *tp,
                struct xfs_exchmaps_intent *xmi);

int xfs_exchmaps_check_forks(struct xfs_mount *mp,
                const struct xfs_exchmaps_req *req);

void xfs_exchange_mappings(struct xfs_trans *tp,
                const struct xfs_exchmaps_req *req);

#endif /* __XFS_EXCHMAPS_H__ */