summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_swapext.h
blob: c92c20fc7f320d94ed55ef3bd0fe0b0362e88492 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2021 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <djwong@kernel.org>
 */
#ifndef __XFS_SWAPEXT_H_
#define __XFS_SWAPEXT_H_ 1

/*
 * In-core information about an extent swap request between ranges of two
 * inodes.
 */
struct xfs_swapext_intent {
	/* List of other incore deferred work. */
	struct list_head	sxi_list;

	/* Inodes participating in the operation. */
	struct xfs_inode	*sxi_ip1;
	struct xfs_inode	*sxi_ip2;

	/* File offset range information. */
	xfs_fileoff_t		sxi_startoff1;
	xfs_fileoff_t		sxi_startoff2;
	xfs_filblks_t		sxi_blockcount;

	/* Set these file sizes after the operation, unless negative. */
	xfs_fsize_t		sxi_isize1;
	xfs_fsize_t		sxi_isize2;

	/* XFS_SWAP_EXT_* log operation flags */
	uint64_t		sxi_flags;
};

static inline int
xfs_swapext_whichfork(const struct xfs_swapext_intent *sxi)
{
	if (sxi->sxi_flags & XFS_SWAP_EXT_ATTR_FORK)
		return XFS_ATTR_FORK;
	return XFS_DATA_FORK;
}

/* Parameters for a swapext request. */
struct xfs_swapext_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;

	/* Data or attr fork? */
	int			whichfork;

	/* XFS_SWAP_REQ_* operation flags */
	unsigned int		req_flags;
};

/* Set the file sizes when finished. */
#define XFS_SWAP_REQ_SET_SIZES		(1U << 1)

/* Do not swap any part of the range where file1's mapping is a hole. */
#define XFS_SWAP_REQ_SKIP_FILE1_HOLES	(1U << 2)

/* Try to convert inode2's fork to local format, if possible. */
#define XFS_SWAP_REQ_FILE2_CVT_SF	(1U << 3)

#define XFS_SWAP_REQ_FLAGS		(XFS_SWAP_REQ_SET_SIZES | \
					 XFS_SWAP_REQ_SKIP_FILE1_HOLES | \
					 XFS_SWAP_REQ_FILE2_CVT_SF)

#define XFS_SWAP_REQ_STRINGS \
	{ XFS_SWAP_REQ_SET_SIZES,		"SETSIZES" }, \
	{ XFS_SWAP_REQ_SKIP_FILE1_HOLES,	"SKIP_FILE1_HOLES" }, \
	{ XFS_SWAP_REQ_FILE2_CVT_SF,		"INO2_SHORTFORM" }

/* Estimated resource requirements for a swapext operation. */
struct xfs_swapext_res {
	xfs_filblks_t		ip1_bcount;
	xfs_filblks_t		ip2_bcount;
	xfs_filblks_t		ip1_rtbcount;
	xfs_filblks_t		ip2_rtbcount;
	unsigned long long	resblks;
	unsigned int		nr_exchanges;
};

unsigned int xfs_swapext_reflink_prep(const struct xfs_swapext_req *req);
void xfs_swapext_reflink_finish(struct xfs_trans *tp,
		const struct xfs_swapext_req *req, unsigned int reflink_state);

int xfs_swapext_estimate_overhead(const struct xfs_swapext_req *req,
		struct xfs_swapext_res *res);
int xfs_swapext_estimate(const struct xfs_swapext_req *req,
		struct xfs_swapext_res *res);

struct xfs_swapext_intent *xfs_swapext_init_intent(
		const struct xfs_swapext_req *req);

void xfs_swapext_schedule(struct xfs_trans *tp,
		struct xfs_swapext_intent *sxi);
int xfs_swapext_finish_one(struct xfs_trans *tp,
		struct xfs_swapext_intent *sxi);

int xfs_swapext_check_extents(struct xfs_mount *mp,
		const struct xfs_swapext_req *req);

int xfs_swapext(struct xfs_trans **tpp, const struct xfs_swapext_req *req);

#endif /* __XFS_SWAPEXT_H_ */