/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2020-2024 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <[email protected]>
*/
#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__ */