xref: /OK3568_Linux_fs/kernel/fs/xfs/xfs_fsmap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2017 Oracle.  All Rights Reserved.
4*4882a593Smuzhiyun  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_log_format.h"
11*4882a593Smuzhiyun #include "xfs_trans_resv.h"
12*4882a593Smuzhiyun #include "xfs_mount.h"
13*4882a593Smuzhiyun #include "xfs_inode.h"
14*4882a593Smuzhiyun #include "xfs_trans.h"
15*4882a593Smuzhiyun #include "xfs_btree.h"
16*4882a593Smuzhiyun #include "xfs_rmap_btree.h"
17*4882a593Smuzhiyun #include "xfs_trace.h"
18*4882a593Smuzhiyun #include "xfs_rmap.h"
19*4882a593Smuzhiyun #include "xfs_alloc.h"
20*4882a593Smuzhiyun #include "xfs_bit.h"
21*4882a593Smuzhiyun #include <linux/fsmap.h>
22*4882a593Smuzhiyun #include "xfs_fsmap.h"
23*4882a593Smuzhiyun #include "xfs_refcount.h"
24*4882a593Smuzhiyun #include "xfs_refcount_btree.h"
25*4882a593Smuzhiyun #include "xfs_alloc_btree.h"
26*4882a593Smuzhiyun #include "xfs_rtalloc.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Convert an xfs_fsmap to an fsmap. */
29*4882a593Smuzhiyun static void
xfs_fsmap_from_internal(struct fsmap * dest,struct xfs_fsmap * src)30*4882a593Smuzhiyun xfs_fsmap_from_internal(
31*4882a593Smuzhiyun 	struct fsmap		*dest,
32*4882a593Smuzhiyun 	struct xfs_fsmap	*src)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	dest->fmr_device = src->fmr_device;
35*4882a593Smuzhiyun 	dest->fmr_flags = src->fmr_flags;
36*4882a593Smuzhiyun 	dest->fmr_physical = BBTOB(src->fmr_physical);
37*4882a593Smuzhiyun 	dest->fmr_owner = src->fmr_owner;
38*4882a593Smuzhiyun 	dest->fmr_offset = BBTOB(src->fmr_offset);
39*4882a593Smuzhiyun 	dest->fmr_length = BBTOB(src->fmr_length);
40*4882a593Smuzhiyun 	dest->fmr_reserved[0] = 0;
41*4882a593Smuzhiyun 	dest->fmr_reserved[1] = 0;
42*4882a593Smuzhiyun 	dest->fmr_reserved[2] = 0;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /* Convert an fsmap to an xfs_fsmap. */
46*4882a593Smuzhiyun void
xfs_fsmap_to_internal(struct xfs_fsmap * dest,struct fsmap * src)47*4882a593Smuzhiyun xfs_fsmap_to_internal(
48*4882a593Smuzhiyun 	struct xfs_fsmap	*dest,
49*4882a593Smuzhiyun 	struct fsmap		*src)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	dest->fmr_device = src->fmr_device;
52*4882a593Smuzhiyun 	dest->fmr_flags = src->fmr_flags;
53*4882a593Smuzhiyun 	dest->fmr_physical = BTOBBT(src->fmr_physical);
54*4882a593Smuzhiyun 	dest->fmr_owner = src->fmr_owner;
55*4882a593Smuzhiyun 	dest->fmr_offset = BTOBBT(src->fmr_offset);
56*4882a593Smuzhiyun 	dest->fmr_length = BTOBBT(src->fmr_length);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* Convert an fsmap owner into an rmapbt owner. */
60*4882a593Smuzhiyun static int
xfs_fsmap_owner_to_rmap(struct xfs_rmap_irec * dest,struct xfs_fsmap * src)61*4882a593Smuzhiyun xfs_fsmap_owner_to_rmap(
62*4882a593Smuzhiyun 	struct xfs_rmap_irec	*dest,
63*4882a593Smuzhiyun 	struct xfs_fsmap	*src)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	if (!(src->fmr_flags & FMR_OF_SPECIAL_OWNER)) {
66*4882a593Smuzhiyun 		dest->rm_owner = src->fmr_owner;
67*4882a593Smuzhiyun 		return 0;
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	switch (src->fmr_owner) {
71*4882a593Smuzhiyun 	case 0:			/* "lowest owner id possible" */
72*4882a593Smuzhiyun 	case -1ULL:		/* "highest owner id possible" */
73*4882a593Smuzhiyun 		dest->rm_owner = 0;
74*4882a593Smuzhiyun 		break;
75*4882a593Smuzhiyun 	case XFS_FMR_OWN_FREE:
76*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_NULL;
77*4882a593Smuzhiyun 		break;
78*4882a593Smuzhiyun 	case XFS_FMR_OWN_UNKNOWN:
79*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_UNKNOWN;
80*4882a593Smuzhiyun 		break;
81*4882a593Smuzhiyun 	case XFS_FMR_OWN_FS:
82*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_FS;
83*4882a593Smuzhiyun 		break;
84*4882a593Smuzhiyun 	case XFS_FMR_OWN_LOG:
85*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_LOG;
86*4882a593Smuzhiyun 		break;
87*4882a593Smuzhiyun 	case XFS_FMR_OWN_AG:
88*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_AG;
89*4882a593Smuzhiyun 		break;
90*4882a593Smuzhiyun 	case XFS_FMR_OWN_INOBT:
91*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_INOBT;
92*4882a593Smuzhiyun 		break;
93*4882a593Smuzhiyun 	case XFS_FMR_OWN_INODES:
94*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_INODES;
95*4882a593Smuzhiyun 		break;
96*4882a593Smuzhiyun 	case XFS_FMR_OWN_REFC:
97*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_REFC;
98*4882a593Smuzhiyun 		break;
99*4882a593Smuzhiyun 	case XFS_FMR_OWN_COW:
100*4882a593Smuzhiyun 		dest->rm_owner = XFS_RMAP_OWN_COW;
101*4882a593Smuzhiyun 		break;
102*4882a593Smuzhiyun 	case XFS_FMR_OWN_DEFECTIVE:	/* not implemented */
103*4882a593Smuzhiyun 		/* fall through */
104*4882a593Smuzhiyun 	default:
105*4882a593Smuzhiyun 		return -EINVAL;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun /* Convert an rmapbt owner into an fsmap owner. */
111*4882a593Smuzhiyun static int
xfs_fsmap_owner_from_rmap(struct xfs_fsmap * dest,struct xfs_rmap_irec * src)112*4882a593Smuzhiyun xfs_fsmap_owner_from_rmap(
113*4882a593Smuzhiyun 	struct xfs_fsmap	*dest,
114*4882a593Smuzhiyun 	struct xfs_rmap_irec	*src)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	dest->fmr_flags = 0;
117*4882a593Smuzhiyun 	if (!XFS_RMAP_NON_INODE_OWNER(src->rm_owner)) {
118*4882a593Smuzhiyun 		dest->fmr_owner = src->rm_owner;
119*4882a593Smuzhiyun 		return 0;
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 	dest->fmr_flags |= FMR_OF_SPECIAL_OWNER;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	switch (src->rm_owner) {
124*4882a593Smuzhiyun 	case XFS_RMAP_OWN_FS:
125*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_FS;
126*4882a593Smuzhiyun 		break;
127*4882a593Smuzhiyun 	case XFS_RMAP_OWN_LOG:
128*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_LOG;
129*4882a593Smuzhiyun 		break;
130*4882a593Smuzhiyun 	case XFS_RMAP_OWN_AG:
131*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_AG;
132*4882a593Smuzhiyun 		break;
133*4882a593Smuzhiyun 	case XFS_RMAP_OWN_INOBT:
134*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_INOBT;
135*4882a593Smuzhiyun 		break;
136*4882a593Smuzhiyun 	case XFS_RMAP_OWN_INODES:
137*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_INODES;
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 	case XFS_RMAP_OWN_REFC:
140*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_REFC;
141*4882a593Smuzhiyun 		break;
142*4882a593Smuzhiyun 	case XFS_RMAP_OWN_COW:
143*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_COW;
144*4882a593Smuzhiyun 		break;
145*4882a593Smuzhiyun 	case XFS_RMAP_OWN_NULL:	/* "free" */
146*4882a593Smuzhiyun 		dest->fmr_owner = XFS_FMR_OWN_FREE;
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 	default:
149*4882a593Smuzhiyun 		ASSERT(0);
150*4882a593Smuzhiyun 		return -EFSCORRUPTED;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /* getfsmap query state */
156*4882a593Smuzhiyun struct xfs_getfsmap_info {
157*4882a593Smuzhiyun 	struct xfs_fsmap_head	*head;
158*4882a593Smuzhiyun 	struct fsmap		*fsmap_recs;	/* mapping records */
159*4882a593Smuzhiyun 	struct xfs_buf		*agf_bp;	/* AGF, for refcount queries */
160*4882a593Smuzhiyun 	xfs_daddr_t		next_daddr;	/* next daddr we expect */
161*4882a593Smuzhiyun 	u64			missing_owner;	/* owner of holes */
162*4882a593Smuzhiyun 	u32			dev;		/* device id */
163*4882a593Smuzhiyun 	xfs_agnumber_t		agno;		/* AG number, if applicable */
164*4882a593Smuzhiyun 	struct xfs_rmap_irec	low;		/* low rmap key */
165*4882a593Smuzhiyun 	struct xfs_rmap_irec	high;		/* high rmap key */
166*4882a593Smuzhiyun 	bool			last;		/* last extent? */
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /* Associate a device with a getfsmap handler. */
170*4882a593Smuzhiyun struct xfs_getfsmap_dev {
171*4882a593Smuzhiyun 	u32			dev;
172*4882a593Smuzhiyun 	int			(*fn)(struct xfs_trans *tp,
173*4882a593Smuzhiyun 				      struct xfs_fsmap *keys,
174*4882a593Smuzhiyun 				      struct xfs_getfsmap_info *info);
175*4882a593Smuzhiyun };
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun /* Compare two getfsmap device handlers. */
178*4882a593Smuzhiyun static int
xfs_getfsmap_dev_compare(const void * p1,const void * p2)179*4882a593Smuzhiyun xfs_getfsmap_dev_compare(
180*4882a593Smuzhiyun 	const void			*p1,
181*4882a593Smuzhiyun 	const void			*p2)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	const struct xfs_getfsmap_dev	*d1 = p1;
184*4882a593Smuzhiyun 	const struct xfs_getfsmap_dev	*d2 = p2;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return d1->dev - d2->dev;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /* Decide if this mapping is shared. */
190*4882a593Smuzhiyun STATIC int
xfs_getfsmap_is_shared(struct xfs_trans * tp,struct xfs_getfsmap_info * info,struct xfs_rmap_irec * rec,bool * stat)191*4882a593Smuzhiyun xfs_getfsmap_is_shared(
192*4882a593Smuzhiyun 	struct xfs_trans		*tp,
193*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info,
194*4882a593Smuzhiyun 	struct xfs_rmap_irec		*rec,
195*4882a593Smuzhiyun 	bool				*stat)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
198*4882a593Smuzhiyun 	struct xfs_btree_cur		*cur;
199*4882a593Smuzhiyun 	xfs_agblock_t			fbno;
200*4882a593Smuzhiyun 	xfs_extlen_t			flen;
201*4882a593Smuzhiyun 	int				error;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	*stat = false;
204*4882a593Smuzhiyun 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
205*4882a593Smuzhiyun 		return 0;
206*4882a593Smuzhiyun 	/* rt files will have agno set to NULLAGNUMBER */
207*4882a593Smuzhiyun 	if (info->agno == NULLAGNUMBER)
208*4882a593Smuzhiyun 		return 0;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* Are there any shared blocks here? */
211*4882a593Smuzhiyun 	flen = 0;
212*4882a593Smuzhiyun 	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
213*4882a593Smuzhiyun 			info->agno);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
216*4882a593Smuzhiyun 			rec->rm_blockcount, &fbno, &flen, false);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	xfs_btree_del_cursor(cur, error);
219*4882a593Smuzhiyun 	if (error)
220*4882a593Smuzhiyun 		return error;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	*stat = flen > 0;
223*4882a593Smuzhiyun 	return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static inline void
xfs_getfsmap_format(struct xfs_mount * mp,struct xfs_fsmap * xfm,struct xfs_getfsmap_info * info)227*4882a593Smuzhiyun xfs_getfsmap_format(
228*4882a593Smuzhiyun 	struct xfs_mount		*mp,
229*4882a593Smuzhiyun 	struct xfs_fsmap		*xfm,
230*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct fsmap			*rec;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	trace_xfs_getfsmap_mapping(mp, xfm);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	rec = &info->fsmap_recs[info->head->fmh_entries++];
237*4882a593Smuzhiyun 	xfs_fsmap_from_internal(rec, xfm);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun  * Format a reverse mapping for getfsmap, having translated rm_startblock
242*4882a593Smuzhiyun  * into the appropriate daddr units.
243*4882a593Smuzhiyun  */
244*4882a593Smuzhiyun STATIC int
xfs_getfsmap_helper(struct xfs_trans * tp,struct xfs_getfsmap_info * info,struct xfs_rmap_irec * rec,xfs_daddr_t rec_daddr)245*4882a593Smuzhiyun xfs_getfsmap_helper(
246*4882a593Smuzhiyun 	struct xfs_trans		*tp,
247*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info,
248*4882a593Smuzhiyun 	struct xfs_rmap_irec		*rec,
249*4882a593Smuzhiyun 	xfs_daddr_t			rec_daddr)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct xfs_fsmap		fmr;
252*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
253*4882a593Smuzhiyun 	bool				shared;
254*4882a593Smuzhiyun 	int				error;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (fatal_signal_pending(current))
257*4882a593Smuzhiyun 		return -EINTR;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	/*
260*4882a593Smuzhiyun 	 * Filter out records that start before our startpoint, if the
261*4882a593Smuzhiyun 	 * caller requested that.
262*4882a593Smuzhiyun 	 */
263*4882a593Smuzhiyun 	if (xfs_rmap_compare(rec, &info->low) < 0) {
264*4882a593Smuzhiyun 		rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
265*4882a593Smuzhiyun 		if (info->next_daddr < rec_daddr)
266*4882a593Smuzhiyun 			info->next_daddr = rec_daddr;
267*4882a593Smuzhiyun 		return 0;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/* Are we just counting mappings? */
271*4882a593Smuzhiyun 	if (info->head->fmh_count == 0) {
272*4882a593Smuzhiyun 		if (info->head->fmh_entries == UINT_MAX)
273*4882a593Smuzhiyun 			return -ECANCELED;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		if (rec_daddr > info->next_daddr)
276*4882a593Smuzhiyun 			info->head->fmh_entries++;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		if (info->last)
279*4882a593Smuzhiyun 			return 0;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 		info->head->fmh_entries++;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
284*4882a593Smuzhiyun 		if (info->next_daddr < rec_daddr)
285*4882a593Smuzhiyun 			info->next_daddr = rec_daddr;
286*4882a593Smuzhiyun 		return 0;
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/*
290*4882a593Smuzhiyun 	 * If the record starts past the last physical block we saw,
291*4882a593Smuzhiyun 	 * then we've found a gap.  Report the gap as being owned by
292*4882a593Smuzhiyun 	 * whatever the caller specified is the missing owner.
293*4882a593Smuzhiyun 	 */
294*4882a593Smuzhiyun 	if (rec_daddr > info->next_daddr) {
295*4882a593Smuzhiyun 		if (info->head->fmh_entries >= info->head->fmh_count)
296*4882a593Smuzhiyun 			return -ECANCELED;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		fmr.fmr_device = info->dev;
299*4882a593Smuzhiyun 		fmr.fmr_physical = info->next_daddr;
300*4882a593Smuzhiyun 		fmr.fmr_owner = info->missing_owner;
301*4882a593Smuzhiyun 		fmr.fmr_offset = 0;
302*4882a593Smuzhiyun 		fmr.fmr_length = rec_daddr - info->next_daddr;
303*4882a593Smuzhiyun 		fmr.fmr_flags = FMR_OF_SPECIAL_OWNER;
304*4882a593Smuzhiyun 		xfs_getfsmap_format(mp, &fmr, info);
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (info->last)
308*4882a593Smuzhiyun 		goto out;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/* Fill out the extent we found */
311*4882a593Smuzhiyun 	if (info->head->fmh_entries >= info->head->fmh_count)
312*4882a593Smuzhiyun 		return -ECANCELED;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	fmr.fmr_device = info->dev;
317*4882a593Smuzhiyun 	fmr.fmr_physical = rec_daddr;
318*4882a593Smuzhiyun 	error = xfs_fsmap_owner_from_rmap(&fmr, rec);
319*4882a593Smuzhiyun 	if (error)
320*4882a593Smuzhiyun 		return error;
321*4882a593Smuzhiyun 	fmr.fmr_offset = XFS_FSB_TO_BB(mp, rec->rm_offset);
322*4882a593Smuzhiyun 	fmr.fmr_length = XFS_FSB_TO_BB(mp, rec->rm_blockcount);
323*4882a593Smuzhiyun 	if (rec->rm_flags & XFS_RMAP_UNWRITTEN)
324*4882a593Smuzhiyun 		fmr.fmr_flags |= FMR_OF_PREALLOC;
325*4882a593Smuzhiyun 	if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
326*4882a593Smuzhiyun 		fmr.fmr_flags |= FMR_OF_ATTR_FORK;
327*4882a593Smuzhiyun 	if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
328*4882a593Smuzhiyun 		fmr.fmr_flags |= FMR_OF_EXTENT_MAP;
329*4882a593Smuzhiyun 	if (fmr.fmr_flags == 0) {
330*4882a593Smuzhiyun 		error = xfs_getfsmap_is_shared(tp, info, rec, &shared);
331*4882a593Smuzhiyun 		if (error)
332*4882a593Smuzhiyun 			return error;
333*4882a593Smuzhiyun 		if (shared)
334*4882a593Smuzhiyun 			fmr.fmr_flags |= FMR_OF_SHARED;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	xfs_getfsmap_format(mp, &fmr, info);
338*4882a593Smuzhiyun out:
339*4882a593Smuzhiyun 	rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
340*4882a593Smuzhiyun 	if (info->next_daddr < rec_daddr)
341*4882a593Smuzhiyun 		info->next_daddr = rec_daddr;
342*4882a593Smuzhiyun 	return 0;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun /* Transform a rmapbt irec into a fsmap */
346*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_helper(struct xfs_btree_cur * cur,struct xfs_rmap_irec * rec,void * priv)347*4882a593Smuzhiyun xfs_getfsmap_datadev_helper(
348*4882a593Smuzhiyun 	struct xfs_btree_cur		*cur,
349*4882a593Smuzhiyun 	struct xfs_rmap_irec		*rec,
350*4882a593Smuzhiyun 	void				*priv)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct xfs_mount		*mp = cur->bc_mp;
353*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info = priv;
354*4882a593Smuzhiyun 	xfs_fsblock_t			fsb;
355*4882a593Smuzhiyun 	xfs_daddr_t			rec_daddr;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.agno, rec->rm_startblock);
358*4882a593Smuzhiyun 	rec_daddr = XFS_FSB_TO_DADDR(mp, fsb);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun /* Transform a bnobt irec into a fsmap */
364*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_bnobt_helper(struct xfs_btree_cur * cur,struct xfs_alloc_rec_incore * rec,void * priv)365*4882a593Smuzhiyun xfs_getfsmap_datadev_bnobt_helper(
366*4882a593Smuzhiyun 	struct xfs_btree_cur		*cur,
367*4882a593Smuzhiyun 	struct xfs_alloc_rec_incore	*rec,
368*4882a593Smuzhiyun 	void				*priv)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct xfs_mount		*mp = cur->bc_mp;
371*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info = priv;
372*4882a593Smuzhiyun 	struct xfs_rmap_irec		irec;
373*4882a593Smuzhiyun 	xfs_daddr_t			rec_daddr;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.agno,
376*4882a593Smuzhiyun 			rec->ar_startblock);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	irec.rm_startblock = rec->ar_startblock;
379*4882a593Smuzhiyun 	irec.rm_blockcount = rec->ar_blockcount;
380*4882a593Smuzhiyun 	irec.rm_owner = XFS_RMAP_OWN_NULL;	/* "free" */
381*4882a593Smuzhiyun 	irec.rm_offset = 0;
382*4882a593Smuzhiyun 	irec.rm_flags = 0;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	return xfs_getfsmap_helper(cur->bc_tp, info, &irec, rec_daddr);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun /* Set rmap flags based on the getfsmap flags */
388*4882a593Smuzhiyun static void
xfs_getfsmap_set_irec_flags(struct xfs_rmap_irec * irec,struct xfs_fsmap * fmr)389*4882a593Smuzhiyun xfs_getfsmap_set_irec_flags(
390*4882a593Smuzhiyun 	struct xfs_rmap_irec	*irec,
391*4882a593Smuzhiyun 	struct xfs_fsmap	*fmr)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	irec->rm_flags = 0;
394*4882a593Smuzhiyun 	if (fmr->fmr_flags & FMR_OF_ATTR_FORK)
395*4882a593Smuzhiyun 		irec->rm_flags |= XFS_RMAP_ATTR_FORK;
396*4882a593Smuzhiyun 	if (fmr->fmr_flags & FMR_OF_EXTENT_MAP)
397*4882a593Smuzhiyun 		irec->rm_flags |= XFS_RMAP_BMBT_BLOCK;
398*4882a593Smuzhiyun 	if (fmr->fmr_flags & FMR_OF_PREALLOC)
399*4882a593Smuzhiyun 		irec->rm_flags |= XFS_RMAP_UNWRITTEN;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun /* Execute a getfsmap query against the log device. */
403*4882a593Smuzhiyun STATIC int
xfs_getfsmap_logdev(struct xfs_trans * tp,struct xfs_fsmap * keys,struct xfs_getfsmap_info * info)404*4882a593Smuzhiyun xfs_getfsmap_logdev(
405*4882a593Smuzhiyun 	struct xfs_trans		*tp,
406*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
407*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
410*4882a593Smuzhiyun 	struct xfs_rmap_irec		rmap;
411*4882a593Smuzhiyun 	int				error;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	/* Set up search keys */
414*4882a593Smuzhiyun 	info->low.rm_startblock = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
415*4882a593Smuzhiyun 	info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
416*4882a593Smuzhiyun 	error = xfs_fsmap_owner_to_rmap(&info->low, keys);
417*4882a593Smuzhiyun 	if (error)
418*4882a593Smuzhiyun 		return error;
419*4882a593Smuzhiyun 	info->low.rm_blockcount = 0;
420*4882a593Smuzhiyun 	xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	error = xfs_fsmap_owner_to_rmap(&info->high, keys + 1);
423*4882a593Smuzhiyun 	if (error)
424*4882a593Smuzhiyun 		return error;
425*4882a593Smuzhiyun 	info->high.rm_startblock = -1U;
426*4882a593Smuzhiyun 	info->high.rm_owner = ULLONG_MAX;
427*4882a593Smuzhiyun 	info->high.rm_offset = ULLONG_MAX;
428*4882a593Smuzhiyun 	info->high.rm_blockcount = 0;
429*4882a593Smuzhiyun 	info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
430*4882a593Smuzhiyun 	info->missing_owner = XFS_FMR_OWN_FREE;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
433*4882a593Smuzhiyun 	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (keys[0].fmr_physical > 0)
436*4882a593Smuzhiyun 		return 0;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	/* Fabricate an rmap entry for the external log device. */
439*4882a593Smuzhiyun 	rmap.rm_startblock = 0;
440*4882a593Smuzhiyun 	rmap.rm_blockcount = mp->m_sb.sb_logblocks;
441*4882a593Smuzhiyun 	rmap.rm_owner = XFS_RMAP_OWN_LOG;
442*4882a593Smuzhiyun 	rmap.rm_offset = 0;
443*4882a593Smuzhiyun 	rmap.rm_flags = 0;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	return xfs_getfsmap_helper(tp, info, &rmap, 0);
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun #ifdef CONFIG_XFS_RT
449*4882a593Smuzhiyun /* Transform a rtbitmap "record" into a fsmap */
450*4882a593Smuzhiyun STATIC int
xfs_getfsmap_rtdev_rtbitmap_helper(struct xfs_trans * tp,struct xfs_rtalloc_rec * rec,void * priv)451*4882a593Smuzhiyun xfs_getfsmap_rtdev_rtbitmap_helper(
452*4882a593Smuzhiyun 	struct xfs_trans		*tp,
453*4882a593Smuzhiyun 	struct xfs_rtalloc_rec		*rec,
454*4882a593Smuzhiyun 	void				*priv)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
457*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info = priv;
458*4882a593Smuzhiyun 	struct xfs_rmap_irec		irec;
459*4882a593Smuzhiyun 	xfs_daddr_t			rec_daddr;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	irec.rm_startblock = rec->ar_startext * mp->m_sb.sb_rextsize;
462*4882a593Smuzhiyun 	rec_daddr = XFS_FSB_TO_BB(mp, irec.rm_startblock);
463*4882a593Smuzhiyun 	irec.rm_blockcount = rec->ar_extcount * mp->m_sb.sb_rextsize;
464*4882a593Smuzhiyun 	irec.rm_owner = XFS_RMAP_OWN_NULL;	/* "free" */
465*4882a593Smuzhiyun 	irec.rm_offset = 0;
466*4882a593Smuzhiyun 	irec.rm_flags = 0;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	return xfs_getfsmap_helper(tp, info, &irec, rec_daddr);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun /* Execute a getfsmap query against the realtime device. */
472*4882a593Smuzhiyun STATIC int
__xfs_getfsmap_rtdev(struct xfs_trans * tp,struct xfs_fsmap * keys,int (* query_fn)(struct xfs_trans *,struct xfs_getfsmap_info *),struct xfs_getfsmap_info * info)473*4882a593Smuzhiyun __xfs_getfsmap_rtdev(
474*4882a593Smuzhiyun 	struct xfs_trans		*tp,
475*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
476*4882a593Smuzhiyun 	int				(*query_fn)(struct xfs_trans *,
477*4882a593Smuzhiyun 						    struct xfs_getfsmap_info *),
478*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
481*4882a593Smuzhiyun 	xfs_fsblock_t			start_fsb;
482*4882a593Smuzhiyun 	xfs_fsblock_t			end_fsb;
483*4882a593Smuzhiyun 	xfs_daddr_t			eofs;
484*4882a593Smuzhiyun 	int				error = 0;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
487*4882a593Smuzhiyun 	if (keys[0].fmr_physical >= eofs)
488*4882a593Smuzhiyun 		return 0;
489*4882a593Smuzhiyun 	if (keys[1].fmr_physical >= eofs)
490*4882a593Smuzhiyun 		keys[1].fmr_physical = eofs - 1;
491*4882a593Smuzhiyun 	start_fsb = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
492*4882a593Smuzhiyun 	end_fsb = XFS_BB_TO_FSB(mp, keys[1].fmr_physical);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	/* Set up search keys */
495*4882a593Smuzhiyun 	info->low.rm_startblock = start_fsb;
496*4882a593Smuzhiyun 	error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
497*4882a593Smuzhiyun 	if (error)
498*4882a593Smuzhiyun 		return error;
499*4882a593Smuzhiyun 	info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
500*4882a593Smuzhiyun 	info->low.rm_blockcount = 0;
501*4882a593Smuzhiyun 	xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	info->high.rm_startblock = end_fsb;
504*4882a593Smuzhiyun 	error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
505*4882a593Smuzhiyun 	if (error)
506*4882a593Smuzhiyun 		return error;
507*4882a593Smuzhiyun 	info->high.rm_offset = XFS_BB_TO_FSBT(mp, keys[1].fmr_offset);
508*4882a593Smuzhiyun 	info->high.rm_blockcount = 0;
509*4882a593Smuzhiyun 	xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
512*4882a593Smuzhiyun 	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return query_fn(tp, info);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun /* Actually query the realtime bitmap. */
518*4882a593Smuzhiyun STATIC int
xfs_getfsmap_rtdev_rtbitmap_query(struct xfs_trans * tp,struct xfs_getfsmap_info * info)519*4882a593Smuzhiyun xfs_getfsmap_rtdev_rtbitmap_query(
520*4882a593Smuzhiyun 	struct xfs_trans		*tp,
521*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	struct xfs_rtalloc_rec		alow = { 0 };
524*4882a593Smuzhiyun 	struct xfs_rtalloc_rec		ahigh = { 0 };
525*4882a593Smuzhiyun 	int				error;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	xfs_ilock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	alow.ar_startext = info->low.rm_startblock;
530*4882a593Smuzhiyun 	ahigh.ar_startext = info->high.rm_startblock;
531*4882a593Smuzhiyun 	do_div(alow.ar_startext, tp->t_mountp->m_sb.sb_rextsize);
532*4882a593Smuzhiyun 	if (do_div(ahigh.ar_startext, tp->t_mountp->m_sb.sb_rextsize))
533*4882a593Smuzhiyun 		ahigh.ar_startext++;
534*4882a593Smuzhiyun 	error = xfs_rtalloc_query_range(tp, &alow, &ahigh,
535*4882a593Smuzhiyun 			xfs_getfsmap_rtdev_rtbitmap_helper, info);
536*4882a593Smuzhiyun 	if (error)
537*4882a593Smuzhiyun 		goto err;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	/* Report any gaps at the end of the rtbitmap */
540*4882a593Smuzhiyun 	info->last = true;
541*4882a593Smuzhiyun 	error = xfs_getfsmap_rtdev_rtbitmap_helper(tp, &ahigh, info);
542*4882a593Smuzhiyun 	if (error)
543*4882a593Smuzhiyun 		goto err;
544*4882a593Smuzhiyun err:
545*4882a593Smuzhiyun 	xfs_iunlock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
546*4882a593Smuzhiyun 	return error;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun /* Execute a getfsmap query against the realtime device rtbitmap. */
550*4882a593Smuzhiyun STATIC int
xfs_getfsmap_rtdev_rtbitmap(struct xfs_trans * tp,struct xfs_fsmap * keys,struct xfs_getfsmap_info * info)551*4882a593Smuzhiyun xfs_getfsmap_rtdev_rtbitmap(
552*4882a593Smuzhiyun 	struct xfs_trans		*tp,
553*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
554*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	info->missing_owner = XFS_FMR_OWN_UNKNOWN;
557*4882a593Smuzhiyun 	return __xfs_getfsmap_rtdev(tp, keys, xfs_getfsmap_rtdev_rtbitmap_query,
558*4882a593Smuzhiyun 			info);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun #endif /* CONFIG_XFS_RT */
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun /* Execute a getfsmap query against the regular data device. */
563*4882a593Smuzhiyun STATIC int
__xfs_getfsmap_datadev(struct xfs_trans * tp,struct xfs_fsmap * keys,struct xfs_getfsmap_info * info,int (* query_fn)(struct xfs_trans *,struct xfs_getfsmap_info *,struct xfs_btree_cur **,void *),void * priv)564*4882a593Smuzhiyun __xfs_getfsmap_datadev(
565*4882a593Smuzhiyun 	struct xfs_trans		*tp,
566*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
567*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info,
568*4882a593Smuzhiyun 	int				(*query_fn)(struct xfs_trans *,
569*4882a593Smuzhiyun 						    struct xfs_getfsmap_info *,
570*4882a593Smuzhiyun 						    struct xfs_btree_cur **,
571*4882a593Smuzhiyun 						    void *),
572*4882a593Smuzhiyun 	void				*priv)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	struct xfs_mount		*mp = tp->t_mountp;
575*4882a593Smuzhiyun 	struct xfs_btree_cur		*bt_cur = NULL;
576*4882a593Smuzhiyun 	xfs_fsblock_t			start_fsb;
577*4882a593Smuzhiyun 	xfs_fsblock_t			end_fsb;
578*4882a593Smuzhiyun 	xfs_agnumber_t			start_ag;
579*4882a593Smuzhiyun 	xfs_agnumber_t			end_ag;
580*4882a593Smuzhiyun 	xfs_daddr_t			eofs;
581*4882a593Smuzhiyun 	int				error = 0;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
584*4882a593Smuzhiyun 	if (keys[0].fmr_physical >= eofs)
585*4882a593Smuzhiyun 		return 0;
586*4882a593Smuzhiyun 	if (keys[1].fmr_physical >= eofs)
587*4882a593Smuzhiyun 		keys[1].fmr_physical = eofs - 1;
588*4882a593Smuzhiyun 	start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fmr_physical);
589*4882a593Smuzhiyun 	end_fsb = XFS_DADDR_TO_FSB(mp, keys[1].fmr_physical);
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	/*
592*4882a593Smuzhiyun 	 * Convert the fsmap low/high keys to AG based keys.  Initialize
593*4882a593Smuzhiyun 	 * low to the fsmap low key and max out the high key to the end
594*4882a593Smuzhiyun 	 * of the AG.
595*4882a593Smuzhiyun 	 */
596*4882a593Smuzhiyun 	info->low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
597*4882a593Smuzhiyun 	info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
598*4882a593Smuzhiyun 	error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
599*4882a593Smuzhiyun 	if (error)
600*4882a593Smuzhiyun 		return error;
601*4882a593Smuzhiyun 	info->low.rm_blockcount = 0;
602*4882a593Smuzhiyun 	xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	info->high.rm_startblock = -1U;
605*4882a593Smuzhiyun 	info->high.rm_owner = ULLONG_MAX;
606*4882a593Smuzhiyun 	info->high.rm_offset = ULLONG_MAX;
607*4882a593Smuzhiyun 	info->high.rm_blockcount = 0;
608*4882a593Smuzhiyun 	info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
611*4882a593Smuzhiyun 	end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	/* Query each AG */
614*4882a593Smuzhiyun 	for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
615*4882a593Smuzhiyun 		/*
616*4882a593Smuzhiyun 		 * Set the AG high key from the fsmap high key if this
617*4882a593Smuzhiyun 		 * is the last AG that we're querying.
618*4882a593Smuzhiyun 		 */
619*4882a593Smuzhiyun 		if (info->agno == end_ag) {
620*4882a593Smuzhiyun 			info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
621*4882a593Smuzhiyun 					end_fsb);
622*4882a593Smuzhiyun 			info->high.rm_offset = XFS_BB_TO_FSBT(mp,
623*4882a593Smuzhiyun 					keys[1].fmr_offset);
624*4882a593Smuzhiyun 			error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
625*4882a593Smuzhiyun 			if (error)
626*4882a593Smuzhiyun 				goto err;
627*4882a593Smuzhiyun 			xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
628*4882a593Smuzhiyun 		}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 		if (bt_cur) {
631*4882a593Smuzhiyun 			xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
632*4882a593Smuzhiyun 			bt_cur = NULL;
633*4882a593Smuzhiyun 			xfs_trans_brelse(tp, info->agf_bp);
634*4882a593Smuzhiyun 			info->agf_bp = NULL;
635*4882a593Smuzhiyun 		}
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 		error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
638*4882a593Smuzhiyun 				&info->agf_bp);
639*4882a593Smuzhiyun 		if (error)
640*4882a593Smuzhiyun 			goto err;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 		trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
643*4882a593Smuzhiyun 		trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
644*4882a593Smuzhiyun 				&info->high);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 		error = query_fn(tp, info, &bt_cur, priv);
647*4882a593Smuzhiyun 		if (error)
648*4882a593Smuzhiyun 			goto err;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 		/*
651*4882a593Smuzhiyun 		 * Set the AG low key to the start of the AG prior to
652*4882a593Smuzhiyun 		 * moving on to the next AG.
653*4882a593Smuzhiyun 		 */
654*4882a593Smuzhiyun 		if (info->agno == start_ag) {
655*4882a593Smuzhiyun 			info->low.rm_startblock = 0;
656*4882a593Smuzhiyun 			info->low.rm_owner = 0;
657*4882a593Smuzhiyun 			info->low.rm_offset = 0;
658*4882a593Smuzhiyun 			info->low.rm_flags = 0;
659*4882a593Smuzhiyun 		}
660*4882a593Smuzhiyun 	}
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Report any gap at the end of the AG */
663*4882a593Smuzhiyun 	info->last = true;
664*4882a593Smuzhiyun 	error = query_fn(tp, info, &bt_cur, priv);
665*4882a593Smuzhiyun 	if (error)
666*4882a593Smuzhiyun 		goto err;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun err:
669*4882a593Smuzhiyun 	if (bt_cur)
670*4882a593Smuzhiyun 		xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
671*4882a593Smuzhiyun 							 XFS_BTREE_NOERROR);
672*4882a593Smuzhiyun 	if (info->agf_bp) {
673*4882a593Smuzhiyun 		xfs_trans_brelse(tp, info->agf_bp);
674*4882a593Smuzhiyun 		info->agf_bp = NULL;
675*4882a593Smuzhiyun 	}
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	return error;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun /* Actually query the rmap btree. */
681*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_rmapbt_query(struct xfs_trans * tp,struct xfs_getfsmap_info * info,struct xfs_btree_cur ** curpp,void * priv)682*4882a593Smuzhiyun xfs_getfsmap_datadev_rmapbt_query(
683*4882a593Smuzhiyun 	struct xfs_trans		*tp,
684*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info,
685*4882a593Smuzhiyun 	struct xfs_btree_cur		**curpp,
686*4882a593Smuzhiyun 	void				*priv)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	/* Report any gap at the end of the last AG. */
689*4882a593Smuzhiyun 	if (info->last)
690*4882a593Smuzhiyun 		return xfs_getfsmap_datadev_helper(*curpp, &info->high, info);
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	/* Allocate cursor for this AG and query_range it. */
693*4882a593Smuzhiyun 	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
694*4882a593Smuzhiyun 			info->agno);
695*4882a593Smuzhiyun 	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
696*4882a593Smuzhiyun 			xfs_getfsmap_datadev_helper, info);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun /* Execute a getfsmap query against the regular data device rmapbt. */
700*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_rmapbt(struct xfs_trans * tp,struct xfs_fsmap * keys,struct xfs_getfsmap_info * info)701*4882a593Smuzhiyun xfs_getfsmap_datadev_rmapbt(
702*4882a593Smuzhiyun 	struct xfs_trans		*tp,
703*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
704*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	info->missing_owner = XFS_FMR_OWN_FREE;
707*4882a593Smuzhiyun 	return __xfs_getfsmap_datadev(tp, keys, info,
708*4882a593Smuzhiyun 			xfs_getfsmap_datadev_rmapbt_query, NULL);
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun /* Actually query the bno btree. */
712*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_bnobt_query(struct xfs_trans * tp,struct xfs_getfsmap_info * info,struct xfs_btree_cur ** curpp,void * priv)713*4882a593Smuzhiyun xfs_getfsmap_datadev_bnobt_query(
714*4882a593Smuzhiyun 	struct xfs_trans		*tp,
715*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info,
716*4882a593Smuzhiyun 	struct xfs_btree_cur		**curpp,
717*4882a593Smuzhiyun 	void				*priv)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun 	struct xfs_alloc_rec_incore	*key = priv;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	/* Report any gap at the end of the last AG. */
722*4882a593Smuzhiyun 	if (info->last)
723*4882a593Smuzhiyun 		return xfs_getfsmap_datadev_bnobt_helper(*curpp, &key[1], info);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	/* Allocate cursor for this AG and query_range it. */
726*4882a593Smuzhiyun 	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
727*4882a593Smuzhiyun 			info->agno, XFS_BTNUM_BNO);
728*4882a593Smuzhiyun 	key->ar_startblock = info->low.rm_startblock;
729*4882a593Smuzhiyun 	key[1].ar_startblock = info->high.rm_startblock;
730*4882a593Smuzhiyun 	return xfs_alloc_query_range(*curpp, key, &key[1],
731*4882a593Smuzhiyun 			xfs_getfsmap_datadev_bnobt_helper, info);
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun /* Execute a getfsmap query against the regular data device's bnobt. */
735*4882a593Smuzhiyun STATIC int
xfs_getfsmap_datadev_bnobt(struct xfs_trans * tp,struct xfs_fsmap * keys,struct xfs_getfsmap_info * info)736*4882a593Smuzhiyun xfs_getfsmap_datadev_bnobt(
737*4882a593Smuzhiyun 	struct xfs_trans		*tp,
738*4882a593Smuzhiyun 	struct xfs_fsmap		*keys,
739*4882a593Smuzhiyun 	struct xfs_getfsmap_info	*info)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun 	struct xfs_alloc_rec_incore	akeys[2];
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	info->missing_owner = XFS_FMR_OWN_UNKNOWN;
744*4882a593Smuzhiyun 	return __xfs_getfsmap_datadev(tp, keys, info,
745*4882a593Smuzhiyun 			xfs_getfsmap_datadev_bnobt_query, &akeys[0]);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun /* Do we recognize the device? */
749*4882a593Smuzhiyun STATIC bool
xfs_getfsmap_is_valid_device(struct xfs_mount * mp,struct xfs_fsmap * fm)750*4882a593Smuzhiyun xfs_getfsmap_is_valid_device(
751*4882a593Smuzhiyun 	struct xfs_mount	*mp,
752*4882a593Smuzhiyun 	struct xfs_fsmap	*fm)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun 	if (fm->fmr_device == 0 || fm->fmr_device == UINT_MAX ||
755*4882a593Smuzhiyun 	    fm->fmr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
756*4882a593Smuzhiyun 		return true;
757*4882a593Smuzhiyun 	if (mp->m_logdev_targp &&
758*4882a593Smuzhiyun 	    fm->fmr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
759*4882a593Smuzhiyun 		return true;
760*4882a593Smuzhiyun 	if (mp->m_rtdev_targp &&
761*4882a593Smuzhiyun 	    fm->fmr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
762*4882a593Smuzhiyun 		return true;
763*4882a593Smuzhiyun 	return false;
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun /* Ensure that the low key is less than the high key. */
767*4882a593Smuzhiyun STATIC bool
xfs_getfsmap_check_keys(struct xfs_fsmap * low_key,struct xfs_fsmap * high_key)768*4882a593Smuzhiyun xfs_getfsmap_check_keys(
769*4882a593Smuzhiyun 	struct xfs_fsmap		*low_key,
770*4882a593Smuzhiyun 	struct xfs_fsmap		*high_key)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	if (low_key->fmr_device > high_key->fmr_device)
773*4882a593Smuzhiyun 		return false;
774*4882a593Smuzhiyun 	if (low_key->fmr_device < high_key->fmr_device)
775*4882a593Smuzhiyun 		return true;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	if (low_key->fmr_physical > high_key->fmr_physical)
778*4882a593Smuzhiyun 		return false;
779*4882a593Smuzhiyun 	if (low_key->fmr_physical < high_key->fmr_physical)
780*4882a593Smuzhiyun 		return true;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	if (low_key->fmr_owner > high_key->fmr_owner)
783*4882a593Smuzhiyun 		return false;
784*4882a593Smuzhiyun 	if (low_key->fmr_owner < high_key->fmr_owner)
785*4882a593Smuzhiyun 		return true;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	if (low_key->fmr_offset > high_key->fmr_offset)
788*4882a593Smuzhiyun 		return false;
789*4882a593Smuzhiyun 	if (low_key->fmr_offset < high_key->fmr_offset)
790*4882a593Smuzhiyun 		return true;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	return false;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun /*
796*4882a593Smuzhiyun  * There are only two devices if we didn't configure RT devices at build time.
797*4882a593Smuzhiyun  */
798*4882a593Smuzhiyun #ifdef CONFIG_XFS_RT
799*4882a593Smuzhiyun #define XFS_GETFSMAP_DEVS	3
800*4882a593Smuzhiyun #else
801*4882a593Smuzhiyun #define XFS_GETFSMAP_DEVS	2
802*4882a593Smuzhiyun #endif /* CONFIG_XFS_RT */
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun /*
805*4882a593Smuzhiyun  * Get filesystem's extents as described in head, and format for output. Fills
806*4882a593Smuzhiyun  * in the supplied records array until there are no more reverse mappings to
807*4882a593Smuzhiyun  * return or head.fmh_entries == head.fmh_count.  In the second case, this
808*4882a593Smuzhiyun  * function returns -ECANCELED to indicate that more records would have been
809*4882a593Smuzhiyun  * returned.
810*4882a593Smuzhiyun  *
811*4882a593Smuzhiyun  * Key to Confusion
812*4882a593Smuzhiyun  * ----------------
813*4882a593Smuzhiyun  * There are multiple levels of keys and counters at work here:
814*4882a593Smuzhiyun  * xfs_fsmap_head.fmh_keys	-- low and high fsmap keys passed in;
815*4882a593Smuzhiyun  * 				   these reflect fs-wide sector addrs.
816*4882a593Smuzhiyun  * dkeys			-- fmh_keys used to query each device;
817*4882a593Smuzhiyun  * 				   these are fmh_keys but w/ the low key
818*4882a593Smuzhiyun  * 				   bumped up by fmr_length.
819*4882a593Smuzhiyun  * xfs_getfsmap_info.next_daddr	-- next disk addr we expect to see; this
820*4882a593Smuzhiyun  *				   is how we detect gaps in the fsmap
821*4882a593Smuzhiyun 				   records and report them.
822*4882a593Smuzhiyun  * xfs_getfsmap_info.low/high	-- per-AG low/high keys computed from
823*4882a593Smuzhiyun  * 				   dkeys; used to query the metadata.
824*4882a593Smuzhiyun  */
825*4882a593Smuzhiyun int
xfs_getfsmap(struct xfs_mount * mp,struct xfs_fsmap_head * head,struct fsmap * fsmap_recs)826*4882a593Smuzhiyun xfs_getfsmap(
827*4882a593Smuzhiyun 	struct xfs_mount		*mp,
828*4882a593Smuzhiyun 	struct xfs_fsmap_head		*head,
829*4882a593Smuzhiyun 	struct fsmap			*fsmap_recs)
830*4882a593Smuzhiyun {
831*4882a593Smuzhiyun 	struct xfs_trans		*tp = NULL;
832*4882a593Smuzhiyun 	struct xfs_fsmap		dkeys[2];	/* per-dev keys */
833*4882a593Smuzhiyun 	struct xfs_getfsmap_dev		handlers[XFS_GETFSMAP_DEVS];
834*4882a593Smuzhiyun 	struct xfs_getfsmap_info	info = { NULL };
835*4882a593Smuzhiyun 	bool				use_rmap;
836*4882a593Smuzhiyun 	int				i;
837*4882a593Smuzhiyun 	int				error = 0;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	if (head->fmh_iflags & ~FMH_IF_VALID)
840*4882a593Smuzhiyun 		return -EINVAL;
841*4882a593Smuzhiyun 	if (!xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[0]) ||
842*4882a593Smuzhiyun 	    !xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[1]))
843*4882a593Smuzhiyun 		return -EINVAL;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	use_rmap = capable(CAP_SYS_ADMIN) &&
846*4882a593Smuzhiyun 		   xfs_sb_version_hasrmapbt(&mp->m_sb);
847*4882a593Smuzhiyun 	head->fmh_entries = 0;
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	/* Set up our device handlers. */
850*4882a593Smuzhiyun 	memset(handlers, 0, sizeof(handlers));
851*4882a593Smuzhiyun 	handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
852*4882a593Smuzhiyun 	if (use_rmap)
853*4882a593Smuzhiyun 		handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
854*4882a593Smuzhiyun 	else
855*4882a593Smuzhiyun 		handlers[0].fn = xfs_getfsmap_datadev_bnobt;
856*4882a593Smuzhiyun 	if (mp->m_logdev_targp != mp->m_ddev_targp) {
857*4882a593Smuzhiyun 		handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
858*4882a593Smuzhiyun 		handlers[1].fn = xfs_getfsmap_logdev;
859*4882a593Smuzhiyun 	}
860*4882a593Smuzhiyun #ifdef CONFIG_XFS_RT
861*4882a593Smuzhiyun 	if (mp->m_rtdev_targp) {
862*4882a593Smuzhiyun 		handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
863*4882a593Smuzhiyun 		handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun #endif /* CONFIG_XFS_RT */
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	xfs_sort(handlers, XFS_GETFSMAP_DEVS, sizeof(struct xfs_getfsmap_dev),
868*4882a593Smuzhiyun 			xfs_getfsmap_dev_compare);
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	/*
871*4882a593Smuzhiyun 	 * To continue where we left off, we allow userspace to use the
872*4882a593Smuzhiyun 	 * last mapping from a previous call as the low key of the next.
873*4882a593Smuzhiyun 	 * This is identified by a non-zero length in the low key. We
874*4882a593Smuzhiyun 	 * have to increment the low key in this scenario to ensure we
875*4882a593Smuzhiyun 	 * don't return the same mapping again, and instead return the
876*4882a593Smuzhiyun 	 * very next mapping.
877*4882a593Smuzhiyun 	 *
878*4882a593Smuzhiyun 	 * If the low key mapping refers to file data, the same physical
879*4882a593Smuzhiyun 	 * blocks could be mapped to several other files/offsets.
880*4882a593Smuzhiyun 	 * According to rmapbt record ordering, the minimal next
881*4882a593Smuzhiyun 	 * possible record for the block range is the next starting
882*4882a593Smuzhiyun 	 * offset in the same inode. Therefore, bump the file offset to
883*4882a593Smuzhiyun 	 * continue the search appropriately.  For all other low key
884*4882a593Smuzhiyun 	 * mapping types (attr blocks, metadata), bump the physical
885*4882a593Smuzhiyun 	 * offset as there can be no other mapping for the same physical
886*4882a593Smuzhiyun 	 * block range.
887*4882a593Smuzhiyun 	 */
888*4882a593Smuzhiyun 	dkeys[0] = head->fmh_keys[0];
889*4882a593Smuzhiyun 	if (dkeys[0].fmr_flags & (FMR_OF_SPECIAL_OWNER | FMR_OF_EXTENT_MAP)) {
890*4882a593Smuzhiyun 		dkeys[0].fmr_physical += dkeys[0].fmr_length;
891*4882a593Smuzhiyun 		dkeys[0].fmr_owner = 0;
892*4882a593Smuzhiyun 		if (dkeys[0].fmr_offset)
893*4882a593Smuzhiyun 			return -EINVAL;
894*4882a593Smuzhiyun 	} else
895*4882a593Smuzhiyun 		dkeys[0].fmr_offset += dkeys[0].fmr_length;
896*4882a593Smuzhiyun 	dkeys[0].fmr_length = 0;
897*4882a593Smuzhiyun 	memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsmap));
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	if (!xfs_getfsmap_check_keys(dkeys, &head->fmh_keys[1]))
900*4882a593Smuzhiyun 		return -EINVAL;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	info.next_daddr = head->fmh_keys[0].fmr_physical +
903*4882a593Smuzhiyun 			  head->fmh_keys[0].fmr_length;
904*4882a593Smuzhiyun 	info.fsmap_recs = fsmap_recs;
905*4882a593Smuzhiyun 	info.head = head;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	/*
908*4882a593Smuzhiyun 	 * If fsmap runs concurrently with a scrub, the freeze can be delayed
909*4882a593Smuzhiyun 	 * indefinitely as we walk the rmapbt and iterate over metadata
910*4882a593Smuzhiyun 	 * buffers.  Freeze quiesces the log (which waits for the buffer LRU to
911*4882a593Smuzhiyun 	 * be emptied) and that won't happen while we're reading buffers.
912*4882a593Smuzhiyun 	 */
913*4882a593Smuzhiyun 	sb_start_write(mp->m_super);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	/* For each device we support... */
916*4882a593Smuzhiyun 	for (i = 0; i < XFS_GETFSMAP_DEVS; i++) {
917*4882a593Smuzhiyun 		/* Is this device within the range the user asked for? */
918*4882a593Smuzhiyun 		if (!handlers[i].fn)
919*4882a593Smuzhiyun 			continue;
920*4882a593Smuzhiyun 		if (head->fmh_keys[0].fmr_device > handlers[i].dev)
921*4882a593Smuzhiyun 			continue;
922*4882a593Smuzhiyun 		if (head->fmh_keys[1].fmr_device < handlers[i].dev)
923*4882a593Smuzhiyun 			break;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 		/*
926*4882a593Smuzhiyun 		 * If this device number matches the high key, we have
927*4882a593Smuzhiyun 		 * to pass the high key to the handler to limit the
928*4882a593Smuzhiyun 		 * query results.  If the device number exceeds the
929*4882a593Smuzhiyun 		 * low key, zero out the low key so that we get
930*4882a593Smuzhiyun 		 * everything from the beginning.
931*4882a593Smuzhiyun 		 */
932*4882a593Smuzhiyun 		if (handlers[i].dev == head->fmh_keys[1].fmr_device)
933*4882a593Smuzhiyun 			dkeys[1] = head->fmh_keys[1];
934*4882a593Smuzhiyun 		if (handlers[i].dev > head->fmh_keys[0].fmr_device)
935*4882a593Smuzhiyun 			memset(&dkeys[0], 0, sizeof(struct xfs_fsmap));
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 		error = xfs_trans_alloc_empty(mp, &tp);
938*4882a593Smuzhiyun 		if (error)
939*4882a593Smuzhiyun 			break;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 		info.dev = handlers[i].dev;
942*4882a593Smuzhiyun 		info.last = false;
943*4882a593Smuzhiyun 		info.agno = NULLAGNUMBER;
944*4882a593Smuzhiyun 		error = handlers[i].fn(tp, dkeys, &info);
945*4882a593Smuzhiyun 		if (error)
946*4882a593Smuzhiyun 			break;
947*4882a593Smuzhiyun 		xfs_trans_cancel(tp);
948*4882a593Smuzhiyun 		tp = NULL;
949*4882a593Smuzhiyun 		info.next_daddr = 0;
950*4882a593Smuzhiyun 	}
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	if (tp)
953*4882a593Smuzhiyun 		xfs_trans_cancel(tp);
954*4882a593Smuzhiyun 	sb_end_write(mp->m_super);
955*4882a593Smuzhiyun 	head->fmh_oflags = FMH_OF_DEV_T;
956*4882a593Smuzhiyun 	return error;
957*4882a593Smuzhiyun }
958