1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc#include "xfs.h"
19159451Srodrigc#include "xfs_fs.h"
20153323Srodrigc#include "xfs_types.h"
21159451Srodrigc#include "xfs_bit.h"
22159451Srodrigc#include "xfs_log.h"
23153323Srodrigc#include "xfs_inum.h"
24153323Srodrigc#include "xfs_trans.h"
25153323Srodrigc#include "xfs_sb.h"
26153323Srodrigc#include "xfs_ag.h"
27153323Srodrigc#include "xfs_dir.h"
28153323Srodrigc#include "xfs_dir2.h"
29159451Srodrigc#include "xfs_da_btree.h"
30159451Srodrigc#include "xfs_bmap_btree.h"
31153323Srodrigc#include "xfs_alloc_btree.h"
32153323Srodrigc#include "xfs_ialloc_btree.h"
33153323Srodrigc#include "xfs_dir_sf.h"
34153323Srodrigc#include "xfs_dir2_sf.h"
35159451Srodrigc#include "xfs_attr_sf.h"
36153323Srodrigc#include "xfs_dinode.h"
37153323Srodrigc#include "xfs_inode.h"
38159451Srodrigc#include "xfs_btree.h"
39159451Srodrigc#include "xfs_dmapi.h"
40159451Srodrigc#include "xfs_mount.h"
41159451Srodrigc#include "xfs_ialloc.h"
42153323Srodrigc#include "xfs_itable.h"
43159451Srodrigc#include "xfs_inode_item.h"
44153323Srodrigc#include "xfs_extfree_item.h"
45153323Srodrigc#include "xfs_alloc.h"
46153323Srodrigc#include "xfs_bmap.h"
47153323Srodrigc#include "xfs_rtalloc.h"
48153323Srodrigc#include "xfs_error.h"
49153323Srodrigc#include "xfs_dir_leaf.h"
50159451Srodrigc#include "xfs_attr_leaf.h"
51153323Srodrigc#include "xfs_rw.h"
52153323Srodrigc#include "xfs_quota.h"
53153323Srodrigc#include "xfs_trans_space.h"
54153323Srodrigc#include "xfs_buf_item.h"
55153323Srodrigc
56153323Srodrigc
57159451Srodrigc#ifdef DEBUG
58153323SrodrigcSTATIC void
59153323Srodrigcxfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork);
60153323Srodrigc#endif
61153323Srodrigc
62153323Srodrigckmem_zone_t		*xfs_bmap_free_item_zone;
63153323Srodrigc
64153323Srodrigc/*
65153323Srodrigc * Prototypes for internal bmap routines.
66153323Srodrigc */
67153323Srodrigc
68153323Srodrigc
69153323Srodrigc/*
70153323Srodrigc * Called from xfs_bmap_add_attrfork to handle extents format files.
71153323Srodrigc */
72153323SrodrigcSTATIC int					/* error */
73153323Srodrigcxfs_bmap_add_attrfork_extents(
74153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
75153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
76153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first block allocated */
77153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
78153323Srodrigc	int			*flags);	/* inode logging flags */
79153323Srodrigc
80153323Srodrigc/*
81153323Srodrigc * Called from xfs_bmap_add_attrfork to handle local format files.
82153323Srodrigc */
83153323SrodrigcSTATIC int					/* error */
84153323Srodrigcxfs_bmap_add_attrfork_local(
85153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
86153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
87153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first block allocated */
88153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
89153323Srodrigc	int			*flags);	/* inode logging flags */
90153323Srodrigc
91153323Srodrigc/*
92159451Srodrigc * Called by xfs_bmapi to update file extent records and the btree
93153323Srodrigc * after allocating space (or doing a delayed allocation).
94153323Srodrigc */
95153323SrodrigcSTATIC int				/* error */
96153323Srodrigcxfs_bmap_add_extent(
97153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
98153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
99153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
100159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
101153323Srodrigc	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
102153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
103153323Srodrigc	int			*logflagsp, /* inode logging flags */
104159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
105153323Srodrigc	int			whichfork, /* data or attr fork */
106153323Srodrigc	int			rsvd);	/* OK to allocate reserved blocks */
107153323Srodrigc
108153323Srodrigc/*
109153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a delayed
110153323Srodrigc * allocation to a real allocation.
111153323Srodrigc */
112153323SrodrigcSTATIC int				/* error */
113153323Srodrigcxfs_bmap_add_extent_delay_real(
114153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
115153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
116153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
117159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
118153323Srodrigc	xfs_filblks_t		*dnew,	/* new delayed-alloc indirect blocks */
119153323Srodrigc	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
120153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
121153323Srodrigc	int			*logflagsp, /* inode logging flags */
122159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
123153323Srodrigc	int			rsvd);	/* OK to allocate reserved blocks */
124153323Srodrigc
125153323Srodrigc/*
126153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a hole
127153323Srodrigc * to a delayed allocation.
128153323Srodrigc */
129153323SrodrigcSTATIC int				/* error */
130153323Srodrigcxfs_bmap_add_extent_hole_delay(
131153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
132153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
133153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
134159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
135153323Srodrigc	int			*logflagsp,/* inode logging flags */
136159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
137153323Srodrigc	int			rsvd);	/* OK to allocate reserved blocks */
138153323Srodrigc
139153323Srodrigc/*
140153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a hole
141153323Srodrigc * to a real allocation.
142153323Srodrigc */
143153323SrodrigcSTATIC int				/* error */
144153323Srodrigcxfs_bmap_add_extent_hole_real(
145153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
146153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
147153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
148159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
149153323Srodrigc	int			*logflagsp, /* inode logging flags */
150159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
151153323Srodrigc	int			whichfork); /* data or attr fork */
152153323Srodrigc
153153323Srodrigc/*
154153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting an unwritten
155153323Srodrigc * allocation to a real allocation or vice versa.
156153323Srodrigc */
157153323SrodrigcSTATIC int				/* error */
158153323Srodrigcxfs_bmap_add_extent_unwritten_real(
159153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
160153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
161153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
162159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
163159451Srodrigc	int			*logflagsp, /* inode logging flags */
164159451Srodrigc	xfs_extdelta_t		*delta); /* Change made to incore extents */
165153323Srodrigc
166153323Srodrigc/*
167153323Srodrigc * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
168153323Srodrigc * It figures out where to ask the underlying allocator to put the new extent.
169153323Srodrigc */
170153323SrodrigcSTATIC int				/* error */
171153323Srodrigcxfs_bmap_alloc(
172153323Srodrigc	xfs_bmalloca_t		*ap);	/* bmap alloc argument struct */
173153323Srodrigc
174153323Srodrigc/*
175153323Srodrigc * Transform a btree format file with only one leaf node, where the
176153323Srodrigc * extents list will fit in the inode, into an extents format file.
177159451Srodrigc * Since the file extents are already in-core, all we have to do is
178153323Srodrigc * give up the space for the btree root and pitch the leaf block.
179153323Srodrigc */
180153323SrodrigcSTATIC int				/* error */
181153323Srodrigcxfs_bmap_btree_to_extents(
182153323Srodrigc	xfs_trans_t		*tp,	/* transaction pointer */
183153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
184153323Srodrigc	xfs_btree_cur_t		*cur,	/* btree cursor */
185153323Srodrigc	int			*logflagsp, /* inode logging flags */
186153323Srodrigc	int			whichfork); /* data or attr fork */
187153323Srodrigc
188159451Srodrigc#ifdef DEBUG
189159451Srodrigc#if 0
190153323Srodrigc/*
191153323Srodrigc * Check that the extents list for the inode ip is in the right order.
192153323Srodrigc */
193153323SrodrigcSTATIC void
194153323Srodrigcxfs_bmap_check_extents(
195153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
196153323Srodrigc	int			whichfork);	/* data or attr fork */
197153323Srodrigc#endif
198159451Srodrigc#endif
199153323Srodrigc
200153323Srodrigc/*
201159451Srodrigc * Called by xfs_bmapi to update file extent records and the btree
202153323Srodrigc * after removing space (or undoing a delayed allocation).
203153323Srodrigc */
204153323SrodrigcSTATIC int				/* error */
205153323Srodrigcxfs_bmap_del_extent(
206153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
207153323Srodrigc	xfs_trans_t		*tp,	/* current trans pointer */
208153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
209153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
210153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
211159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
212153323Srodrigc	int			*logflagsp,/* inode logging flags */
213159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
214153323Srodrigc	int			whichfork, /* data or attr fork */
215153323Srodrigc	int			rsvd);	 /* OK to allocate reserved blocks */
216153323Srodrigc
217153323Srodrigc/*
218153323Srodrigc * Remove the entry "free" from the free item list.  Prev points to the
219153323Srodrigc * previous entry, unless "free" is the head of the list.
220153323Srodrigc */
221153323SrodrigcSTATIC void
222153323Srodrigcxfs_bmap_del_free(
223153323Srodrigc	xfs_bmap_free_t		*flist,	/* free item list header */
224153323Srodrigc	xfs_bmap_free_item_t	*prev,	/* previous item on list, if any */
225153323Srodrigc	xfs_bmap_free_item_t	*free);	/* list item to be freed */
226153323Srodrigc
227153323Srodrigc/*
228153323Srodrigc * Convert an extents-format file into a btree-format file.
229153323Srodrigc * The new file will have a root block (in the inode) and a single child block.
230153323Srodrigc */
231153323SrodrigcSTATIC int					/* error */
232153323Srodrigcxfs_bmap_extents_to_btree(
233153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
234153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
235153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first-block-allocated */
236153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks freed in xaction */
237153323Srodrigc	xfs_btree_cur_t		**curp,		/* cursor returned to caller */
238153323Srodrigc	int			wasdel,		/* converting a delayed alloc */
239153323Srodrigc	int			*logflagsp,	/* inode logging flags */
240153323Srodrigc	int			whichfork);	/* data or attr fork */
241153323Srodrigc
242153323Srodrigc/*
243153323Srodrigc * Convert a local file to an extents file.
244153323Srodrigc * This code is sort of bogus, since the file data needs to get
245153323Srodrigc * logged so it won't be lost.  The bmap-level manipulations are ok, though.
246153323Srodrigc */
247153323SrodrigcSTATIC int				/* error */
248153323Srodrigcxfs_bmap_local_to_extents(
249153323Srodrigc	xfs_trans_t	*tp,		/* transaction pointer */
250153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
251153323Srodrigc	xfs_fsblock_t	*firstblock,	/* first block allocated in xaction */
252153323Srodrigc	xfs_extlen_t	total,		/* total blocks needed by transaction */
253153323Srodrigc	int		*logflagsp,	/* inode logging flags */
254153323Srodrigc	int		whichfork);	/* data or attr fork */
255153323Srodrigc
256153323Srodrigc/*
257153323Srodrigc * Search the extents list for the inode, for the extent containing bno.
258153323Srodrigc * If bno lies in a hole, point to the next entry.  If bno lies past eof,
259153323Srodrigc * *eofp will be set, and *prevp will contain the last entry (null if none).
260153323Srodrigc * Else, *lastxp will be set to the index of the found
261153323Srodrigc * entry; *gotp will contain the entry.
262153323Srodrigc */
263153323SrodrigcSTATIC xfs_bmbt_rec_t *			/* pointer to found extent entry */
264153323Srodrigcxfs_bmap_search_extents(
265153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
266153323Srodrigc	xfs_fileoff_t	bno,		/* block number searched for */
267153323Srodrigc	int		whichfork,	/* data or attr fork */
268153323Srodrigc	int		*eofp,		/* out: end of file found */
269153323Srodrigc	xfs_extnum_t	*lastxp,	/* out: last extent index */
270153323Srodrigc	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */
271153323Srodrigc	xfs_bmbt_irec_t	*prevp);	/* out: previous extent entry found */
272153323Srodrigc
273159451Srodrigc/*
274159451Srodrigc * Check the last inode extent to determine whether this allocation will result
275159451Srodrigc * in blocks being allocated at the end of the file. When we allocate new data
276159451Srodrigc * blocks at the end of the file which do not start at the previous data block,
277159451Srodrigc * we will try to align the new blocks at stripe unit boundaries.
278159451Srodrigc */
279159451SrodrigcSTATIC int				/* error */
280159451Srodrigcxfs_bmap_isaeof(
281159451Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
282159451Srodrigc	xfs_fileoff_t   off,		/* file offset in fsblocks */
283159451Srodrigc	int             whichfork,	/* data or attribute fork */
284159451Srodrigc	char		*aeof);		/* return value */
285159451Srodrigc
286153323Srodrigc#ifdef XFS_BMAP_TRACE
287153323Srodrigc/*
288153323Srodrigc * Add a bmap trace buffer entry.  Base routine for the others.
289153323Srodrigc */
290153323SrodrigcSTATIC void
291153323Srodrigcxfs_bmap_trace_addentry(
292153323Srodrigc	int		opcode,		/* operation */
293153323Srodrigc	char		*fname,		/* function name */
294153323Srodrigc	char		*desc,		/* operation description */
295153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
296153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(ies) */
297153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries, 1 or 2 */
298153323Srodrigc	xfs_bmbt_rec_t	*r1,		/* first record */
299153323Srodrigc	xfs_bmbt_rec_t	*r2,		/* second record or null */
300153323Srodrigc	int		whichfork);	/* data or attr fork */
301153323Srodrigc
302153323Srodrigc/*
303159451Srodrigc * Add bmap trace entry prior to a call to xfs_iext_remove.
304153323Srodrigc */
305153323SrodrigcSTATIC void
306153323Srodrigcxfs_bmap_trace_delete(
307153323Srodrigc	char		*fname,		/* function name */
308153323Srodrigc	char		*desc,		/* operation description */
309153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
310153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(entries) deleted */
311153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries deleted, 1 or 2 */
312153323Srodrigc	int		whichfork);	/* data or attr fork */
313153323Srodrigc
314153323Srodrigc/*
315159451Srodrigc * Add bmap trace entry prior to a call to xfs_iext_insert, or
316153323Srodrigc * reading in the extents list from the disk (in the btree).
317153323Srodrigc */
318153323SrodrigcSTATIC void
319153323Srodrigcxfs_bmap_trace_insert(
320153323Srodrigc	char		*fname,		/* function name */
321153323Srodrigc	char		*desc,		/* operation description */
322153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
323153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(entries) inserted */
324153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries inserted, 1 or 2 */
325153323Srodrigc	xfs_bmbt_irec_t	*r1,		/* inserted record 1 */
326153323Srodrigc	xfs_bmbt_irec_t	*r2,		/* inserted record 2 or null */
327153323Srodrigc	int		whichfork);	/* data or attr fork */
328153323Srodrigc
329153323Srodrigc/*
330159451Srodrigc * Add bmap trace entry after updating an extent record in place.
331153323Srodrigc */
332153323SrodrigcSTATIC void
333153323Srodrigcxfs_bmap_trace_post_update(
334153323Srodrigc	char		*fname,		/* function name */
335153323Srodrigc	char		*desc,		/* operation description */
336153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
337153323Srodrigc	xfs_extnum_t	idx,		/* index of entry updated */
338153323Srodrigc	int		whichfork);	/* data or attr fork */
339153323Srodrigc
340153323Srodrigc/*
341159451Srodrigc * Add bmap trace entry prior to updating an extent record in place.
342153323Srodrigc */
343153323SrodrigcSTATIC void
344153323Srodrigcxfs_bmap_trace_pre_update(
345153323Srodrigc	char		*fname,		/* function name */
346153323Srodrigc	char		*desc,		/* operation description */
347153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
348153323Srodrigc	xfs_extnum_t	idx,		/* index of entry to be updated */
349153323Srodrigc	int		whichfork);	/* data or attr fork */
350153323Srodrigc
351153323Srodrigc#else
352153323Srodrigc#define	xfs_bmap_trace_delete(f,d,ip,i,c,w)
353153323Srodrigc#define	xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w)
354153323Srodrigc#define	xfs_bmap_trace_post_update(f,d,ip,i,w)
355153323Srodrigc#define	xfs_bmap_trace_pre_update(f,d,ip,i,w)
356153323Srodrigc#endif	/* XFS_BMAP_TRACE */
357153323Srodrigc
358153323Srodrigc/*
359153323Srodrigc * Compute the worst-case number of indirect blocks that will be used
360153323Srodrigc * for ip's delayed extent of length "len".
361153323Srodrigc */
362153323SrodrigcSTATIC xfs_filblks_t
363153323Srodrigcxfs_bmap_worst_indlen(
364153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
365153323Srodrigc	xfs_filblks_t		len);	/* delayed extent length */
366153323Srodrigc
367153323Srodrigc#ifdef DEBUG
368153323Srodrigc/*
369153323Srodrigc * Perform various validation checks on the values being returned
370153323Srodrigc * from xfs_bmapi().
371153323Srodrigc */
372153323SrodrigcSTATIC void
373153323Srodrigcxfs_bmap_validate_ret(
374153323Srodrigc	xfs_fileoff_t		bno,
375153323Srodrigc	xfs_filblks_t		len,
376153323Srodrigc	int			flags,
377153323Srodrigc	xfs_bmbt_irec_t		*mval,
378153323Srodrigc	int			nmap,
379153323Srodrigc	int			ret_nmap);
380153323Srodrigc#else
381153323Srodrigc#define	xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap)
382153323Srodrigc#endif /* DEBUG */
383153323Srodrigc
384153323Srodrigc#if defined(XFS_RW_TRACE)
385153323SrodrigcSTATIC void
386153323Srodrigcxfs_bunmap_trace(
387153323Srodrigc	xfs_inode_t		*ip,
388153323Srodrigc	xfs_fileoff_t		bno,
389153323Srodrigc	xfs_filblks_t		len,
390153323Srodrigc	int			flags,
391153323Srodrigc	inst_t			*ra);
392153323Srodrigc#else
393153323Srodrigc#define	xfs_bunmap_trace(ip, bno, len, flags, ra)
394153323Srodrigc#endif	/* XFS_RW_TRACE */
395153323Srodrigc
396153323SrodrigcSTATIC int
397153323Srodrigcxfs_bmap_count_tree(
398153323Srodrigc	xfs_mount_t     *mp,
399153323Srodrigc	xfs_trans_t     *tp,
400159451Srodrigc	xfs_ifork_t	*ifp,
401153323Srodrigc	xfs_fsblock_t   blockno,
402153323Srodrigc	int             levelin,
403153323Srodrigc	int		*count);
404153323Srodrigc
405153323SrodrigcSTATIC int
406153323Srodrigcxfs_bmap_count_leaves(
407159451Srodrigc	xfs_ifork_t		*ifp,
408159451Srodrigc	xfs_extnum_t		idx,
409153323Srodrigc	int			numrecs,
410153323Srodrigc	int			*count);
411153323Srodrigc
412159451SrodrigcSTATIC int
413159451Srodrigcxfs_bmap_disk_count_leaves(
414159451Srodrigc	xfs_ifork_t		*ifp,
415159451Srodrigc	xfs_mount_t		*mp,
416159451Srodrigc	xfs_extnum_t		idx,
417159451Srodrigc	xfs_bmbt_block_t	*block,
418159451Srodrigc	int			numrecs,
419159451Srodrigc	int			*count);
420159451Srodrigc
421153323Srodrigc/*
422153323Srodrigc * Bmap internal routines.
423153323Srodrigc */
424153323Srodrigc
425153323Srodrigc/*
426153323Srodrigc * Called from xfs_bmap_add_attrfork to handle btree format files.
427153323Srodrigc */
428153323SrodrigcSTATIC int					/* error */
429153323Srodrigcxfs_bmap_add_attrfork_btree(
430153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
431153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
432153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first block allocated */
433153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
434153323Srodrigc	int			*flags)		/* inode logging flags */
435153323Srodrigc{
436153323Srodrigc	xfs_btree_cur_t		*cur;		/* btree cursor */
437153323Srodrigc	int			error;		/* error return value */
438153323Srodrigc	xfs_mount_t		*mp;		/* file system mount struct */
439153323Srodrigc	int			stat;		/* newroot status */
440153323Srodrigc
441153323Srodrigc	mp = ip->i_mount;
442153323Srodrigc	if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))
443153323Srodrigc		*flags |= XFS_ILOG_DBROOT;
444153323Srodrigc	else {
445153323Srodrigc		cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
446153323Srodrigc			XFS_DATA_FORK);
447153323Srodrigc		cur->bc_private.b.flist = flist;
448153323Srodrigc		cur->bc_private.b.firstblock = *firstblock;
449153323Srodrigc		if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
450153323Srodrigc			goto error0;
451153323Srodrigc		ASSERT(stat == 1);	/* must be at least one entry */
452153323Srodrigc		if ((error = xfs_bmbt_newroot(cur, flags, &stat)))
453153323Srodrigc			goto error0;
454153323Srodrigc		if (stat == 0) {
455153323Srodrigc			xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
456153323Srodrigc			return XFS_ERROR(ENOSPC);
457153323Srodrigc		}
458153323Srodrigc		*firstblock = cur->bc_private.b.firstblock;
459153323Srodrigc		cur->bc_private.b.allocated = 0;
460153323Srodrigc		xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
461153323Srodrigc	}
462153323Srodrigc	return 0;
463153323Srodrigcerror0:
464153323Srodrigc	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
465153323Srodrigc	return error;
466153323Srodrigc}
467153323Srodrigc
468153323Srodrigc/*
469153323Srodrigc * Called from xfs_bmap_add_attrfork to handle extents format files.
470153323Srodrigc */
471153323SrodrigcSTATIC int					/* error */
472153323Srodrigcxfs_bmap_add_attrfork_extents(
473153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
474153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
475153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first block allocated */
476153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
477153323Srodrigc	int			*flags)		/* inode logging flags */
478153323Srodrigc{
479153323Srodrigc	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
480153323Srodrigc	int			error;		/* error return value */
481153323Srodrigc
482153323Srodrigc	if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip))
483153323Srodrigc		return 0;
484153323Srodrigc	cur = NULL;
485153323Srodrigc	error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0,
486153323Srodrigc		flags, XFS_DATA_FORK);
487153323Srodrigc	if (cur) {
488153323Srodrigc		cur->bc_private.b.allocated = 0;
489153323Srodrigc		xfs_btree_del_cursor(cur,
490153323Srodrigc			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
491153323Srodrigc	}
492153323Srodrigc	return error;
493153323Srodrigc}
494153323Srodrigc
495153323Srodrigc/*
496153323Srodrigc * Called from xfs_bmap_add_attrfork to handle local format files.
497153323Srodrigc */
498153323SrodrigcSTATIC int					/* error */
499153323Srodrigcxfs_bmap_add_attrfork_local(
500153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
501153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
502153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first block allocated */
503153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
504153323Srodrigc	int			*flags)		/* inode logging flags */
505153323Srodrigc{
506153323Srodrigc	xfs_da_args_t		dargs;		/* args for dir/attr code */
507153323Srodrigc	int			error;		/* error return value */
508153323Srodrigc	xfs_mount_t		*mp;		/* mount structure pointer */
509153323Srodrigc
510153323Srodrigc	if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
511153323Srodrigc		return 0;
512153323Srodrigc	if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
513153323Srodrigc		mp = ip->i_mount;
514153323Srodrigc		memset(&dargs, 0, sizeof(dargs));
515153323Srodrigc		dargs.dp = ip;
516153323Srodrigc		dargs.firstblock = firstblock;
517153323Srodrigc		dargs.flist = flist;
518153323Srodrigc		dargs.total = mp->m_dirblkfsbs;
519153323Srodrigc		dargs.whichfork = XFS_DATA_FORK;
520153323Srodrigc		dargs.trans = tp;
521153323Srodrigc		error = XFS_DIR_SHORTFORM_TO_SINGLE(mp, &dargs);
522153323Srodrigc	} else
523153323Srodrigc		error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
524153323Srodrigc			XFS_DATA_FORK);
525153323Srodrigc	return error;
526153323Srodrigc}
527153323Srodrigc
528153323Srodrigc/*
529159451Srodrigc * Called by xfs_bmapi to update file extent records and the btree
530153323Srodrigc * after allocating space (or doing a delayed allocation).
531153323Srodrigc */
532153323SrodrigcSTATIC int				/* error */
533153323Srodrigcxfs_bmap_add_extent(
534153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
535153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
536153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
537159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
538153323Srodrigc	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
539153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
540153323Srodrigc	int			*logflagsp, /* inode logging flags */
541159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
542153323Srodrigc	int			whichfork, /* data or attr fork */
543153323Srodrigc	int			rsvd)	/* OK to use reserved data blocks */
544153323Srodrigc{
545153323Srodrigc	xfs_btree_cur_t		*cur;	/* btree cursor or null */
546153323Srodrigc	xfs_filblks_t		da_new; /* new count del alloc blocks used */
547153323Srodrigc	xfs_filblks_t		da_old; /* old count del alloc blocks used */
548153323Srodrigc	int			error;	/* error return value */
549153323Srodrigc#ifdef XFS_BMAP_TRACE
550153323Srodrigc	static char		fname[] = "xfs_bmap_add_extent";
551153323Srodrigc#endif
552153323Srodrigc	xfs_ifork_t		*ifp;	/* inode fork ptr */
553153323Srodrigc	int			logflags; /* returned value */
554153323Srodrigc	xfs_extnum_t		nextents; /* number of extents in file now */
555153323Srodrigc
556153323Srodrigc	XFS_STATS_INC(xs_add_exlist);
557153323Srodrigc	cur = *curp;
558153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
559153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
560153323Srodrigc	ASSERT(idx <= nextents);
561153323Srodrigc	da_old = da_new = 0;
562153323Srodrigc	error = 0;
563153323Srodrigc	/*
564153323Srodrigc	 * This is the first extent added to a new/empty file.
565153323Srodrigc	 * Special case this one, so other routines get to assume there are
566153323Srodrigc	 * already extents in the list.
567153323Srodrigc	 */
568153323Srodrigc	if (nextents == 0) {
569153323Srodrigc		xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new,
570153323Srodrigc			NULL, whichfork);
571159451Srodrigc		xfs_iext_insert(ifp, 0, 1, new);
572153323Srodrigc		ASSERT(cur == NULL);
573153323Srodrigc		ifp->if_lastex = 0;
574153323Srodrigc		if (!ISNULLSTARTBLOCK(new->br_startblock)) {
575153323Srodrigc			XFS_IFORK_NEXT_SET(ip, whichfork, 1);
576153323Srodrigc			logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
577153323Srodrigc		} else
578153323Srodrigc			logflags = 0;
579159451Srodrigc		/* DELTA: single new extent */
580159451Srodrigc		if (delta) {
581159451Srodrigc			if (delta->xed_startoff > new->br_startoff)
582159451Srodrigc				delta->xed_startoff = new->br_startoff;
583159451Srodrigc			if (delta->xed_blockcount <
584159451Srodrigc					new->br_startoff + new->br_blockcount)
585159451Srodrigc				delta->xed_blockcount = new->br_startoff +
586159451Srodrigc						new->br_blockcount;
587159451Srodrigc		}
588153323Srodrigc	}
589153323Srodrigc	/*
590153323Srodrigc	 * Any kind of new delayed allocation goes here.
591153323Srodrigc	 */
592153323Srodrigc	else if (ISNULLSTARTBLOCK(new->br_startblock)) {
593153323Srodrigc		if (cur)
594153323Srodrigc			ASSERT((cur->bc_private.b.flags &
595153323Srodrigc				XFS_BTCUR_BPRV_WASDEL) == 0);
596153323Srodrigc		if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new,
597159451Srodrigc				&logflags, delta, rsvd)))
598153323Srodrigc			goto done;
599153323Srodrigc	}
600153323Srodrigc	/*
601153323Srodrigc	 * Real allocation off the end of the file.
602153323Srodrigc	 */
603153323Srodrigc	else if (idx == nextents) {
604153323Srodrigc		if (cur)
605153323Srodrigc			ASSERT((cur->bc_private.b.flags &
606153323Srodrigc				XFS_BTCUR_BPRV_WASDEL) == 0);
607153323Srodrigc		if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
608159451Srodrigc				&logflags, delta, whichfork)))
609153323Srodrigc			goto done;
610153323Srodrigc	} else {
611153323Srodrigc		xfs_bmbt_irec_t	prev;	/* old extent at offset idx */
612153323Srodrigc
613153323Srodrigc		/*
614153323Srodrigc		 * Get the record referred to by idx.
615153323Srodrigc		 */
616159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &prev);
617153323Srodrigc		/*
618153323Srodrigc		 * If it's a real allocation record, and the new allocation ends
619153323Srodrigc		 * after the start of the referred to record, then we're filling
620153323Srodrigc		 * in a delayed or unwritten allocation with a real one, or
621153323Srodrigc		 * converting real back to unwritten.
622153323Srodrigc		 */
623153323Srodrigc		if (!ISNULLSTARTBLOCK(new->br_startblock) &&
624153323Srodrigc		    new->br_startoff + new->br_blockcount > prev.br_startoff) {
625153323Srodrigc			if (prev.br_state != XFS_EXT_UNWRITTEN &&
626153323Srodrigc			    ISNULLSTARTBLOCK(prev.br_startblock)) {
627153323Srodrigc				da_old = STARTBLOCKVAL(prev.br_startblock);
628153323Srodrigc				if (cur)
629153323Srodrigc					ASSERT(cur->bc_private.b.flags &
630153323Srodrigc						XFS_BTCUR_BPRV_WASDEL);
631153323Srodrigc				if ((error = xfs_bmap_add_extent_delay_real(ip,
632153323Srodrigc					idx, &cur, new, &da_new, first, flist,
633159451Srodrigc					&logflags, delta, rsvd)))
634153323Srodrigc					goto done;
635153323Srodrigc			} else if (new->br_state == XFS_EXT_NORM) {
636153323Srodrigc				ASSERT(new->br_state == XFS_EXT_NORM);
637153323Srodrigc				if ((error = xfs_bmap_add_extent_unwritten_real(
638159451Srodrigc					ip, idx, &cur, new, &logflags, delta)))
639153323Srodrigc					goto done;
640153323Srodrigc			} else {
641153323Srodrigc				ASSERT(new->br_state == XFS_EXT_UNWRITTEN);
642153323Srodrigc				if ((error = xfs_bmap_add_extent_unwritten_real(
643159451Srodrigc					ip, idx, &cur, new, &logflags, delta)))
644153323Srodrigc					goto done;
645153323Srodrigc			}
646153323Srodrigc			ASSERT(*curp == cur || *curp == NULL);
647153323Srodrigc		}
648153323Srodrigc		/*
649153323Srodrigc		 * Otherwise we're filling in a hole with an allocation.
650153323Srodrigc		 */
651153323Srodrigc		else {
652153323Srodrigc			if (cur)
653153323Srodrigc				ASSERT((cur->bc_private.b.flags &
654153323Srodrigc					XFS_BTCUR_BPRV_WASDEL) == 0);
655153323Srodrigc			if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
656159451Srodrigc					new, &logflags, delta, whichfork)))
657153323Srodrigc				goto done;
658153323Srodrigc		}
659153323Srodrigc	}
660153323Srodrigc
661153323Srodrigc	ASSERT(*curp == cur || *curp == NULL);
662153323Srodrigc	/*
663153323Srodrigc	 * Convert to a btree if necessary.
664153323Srodrigc	 */
665153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
666153323Srodrigc	    XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
667153323Srodrigc		int	tmp_logflags;	/* partial log flag return val */
668153323Srodrigc
669153323Srodrigc		ASSERT(cur == NULL);
670153323Srodrigc		error = xfs_bmap_extents_to_btree(ip->i_transp, ip, first,
671153323Srodrigc			flist, &cur, da_old > 0, &tmp_logflags, whichfork);
672153323Srodrigc		logflags |= tmp_logflags;
673153323Srodrigc		if (error)
674153323Srodrigc			goto done;
675153323Srodrigc	}
676153323Srodrigc	/*
677153323Srodrigc	 * Adjust for changes in reserved delayed indirect blocks.
678153323Srodrigc	 * Nothing to do for disk quotas here.
679153323Srodrigc	 */
680153323Srodrigc	if (da_old || da_new) {
681153323Srodrigc		xfs_filblks_t	nblks;
682153323Srodrigc
683153323Srodrigc		nblks = da_new;
684153323Srodrigc		if (cur)
685153323Srodrigc			nblks += cur->bc_private.b.allocated;
686153323Srodrigc		ASSERT(nblks <= da_old);
687153323Srodrigc		if (nblks < da_old)
688153323Srodrigc			xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS,
689153323Srodrigc				(int)(da_old - nblks), rsvd);
690153323Srodrigc	}
691153323Srodrigc	/*
692153323Srodrigc	 * Clear out the allocated field, done with it now in any case.
693153323Srodrigc	 */
694153323Srodrigc	if (cur) {
695153323Srodrigc		cur->bc_private.b.allocated = 0;
696153323Srodrigc		*curp = cur;
697153323Srodrigc	}
698153323Srodrigcdone:
699159451Srodrigc#ifdef DEBUG
700153323Srodrigc	if (!error)
701153323Srodrigc		xfs_bmap_check_leaf_extents(*curp, ip, whichfork);
702153323Srodrigc#endif
703153323Srodrigc	*logflagsp = logflags;
704153323Srodrigc	return error;
705153323Srodrigc}
706153323Srodrigc
707153323Srodrigc/*
708153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a delayed
709153323Srodrigc * allocation to a real allocation.
710153323Srodrigc */
711153323SrodrigcSTATIC int				/* error */
712153323Srodrigcxfs_bmap_add_extent_delay_real(
713153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
714153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
715153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
716159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
717153323Srodrigc	xfs_filblks_t		*dnew,	/* new delayed-alloc indirect blocks */
718153323Srodrigc	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
719153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
720153323Srodrigc	int			*logflagsp, /* inode logging flags */
721159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
722153323Srodrigc	int			rsvd)	/* OK to use reserved data block allocation */
723153323Srodrigc{
724153323Srodrigc	xfs_btree_cur_t		*cur;	/* btree cursor */
725153323Srodrigc	int			diff;	/* temp value */
726153323Srodrigc	xfs_bmbt_rec_t		*ep;	/* extent entry for idx */
727153323Srodrigc	int			error;	/* error return value */
728153323Srodrigc#ifdef XFS_BMAP_TRACE
729153323Srodrigc	static char		fname[] = "xfs_bmap_add_extent_delay_real";
730153323Srodrigc#endif
731153323Srodrigc	int			i;	/* temp state */
732159451Srodrigc	xfs_ifork_t		*ifp;	/* inode fork pointer */
733153323Srodrigc	xfs_fileoff_t		new_endoff;	/* end offset of new entry */
734153323Srodrigc	xfs_bmbt_irec_t		r[3];	/* neighbor extent entries */
735153323Srodrigc					/* left is 0, right is 1, prev is 2 */
736153323Srodrigc	int			rval=0;	/* return value (logging flags) */
737153323Srodrigc	int			state = 0;/* state bits, accessed thru macros */
738159451Srodrigc	xfs_filblks_t		temp=0;	/* value for dnew calculations */
739159451Srodrigc	xfs_filblks_t		temp2=0;/* value for dnew calculations */
740153323Srodrigc	int			tmp_rval;	/* partial logging flags */
741153323Srodrigc	enum {				/* bit number definitions for state */
742153323Srodrigc		LEFT_CONTIG,	RIGHT_CONTIG,
743153323Srodrigc		LEFT_FILLING,	RIGHT_FILLING,
744153323Srodrigc		LEFT_DELAY,	RIGHT_DELAY,
745153323Srodrigc		LEFT_VALID,	RIGHT_VALID
746153323Srodrigc	};
747153323Srodrigc
748153323Srodrigc#define	LEFT		r[0]
749153323Srodrigc#define	RIGHT		r[1]
750153323Srodrigc#define	PREV		r[2]
751153323Srodrigc#define	MASK(b)		(1 << (b))
752153323Srodrigc#define	MASK2(a,b)	(MASK(a) | MASK(b))
753153323Srodrigc#define	MASK3(a,b,c)	(MASK2(a,b) | MASK(c))
754153323Srodrigc#define	MASK4(a,b,c,d)	(MASK3(a,b,c) | MASK(d))
755153323Srodrigc#define	STATE_SET(b,v)	((v) ? (state |= MASK(b)) : (state &= ~MASK(b)))
756153323Srodrigc#define	STATE_TEST(b)	(state & MASK(b))
757153323Srodrigc#define	STATE_SET_TEST(b,v)	((v) ? ((state |= MASK(b)), 1) : \
758153323Srodrigc				       ((state &= ~MASK(b)), 0))
759153323Srodrigc#define	SWITCH_STATE		\
760153323Srodrigc	(state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG))
761153323Srodrigc
762153323Srodrigc	/*
763153323Srodrigc	 * Set up a bunch of variables to make the tests simpler.
764153323Srodrigc	 */
765153323Srodrigc	cur = *curp;
766159451Srodrigc	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
767159451Srodrigc	ep = xfs_iext_get_ext(ifp, idx);
768153323Srodrigc	xfs_bmbt_get_all(ep, &PREV);
769153323Srodrigc	new_endoff = new->br_startoff + new->br_blockcount;
770153323Srodrigc	ASSERT(PREV.br_startoff <= new->br_startoff);
771153323Srodrigc	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
772153323Srodrigc	/*
773153323Srodrigc	 * Set flags determining what part of the previous delayed allocation
774153323Srodrigc	 * extent is being replaced by a real allocation.
775153323Srodrigc	 */
776153323Srodrigc	STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff);
777153323Srodrigc	STATE_SET(RIGHT_FILLING,
778153323Srodrigc		PREV.br_startoff + PREV.br_blockcount == new_endoff);
779153323Srodrigc	/*
780153323Srodrigc	 * Check and set flags if this segment has a left neighbor.
781153323Srodrigc	 * Don't set contiguous if the combined extent would be too large.
782153323Srodrigc	 */
783153323Srodrigc	if (STATE_SET_TEST(LEFT_VALID, idx > 0)) {
784159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &LEFT);
785153323Srodrigc		STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock));
786153323Srodrigc	}
787153323Srodrigc	STATE_SET(LEFT_CONTIG,
788153323Srodrigc		STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) &&
789153323Srodrigc		LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&
790153323Srodrigc		LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&
791153323Srodrigc		LEFT.br_state == new->br_state &&
792153323Srodrigc		LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN);
793153323Srodrigc	/*
794153323Srodrigc	 * Check and set flags if this segment has a right neighbor.
795153323Srodrigc	 * Don't set contiguous if the combined extent would be too large.
796153323Srodrigc	 * Also check for all-three-contiguous being too large.
797153323Srodrigc	 */
798153323Srodrigc	if (STATE_SET_TEST(RIGHT_VALID,
799153323Srodrigc			idx <
800153323Srodrigc			ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) {
801159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx + 1), &RIGHT);
802153323Srodrigc		STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock));
803153323Srodrigc	}
804153323Srodrigc	STATE_SET(RIGHT_CONTIG,
805153323Srodrigc		STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) &&
806153323Srodrigc		new_endoff == RIGHT.br_startoff &&
807153323Srodrigc		new->br_startblock + new->br_blockcount ==
808153323Srodrigc		    RIGHT.br_startblock &&
809153323Srodrigc		new->br_state == RIGHT.br_state &&
810153323Srodrigc		new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&
811153323Srodrigc		((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) !=
812153323Srodrigc		  MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) ||
813153323Srodrigc		 LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount
814153323Srodrigc		     <= MAXEXTLEN));
815153323Srodrigc	error = 0;
816153323Srodrigc	/*
817153323Srodrigc	 * Switch out based on the FILLING and CONTIG state bits.
818153323Srodrigc	 */
819153323Srodrigc	switch (SWITCH_STATE) {
820153323Srodrigc
821153323Srodrigc	case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
822153323Srodrigc		/*
823153323Srodrigc		 * Filling in all of a previously delayed allocation extent.
824153323Srodrigc		 * The left and right neighbors are both contiguous with new.
825153323Srodrigc		 */
826153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
827153323Srodrigc			XFS_DATA_FORK);
828159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
829153323Srodrigc			LEFT.br_blockcount + PREV.br_blockcount +
830153323Srodrigc			RIGHT.br_blockcount);
831153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
832153323Srodrigc			XFS_DATA_FORK);
833153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
834153323Srodrigc			XFS_DATA_FORK);
835159451Srodrigc		xfs_iext_remove(ifp, idx, 2);
836153323Srodrigc		ip->i_df.if_lastex = idx - 1;
837153323Srodrigc		ip->i_d.di_nextents--;
838153323Srodrigc		if (cur == NULL)
839153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
840153323Srodrigc		else {
841153323Srodrigc			rval = XFS_ILOG_CORE;
842153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
843153323Srodrigc					RIGHT.br_startblock,
844153323Srodrigc					RIGHT.br_blockcount, &i)))
845153323Srodrigc				goto done;
846153323Srodrigc			ASSERT(i == 1);
847153323Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
848153323Srodrigc				goto done;
849153323Srodrigc			ASSERT(i == 1);
850153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
851153323Srodrigc				goto done;
852153323Srodrigc			ASSERT(i == 1);
853153323Srodrigc			if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
854153323Srodrigc					LEFT.br_startblock,
855153323Srodrigc					LEFT.br_blockcount +
856153323Srodrigc					PREV.br_blockcount +
857153323Srodrigc					RIGHT.br_blockcount, LEFT.br_state)))
858153323Srodrigc				goto done;
859153323Srodrigc		}
860153323Srodrigc		*dnew = 0;
861159451Srodrigc		/* DELTA: Three in-core extents are replaced by one. */
862159451Srodrigc		temp = LEFT.br_startoff;
863159451Srodrigc		temp2 = LEFT.br_blockcount +
864159451Srodrigc			PREV.br_blockcount +
865159451Srodrigc			RIGHT.br_blockcount;
866153323Srodrigc		break;
867153323Srodrigc
868153323Srodrigc	case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG):
869153323Srodrigc		/*
870153323Srodrigc		 * Filling in all of a previously delayed allocation extent.
871153323Srodrigc		 * The left neighbor is contiguous, the right is not.
872153323Srodrigc		 */
873153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
874153323Srodrigc			XFS_DATA_FORK);
875159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
876153323Srodrigc			LEFT.br_blockcount + PREV.br_blockcount);
877153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
878153323Srodrigc			XFS_DATA_FORK);
879153323Srodrigc		ip->i_df.if_lastex = idx - 1;
880153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
881153323Srodrigc			XFS_DATA_FORK);
882159451Srodrigc		xfs_iext_remove(ifp, idx, 1);
883153323Srodrigc		if (cur == NULL)
884153323Srodrigc			rval = XFS_ILOG_DEXT;
885153323Srodrigc		else {
886153323Srodrigc			rval = 0;
887153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff,
888153323Srodrigc					LEFT.br_startblock, LEFT.br_blockcount,
889153323Srodrigc					&i)))
890153323Srodrigc				goto done;
891153323Srodrigc			ASSERT(i == 1);
892153323Srodrigc			if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
893153323Srodrigc					LEFT.br_startblock,
894153323Srodrigc					LEFT.br_blockcount +
895153323Srodrigc					PREV.br_blockcount, LEFT.br_state)))
896153323Srodrigc				goto done;
897153323Srodrigc		}
898153323Srodrigc		*dnew = 0;
899159451Srodrigc		/* DELTA: Two in-core extents are replaced by one. */
900159451Srodrigc		temp = LEFT.br_startoff;
901159451Srodrigc		temp2 = LEFT.br_blockcount +
902159451Srodrigc			PREV.br_blockcount;
903153323Srodrigc		break;
904153323Srodrigc
905153323Srodrigc	case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG):
906153323Srodrigc		/*
907153323Srodrigc		 * Filling in all of a previously delayed allocation extent.
908153323Srodrigc		 * The right neighbor is contiguous, the left is not.
909153323Srodrigc		 */
910153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
911153323Srodrigc			XFS_DATA_FORK);
912153323Srodrigc		xfs_bmbt_set_startblock(ep, new->br_startblock);
913153323Srodrigc		xfs_bmbt_set_blockcount(ep,
914153323Srodrigc			PREV.br_blockcount + RIGHT.br_blockcount);
915153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
916153323Srodrigc			XFS_DATA_FORK);
917153323Srodrigc		ip->i_df.if_lastex = idx;
918153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
919153323Srodrigc			XFS_DATA_FORK);
920159451Srodrigc		xfs_iext_remove(ifp, idx + 1, 1);
921153323Srodrigc		if (cur == NULL)
922153323Srodrigc			rval = XFS_ILOG_DEXT;
923153323Srodrigc		else {
924153323Srodrigc			rval = 0;
925153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
926153323Srodrigc					RIGHT.br_startblock,
927153323Srodrigc					RIGHT.br_blockcount, &i)))
928153323Srodrigc				goto done;
929153323Srodrigc			ASSERT(i == 1);
930153323Srodrigc			if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
931153323Srodrigc					new->br_startblock,
932153323Srodrigc					PREV.br_blockcount +
933153323Srodrigc					RIGHT.br_blockcount, PREV.br_state)))
934153323Srodrigc				goto done;
935153323Srodrigc		}
936153323Srodrigc		*dnew = 0;
937159451Srodrigc		/* DELTA: Two in-core extents are replaced by one. */
938159451Srodrigc		temp = PREV.br_startoff;
939159451Srodrigc		temp2 = PREV.br_blockcount +
940159451Srodrigc			RIGHT.br_blockcount;
941153323Srodrigc		break;
942153323Srodrigc
943153323Srodrigc	case MASK2(LEFT_FILLING, RIGHT_FILLING):
944153323Srodrigc		/*
945153323Srodrigc		 * Filling in all of a previously delayed allocation extent.
946153323Srodrigc		 * Neither the left nor right neighbors are contiguous with
947153323Srodrigc		 * the new one.
948153323Srodrigc		 */
949153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
950153323Srodrigc			XFS_DATA_FORK);
951153323Srodrigc		xfs_bmbt_set_startblock(ep, new->br_startblock);
952153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
953153323Srodrigc			XFS_DATA_FORK);
954153323Srodrigc		ip->i_df.if_lastex = idx;
955153323Srodrigc		ip->i_d.di_nextents++;
956153323Srodrigc		if (cur == NULL)
957153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
958153323Srodrigc		else {
959153323Srodrigc			rval = XFS_ILOG_CORE;
960153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
961153323Srodrigc					new->br_startblock, new->br_blockcount,
962153323Srodrigc					&i)))
963153323Srodrigc				goto done;
964153323Srodrigc			ASSERT(i == 0);
965153323Srodrigc			cur->bc_rec.b.br_state = XFS_EXT_NORM;
966153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
967153323Srodrigc				goto done;
968153323Srodrigc			ASSERT(i == 1);
969153323Srodrigc		}
970153323Srodrigc		*dnew = 0;
971159451Srodrigc		/* DELTA: The in-core extent described by new changed type. */
972159451Srodrigc		temp = new->br_startoff;
973159451Srodrigc		temp2 = new->br_blockcount;
974153323Srodrigc		break;
975153323Srodrigc
976153323Srodrigc	case MASK2(LEFT_FILLING, LEFT_CONTIG):
977153323Srodrigc		/*
978153323Srodrigc		 * Filling in the first part of a previous delayed allocation.
979153323Srodrigc		 * The left neighbor is contiguous.
980153323Srodrigc		 */
981153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
982153323Srodrigc			XFS_DATA_FORK);
983159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
984153323Srodrigc			LEFT.br_blockcount + new->br_blockcount);
985153323Srodrigc		xfs_bmbt_set_startoff(ep,
986153323Srodrigc			PREV.br_startoff + new->br_blockcount);
987153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
988153323Srodrigc			XFS_DATA_FORK);
989153323Srodrigc		temp = PREV.br_blockcount - new->br_blockcount;
990153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
991153323Srodrigc			XFS_DATA_FORK);
992153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
993153323Srodrigc		ip->i_df.if_lastex = idx - 1;
994153323Srodrigc		if (cur == NULL)
995153323Srodrigc			rval = XFS_ILOG_DEXT;
996153323Srodrigc		else {
997153323Srodrigc			rval = 0;
998153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff,
999153323Srodrigc					LEFT.br_startblock, LEFT.br_blockcount,
1000153323Srodrigc					&i)))
1001153323Srodrigc				goto done;
1002153323Srodrigc			ASSERT(i == 1);
1003153323Srodrigc			if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
1004153323Srodrigc					LEFT.br_startblock,
1005153323Srodrigc					LEFT.br_blockcount +
1006153323Srodrigc					new->br_blockcount,
1007153323Srodrigc					LEFT.br_state)))
1008153323Srodrigc				goto done;
1009153323Srodrigc		}
1010153323Srodrigc		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
1011153323Srodrigc			STARTBLOCKVAL(PREV.br_startblock));
1012153323Srodrigc		xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
1013153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
1014153323Srodrigc			XFS_DATA_FORK);
1015153323Srodrigc		*dnew = temp;
1016159451Srodrigc		/* DELTA: The boundary between two in-core extents moved. */
1017159451Srodrigc		temp = LEFT.br_startoff;
1018159451Srodrigc		temp2 = LEFT.br_blockcount +
1019159451Srodrigc			PREV.br_blockcount;
1020153323Srodrigc		break;
1021153323Srodrigc
1022153323Srodrigc	case MASK(LEFT_FILLING):
1023153323Srodrigc		/*
1024153323Srodrigc		 * Filling in the first part of a previous delayed allocation.
1025153323Srodrigc		 * The left neighbor is not contiguous.
1026153323Srodrigc		 */
1027153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
1028153323Srodrigc		xfs_bmbt_set_startoff(ep, new_endoff);
1029153323Srodrigc		temp = PREV.br_blockcount - new->br_blockcount;
1030153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
1031153323Srodrigc		xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
1032153323Srodrigc			XFS_DATA_FORK);
1033159451Srodrigc		xfs_iext_insert(ifp, idx, 1, new);
1034153323Srodrigc		ip->i_df.if_lastex = idx;
1035153323Srodrigc		ip->i_d.di_nextents++;
1036153323Srodrigc		if (cur == NULL)
1037153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1038153323Srodrigc		else {
1039153323Srodrigc			rval = XFS_ILOG_CORE;
1040153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
1041153323Srodrigc					new->br_startblock, new->br_blockcount,
1042153323Srodrigc					&i)))
1043153323Srodrigc				goto done;
1044153323Srodrigc			ASSERT(i == 0);
1045153323Srodrigc			cur->bc_rec.b.br_state = XFS_EXT_NORM;
1046153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1047153323Srodrigc				goto done;
1048153323Srodrigc			ASSERT(i == 1);
1049153323Srodrigc		}
1050153323Srodrigc		if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1051153323Srodrigc		    ip->i_d.di_nextents > ip->i_df.if_ext_max) {
1052153323Srodrigc			error = xfs_bmap_extents_to_btree(ip->i_transp, ip,
1053153323Srodrigc					first, flist, &cur, 1, &tmp_rval,
1054153323Srodrigc					XFS_DATA_FORK);
1055153323Srodrigc			rval |= tmp_rval;
1056153323Srodrigc			if (error)
1057153323Srodrigc				goto done;
1058153323Srodrigc		}
1059153323Srodrigc		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
1060153323Srodrigc			STARTBLOCKVAL(PREV.br_startblock) -
1061153323Srodrigc			(cur ? cur->bc_private.b.allocated : 0));
1062159451Srodrigc		ep = xfs_iext_get_ext(ifp, idx + 1);
1063153323Srodrigc		xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
1064153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1,
1065153323Srodrigc			XFS_DATA_FORK);
1066153323Srodrigc		*dnew = temp;
1067159451Srodrigc		/* DELTA: One in-core extent is split in two. */
1068159451Srodrigc		temp = PREV.br_startoff;
1069159451Srodrigc		temp2 = PREV.br_blockcount;
1070153323Srodrigc		break;
1071153323Srodrigc
1072153323Srodrigc	case MASK2(RIGHT_FILLING, RIGHT_CONTIG):
1073153323Srodrigc		/*
1074153323Srodrigc		 * Filling in the last part of a previous delayed allocation.
1075153323Srodrigc		 * The right neighbor is contiguous with the new allocation.
1076153323Srodrigc		 */
1077153323Srodrigc		temp = PREV.br_blockcount - new->br_blockcount;
1078153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
1079153323Srodrigc			XFS_DATA_FORK);
1080153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
1081153323Srodrigc			XFS_DATA_FORK);
1082153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
1083159451Srodrigc		xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
1084159451Srodrigc			new->br_startoff, new->br_startblock,
1085153323Srodrigc			new->br_blockcount + RIGHT.br_blockcount,
1086153323Srodrigc			RIGHT.br_state);
1087153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
1088153323Srodrigc			XFS_DATA_FORK);
1089153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1090153323Srodrigc		if (cur == NULL)
1091153323Srodrigc			rval = XFS_ILOG_DEXT;
1092153323Srodrigc		else {
1093153323Srodrigc			rval = 0;
1094153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
1095153323Srodrigc					RIGHT.br_startblock,
1096153323Srodrigc					RIGHT.br_blockcount, &i)))
1097153323Srodrigc				goto done;
1098153323Srodrigc			ASSERT(i == 1);
1099153323Srodrigc			if ((error = xfs_bmbt_update(cur, new->br_startoff,
1100153323Srodrigc					new->br_startblock,
1101153323Srodrigc					new->br_blockcount +
1102153323Srodrigc					RIGHT.br_blockcount,
1103153323Srodrigc					RIGHT.br_state)))
1104153323Srodrigc				goto done;
1105153323Srodrigc		}
1106153323Srodrigc		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
1107153323Srodrigc			STARTBLOCKVAL(PREV.br_startblock));
1108153323Srodrigc		xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
1109153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
1110153323Srodrigc			XFS_DATA_FORK);
1111153323Srodrigc		*dnew = temp;
1112159451Srodrigc		/* DELTA: The boundary between two in-core extents moved. */
1113159451Srodrigc		temp = PREV.br_startoff;
1114159451Srodrigc		temp2 = PREV.br_blockcount +
1115159451Srodrigc			RIGHT.br_blockcount;
1116153323Srodrigc		break;
1117153323Srodrigc
1118153323Srodrigc	case MASK(RIGHT_FILLING):
1119153323Srodrigc		/*
1120153323Srodrigc		 * Filling in the last part of a previous delayed allocation.
1121153323Srodrigc		 * The right neighbor is not contiguous.
1122153323Srodrigc		 */
1123153323Srodrigc		temp = PREV.br_blockcount - new->br_blockcount;
1124153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
1125153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
1126153323Srodrigc		xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
1127153323Srodrigc			new, NULL, XFS_DATA_FORK);
1128159451Srodrigc		xfs_iext_insert(ifp, idx + 1, 1, new);
1129153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1130153323Srodrigc		ip->i_d.di_nextents++;
1131153323Srodrigc		if (cur == NULL)
1132153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1133153323Srodrigc		else {
1134153323Srodrigc			rval = XFS_ILOG_CORE;
1135153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
1136153323Srodrigc					new->br_startblock, new->br_blockcount,
1137153323Srodrigc					&i)))
1138153323Srodrigc				goto done;
1139153323Srodrigc			ASSERT(i == 0);
1140153323Srodrigc			cur->bc_rec.b.br_state = XFS_EXT_NORM;
1141153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1142153323Srodrigc				goto done;
1143153323Srodrigc			ASSERT(i == 1);
1144153323Srodrigc		}
1145153323Srodrigc		if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1146153323Srodrigc		    ip->i_d.di_nextents > ip->i_df.if_ext_max) {
1147153323Srodrigc			error = xfs_bmap_extents_to_btree(ip->i_transp, ip,
1148153323Srodrigc				first, flist, &cur, 1, &tmp_rval,
1149153323Srodrigc				XFS_DATA_FORK);
1150153323Srodrigc			rval |= tmp_rval;
1151153323Srodrigc			if (error)
1152153323Srodrigc				goto done;
1153153323Srodrigc		}
1154153323Srodrigc		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
1155153323Srodrigc			STARTBLOCKVAL(PREV.br_startblock) -
1156153323Srodrigc			(cur ? cur->bc_private.b.allocated : 0));
1157159451Srodrigc		ep = xfs_iext_get_ext(ifp, idx);
1158153323Srodrigc		xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
1159153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
1160153323Srodrigc		*dnew = temp;
1161159451Srodrigc		/* DELTA: One in-core extent is split in two. */
1162159451Srodrigc		temp = PREV.br_startoff;
1163159451Srodrigc		temp2 = PREV.br_blockcount;
1164153323Srodrigc		break;
1165153323Srodrigc
1166153323Srodrigc	case 0:
1167153323Srodrigc		/*
1168153323Srodrigc		 * Filling in the middle part of a previous delayed allocation.
1169153323Srodrigc		 * Contiguity is impossible here.
1170153323Srodrigc		 * This case is avoided almost all the time.
1171153323Srodrigc		 */
1172153323Srodrigc		temp = new->br_startoff - PREV.br_startoff;
1173153323Srodrigc		xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
1174153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
1175153323Srodrigc		r[0] = *new;
1176153323Srodrigc		r[1].br_startoff = new_endoff;
1177153323Srodrigc		temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
1178153323Srodrigc		r[1].br_blockcount = temp2;
1179153323Srodrigc		xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
1180153323Srodrigc			XFS_DATA_FORK);
1181159451Srodrigc		xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
1182153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1183153323Srodrigc		ip->i_d.di_nextents++;
1184153323Srodrigc		if (cur == NULL)
1185153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1186153323Srodrigc		else {
1187153323Srodrigc			rval = XFS_ILOG_CORE;
1188153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
1189153323Srodrigc					new->br_startblock, new->br_blockcount,
1190153323Srodrigc					&i)))
1191153323Srodrigc				goto done;
1192153323Srodrigc			ASSERT(i == 0);
1193153323Srodrigc			cur->bc_rec.b.br_state = XFS_EXT_NORM;
1194153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1195153323Srodrigc				goto done;
1196153323Srodrigc			ASSERT(i == 1);
1197153323Srodrigc		}
1198153323Srodrigc		if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1199153323Srodrigc		    ip->i_d.di_nextents > ip->i_df.if_ext_max) {
1200153323Srodrigc			error = xfs_bmap_extents_to_btree(ip->i_transp, ip,
1201153323Srodrigc					first, flist, &cur, 1, &tmp_rval,
1202153323Srodrigc					XFS_DATA_FORK);
1203153323Srodrigc			rval |= tmp_rval;
1204153323Srodrigc			if (error)
1205153323Srodrigc				goto done;
1206153323Srodrigc		}
1207153323Srodrigc		temp = xfs_bmap_worst_indlen(ip, temp);
1208153323Srodrigc		temp2 = xfs_bmap_worst_indlen(ip, temp2);
1209153323Srodrigc		diff = (int)(temp + temp2 - STARTBLOCKVAL(PREV.br_startblock) -
1210153323Srodrigc			(cur ? cur->bc_private.b.allocated : 0));
1211153323Srodrigc		if (diff > 0 &&
1212153323Srodrigc		    xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -diff, rsvd)) {
1213153323Srodrigc			/*
1214153323Srodrigc			 * Ick gross gag me with a spoon.
1215153323Srodrigc			 */
1216153323Srodrigc			ASSERT(0);	/* want to see if this ever happens! */
1217153323Srodrigc			while (diff > 0) {
1218153323Srodrigc				if (temp) {
1219153323Srodrigc					temp--;
1220153323Srodrigc					diff--;
1221153323Srodrigc					if (!diff ||
1222153323Srodrigc					    !xfs_mod_incore_sb(ip->i_mount,
1223153323Srodrigc						    XFS_SBS_FDBLOCKS, -diff, rsvd))
1224153323Srodrigc						break;
1225153323Srodrigc				}
1226153323Srodrigc				if (temp2) {
1227153323Srodrigc					temp2--;
1228153323Srodrigc					diff--;
1229153323Srodrigc					if (!diff ||
1230153323Srodrigc					    !xfs_mod_incore_sb(ip->i_mount,
1231153323Srodrigc						    XFS_SBS_FDBLOCKS, -diff, rsvd))
1232153323Srodrigc						break;
1233153323Srodrigc				}
1234153323Srodrigc			}
1235153323Srodrigc		}
1236159451Srodrigc		ep = xfs_iext_get_ext(ifp, idx);
1237153323Srodrigc		xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
1238153323Srodrigc		xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
1239153323Srodrigc		xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2,
1240153323Srodrigc			XFS_DATA_FORK);
1241159451Srodrigc		xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx + 2),
1242159451Srodrigc			NULLSTARTBLOCK((int)temp2));
1243153323Srodrigc		xfs_bmap_trace_post_update(fname, "0", ip, idx + 2,
1244153323Srodrigc			XFS_DATA_FORK);
1245153323Srodrigc		*dnew = temp + temp2;
1246159451Srodrigc		/* DELTA: One in-core extent is split in three. */
1247159451Srodrigc		temp = PREV.br_startoff;
1248159451Srodrigc		temp2 = PREV.br_blockcount;
1249153323Srodrigc		break;
1250153323Srodrigc
1251153323Srodrigc	case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
1252153323Srodrigc	case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
1253153323Srodrigc	case MASK2(LEFT_FILLING, RIGHT_CONTIG):
1254153323Srodrigc	case MASK2(RIGHT_FILLING, LEFT_CONTIG):
1255153323Srodrigc	case MASK2(LEFT_CONTIG, RIGHT_CONTIG):
1256153323Srodrigc	case MASK(LEFT_CONTIG):
1257153323Srodrigc	case MASK(RIGHT_CONTIG):
1258153323Srodrigc		/*
1259153323Srodrigc		 * These cases are all impossible.
1260153323Srodrigc		 */
1261153323Srodrigc		ASSERT(0);
1262153323Srodrigc	}
1263153323Srodrigc	*curp = cur;
1264159451Srodrigc	if (delta) {
1265159451Srodrigc		temp2 += temp;
1266159451Srodrigc		if (delta->xed_startoff > temp)
1267159451Srodrigc			delta->xed_startoff = temp;
1268159451Srodrigc		if (delta->xed_blockcount < temp2)
1269159451Srodrigc			delta->xed_blockcount = temp2;
1270159451Srodrigc	}
1271153323Srodrigcdone:
1272153323Srodrigc	*logflagsp = rval;
1273153323Srodrigc	return error;
1274153323Srodrigc#undef	LEFT
1275153323Srodrigc#undef	RIGHT
1276153323Srodrigc#undef	PREV
1277153323Srodrigc#undef	MASK
1278153323Srodrigc#undef	MASK2
1279153323Srodrigc#undef	MASK3
1280153323Srodrigc#undef	MASK4
1281153323Srodrigc#undef	STATE_SET
1282153323Srodrigc#undef	STATE_TEST
1283153323Srodrigc#undef	STATE_SET_TEST
1284153323Srodrigc#undef	SWITCH_STATE
1285153323Srodrigc}
1286153323Srodrigc
1287153323Srodrigc/*
1288153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting an unwritten
1289153323Srodrigc * allocation to a real allocation or vice versa.
1290153323Srodrigc */
1291153323SrodrigcSTATIC int				/* error */
1292153323Srodrigcxfs_bmap_add_extent_unwritten_real(
1293153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
1294153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
1295153323Srodrigc	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
1296159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
1297159451Srodrigc	int			*logflagsp, /* inode logging flags */
1298159451Srodrigc	xfs_extdelta_t		*delta) /* Change made to incore extents */
1299153323Srodrigc{
1300153323Srodrigc	xfs_btree_cur_t		*cur;	/* btree cursor */
1301153323Srodrigc	xfs_bmbt_rec_t		*ep;	/* extent entry for idx */
1302153323Srodrigc	int			error;	/* error return value */
1303153323Srodrigc#ifdef XFS_BMAP_TRACE
1304153323Srodrigc	static char		fname[] = "xfs_bmap_add_extent_unwritten_real";
1305153323Srodrigc#endif
1306153323Srodrigc	int			i;	/* temp state */
1307159451Srodrigc	xfs_ifork_t		*ifp;	/* inode fork pointer */
1308153323Srodrigc	xfs_fileoff_t		new_endoff;	/* end offset of new entry */
1309153323Srodrigc	xfs_exntst_t		newext;	/* new extent state */
1310153323Srodrigc	xfs_exntst_t		oldext;	/* old extent state */
1311153323Srodrigc	xfs_bmbt_irec_t		r[3];	/* neighbor extent entries */
1312153323Srodrigc					/* left is 0, right is 1, prev is 2 */
1313153323Srodrigc	int			rval=0;	/* return value (logging flags) */
1314153323Srodrigc	int			state = 0;/* state bits, accessed thru macros */
1315159451Srodrigc	xfs_filblks_t		temp=0;
1316159451Srodrigc	xfs_filblks_t		temp2=0;
1317153323Srodrigc	enum {				/* bit number definitions for state */
1318153323Srodrigc		LEFT_CONTIG,	RIGHT_CONTIG,
1319153323Srodrigc		LEFT_FILLING,	RIGHT_FILLING,
1320153323Srodrigc		LEFT_DELAY,	RIGHT_DELAY,
1321153323Srodrigc		LEFT_VALID,	RIGHT_VALID
1322153323Srodrigc	};
1323153323Srodrigc
1324153323Srodrigc#define	LEFT		r[0]
1325153323Srodrigc#define	RIGHT		r[1]
1326153323Srodrigc#define	PREV		r[2]
1327153323Srodrigc#define	MASK(b)		(1 << (b))
1328153323Srodrigc#define	MASK2(a,b)	(MASK(a) | MASK(b))
1329153323Srodrigc#define	MASK3(a,b,c)	(MASK2(a,b) | MASK(c))
1330153323Srodrigc#define	MASK4(a,b,c,d)	(MASK3(a,b,c) | MASK(d))
1331153323Srodrigc#define	STATE_SET(b,v)	((v) ? (state |= MASK(b)) : (state &= ~MASK(b)))
1332153323Srodrigc#define	STATE_TEST(b)	(state & MASK(b))
1333153323Srodrigc#define	STATE_SET_TEST(b,v)	((v) ? ((state |= MASK(b)), 1) : \
1334153323Srodrigc				       ((state &= ~MASK(b)), 0))
1335153323Srodrigc#define	SWITCH_STATE		\
1336153323Srodrigc	(state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG))
1337153323Srodrigc
1338153323Srodrigc	/*
1339153323Srodrigc	 * Set up a bunch of variables to make the tests simpler.
1340153323Srodrigc	 */
1341153323Srodrigc	error = 0;
1342153323Srodrigc	cur = *curp;
1343159451Srodrigc	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
1344159451Srodrigc	ep = xfs_iext_get_ext(ifp, idx);
1345153323Srodrigc	xfs_bmbt_get_all(ep, &PREV);
1346153323Srodrigc	newext = new->br_state;
1347153323Srodrigc	oldext = (newext == XFS_EXT_UNWRITTEN) ?
1348153323Srodrigc		XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
1349153323Srodrigc	ASSERT(PREV.br_state == oldext);
1350153323Srodrigc	new_endoff = new->br_startoff + new->br_blockcount;
1351153323Srodrigc	ASSERT(PREV.br_startoff <= new->br_startoff);
1352153323Srodrigc	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
1353153323Srodrigc	/*
1354153323Srodrigc	 * Set flags determining what part of the previous oldext allocation
1355153323Srodrigc	 * extent is being replaced by a newext allocation.
1356153323Srodrigc	 */
1357153323Srodrigc	STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff);
1358153323Srodrigc	STATE_SET(RIGHT_FILLING,
1359153323Srodrigc		PREV.br_startoff + PREV.br_blockcount == new_endoff);
1360153323Srodrigc	/*
1361153323Srodrigc	 * Check and set flags if this segment has a left neighbor.
1362153323Srodrigc	 * Don't set contiguous if the combined extent would be too large.
1363153323Srodrigc	 */
1364153323Srodrigc	if (STATE_SET_TEST(LEFT_VALID, idx > 0)) {
1365159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &LEFT);
1366153323Srodrigc		STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock));
1367153323Srodrigc	}
1368153323Srodrigc	STATE_SET(LEFT_CONTIG,
1369153323Srodrigc		STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) &&
1370153323Srodrigc		LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&
1371153323Srodrigc		LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&
1372153323Srodrigc		LEFT.br_state == newext &&
1373153323Srodrigc		LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN);
1374153323Srodrigc	/*
1375153323Srodrigc	 * Check and set flags if this segment has a right neighbor.
1376153323Srodrigc	 * Don't set contiguous if the combined extent would be too large.
1377153323Srodrigc	 * Also check for all-three-contiguous being too large.
1378153323Srodrigc	 */
1379153323Srodrigc	if (STATE_SET_TEST(RIGHT_VALID,
1380153323Srodrigc			idx <
1381153323Srodrigc			ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) {
1382159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx + 1), &RIGHT);
1383153323Srodrigc		STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock));
1384153323Srodrigc	}
1385153323Srodrigc	STATE_SET(RIGHT_CONTIG,
1386153323Srodrigc		STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) &&
1387153323Srodrigc		new_endoff == RIGHT.br_startoff &&
1388153323Srodrigc		new->br_startblock + new->br_blockcount ==
1389153323Srodrigc		    RIGHT.br_startblock &&
1390153323Srodrigc		newext == RIGHT.br_state &&
1391153323Srodrigc		new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&
1392153323Srodrigc		((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) !=
1393153323Srodrigc		  MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) ||
1394153323Srodrigc		 LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount
1395153323Srodrigc		     <= MAXEXTLEN));
1396153323Srodrigc	/*
1397153323Srodrigc	 * Switch out based on the FILLING and CONTIG state bits.
1398153323Srodrigc	 */
1399153323Srodrigc	switch (SWITCH_STATE) {
1400153323Srodrigc
1401153323Srodrigc	case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
1402153323Srodrigc		/*
1403153323Srodrigc		 * Setting all of a previous oldext extent to newext.
1404153323Srodrigc		 * The left and right neighbors are both contiguous with new.
1405153323Srodrigc		 */
1406153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
1407153323Srodrigc			XFS_DATA_FORK);
1408159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
1409153323Srodrigc			LEFT.br_blockcount + PREV.br_blockcount +
1410153323Srodrigc			RIGHT.br_blockcount);
1411153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
1412153323Srodrigc			XFS_DATA_FORK);
1413153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
1414153323Srodrigc			XFS_DATA_FORK);
1415159451Srodrigc		xfs_iext_remove(ifp, idx, 2);
1416153323Srodrigc		ip->i_df.if_lastex = idx - 1;
1417153323Srodrigc		ip->i_d.di_nextents -= 2;
1418153323Srodrigc		if (cur == NULL)
1419153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1420153323Srodrigc		else {
1421153323Srodrigc			rval = XFS_ILOG_CORE;
1422153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
1423153323Srodrigc					RIGHT.br_startblock,
1424153323Srodrigc					RIGHT.br_blockcount, &i)))
1425153323Srodrigc				goto done;
1426153323Srodrigc			ASSERT(i == 1);
1427153323Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
1428153323Srodrigc				goto done;
1429153323Srodrigc			ASSERT(i == 1);
1430153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
1431153323Srodrigc				goto done;
1432153323Srodrigc			ASSERT(i == 1);
1433153323Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
1434153323Srodrigc				goto done;
1435153323Srodrigc			ASSERT(i == 1);
1436153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
1437153323Srodrigc				goto done;
1438153323Srodrigc			ASSERT(i == 1);
1439153323Srodrigc			if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
1440153323Srodrigc				LEFT.br_startblock,
1441153323Srodrigc				LEFT.br_blockcount + PREV.br_blockcount +
1442153323Srodrigc				RIGHT.br_blockcount, LEFT.br_state)))
1443153323Srodrigc				goto done;
1444153323Srodrigc		}
1445159451Srodrigc		/* DELTA: Three in-core extents are replaced by one. */
1446159451Srodrigc		temp = LEFT.br_startoff;
1447159451Srodrigc		temp2 = LEFT.br_blockcount +
1448159451Srodrigc			PREV.br_blockcount +
1449159451Srodrigc			RIGHT.br_blockcount;
1450153323Srodrigc		break;
1451153323Srodrigc
1452153323Srodrigc	case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG):
1453153323Srodrigc		/*
1454153323Srodrigc		 * Setting all of a previous oldext extent to newext.
1455153323Srodrigc		 * The left neighbor is contiguous, the right is not.
1456153323Srodrigc		 */
1457153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
1458153323Srodrigc			XFS_DATA_FORK);
1459159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
1460153323Srodrigc			LEFT.br_blockcount + PREV.br_blockcount);
1461153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
1462153323Srodrigc			XFS_DATA_FORK);
1463153323Srodrigc		ip->i_df.if_lastex = idx - 1;
1464153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
1465153323Srodrigc			XFS_DATA_FORK);
1466159451Srodrigc		xfs_iext_remove(ifp, idx, 1);
1467153323Srodrigc		ip->i_d.di_nextents--;
1468153323Srodrigc		if (cur == NULL)
1469153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1470153323Srodrigc		else {
1471153323Srodrigc			rval = XFS_ILOG_CORE;
1472153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1473153323Srodrigc					PREV.br_startblock, PREV.br_blockcount,
1474153323Srodrigc					&i)))
1475153323Srodrigc				goto done;
1476153323Srodrigc			ASSERT(i == 1);
1477153323Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
1478153323Srodrigc				goto done;
1479153323Srodrigc			ASSERT(i == 1);
1480153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
1481153323Srodrigc				goto done;
1482153323Srodrigc			ASSERT(i == 1);
1483153323Srodrigc			if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
1484153323Srodrigc				LEFT.br_startblock,
1485153323Srodrigc				LEFT.br_blockcount + PREV.br_blockcount,
1486153323Srodrigc				LEFT.br_state)))
1487153323Srodrigc				goto done;
1488153323Srodrigc		}
1489159451Srodrigc		/* DELTA: Two in-core extents are replaced by one. */
1490159451Srodrigc		temp = LEFT.br_startoff;
1491159451Srodrigc		temp2 = LEFT.br_blockcount +
1492159451Srodrigc			PREV.br_blockcount;
1493153323Srodrigc		break;
1494153323Srodrigc
1495153323Srodrigc	case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG):
1496153323Srodrigc		/*
1497153323Srodrigc		 * Setting all of a previous oldext extent to newext.
1498153323Srodrigc		 * The right neighbor is contiguous, the left is not.
1499153323Srodrigc		 */
1500153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
1501153323Srodrigc			XFS_DATA_FORK);
1502153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1503153323Srodrigc			PREV.br_blockcount + RIGHT.br_blockcount);
1504153323Srodrigc		xfs_bmbt_set_state(ep, newext);
1505153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
1506153323Srodrigc			XFS_DATA_FORK);
1507153323Srodrigc		ip->i_df.if_lastex = idx;
1508153323Srodrigc		xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
1509153323Srodrigc			XFS_DATA_FORK);
1510159451Srodrigc		xfs_iext_remove(ifp, idx + 1, 1);
1511153323Srodrigc		ip->i_d.di_nextents--;
1512153323Srodrigc		if (cur == NULL)
1513153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1514153323Srodrigc		else {
1515153323Srodrigc			rval = XFS_ILOG_CORE;
1516153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
1517153323Srodrigc					RIGHT.br_startblock,
1518153323Srodrigc					RIGHT.br_blockcount, &i)))
1519153323Srodrigc				goto done;
1520153323Srodrigc			ASSERT(i == 1);
1521153323Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
1522153323Srodrigc				goto done;
1523153323Srodrigc			ASSERT(i == 1);
1524153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
1525153323Srodrigc				goto done;
1526153323Srodrigc			ASSERT(i == 1);
1527153323Srodrigc			if ((error = xfs_bmbt_update(cur, new->br_startoff,
1528153323Srodrigc				new->br_startblock,
1529153323Srodrigc				new->br_blockcount + RIGHT.br_blockcount,
1530153323Srodrigc				newext)))
1531153323Srodrigc				goto done;
1532153323Srodrigc		}
1533159451Srodrigc		/* DELTA: Two in-core extents are replaced by one. */
1534159451Srodrigc		temp = PREV.br_startoff;
1535159451Srodrigc		temp2 = PREV.br_blockcount +
1536159451Srodrigc			RIGHT.br_blockcount;
1537153323Srodrigc		break;
1538153323Srodrigc
1539153323Srodrigc	case MASK2(LEFT_FILLING, RIGHT_FILLING):
1540153323Srodrigc		/*
1541153323Srodrigc		 * Setting all of a previous oldext extent to newext.
1542153323Srodrigc		 * Neither the left nor right neighbors are contiguous with
1543153323Srodrigc		 * the new one.
1544153323Srodrigc		 */
1545153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
1546153323Srodrigc			XFS_DATA_FORK);
1547153323Srodrigc		xfs_bmbt_set_state(ep, newext);
1548153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
1549153323Srodrigc			XFS_DATA_FORK);
1550153323Srodrigc		ip->i_df.if_lastex = idx;
1551153323Srodrigc		if (cur == NULL)
1552153323Srodrigc			rval = XFS_ILOG_DEXT;
1553153323Srodrigc		else {
1554153323Srodrigc			rval = 0;
1555153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
1556153323Srodrigc					new->br_startblock, new->br_blockcount,
1557153323Srodrigc					&i)))
1558153323Srodrigc				goto done;
1559153323Srodrigc			ASSERT(i == 1);
1560153323Srodrigc			if ((error = xfs_bmbt_update(cur, new->br_startoff,
1561153323Srodrigc				new->br_startblock, new->br_blockcount,
1562153323Srodrigc				newext)))
1563153323Srodrigc				goto done;
1564153323Srodrigc		}
1565159451Srodrigc		/* DELTA: The in-core extent described by new changed type. */
1566159451Srodrigc		temp = new->br_startoff;
1567159451Srodrigc		temp2 = new->br_blockcount;
1568153323Srodrigc		break;
1569153323Srodrigc
1570153323Srodrigc	case MASK2(LEFT_FILLING, LEFT_CONTIG):
1571153323Srodrigc		/*
1572153323Srodrigc		 * Setting the first part of a previous oldext extent to newext.
1573153323Srodrigc		 * The left neighbor is contiguous.
1574153323Srodrigc		 */
1575153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
1576153323Srodrigc			XFS_DATA_FORK);
1577159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
1578153323Srodrigc			LEFT.br_blockcount + new->br_blockcount);
1579153323Srodrigc		xfs_bmbt_set_startoff(ep,
1580153323Srodrigc			PREV.br_startoff + new->br_blockcount);
1581153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
1582153323Srodrigc			XFS_DATA_FORK);
1583153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
1584153323Srodrigc			XFS_DATA_FORK);
1585153323Srodrigc		xfs_bmbt_set_startblock(ep,
1586153323Srodrigc			new->br_startblock + new->br_blockcount);
1587153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1588153323Srodrigc			PREV.br_blockcount - new->br_blockcount);
1589153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
1590153323Srodrigc			XFS_DATA_FORK);
1591153323Srodrigc		ip->i_df.if_lastex = idx - 1;
1592153323Srodrigc		if (cur == NULL)
1593153323Srodrigc			rval = XFS_ILOG_DEXT;
1594153323Srodrigc		else {
1595153323Srodrigc			rval = 0;
1596153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1597153323Srodrigc					PREV.br_startblock, PREV.br_blockcount,
1598153323Srodrigc					&i)))
1599153323Srodrigc				goto done;
1600153323Srodrigc			ASSERT(i == 1);
1601153323Srodrigc			if ((error = xfs_bmbt_update(cur,
1602153323Srodrigc				PREV.br_startoff + new->br_blockcount,
1603153323Srodrigc				PREV.br_startblock + new->br_blockcount,
1604153323Srodrigc				PREV.br_blockcount - new->br_blockcount,
1605153323Srodrigc				oldext)))
1606153323Srodrigc				goto done;
1607153323Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
1608153323Srodrigc				goto done;
1609153323Srodrigc			if (xfs_bmbt_update(cur, LEFT.br_startoff,
1610153323Srodrigc				LEFT.br_startblock,
1611153323Srodrigc				LEFT.br_blockcount + new->br_blockcount,
1612153323Srodrigc				LEFT.br_state))
1613153323Srodrigc				goto done;
1614153323Srodrigc		}
1615159451Srodrigc		/* DELTA: The boundary between two in-core extents moved. */
1616159451Srodrigc		temp = LEFT.br_startoff;
1617159451Srodrigc		temp2 = LEFT.br_blockcount +
1618159451Srodrigc			PREV.br_blockcount;
1619153323Srodrigc		break;
1620153323Srodrigc
1621153323Srodrigc	case MASK(LEFT_FILLING):
1622153323Srodrigc		/*
1623153323Srodrigc		 * Setting the first part of a previous oldext extent to newext.
1624153323Srodrigc		 * The left neighbor is not contiguous.
1625153323Srodrigc		 */
1626153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
1627153323Srodrigc		ASSERT(ep && xfs_bmbt_get_state(ep) == oldext);
1628153323Srodrigc		xfs_bmbt_set_startoff(ep, new_endoff);
1629153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1630153323Srodrigc			PREV.br_blockcount - new->br_blockcount);
1631153323Srodrigc		xfs_bmbt_set_startblock(ep,
1632153323Srodrigc			new->br_startblock + new->br_blockcount);
1633153323Srodrigc		xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK);
1634153323Srodrigc		xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
1635153323Srodrigc			XFS_DATA_FORK);
1636159451Srodrigc		xfs_iext_insert(ifp, idx, 1, new);
1637153323Srodrigc		ip->i_df.if_lastex = idx;
1638153323Srodrigc		ip->i_d.di_nextents++;
1639153323Srodrigc		if (cur == NULL)
1640153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1641153323Srodrigc		else {
1642153323Srodrigc			rval = XFS_ILOG_CORE;
1643153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1644153323Srodrigc					PREV.br_startblock, PREV.br_blockcount,
1645153323Srodrigc					&i)))
1646153323Srodrigc				goto done;
1647153323Srodrigc			ASSERT(i == 1);
1648153323Srodrigc			if ((error = xfs_bmbt_update(cur,
1649153323Srodrigc				PREV.br_startoff + new->br_blockcount,
1650153323Srodrigc				PREV.br_startblock + new->br_blockcount,
1651153323Srodrigc				PREV.br_blockcount - new->br_blockcount,
1652153323Srodrigc				oldext)))
1653153323Srodrigc				goto done;
1654153323Srodrigc			cur->bc_rec.b = *new;
1655153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1656153323Srodrigc				goto done;
1657153323Srodrigc			ASSERT(i == 1);
1658153323Srodrigc		}
1659159451Srodrigc		/* DELTA: One in-core extent is split in two. */
1660159451Srodrigc		temp = PREV.br_startoff;
1661159451Srodrigc		temp2 = PREV.br_blockcount;
1662153323Srodrigc		break;
1663153323Srodrigc
1664153323Srodrigc	case MASK2(RIGHT_FILLING, RIGHT_CONTIG):
1665153323Srodrigc		/*
1666153323Srodrigc		 * Setting the last part of a previous oldext extent to newext.
1667153323Srodrigc		 * The right neighbor is contiguous with the new allocation.
1668153323Srodrigc		 */
1669153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
1670153323Srodrigc			XFS_DATA_FORK);
1671153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
1672153323Srodrigc			XFS_DATA_FORK);
1673153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1674153323Srodrigc			PREV.br_blockcount - new->br_blockcount);
1675153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
1676153323Srodrigc			XFS_DATA_FORK);
1677159451Srodrigc		xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
1678159451Srodrigc			new->br_startoff, new->br_startblock,
1679153323Srodrigc			new->br_blockcount + RIGHT.br_blockcount, newext);
1680153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
1681153323Srodrigc			XFS_DATA_FORK);
1682153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1683153323Srodrigc		if (cur == NULL)
1684153323Srodrigc			rval = XFS_ILOG_DEXT;
1685153323Srodrigc		else {
1686153323Srodrigc			rval = 0;
1687153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1688153323Srodrigc					PREV.br_startblock,
1689153323Srodrigc					PREV.br_blockcount, &i)))
1690153323Srodrigc				goto done;
1691153323Srodrigc			ASSERT(i == 1);
1692153323Srodrigc			if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
1693153323Srodrigc				PREV.br_startblock,
1694153323Srodrigc				PREV.br_blockcount - new->br_blockcount,
1695153323Srodrigc				oldext)))
1696153323Srodrigc				goto done;
1697153323Srodrigc			if ((error = xfs_bmbt_increment(cur, 0, &i)))
1698153323Srodrigc				goto done;
1699153323Srodrigc			if ((error = xfs_bmbt_update(cur, new->br_startoff,
1700153323Srodrigc				new->br_startblock,
1701153323Srodrigc				new->br_blockcount + RIGHT.br_blockcount,
1702153323Srodrigc				newext)))
1703153323Srodrigc				goto done;
1704153323Srodrigc		}
1705159451Srodrigc		/* DELTA: The boundary between two in-core extents moved. */
1706159451Srodrigc		temp = PREV.br_startoff;
1707159451Srodrigc		temp2 = PREV.br_blockcount +
1708159451Srodrigc			RIGHT.br_blockcount;
1709153323Srodrigc		break;
1710153323Srodrigc
1711153323Srodrigc	case MASK(RIGHT_FILLING):
1712153323Srodrigc		/*
1713153323Srodrigc		 * Setting the last part of a previous oldext extent to newext.
1714153323Srodrigc		 * The right neighbor is not contiguous.
1715153323Srodrigc		 */
1716153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
1717153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1718153323Srodrigc			PREV.br_blockcount - new->br_blockcount);
1719153323Srodrigc		xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
1720153323Srodrigc		xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
1721153323Srodrigc			new, NULL, XFS_DATA_FORK);
1722159451Srodrigc		xfs_iext_insert(ifp, idx + 1, 1, new);
1723153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1724153323Srodrigc		ip->i_d.di_nextents++;
1725153323Srodrigc		if (cur == NULL)
1726153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1727153323Srodrigc		else {
1728153323Srodrigc			rval = XFS_ILOG_CORE;
1729153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1730153323Srodrigc					PREV.br_startblock, PREV.br_blockcount,
1731153323Srodrigc					&i)))
1732153323Srodrigc				goto done;
1733153323Srodrigc			ASSERT(i == 1);
1734153323Srodrigc			if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
1735153323Srodrigc				PREV.br_startblock,
1736153323Srodrigc				PREV.br_blockcount - new->br_blockcount,
1737153323Srodrigc				oldext)))
1738153323Srodrigc				goto done;
1739153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
1740153323Srodrigc					new->br_startblock, new->br_blockcount,
1741153323Srodrigc					&i)))
1742153323Srodrigc				goto done;
1743153323Srodrigc			ASSERT(i == 0);
1744153323Srodrigc			cur->bc_rec.b.br_state = XFS_EXT_NORM;
1745153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1746153323Srodrigc				goto done;
1747153323Srodrigc			ASSERT(i == 1);
1748153323Srodrigc		}
1749159451Srodrigc		/* DELTA: One in-core extent is split in two. */
1750159451Srodrigc		temp = PREV.br_startoff;
1751159451Srodrigc		temp2 = PREV.br_blockcount;
1752153323Srodrigc		break;
1753153323Srodrigc
1754153323Srodrigc	case 0:
1755153323Srodrigc		/*
1756153323Srodrigc		 * Setting the middle part of a previous oldext extent to
1757153323Srodrigc		 * newext.  Contiguity is impossible here.
1758153323Srodrigc		 * One extent becomes three extents.
1759153323Srodrigc		 */
1760153323Srodrigc		xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
1761153323Srodrigc		xfs_bmbt_set_blockcount(ep,
1762153323Srodrigc			new->br_startoff - PREV.br_startoff);
1763153323Srodrigc		xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
1764153323Srodrigc		r[0] = *new;
1765153323Srodrigc		r[1].br_startoff = new_endoff;
1766153323Srodrigc		r[1].br_blockcount =
1767153323Srodrigc			PREV.br_startoff + PREV.br_blockcount - new_endoff;
1768153323Srodrigc		r[1].br_startblock = new->br_startblock + new->br_blockcount;
1769153323Srodrigc		r[1].br_state = oldext;
1770153323Srodrigc		xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
1771153323Srodrigc			XFS_DATA_FORK);
1772159451Srodrigc		xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
1773153323Srodrigc		ip->i_df.if_lastex = idx + 1;
1774153323Srodrigc		ip->i_d.di_nextents += 2;
1775153323Srodrigc		if (cur == NULL)
1776153323Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
1777153323Srodrigc		else {
1778153323Srodrigc			rval = XFS_ILOG_CORE;
1779153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff,
1780153323Srodrigc					PREV.br_startblock, PREV.br_blockcount,
1781153323Srodrigc					&i)))
1782153323Srodrigc				goto done;
1783153323Srodrigc			ASSERT(i == 1);
1784153323Srodrigc			/* new right extent - oldext */
1785153323Srodrigc			if ((error = xfs_bmbt_update(cur, r[1].br_startoff,
1786153323Srodrigc				r[1].br_startblock, r[1].br_blockcount,
1787153323Srodrigc				r[1].br_state)))
1788153323Srodrigc				goto done;
1789153323Srodrigc			/* new left extent - oldext */
1790153323Srodrigc			PREV.br_blockcount =
1791153323Srodrigc				new->br_startoff - PREV.br_startoff;
1792153323Srodrigc			cur->bc_rec.b = PREV;
1793153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1794153323Srodrigc				goto done;
1795153323Srodrigc			ASSERT(i == 1);
1796153323Srodrigc			if ((error = xfs_bmbt_increment(cur, 0, &i)))
1797153323Srodrigc				goto done;
1798153323Srodrigc			ASSERT(i == 1);
1799153323Srodrigc			/* new middle extent - newext */
1800153323Srodrigc			cur->bc_rec.b = *new;
1801153323Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
1802153323Srodrigc				goto done;
1803153323Srodrigc			ASSERT(i == 1);
1804153323Srodrigc		}
1805159451Srodrigc		/* DELTA: One in-core extent is split in three. */
1806159451Srodrigc		temp = PREV.br_startoff;
1807159451Srodrigc		temp2 = PREV.br_blockcount;
1808153323Srodrigc		break;
1809153323Srodrigc
1810153323Srodrigc	case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
1811153323Srodrigc	case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
1812153323Srodrigc	case MASK2(LEFT_FILLING, RIGHT_CONTIG):
1813153323Srodrigc	case MASK2(RIGHT_FILLING, LEFT_CONTIG):
1814153323Srodrigc	case MASK2(LEFT_CONTIG, RIGHT_CONTIG):
1815153323Srodrigc	case MASK(LEFT_CONTIG):
1816153323Srodrigc	case MASK(RIGHT_CONTIG):
1817153323Srodrigc		/*
1818153323Srodrigc		 * These cases are all impossible.
1819153323Srodrigc		 */
1820153323Srodrigc		ASSERT(0);
1821153323Srodrigc	}
1822153323Srodrigc	*curp = cur;
1823159451Srodrigc	if (delta) {
1824159451Srodrigc		temp2 += temp;
1825159451Srodrigc		if (delta->xed_startoff > temp)
1826159451Srodrigc			delta->xed_startoff = temp;
1827159451Srodrigc		if (delta->xed_blockcount < temp2)
1828159451Srodrigc			delta->xed_blockcount = temp2;
1829159451Srodrigc	}
1830153323Srodrigcdone:
1831153323Srodrigc	*logflagsp = rval;
1832153323Srodrigc	return error;
1833153323Srodrigc#undef	LEFT
1834153323Srodrigc#undef	RIGHT
1835153323Srodrigc#undef	PREV
1836153323Srodrigc#undef	MASK
1837153323Srodrigc#undef	MASK2
1838153323Srodrigc#undef	MASK3
1839153323Srodrigc#undef	MASK4
1840153323Srodrigc#undef	STATE_SET
1841153323Srodrigc#undef	STATE_TEST
1842153323Srodrigc#undef	STATE_SET_TEST
1843153323Srodrigc#undef	SWITCH_STATE
1844153323Srodrigc}
1845153323Srodrigc
1846153323Srodrigc/*
1847153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a hole
1848153323Srodrigc * to a delayed allocation.
1849153323Srodrigc */
1850153323Srodrigc/*ARGSUSED*/
1851153323SrodrigcSTATIC int				/* error */
1852153323Srodrigcxfs_bmap_add_extent_hole_delay(
1853153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
1854153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
1855153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
1856159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
1857153323Srodrigc	int			*logflagsp, /* inode logging flags */
1858159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
1859153323Srodrigc	int			rsvd)		/* OK to allocate reserved blocks */
1860153323Srodrigc{
1861159451Srodrigc	xfs_bmbt_rec_t		*ep;	/* extent record for idx */
1862153323Srodrigc#ifdef XFS_BMAP_TRACE
1863153323Srodrigc	static char		fname[] = "xfs_bmap_add_extent_hole_delay";
1864153323Srodrigc#endif
1865159451Srodrigc	xfs_ifork_t		*ifp;	/* inode fork pointer */
1866153323Srodrigc	xfs_bmbt_irec_t		left;	/* left neighbor extent entry */
1867153323Srodrigc	xfs_filblks_t		newlen=0;	/* new indirect size */
1868153323Srodrigc	xfs_filblks_t		oldlen=0;	/* old indirect size */
1869153323Srodrigc	xfs_bmbt_irec_t		right;	/* right neighbor extent entry */
1870153323Srodrigc	int			state;  /* state bits, accessed thru macros */
1871159451Srodrigc	xfs_filblks_t		temp=0;	/* temp for indirect calculations */
1872159451Srodrigc	xfs_filblks_t		temp2=0;
1873153323Srodrigc	enum {				/* bit number definitions for state */
1874153323Srodrigc		LEFT_CONTIG,	RIGHT_CONTIG,
1875153323Srodrigc		LEFT_DELAY,	RIGHT_DELAY,
1876153323Srodrigc		LEFT_VALID,	RIGHT_VALID
1877153323Srodrigc	};
1878153323Srodrigc
1879153323Srodrigc#define	MASK(b)			(1 << (b))
1880153323Srodrigc#define	MASK2(a,b)		(MASK(a) | MASK(b))
1881153323Srodrigc#define	STATE_SET(b,v)		((v) ? (state |= MASK(b)) : (state &= ~MASK(b)))
1882153323Srodrigc#define	STATE_TEST(b)		(state & MASK(b))
1883153323Srodrigc#define	STATE_SET_TEST(b,v)	((v) ? ((state |= MASK(b)), 1) : \
1884153323Srodrigc				       ((state &= ~MASK(b)), 0))
1885153323Srodrigc#define	SWITCH_STATE		(state & MASK2(LEFT_CONTIG, RIGHT_CONTIG))
1886153323Srodrigc
1887159451Srodrigc	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
1888159451Srodrigc	ep = xfs_iext_get_ext(ifp, idx);
1889153323Srodrigc	state = 0;
1890153323Srodrigc	ASSERT(ISNULLSTARTBLOCK(new->br_startblock));
1891153323Srodrigc	/*
1892153323Srodrigc	 * Check and set flags if this segment has a left neighbor
1893153323Srodrigc	 */
1894153323Srodrigc	if (STATE_SET_TEST(LEFT_VALID, idx > 0)) {
1895159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &left);
1896153323Srodrigc		STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock));
1897153323Srodrigc	}
1898153323Srodrigc	/*
1899153323Srodrigc	 * Check and set flags if the current (right) segment exists.
1900153323Srodrigc	 * If it doesn't exist, we're converting the hole at end-of-file.
1901153323Srodrigc	 */
1902153323Srodrigc	if (STATE_SET_TEST(RIGHT_VALID,
1903153323Srodrigc			   idx <
1904153323Srodrigc			   ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) {
1905153323Srodrigc		xfs_bmbt_get_all(ep, &right);
1906153323Srodrigc		STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock));
1907153323Srodrigc	}
1908153323Srodrigc	/*
1909153323Srodrigc	 * Set contiguity flags on the left and right neighbors.
1910153323Srodrigc	 * Don't let extents get too large, even if the pieces are contiguous.
1911153323Srodrigc	 */
1912153323Srodrigc	STATE_SET(LEFT_CONTIG,
1913153323Srodrigc		STATE_TEST(LEFT_VALID) && STATE_TEST(LEFT_DELAY) &&
1914153323Srodrigc		left.br_startoff + left.br_blockcount == new->br_startoff &&
1915153323Srodrigc		left.br_blockcount + new->br_blockcount <= MAXEXTLEN);
1916153323Srodrigc	STATE_SET(RIGHT_CONTIG,
1917153323Srodrigc		STATE_TEST(RIGHT_VALID) && STATE_TEST(RIGHT_DELAY) &&
1918153323Srodrigc		new->br_startoff + new->br_blockcount == right.br_startoff &&
1919153323Srodrigc		new->br_blockcount + right.br_blockcount <= MAXEXTLEN &&
1920153323Srodrigc		(!STATE_TEST(LEFT_CONTIG) ||
1921153323Srodrigc		 (left.br_blockcount + new->br_blockcount +
1922153323Srodrigc		     right.br_blockcount <= MAXEXTLEN)));
1923153323Srodrigc	/*
1924153323Srodrigc	 * Switch out based on the contiguity flags.
1925153323Srodrigc	 */
1926153323Srodrigc	switch (SWITCH_STATE) {
1927153323Srodrigc
1928153323Srodrigc	case MASK2(LEFT_CONTIG, RIGHT_CONTIG):
1929153323Srodrigc		/*
1930153323Srodrigc		 * New allocation is contiguous with delayed allocations
1931153323Srodrigc		 * on the left and on the right.
1932159451Srodrigc		 * Merge all three into a single extent record.
1933153323Srodrigc		 */
1934153323Srodrigc		temp = left.br_blockcount + new->br_blockcount +
1935153323Srodrigc			right.br_blockcount;
1936153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
1937153323Srodrigc			XFS_DATA_FORK);
1938159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
1939153323Srodrigc		oldlen = STARTBLOCKVAL(left.br_startblock) +
1940153323Srodrigc			STARTBLOCKVAL(new->br_startblock) +
1941153323Srodrigc			STARTBLOCKVAL(right.br_startblock);
1942153323Srodrigc		newlen = xfs_bmap_worst_indlen(ip, temp);
1943159451Srodrigc		xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
1944159451Srodrigc			NULLSTARTBLOCK((int)newlen));
1945153323Srodrigc		xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
1946153323Srodrigc			XFS_DATA_FORK);
1947153323Srodrigc		xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1,
1948153323Srodrigc			XFS_DATA_FORK);
1949159451Srodrigc		xfs_iext_remove(ifp, idx, 1);
1950153323Srodrigc		ip->i_df.if_lastex = idx - 1;
1951159451Srodrigc		/* DELTA: Two in-core extents were replaced by one. */
1952159451Srodrigc		temp2 = temp;
1953159451Srodrigc		temp = left.br_startoff;
1954153323Srodrigc		break;
1955153323Srodrigc
1956153323Srodrigc	case MASK(LEFT_CONTIG):
1957153323Srodrigc		/*
1958153323Srodrigc		 * New allocation is contiguous with a delayed allocation
1959153323Srodrigc		 * on the left.
1960153323Srodrigc		 * Merge the new allocation with the left neighbor.
1961153323Srodrigc		 */
1962153323Srodrigc		temp = left.br_blockcount + new->br_blockcount;
1963153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1,
1964153323Srodrigc			XFS_DATA_FORK);
1965159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
1966153323Srodrigc		oldlen = STARTBLOCKVAL(left.br_startblock) +
1967153323Srodrigc			STARTBLOCKVAL(new->br_startblock);
1968153323Srodrigc		newlen = xfs_bmap_worst_indlen(ip, temp);
1969159451Srodrigc		xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
1970159451Srodrigc			NULLSTARTBLOCK((int)newlen));
1971153323Srodrigc		xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1,
1972153323Srodrigc			XFS_DATA_FORK);
1973153323Srodrigc		ip->i_df.if_lastex = idx - 1;
1974159451Srodrigc		/* DELTA: One in-core extent grew into a hole. */
1975159451Srodrigc		temp2 = temp;
1976159451Srodrigc		temp = left.br_startoff;
1977153323Srodrigc		break;
1978153323Srodrigc
1979153323Srodrigc	case MASK(RIGHT_CONTIG):
1980153323Srodrigc		/*
1981153323Srodrigc		 * New allocation is contiguous with a delayed allocation
1982153323Srodrigc		 * on the right.
1983153323Srodrigc		 * Merge the new allocation with the right neighbor.
1984153323Srodrigc		 */
1985153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK);
1986153323Srodrigc		temp = new->br_blockcount + right.br_blockcount;
1987153323Srodrigc		oldlen = STARTBLOCKVAL(new->br_startblock) +
1988153323Srodrigc			STARTBLOCKVAL(right.br_startblock);
1989153323Srodrigc		newlen = xfs_bmap_worst_indlen(ip, temp);
1990153323Srodrigc		xfs_bmbt_set_allf(ep, new->br_startoff,
1991153323Srodrigc			NULLSTARTBLOCK((int)newlen), temp, right.br_state);
1992153323Srodrigc		xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK);
1993153323Srodrigc		ip->i_df.if_lastex = idx;
1994159451Srodrigc		/* DELTA: One in-core extent grew into a hole. */
1995159451Srodrigc		temp2 = temp;
1996159451Srodrigc		temp = new->br_startoff;
1997153323Srodrigc		break;
1998153323Srodrigc
1999153323Srodrigc	case 0:
2000153323Srodrigc		/*
2001153323Srodrigc		 * New allocation is not contiguous with another
2002153323Srodrigc		 * delayed allocation.
2003153323Srodrigc		 * Insert a new entry.
2004153323Srodrigc		 */
2005153323Srodrigc		oldlen = newlen = 0;
2006153323Srodrigc		xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
2007153323Srodrigc			XFS_DATA_FORK);
2008159451Srodrigc		xfs_iext_insert(ifp, idx, 1, new);
2009153323Srodrigc		ip->i_df.if_lastex = idx;
2010159451Srodrigc		/* DELTA: A new in-core extent was added in a hole. */
2011159451Srodrigc		temp2 = new->br_blockcount;
2012159451Srodrigc		temp = new->br_startoff;
2013153323Srodrigc		break;
2014153323Srodrigc	}
2015153323Srodrigc	if (oldlen != newlen) {
2016153323Srodrigc		ASSERT(oldlen > newlen);
2017153323Srodrigc		xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS,
2018153323Srodrigc			(int)(oldlen - newlen), rsvd);
2019153323Srodrigc		/*
2020153323Srodrigc		 * Nothing to do for disk quota accounting here.
2021153323Srodrigc		 */
2022153323Srodrigc	}
2023159451Srodrigc	if (delta) {
2024159451Srodrigc		temp2 += temp;
2025159451Srodrigc		if (delta->xed_startoff > temp)
2026159451Srodrigc			delta->xed_startoff = temp;
2027159451Srodrigc		if (delta->xed_blockcount < temp2)
2028159451Srodrigc			delta->xed_blockcount = temp2;
2029159451Srodrigc	}
2030153323Srodrigc	*logflagsp = 0;
2031153323Srodrigc	return 0;
2032153323Srodrigc#undef	MASK
2033153323Srodrigc#undef	MASK2
2034153323Srodrigc#undef	STATE_SET
2035153323Srodrigc#undef	STATE_TEST
2036153323Srodrigc#undef	STATE_SET_TEST
2037153323Srodrigc#undef	SWITCH_STATE
2038153323Srodrigc}
2039153323Srodrigc
2040153323Srodrigc/*
2041153323Srodrigc * Called by xfs_bmap_add_extent to handle cases converting a hole
2042153323Srodrigc * to a real allocation.
2043153323Srodrigc */
2044153323SrodrigcSTATIC int				/* error */
2045153323Srodrigcxfs_bmap_add_extent_hole_real(
2046153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
2047153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/insert */
2048153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
2049159451Srodrigc	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
2050153323Srodrigc	int			*logflagsp, /* inode logging flags */
2051159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
2052153323Srodrigc	int			whichfork) /* data or attr fork */
2053153323Srodrigc{
2054153323Srodrigc	xfs_bmbt_rec_t		*ep;	/* pointer to extent entry ins. point */
2055153323Srodrigc	int			error;	/* error return value */
2056153323Srodrigc#ifdef XFS_BMAP_TRACE
2057153323Srodrigc	static char		fname[] = "xfs_bmap_add_extent_hole_real";
2058153323Srodrigc#endif
2059153323Srodrigc	int			i;	/* temp state */
2060153323Srodrigc	xfs_ifork_t		*ifp;	/* inode fork pointer */
2061153323Srodrigc	xfs_bmbt_irec_t		left;	/* left neighbor extent entry */
2062153323Srodrigc	xfs_bmbt_irec_t		right;	/* right neighbor extent entry */
2063159451Srodrigc	int			rval=0;	/* return value (logging flags) */
2064153323Srodrigc	int			state;	/* state bits, accessed thru macros */
2065159451Srodrigc	xfs_filblks_t		temp=0;
2066159451Srodrigc	xfs_filblks_t		temp2=0;
2067153323Srodrigc	enum {				/* bit number definitions for state */
2068153323Srodrigc		LEFT_CONTIG,	RIGHT_CONTIG,
2069153323Srodrigc		LEFT_DELAY,	RIGHT_DELAY,
2070153323Srodrigc		LEFT_VALID,	RIGHT_VALID
2071153323Srodrigc	};
2072153323Srodrigc
2073153323Srodrigc#define	MASK(b)			(1 << (b))
2074153323Srodrigc#define	MASK2(a,b)		(MASK(a) | MASK(b))
2075153323Srodrigc#define	STATE_SET(b,v)		((v) ? (state |= MASK(b)) : (state &= ~MASK(b)))
2076153323Srodrigc#define	STATE_TEST(b)		(state & MASK(b))
2077153323Srodrigc#define	STATE_SET_TEST(b,v)	((v) ? ((state |= MASK(b)), 1) : \
2078153323Srodrigc				       ((state &= ~MASK(b)), 0))
2079153323Srodrigc#define	SWITCH_STATE		(state & MASK2(LEFT_CONTIG, RIGHT_CONTIG))
2080153323Srodrigc
2081153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
2082153323Srodrigc	ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
2083159451Srodrigc	ep = xfs_iext_get_ext(ifp, idx);
2084153323Srodrigc	state = 0;
2085153323Srodrigc	/*
2086153323Srodrigc	 * Check and set flags if this segment has a left neighbor.
2087153323Srodrigc	 */
2088153323Srodrigc	if (STATE_SET_TEST(LEFT_VALID, idx > 0)) {
2089159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &left);
2090153323Srodrigc		STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock));
2091153323Srodrigc	}
2092153323Srodrigc	/*
2093153323Srodrigc	 * Check and set flags if this segment has a current value.
2094153323Srodrigc	 * Not true if we're inserting into the "hole" at eof.
2095153323Srodrigc	 */
2096153323Srodrigc	if (STATE_SET_TEST(RIGHT_VALID,
2097153323Srodrigc			   idx <
2098153323Srodrigc			   ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) {
2099153323Srodrigc		xfs_bmbt_get_all(ep, &right);
2100153323Srodrigc		STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock));
2101153323Srodrigc	}
2102153323Srodrigc	/*
2103153323Srodrigc	 * We're inserting a real allocation between "left" and "right".
2104153323Srodrigc	 * Set the contiguity flags.  Don't let extents get too large.
2105153323Srodrigc	 */
2106153323Srodrigc	STATE_SET(LEFT_CONTIG,
2107153323Srodrigc		STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) &&
2108153323Srodrigc		left.br_startoff + left.br_blockcount == new->br_startoff &&
2109153323Srodrigc		left.br_startblock + left.br_blockcount == new->br_startblock &&
2110153323Srodrigc		left.br_state == new->br_state &&
2111153323Srodrigc		left.br_blockcount + new->br_blockcount <= MAXEXTLEN);
2112153323Srodrigc	STATE_SET(RIGHT_CONTIG,
2113153323Srodrigc		STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) &&
2114153323Srodrigc		new->br_startoff + new->br_blockcount == right.br_startoff &&
2115153323Srodrigc		new->br_startblock + new->br_blockcount ==
2116153323Srodrigc		    right.br_startblock &&
2117153323Srodrigc		new->br_state == right.br_state &&
2118153323Srodrigc		new->br_blockcount + right.br_blockcount <= MAXEXTLEN &&
2119153323Srodrigc		(!STATE_TEST(LEFT_CONTIG) ||
2120153323Srodrigc		 left.br_blockcount + new->br_blockcount +
2121153323Srodrigc		     right.br_blockcount <= MAXEXTLEN));
2122153323Srodrigc
2123159451Srodrigc	error = 0;
2124153323Srodrigc	/*
2125153323Srodrigc	 * Select which case we're in here, and implement it.
2126153323Srodrigc	 */
2127153323Srodrigc	switch (SWITCH_STATE) {
2128153323Srodrigc
2129153323Srodrigc	case MASK2(LEFT_CONTIG, RIGHT_CONTIG):
2130153323Srodrigc		/*
2131153323Srodrigc		 * New allocation is contiguous with real allocations on the
2132153323Srodrigc		 * left and on the right.
2133159451Srodrigc		 * Merge all three into a single extent record.
2134153323Srodrigc		 */
2135153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
2136153323Srodrigc			whichfork);
2137159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
2138153323Srodrigc			left.br_blockcount + new->br_blockcount +
2139153323Srodrigc			right.br_blockcount);
2140153323Srodrigc		xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
2141153323Srodrigc			whichfork);
2142153323Srodrigc		xfs_bmap_trace_delete(fname, "LC|RC", ip,
2143153323Srodrigc			idx, 1, whichfork);
2144159451Srodrigc		xfs_iext_remove(ifp, idx, 1);
2145153323Srodrigc		ifp->if_lastex = idx - 1;
2146153323Srodrigc		XFS_IFORK_NEXT_SET(ip, whichfork,
2147153323Srodrigc			XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
2148153323Srodrigc		if (cur == NULL) {
2149159451Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
2150159451Srodrigc		} else {
2151159451Srodrigc			rval = XFS_ILOG_CORE;
2152159451Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur,
2153159451Srodrigc					right.br_startoff,
2154159451Srodrigc					right.br_startblock,
2155159451Srodrigc					right.br_blockcount, &i)))
2156159451Srodrigc				goto done;
2157159451Srodrigc			ASSERT(i == 1);
2158159451Srodrigc			if ((error = xfs_bmbt_delete(cur, &i)))
2159159451Srodrigc				goto done;
2160159451Srodrigc			ASSERT(i == 1);
2161159451Srodrigc			if ((error = xfs_bmbt_decrement(cur, 0, &i)))
2162159451Srodrigc				goto done;
2163159451Srodrigc			ASSERT(i == 1);
2164159451Srodrigc			if ((error = xfs_bmbt_update(cur, left.br_startoff,
2165159451Srodrigc					left.br_startblock,
2166159451Srodrigc					left.br_blockcount +
2167159451Srodrigc						new->br_blockcount +
2168159451Srodrigc						right.br_blockcount,
2169159451Srodrigc					left.br_state)))
2170159451Srodrigc				goto done;
2171153323Srodrigc		}
2172159451Srodrigc		/* DELTA: Two in-core extents were replaced by one. */
2173159451Srodrigc		temp = left.br_startoff;
2174159451Srodrigc		temp2 = left.br_blockcount +
2175159451Srodrigc			new->br_blockcount +
2176159451Srodrigc			right.br_blockcount;
2177159451Srodrigc		break;
2178153323Srodrigc
2179153323Srodrigc	case MASK(LEFT_CONTIG):
2180153323Srodrigc		/*
2181153323Srodrigc		 * New allocation is contiguous with a real allocation
2182153323Srodrigc		 * on the left.
2183153323Srodrigc		 * Merge the new allocation with the left neighbor.
2184153323Srodrigc		 */
2185153323Srodrigc		xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork);
2186159451Srodrigc		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
2187153323Srodrigc			left.br_blockcount + new->br_blockcount);
2188153323Srodrigc		xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork);
2189153323Srodrigc		ifp->if_lastex = idx - 1;
2190153323Srodrigc		if (cur == NULL) {
2191159451Srodrigc			rval = XFS_ILOG_FEXT(whichfork);
2192159451Srodrigc		} else {
2193159451Srodrigc			rval = 0;
2194159451Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur,
2195159451Srodrigc					left.br_startoff,
2196159451Srodrigc					left.br_startblock,
2197159451Srodrigc					left.br_blockcount, &i)))
2198159451Srodrigc				goto done;
2199159451Srodrigc			ASSERT(i == 1);
2200159451Srodrigc			if ((error = xfs_bmbt_update(cur, left.br_startoff,
2201159451Srodrigc					left.br_startblock,
2202159451Srodrigc					left.br_blockcount +
2203159451Srodrigc						new->br_blockcount,
2204159451Srodrigc					left.br_state)))
2205159451Srodrigc				goto done;
2206153323Srodrigc		}
2207159451Srodrigc		/* DELTA: One in-core extent grew. */
2208159451Srodrigc		temp = left.br_startoff;
2209159451Srodrigc		temp2 = left.br_blockcount +
2210159451Srodrigc			new->br_blockcount;
2211159451Srodrigc		break;
2212153323Srodrigc
2213153323Srodrigc	case MASK(RIGHT_CONTIG):
2214153323Srodrigc		/*
2215153323Srodrigc		 * New allocation is contiguous with a real allocation
2216153323Srodrigc		 * on the right.
2217153323Srodrigc		 * Merge the new allocation with the right neighbor.
2218153323Srodrigc		 */
2219153323Srodrigc		xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork);
2220153323Srodrigc		xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock,
2221153323Srodrigc			new->br_blockcount + right.br_blockcount,
2222153323Srodrigc			right.br_state);
2223153323Srodrigc		xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork);
2224153323Srodrigc		ifp->if_lastex = idx;
2225153323Srodrigc		if (cur == NULL) {
2226159451Srodrigc			rval = XFS_ILOG_FEXT(whichfork);
2227159451Srodrigc		} else {
2228159451Srodrigc			rval = 0;
2229159451Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur,
2230159451Srodrigc					right.br_startoff,
2231159451Srodrigc					right.br_startblock,
2232159451Srodrigc					right.br_blockcount, &i)))
2233159451Srodrigc				goto done;
2234159451Srodrigc			ASSERT(i == 1);
2235159451Srodrigc			if ((error = xfs_bmbt_update(cur, new->br_startoff,
2236159451Srodrigc					new->br_startblock,
2237159451Srodrigc					new->br_blockcount +
2238159451Srodrigc						right.br_blockcount,
2239159451Srodrigc					right.br_state)))
2240159451Srodrigc				goto done;
2241153323Srodrigc		}
2242159451Srodrigc		/* DELTA: One in-core extent grew. */
2243159451Srodrigc		temp = new->br_startoff;
2244159451Srodrigc		temp2 = new->br_blockcount +
2245159451Srodrigc			right.br_blockcount;
2246159451Srodrigc		break;
2247153323Srodrigc
2248153323Srodrigc	case 0:
2249153323Srodrigc		/*
2250153323Srodrigc		 * New allocation is not contiguous with another
2251153323Srodrigc		 * real allocation.
2252153323Srodrigc		 * Insert a new entry.
2253153323Srodrigc		 */
2254153323Srodrigc		xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
2255153323Srodrigc			whichfork);
2256159451Srodrigc		xfs_iext_insert(ifp, idx, 1, new);
2257153323Srodrigc		ifp->if_lastex = idx;
2258153323Srodrigc		XFS_IFORK_NEXT_SET(ip, whichfork,
2259153323Srodrigc			XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
2260153323Srodrigc		if (cur == NULL) {
2261159451Srodrigc			rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
2262159451Srodrigc		} else {
2263159451Srodrigc			rval = XFS_ILOG_CORE;
2264159451Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur,
2265159451Srodrigc					new->br_startoff,
2266159451Srodrigc					new->br_startblock,
2267159451Srodrigc					new->br_blockcount, &i)))
2268159451Srodrigc				goto done;
2269159451Srodrigc			ASSERT(i == 0);
2270159451Srodrigc			cur->bc_rec.b.br_state = new->br_state;
2271159451Srodrigc			if ((error = xfs_bmbt_insert(cur, &i)))
2272159451Srodrigc				goto done;
2273159451Srodrigc			ASSERT(i == 1);
2274153323Srodrigc		}
2275159451Srodrigc		/* DELTA: A new extent was added in a hole. */
2276159451Srodrigc		temp = new->br_startoff;
2277159451Srodrigc		temp2 = new->br_blockcount;
2278159451Srodrigc		break;
2279153323Srodrigc	}
2280159451Srodrigc	if (delta) {
2281159451Srodrigc		temp2 += temp;
2282159451Srodrigc		if (delta->xed_startoff > temp)
2283159451Srodrigc			delta->xed_startoff = temp;
2284159451Srodrigc		if (delta->xed_blockcount < temp2)
2285159451Srodrigc			delta->xed_blockcount = temp2;
2286159451Srodrigc	}
2287159451Srodrigcdone:
2288159451Srodrigc	*logflagsp = rval;
2289159451Srodrigc	return error;
2290153323Srodrigc#undef	MASK
2291153323Srodrigc#undef	MASK2
2292153323Srodrigc#undef	STATE_SET
2293153323Srodrigc#undef	STATE_TEST
2294153323Srodrigc#undef	STATE_SET_TEST
2295153323Srodrigc#undef	SWITCH_STATE
2296153323Srodrigc}
2297153323Srodrigc
2298159451Srodrigc/*
2299159451Srodrigc * Adjust the size of the new extent based on di_extsize and rt extsize.
2300159451Srodrigc */
2301159451SrodrigcSTATIC int
2302159451Srodrigcxfs_bmap_extsize_align(
2303159451Srodrigc	xfs_mount_t	*mp,
2304159451Srodrigc	xfs_bmbt_irec_t	*gotp,		/* next extent pointer */
2305159451Srodrigc	xfs_bmbt_irec_t	*prevp,		/* previous extent pointer */
2306159451Srodrigc	xfs_extlen_t	extsz,		/* align to this extent size */
2307159451Srodrigc	int		rt,		/* is this a realtime inode? */
2308159451Srodrigc	int		eof,		/* is extent at end-of-file? */
2309159451Srodrigc	int		delay,		/* creating delalloc extent? */
2310159451Srodrigc	int		convert,	/* overwriting unwritten extent? */
2311159451Srodrigc	xfs_fileoff_t	*offp,		/* in/out: aligned offset */
2312159451Srodrigc	xfs_extlen_t	*lenp)		/* in/out: aligned length */
2313159451Srodrigc{
2314159451Srodrigc	xfs_fileoff_t	orig_off;	/* original offset */
2315159451Srodrigc	xfs_extlen_t	orig_alen;	/* original length */
2316159451Srodrigc	xfs_fileoff_t	orig_end;	/* original off+len */
2317159451Srodrigc	xfs_fileoff_t	nexto;		/* next file offset */
2318159451Srodrigc	xfs_fileoff_t	prevo;		/* previous file offset */
2319159451Srodrigc	xfs_fileoff_t	align_off;	/* temp for offset */
2320159451Srodrigc	xfs_extlen_t	align_alen;	/* temp for length */
2321159451Srodrigc	xfs_extlen_t	temp;		/* temp for calculations */
2322159451Srodrigc
2323159451Srodrigc	if (convert)
2324159451Srodrigc		return 0;
2325159451Srodrigc
2326159451Srodrigc	orig_off = align_off = *offp;
2327159451Srodrigc	orig_alen = align_alen = *lenp;
2328159451Srodrigc	orig_end = orig_off + orig_alen;
2329159451Srodrigc
2330159451Srodrigc	/*
2331159451Srodrigc	 * If this request overlaps an existing extent, then don't
2332159451Srodrigc	 * attempt to perform any additional alignment.
2333159451Srodrigc	 */
2334159451Srodrigc	if (!delay && !eof &&
2335159451Srodrigc	    (orig_off >= gotp->br_startoff) &&
2336159451Srodrigc	    (orig_end <= gotp->br_startoff + gotp->br_blockcount)) {
2337159451Srodrigc		return 0;
2338159451Srodrigc	}
2339159451Srodrigc
2340159451Srodrigc	/*
2341159451Srodrigc	 * If the file offset is unaligned vs. the extent size
2342159451Srodrigc	 * we need to align it.  This will be possible unless
2343159451Srodrigc	 * the file was previously written with a kernel that didn't
2344159451Srodrigc	 * perform this alignment, or if a truncate shot us in the
2345159451Srodrigc	 * foot.
2346159451Srodrigc	 */
2347159451Srodrigc	temp = do_mod(orig_off, extsz);
2348159451Srodrigc	if (temp) {
2349159451Srodrigc		align_alen += temp;
2350159451Srodrigc		align_off -= temp;
2351159451Srodrigc	}
2352159451Srodrigc	/*
2353159451Srodrigc	 * Same adjustment for the end of the requested area.
2354159451Srodrigc	 */
2355159451Srodrigc	if ((temp = (align_alen % extsz))) {
2356159451Srodrigc		align_alen += extsz - temp;
2357159451Srodrigc	}
2358159451Srodrigc	/*
2359159451Srodrigc	 * If the previous block overlaps with this proposed allocation
2360159451Srodrigc	 * then move the start forward without adjusting the length.
2361159451Srodrigc	 */
2362159451Srodrigc	if (prevp->br_startoff != NULLFILEOFF) {
2363159451Srodrigc		if (prevp->br_startblock == HOLESTARTBLOCK)
2364159451Srodrigc			prevo = prevp->br_startoff;
2365159451Srodrigc		else
2366159451Srodrigc			prevo = prevp->br_startoff + prevp->br_blockcount;
2367159451Srodrigc	} else
2368159451Srodrigc		prevo = 0;
2369159451Srodrigc	if (align_off != orig_off && align_off < prevo)
2370159451Srodrigc		align_off = prevo;
2371159451Srodrigc	/*
2372159451Srodrigc	 * If the next block overlaps with this proposed allocation
2373159451Srodrigc	 * then move the start back without adjusting the length,
2374159451Srodrigc	 * but not before offset 0.
2375159451Srodrigc	 * This may of course make the start overlap previous block,
2376159451Srodrigc	 * and if we hit the offset 0 limit then the next block
2377159451Srodrigc	 * can still overlap too.
2378159451Srodrigc	 */
2379159451Srodrigc	if (!eof && gotp->br_startoff != NULLFILEOFF) {
2380159451Srodrigc		if ((delay && gotp->br_startblock == HOLESTARTBLOCK) ||
2381159451Srodrigc		    (!delay && gotp->br_startblock == DELAYSTARTBLOCK))
2382159451Srodrigc			nexto = gotp->br_startoff + gotp->br_blockcount;
2383159451Srodrigc		else
2384159451Srodrigc			nexto = gotp->br_startoff;
2385159451Srodrigc	} else
2386159451Srodrigc		nexto = NULLFILEOFF;
2387159451Srodrigc	if (!eof &&
2388159451Srodrigc	    align_off + align_alen != orig_end &&
2389159451Srodrigc	    align_off + align_alen > nexto)
2390159451Srodrigc		align_off = nexto > align_alen ? nexto - align_alen : 0;
2391159451Srodrigc	/*
2392159451Srodrigc	 * If we're now overlapping the next or previous extent that
2393159451Srodrigc	 * means we can't fit an extsz piece in this hole.  Just move
2394159451Srodrigc	 * the start forward to the first valid spot and set
2395159451Srodrigc	 * the length so we hit the end.
2396159451Srodrigc	 */
2397159451Srodrigc	if (align_off != orig_off && align_off < prevo)
2398159451Srodrigc		align_off = prevo;
2399159451Srodrigc	if (align_off + align_alen != orig_end &&
2400159451Srodrigc	    align_off + align_alen > nexto &&
2401159451Srodrigc	    nexto != NULLFILEOFF) {
2402159451Srodrigc		ASSERT(nexto > prevo);
2403159451Srodrigc		align_alen = nexto - align_off;
2404159451Srodrigc	}
2405159451Srodrigc
2406159451Srodrigc	/*
2407159451Srodrigc	 * If realtime, and the result isn't a multiple of the realtime
2408159451Srodrigc	 * extent size we need to remove blocks until it is.
2409159451Srodrigc	 */
2410159451Srodrigc	if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) {
2411159451Srodrigc		/*
2412159451Srodrigc		 * We're not covering the original request, or
2413159451Srodrigc		 * we won't be able to once we fix the length.
2414159451Srodrigc		 */
2415159451Srodrigc		if (orig_off < align_off ||
2416159451Srodrigc		    orig_end > align_off + align_alen ||
2417159451Srodrigc		    align_alen - temp < orig_alen)
2418159451Srodrigc			return XFS_ERROR(EINVAL);
2419159451Srodrigc		/*
2420159451Srodrigc		 * Try to fix it by moving the start up.
2421159451Srodrigc		 */
2422159451Srodrigc		if (align_off + temp <= orig_off) {
2423159451Srodrigc			align_alen -= temp;
2424159451Srodrigc			align_off += temp;
2425159451Srodrigc		}
2426159451Srodrigc		/*
2427159451Srodrigc		 * Try to fix it by moving the end in.
2428159451Srodrigc		 */
2429159451Srodrigc		else if (align_off + align_alen - temp >= orig_end)
2430159451Srodrigc			align_alen -= temp;
2431159451Srodrigc		/*
2432159451Srodrigc		 * Set the start to the minimum then trim the length.
2433159451Srodrigc		 */
2434159451Srodrigc		else {
2435159451Srodrigc			align_alen -= orig_off - align_off;
2436159451Srodrigc			align_off = orig_off;
2437159451Srodrigc			align_alen -= align_alen % mp->m_sb.sb_rextsize;
2438159451Srodrigc		}
2439159451Srodrigc		/*
2440159451Srodrigc		 * Result doesn't cover the request, fail it.
2441159451Srodrigc		 */
2442159451Srodrigc		if (orig_off < align_off || orig_end > align_off + align_alen)
2443159451Srodrigc			return XFS_ERROR(EINVAL);
2444159451Srodrigc	} else {
2445159451Srodrigc		ASSERT(orig_off >= align_off);
2446159451Srodrigc		ASSERT(orig_end <= align_off + align_alen);
2447159451Srodrigc	}
2448159451Srodrigc
2449159451Srodrigc#ifdef DEBUG
2450159451Srodrigc	if (!eof && gotp->br_startoff != NULLFILEOFF)
2451159451Srodrigc		ASSERT(align_off + align_alen <= gotp->br_startoff);
2452159451Srodrigc	if (prevp->br_startoff != NULLFILEOFF)
2453159451Srodrigc		ASSERT(align_off >= prevp->br_startoff + prevp->br_blockcount);
2454159451Srodrigc#endif
2455159451Srodrigc
2456159451Srodrigc	*lenp = align_alen;
2457159451Srodrigc	*offp = align_off;
2458159451Srodrigc	return 0;
2459159451Srodrigc}
2460159451Srodrigc
2461153323Srodrigc#define XFS_ALLOC_GAP_UNITS	4
2462153323Srodrigc
2463159451SrodrigcSTATIC int
2464159451Srodrigcxfs_bmap_adjacent(
2465153323Srodrigc	xfs_bmalloca_t	*ap)		/* bmap alloc argument struct */
2466153323Srodrigc{
2467153323Srodrigc	xfs_fsblock_t	adjust;		/* adjustment to block numbers */
2468153323Srodrigc	xfs_agnumber_t	fb_agno;	/* ag number of ap->firstblock */
2469153323Srodrigc	xfs_mount_t	*mp;		/* mount point structure */
2470153323Srodrigc	int		nullfb;		/* true if ap->firstblock isn't set */
2471153323Srodrigc	int		rt;		/* true if inode is realtime */
2472153323Srodrigc
2473153323Srodrigc#define	ISVALID(x,y)	\
2474153323Srodrigc	(rt ? \
2475153323Srodrigc		(x) < mp->m_sb.sb_rblocks : \
2476153323Srodrigc		XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \
2477153323Srodrigc		XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \
2478153323Srodrigc		XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
2479153323Srodrigc
2480153323Srodrigc	mp = ap->ip->i_mount;
2481153323Srodrigc	nullfb = ap->firstblock == NULLFSBLOCK;
2482153323Srodrigc	rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata;
2483153323Srodrigc	fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
2484153323Srodrigc	/*
2485153323Srodrigc	 * If allocating at eof, and there's a previous real block,
2486153323Srodrigc	 * try to use it's last block as our starting point.
2487153323Srodrigc	 */
2488153323Srodrigc	if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF &&
2489153323Srodrigc	    !ISNULLSTARTBLOCK(ap->prevp->br_startblock) &&
2490153323Srodrigc	    ISVALID(ap->prevp->br_startblock + ap->prevp->br_blockcount,
2491153323Srodrigc		    ap->prevp->br_startblock)) {
2492153323Srodrigc		ap->rval = ap->prevp->br_startblock + ap->prevp->br_blockcount;
2493153323Srodrigc		/*
2494153323Srodrigc		 * Adjust for the gap between prevp and us.
2495153323Srodrigc		 */
2496153323Srodrigc		adjust = ap->off -
2497153323Srodrigc			(ap->prevp->br_startoff + ap->prevp->br_blockcount);
2498153323Srodrigc		if (adjust &&
2499153323Srodrigc		    ISVALID(ap->rval + adjust, ap->prevp->br_startblock))
2500153323Srodrigc			ap->rval += adjust;
2501153323Srodrigc	}
2502153323Srodrigc	/*
2503153323Srodrigc	 * If not at eof, then compare the two neighbor blocks.
2504153323Srodrigc	 * Figure out whether either one gives us a good starting point,
2505153323Srodrigc	 * and pick the better one.
2506153323Srodrigc	 */
2507153323Srodrigc	else if (!ap->eof) {
2508153323Srodrigc		xfs_fsblock_t	gotbno;		/* right side block number */
2509153323Srodrigc		xfs_fsblock_t	gotdiff=0;	/* right side difference */
2510153323Srodrigc		xfs_fsblock_t	prevbno;	/* left side block number */
2511153323Srodrigc		xfs_fsblock_t	prevdiff=0;	/* left side difference */
2512153323Srodrigc
2513153323Srodrigc		/*
2514153323Srodrigc		 * If there's a previous (left) block, select a requested
2515153323Srodrigc		 * start block based on it.
2516153323Srodrigc		 */
2517153323Srodrigc		if (ap->prevp->br_startoff != NULLFILEOFF &&
2518153323Srodrigc		    !ISNULLSTARTBLOCK(ap->prevp->br_startblock) &&
2519153323Srodrigc		    (prevbno = ap->prevp->br_startblock +
2520153323Srodrigc			       ap->prevp->br_blockcount) &&
2521153323Srodrigc		    ISVALID(prevbno, ap->prevp->br_startblock)) {
2522153323Srodrigc			/*
2523153323Srodrigc			 * Calculate gap to end of previous block.
2524153323Srodrigc			 */
2525153323Srodrigc			adjust = prevdiff = ap->off -
2526153323Srodrigc				(ap->prevp->br_startoff +
2527153323Srodrigc				 ap->prevp->br_blockcount);
2528153323Srodrigc			/*
2529153323Srodrigc			 * Figure the startblock based on the previous block's
2530153323Srodrigc			 * end and the gap size.
2531153323Srodrigc			 * Heuristic!
2532153323Srodrigc			 * If the gap is large relative to the piece we're
2533153323Srodrigc			 * allocating, or using it gives us an invalid block
2534153323Srodrigc			 * number, then just use the end of the previous block.
2535153323Srodrigc			 */
2536153323Srodrigc			if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->alen &&
2537153323Srodrigc			    ISVALID(prevbno + prevdiff,
2538153323Srodrigc				    ap->prevp->br_startblock))
2539153323Srodrigc				prevbno += adjust;
2540153323Srodrigc			else
2541153323Srodrigc				prevdiff += adjust;
2542153323Srodrigc			/*
2543153323Srodrigc			 * If the firstblock forbids it, can't use it,
2544153323Srodrigc			 * must use default.
2545153323Srodrigc			 */
2546153323Srodrigc			if (!rt && !nullfb &&
2547153323Srodrigc			    XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno)
2548153323Srodrigc				prevbno = NULLFSBLOCK;
2549153323Srodrigc		}
2550153323Srodrigc		/*
2551153323Srodrigc		 * No previous block or can't follow it, just default.
2552153323Srodrigc		 */
2553153323Srodrigc		else
2554153323Srodrigc			prevbno = NULLFSBLOCK;
2555153323Srodrigc		/*
2556153323Srodrigc		 * If there's a following (right) block, select a requested
2557153323Srodrigc		 * start block based on it.
2558153323Srodrigc		 */
2559153323Srodrigc		if (!ISNULLSTARTBLOCK(ap->gotp->br_startblock)) {
2560153323Srodrigc			/*
2561153323Srodrigc			 * Calculate gap to start of next block.
2562153323Srodrigc			 */
2563153323Srodrigc			adjust = gotdiff = ap->gotp->br_startoff - ap->off;
2564153323Srodrigc			/*
2565153323Srodrigc			 * Figure the startblock based on the next block's
2566153323Srodrigc			 * start and the gap size.
2567153323Srodrigc			 */
2568153323Srodrigc			gotbno = ap->gotp->br_startblock;
2569153323Srodrigc			/*
2570153323Srodrigc			 * Heuristic!
2571153323Srodrigc			 * If the gap is large relative to the piece we're
2572153323Srodrigc			 * allocating, or using it gives us an invalid block
2573153323Srodrigc			 * number, then just use the start of the next block
2574153323Srodrigc			 * offset by our length.
2575153323Srodrigc			 */
2576153323Srodrigc			if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->alen &&
2577153323Srodrigc			    ISVALID(gotbno - gotdiff, gotbno))
2578153323Srodrigc				gotbno -= adjust;
2579153323Srodrigc			else if (ISVALID(gotbno - ap->alen, gotbno)) {
2580153323Srodrigc				gotbno -= ap->alen;
2581153323Srodrigc				gotdiff += adjust - ap->alen;
2582153323Srodrigc			} else
2583153323Srodrigc				gotdiff += adjust;
2584153323Srodrigc			/*
2585153323Srodrigc			 * If the firstblock forbids it, can't use it,
2586153323Srodrigc			 * must use default.
2587153323Srodrigc			 */
2588153323Srodrigc			if (!rt && !nullfb &&
2589153323Srodrigc			    XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno)
2590153323Srodrigc				gotbno = NULLFSBLOCK;
2591153323Srodrigc		}
2592153323Srodrigc		/*
2593153323Srodrigc		 * No next block, just default.
2594153323Srodrigc		 */
2595153323Srodrigc		else
2596153323Srodrigc			gotbno = NULLFSBLOCK;
2597153323Srodrigc		/*
2598153323Srodrigc		 * If both valid, pick the better one, else the only good
2599153323Srodrigc		 * one, else ap->rval is already set (to 0 or the inode block).
2600153323Srodrigc		 */
2601153323Srodrigc		if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK)
2602153323Srodrigc			ap->rval = prevdiff <= gotdiff ? prevbno : gotbno;
2603153323Srodrigc		else if (prevbno != NULLFSBLOCK)
2604153323Srodrigc			ap->rval = prevbno;
2605153323Srodrigc		else if (gotbno != NULLFSBLOCK)
2606153323Srodrigc			ap->rval = gotbno;
2607153323Srodrigc	}
2608159451Srodrigc#undef ISVALID
2609159451Srodrigc	return 0;
2610159451Srodrigc}
2611159451Srodrigc
2612159451SrodrigcSTATIC int
2613159451Srodrigcxfs_bmap_rtalloc(
2614159451Srodrigc	xfs_bmalloca_t	*ap)		/* bmap alloc argument struct */
2615159451Srodrigc{
2616159451Srodrigc	xfs_alloctype_t	atype = 0;	/* type for allocation routines */
2617159451Srodrigc	int		error;		/* error return value */
2618159451Srodrigc	xfs_mount_t	*mp;		/* mount point structure */
2619159451Srodrigc	xfs_extlen_t	prod = 0;	/* product factor for allocators */
2620159451Srodrigc	xfs_extlen_t	ralen = 0;	/* realtime allocation length */
2621159451Srodrigc	xfs_extlen_t	align;		/* minimum allocation alignment */
2622159451Srodrigc	xfs_rtblock_t	rtx;		/* realtime extent number */
2623159451Srodrigc	xfs_rtblock_t	rtb;
2624159451Srodrigc
2625159451Srodrigc	mp = ap->ip->i_mount;
2626159451Srodrigc	align = ap->ip->i_d.di_extsize ?
2627159451Srodrigc		ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize;
2628159451Srodrigc	prod = align / mp->m_sb.sb_rextsize;
2629159451Srodrigc	error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
2630159451Srodrigc					align, 1, ap->eof, 0,
2631159451Srodrigc					ap->conv, &ap->off, &ap->alen);
2632159451Srodrigc	if (error)
2633159451Srodrigc		return error;
2634159451Srodrigc	ASSERT(ap->alen);
2635159451Srodrigc	ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0);
2636159451Srodrigc
2637153323Srodrigc	/*
2638159451Srodrigc	 * If the offset & length are not perfectly aligned
2639159451Srodrigc	 * then kill prod, it will just get us in trouble.
2640159451Srodrigc	 */
2641159451Srodrigc	if (do_mod(ap->off, align) || ap->alen % align)
2642159451Srodrigc		prod = 1;
2643159451Srodrigc	/*
2644159451Srodrigc	 * Set ralen to be the actual requested length in rtextents.
2645159451Srodrigc	 */
2646159451Srodrigc	ralen = ap->alen / mp->m_sb.sb_rextsize;
2647159451Srodrigc	/*
2648159451Srodrigc	 * If the old value was close enough to MAXEXTLEN that
2649159451Srodrigc	 * we rounded up to it, cut it back so it's valid again.
2650159451Srodrigc	 * Note that if it's a really large request (bigger than
2651159451Srodrigc	 * MAXEXTLEN), we don't hear about that number, and can't
2652159451Srodrigc	 * adjust the starting point to match it.
2653159451Srodrigc	 */
2654159451Srodrigc	if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN)
2655159451Srodrigc		ralen = MAXEXTLEN / mp->m_sb.sb_rextsize;
2656159451Srodrigc	/*
2657159451Srodrigc	 * If it's an allocation to an empty file at offset 0,
2658159451Srodrigc	 * pick an extent that will space things out in the rt area.
2659159451Srodrigc	 */
2660159451Srodrigc	if (ap->eof && ap->off == 0) {
2661159451Srodrigc		error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
2662159451Srodrigc		if (error)
2663159451Srodrigc			return error;
2664159451Srodrigc		ap->rval = rtx * mp->m_sb.sb_rextsize;
2665159451Srodrigc	} else {
2666159451Srodrigc		ap->rval = 0;
2667159451Srodrigc	}
2668159451Srodrigc
2669159451Srodrigc	xfs_bmap_adjacent(ap);
2670159451Srodrigc
2671159451Srodrigc	/*
2672159451Srodrigc	 * Realtime allocation, done through xfs_rtallocate_extent.
2673159451Srodrigc	 */
2674159451Srodrigc	atype = ap->rval == 0 ?  XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO;
2675159451Srodrigc	do_div(ap->rval, mp->m_sb.sb_rextsize);
2676159451Srodrigc	rtb = ap->rval;
2677159451Srodrigc	ap->alen = ralen;
2678159451Srodrigc	if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen,
2679159451Srodrigc				&ralen, atype, ap->wasdel, prod, &rtb)))
2680159451Srodrigc		return error;
2681159451Srodrigc	if (rtb == NULLFSBLOCK && prod > 1 &&
2682159451Srodrigc	    (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1,
2683159451Srodrigc					   ap->alen, &ralen, atype,
2684159451Srodrigc					   ap->wasdel, 1, &rtb)))
2685159451Srodrigc		return error;
2686159451Srodrigc	ap->rval = rtb;
2687159451Srodrigc	if (ap->rval != NULLFSBLOCK) {
2688159451Srodrigc		ap->rval *= mp->m_sb.sb_rextsize;
2689159451Srodrigc		ralen *= mp->m_sb.sb_rextsize;
2690159451Srodrigc		ap->alen = ralen;
2691159451Srodrigc		ap->ip->i_d.di_nblocks += ralen;
2692159451Srodrigc		xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
2693159451Srodrigc		if (ap->wasdel)
2694159451Srodrigc			ap->ip->i_delayed_blks -= ralen;
2695159451Srodrigc		/*
2696159451Srodrigc		 * Adjust the disk quota also. This was reserved
2697159451Srodrigc		 * earlier.
2698159451Srodrigc		 */
2699159451Srodrigc		XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
2700159451Srodrigc			ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
2701159451Srodrigc					XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
2702159451Srodrigc	} else {
2703159451Srodrigc		ap->alen = 0;
2704159451Srodrigc	}
2705159451Srodrigc	return 0;
2706159451Srodrigc}
2707159451Srodrigc
2708159451SrodrigcSTATIC int
2709159451Srodrigcxfs_bmap_btalloc(
2710159451Srodrigc	xfs_bmalloca_t	*ap)		/* bmap alloc argument struct */
2711159451Srodrigc{
2712159451Srodrigc	xfs_mount_t	*mp;		/* mount point structure */
2713159451Srodrigc	xfs_alloctype_t	atype = 0;	/* type for allocation routines */
2714159451Srodrigc	xfs_extlen_t	align;		/* minimum allocation alignment */
2715159451Srodrigc	xfs_agnumber_t	ag;
2716159451Srodrigc	xfs_agnumber_t	fb_agno;	/* ag number of ap->firstblock */
2717159451Srodrigc	xfs_agnumber_t	startag;
2718159451Srodrigc	xfs_alloc_arg_t	args;
2719159451Srodrigc	xfs_extlen_t	blen;
2720159451Srodrigc	xfs_extlen_t	delta;
2721159451Srodrigc	xfs_extlen_t	longest;
2722159451Srodrigc	xfs_extlen_t	need;
2723159451Srodrigc	xfs_extlen_t	nextminlen = 0;
2724159451Srodrigc	xfs_perag_t	*pag;
2725159451Srodrigc	int		nullfb;		/* true if ap->firstblock isn't set */
2726159451Srodrigc	int		isaligned;
2727159451Srodrigc	int		notinit;
2728159451Srodrigc	int		tryagain;
2729159451Srodrigc	int		error;
2730159451Srodrigc
2731159451Srodrigc	mp = ap->ip->i_mount;
2732159451Srodrigc	align = (ap->userdata && ap->ip->i_d.di_extsize &&
2733159451Srodrigc		(ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ?
2734159451Srodrigc		ap->ip->i_d.di_extsize : 0;
2735159451Srodrigc	if (unlikely(align)) {
2736159451Srodrigc		error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
2737159451Srodrigc						align, 0, ap->eof, 0, ap->conv,
2738159451Srodrigc						&ap->off, &ap->alen);
2739159451Srodrigc		ASSERT(!error);
2740159451Srodrigc		ASSERT(ap->alen);
2741159451Srodrigc	}
2742159451Srodrigc	nullfb = ap->firstblock == NULLFSBLOCK;
2743159451Srodrigc	fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
2744159451Srodrigc	if (nullfb)
2745159451Srodrigc		ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
2746159451Srodrigc	else
2747159451Srodrigc		ap->rval = ap->firstblock;
2748159451Srodrigc
2749159451Srodrigc	xfs_bmap_adjacent(ap);
2750159451Srodrigc
2751159451Srodrigc	/*
2752153323Srodrigc	 * If allowed, use ap->rval; otherwise must use firstblock since
2753153323Srodrigc	 * it's in the right allocation group.
2754153323Srodrigc	 */
2755159451Srodrigc	if (nullfb || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno)
2756153323Srodrigc		;
2757153323Srodrigc	else
2758153323Srodrigc		ap->rval = ap->firstblock;
2759153323Srodrigc	/*
2760159451Srodrigc	 * Normal allocation, done through xfs_alloc_vextent.
2761153323Srodrigc	 */
2762159451Srodrigc	tryagain = isaligned = 0;
2763159451Srodrigc	args.tp = ap->tp;
2764159451Srodrigc	args.mp = mp;
2765159451Srodrigc	args.fsbno = ap->rval;
2766159451Srodrigc	args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);
2767159451Srodrigc	blen = 0;
2768159451Srodrigc	if (nullfb) {
2769159451Srodrigc		args.type = XFS_ALLOCTYPE_START_BNO;
2770159451Srodrigc		args.total = ap->total;
2771159451Srodrigc		/*
2772159451Srodrigc		 * Find the longest available space.
2773159451Srodrigc		 * We're going to try for the whole allocation at once.
2774159451Srodrigc		 */
2775159451Srodrigc		startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno);
2776159451Srodrigc		notinit = 0;
2777159451Srodrigc		down_read(&mp->m_peraglock);
2778159451Srodrigc		while (blen < ap->alen) {
2779159451Srodrigc			pag = &mp->m_perag[ag];
2780159451Srodrigc			if (!pag->pagf_init &&
2781159451Srodrigc			    (error = xfs_alloc_pagf_init(mp, args.tp,
2782159451Srodrigc				    ag, XFS_ALLOC_FLAG_TRYLOCK))) {
2783159451Srodrigc				up_read(&mp->m_peraglock);
2784159451Srodrigc				return error;
2785159451Srodrigc			}
2786153323Srodrigc			/*
2787159451Srodrigc			 * See xfs_alloc_fix_freelist...
2788153323Srodrigc			 */
2789159451Srodrigc			if (pag->pagf_init) {
2790159451Srodrigc				need = XFS_MIN_FREELIST_PAG(pag, mp);
2791159451Srodrigc				delta = need > pag->pagf_flcount ?
2792159451Srodrigc					need - pag->pagf_flcount : 0;
2793159451Srodrigc				longest = (pag->pagf_longest > delta) ?
2794159451Srodrigc					(pag->pagf_longest - delta) :
2795159451Srodrigc					(pag->pagf_flcount > 0 ||
2796159451Srodrigc					 pag->pagf_longest > 0);
2797159451Srodrigc				if (blen < longest)
2798159451Srodrigc					blen = longest;
2799159451Srodrigc			} else
2800159451Srodrigc				notinit = 1;
2801159451Srodrigc			if (++ag == mp->m_sb.sb_agcount)
2802159451Srodrigc				ag = 0;
2803159451Srodrigc			if (ag == startag)
2804159451Srodrigc				break;
2805159451Srodrigc		}
2806159451Srodrigc		up_read(&mp->m_peraglock);
2807159451Srodrigc		/*
2808159451Srodrigc		 * Since the above loop did a BUF_TRYLOCK, it is
2809159451Srodrigc		 * possible that there is space for this request.
2810159451Srodrigc		 */
2811159451Srodrigc		if (notinit || blen < ap->minlen)
2812159451Srodrigc			args.minlen = ap->minlen;
2813159451Srodrigc		/*
2814159451Srodrigc		 * If the best seen length is less than the request
2815159451Srodrigc		 * length, use the best as the minimum.
2816159451Srodrigc		 */
2817159451Srodrigc		else if (blen < ap->alen)
2818159451Srodrigc			args.minlen = blen;
2819159451Srodrigc		/*
2820159451Srodrigc		 * Otherwise we've seen an extent as big as alen,
2821159451Srodrigc		 * use that as the minimum.
2822159451Srodrigc		 */
2823159451Srodrigc		else
2824159451Srodrigc			args.minlen = ap->alen;
2825159451Srodrigc	} else if (ap->low) {
2826159451Srodrigc		args.type = XFS_ALLOCTYPE_FIRST_AG;
2827159451Srodrigc		args.total = args.minlen = ap->minlen;
2828159451Srodrigc	} else {
2829159451Srodrigc		args.type = XFS_ALLOCTYPE_NEAR_BNO;
2830159451Srodrigc		args.total = ap->total;
2831159451Srodrigc		args.minlen = ap->minlen;
2832153323Srodrigc	}
2833159451Srodrigc	if (unlikely(ap->userdata && ap->ip->i_d.di_extsize &&
2834159451Srodrigc		    (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) {
2835159451Srodrigc		args.prod = ap->ip->i_d.di_extsize;
2836159451Srodrigc		if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod)))
2837159451Srodrigc			args.mod = (xfs_extlen_t)(args.prod - args.mod);
2838159451Srodrigc	} else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) {
2839159451Srodrigc		args.prod = 1;
2840159451Srodrigc		args.mod = 0;
2841159451Srodrigc	} else {
2842159451Srodrigc		args.prod = NBPP >> mp->m_sb.sb_blocklog;
2843159451Srodrigc		if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod))))
2844159451Srodrigc			args.mod = (xfs_extlen_t)(args.prod - args.mod);
2845159451Srodrigc	}
2846153323Srodrigc	/*
2847159451Srodrigc	 * If we are not low on available data blocks, and the
2848159451Srodrigc	 * underlying logical volume manager is a stripe, and
2849159451Srodrigc	 * the file offset is zero then try to allocate data
2850159451Srodrigc	 * blocks on stripe unit boundary.
2851159451Srodrigc	 * NOTE: ap->aeof is only set if the allocation length
2852159451Srodrigc	 * is >= the stripe unit and the allocation offset is
2853159451Srodrigc	 * at the end of file.
2854153323Srodrigc	 */
2855159451Srodrigc	if (!ap->low && ap->aeof) {
2856159451Srodrigc		if (!ap->off) {
2857159451Srodrigc			args.alignment = mp->m_dalign;
2858159451Srodrigc			atype = args.type;
2859159451Srodrigc			isaligned = 1;
2860153323Srodrigc			/*
2861159451Srodrigc			 * Adjust for alignment
2862153323Srodrigc			 */
2863159451Srodrigc			if (blen > args.alignment && blen <= ap->alen)
2864159451Srodrigc				args.minlen = blen - args.alignment;
2865159451Srodrigc			args.minalignslop = 0;
2866159451Srodrigc		} else {
2867153323Srodrigc			/*
2868159451Srodrigc			 * First try an exact bno allocation.
2869159451Srodrigc			 * If it fails then do a near or start bno
2870159451Srodrigc			 * allocation with alignment turned on.
2871153323Srodrigc			 */
2872159451Srodrigc			atype = args.type;
2873159451Srodrigc			tryagain = 1;
2874159451Srodrigc			args.type = XFS_ALLOCTYPE_THIS_BNO;
2875159451Srodrigc			args.alignment = 1;
2876153323Srodrigc			/*
2877159451Srodrigc			 * Compute the minlen+alignment for the
2878159451Srodrigc			 * next case.  Set slop so that the value
2879159451Srodrigc			 * of minlen+alignment+slop doesn't go up
2880159451Srodrigc			 * between the calls.
2881153323Srodrigc			 */
2882159451Srodrigc			if (blen > mp->m_dalign && blen <= ap->alen)
2883159451Srodrigc				nextminlen = blen - mp->m_dalign;
2884153323Srodrigc			else
2885159451Srodrigc				nextminlen = args.minlen;
2886159451Srodrigc			if (nextminlen + mp->m_dalign > args.minlen + 1)
2887159451Srodrigc				args.minalignslop =
2888159451Srodrigc					nextminlen + mp->m_dalign -
2889159451Srodrigc					args.minlen - 1;
2890159451Srodrigc			else
2891159451Srodrigc				args.minalignslop = 0;
2892153323Srodrigc		}
2893159451Srodrigc	} else {
2894159451Srodrigc		args.alignment = 1;
2895159451Srodrigc		args.minalignslop = 0;
2896159451Srodrigc	}
2897159451Srodrigc	args.minleft = ap->minleft;
2898159451Srodrigc	args.wasdel = ap->wasdel;
2899159451Srodrigc	args.isfl = 0;
2900159451Srodrigc	args.userdata = ap->userdata;
2901159451Srodrigc	if ((error = xfs_alloc_vextent(&args)))
2902159451Srodrigc		return error;
2903159451Srodrigc	if (tryagain && args.fsbno == NULLFSBLOCK) {
2904153323Srodrigc		/*
2905159451Srodrigc		 * Exact allocation failed. Now try with alignment
2906159451Srodrigc		 * turned on.
2907153323Srodrigc		 */
2908159451Srodrigc		args.type = atype;
2909159451Srodrigc		args.fsbno = ap->rval;
2910159451Srodrigc		args.alignment = mp->m_dalign;
2911159451Srodrigc		args.minlen = nextminlen;
2912159451Srodrigc		args.minalignslop = 0;
2913159451Srodrigc		isaligned = 1;
2914153323Srodrigc		if ((error = xfs_alloc_vextent(&args)))
2915153323Srodrigc			return error;
2916153323Srodrigc	}
2917159451Srodrigc	if (isaligned && args.fsbno == NULLFSBLOCK) {
2918159451Srodrigc		/*
2919159451Srodrigc		 * allocation failed, so turn off alignment and
2920159451Srodrigc		 * try again.
2921159451Srodrigc		 */
2922159451Srodrigc		args.type = atype;
2923159451Srodrigc		args.fsbno = ap->rval;
2924159451Srodrigc		args.alignment = 0;
2925159451Srodrigc		if ((error = xfs_alloc_vextent(&args)))
2926159451Srodrigc			return error;
2927159451Srodrigc	}
2928159451Srodrigc	if (args.fsbno == NULLFSBLOCK && nullfb &&
2929159451Srodrigc	    args.minlen > ap->minlen) {
2930159451Srodrigc		args.minlen = ap->minlen;
2931159451Srodrigc		args.type = XFS_ALLOCTYPE_START_BNO;
2932159451Srodrigc		args.fsbno = ap->rval;
2933159451Srodrigc		if ((error = xfs_alloc_vextent(&args)))
2934159451Srodrigc			return error;
2935159451Srodrigc	}
2936159451Srodrigc	if (args.fsbno == NULLFSBLOCK && nullfb) {
2937159451Srodrigc		args.fsbno = 0;
2938159451Srodrigc		args.type = XFS_ALLOCTYPE_FIRST_AG;
2939159451Srodrigc		args.total = ap->minlen;
2940159451Srodrigc		args.minleft = 0;
2941159451Srodrigc		if ((error = xfs_alloc_vextent(&args)))
2942159451Srodrigc			return error;
2943159451Srodrigc		ap->low = 1;
2944159451Srodrigc	}
2945159451Srodrigc	if (args.fsbno != NULLFSBLOCK) {
2946159451Srodrigc		ap->firstblock = ap->rval = args.fsbno;
2947159451Srodrigc		ASSERT(nullfb || fb_agno == args.agno ||
2948159451Srodrigc		       (ap->low && fb_agno < args.agno));
2949159451Srodrigc		ap->alen = args.len;
2950159451Srodrigc		ap->ip->i_d.di_nblocks += args.len;
2951159451Srodrigc		xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
2952159451Srodrigc		if (ap->wasdel)
2953159451Srodrigc			ap->ip->i_delayed_blks -= args.len;
2954159451Srodrigc		/*
2955159451Srodrigc		 * Adjust the disk quota also. This was reserved
2956159451Srodrigc		 * earlier.
2957159451Srodrigc		 */
2958159451Srodrigc		XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
2959159451Srodrigc			ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT :
2960159451Srodrigc					XFS_TRANS_DQ_BCOUNT,
2961159451Srodrigc			(long) args.len);
2962159451Srodrigc	} else {
2963159451Srodrigc		ap->rval = NULLFSBLOCK;
2964159451Srodrigc		ap->alen = 0;
2965159451Srodrigc	}
2966153323Srodrigc	return 0;
2967153323Srodrigc}
2968153323Srodrigc
2969153323Srodrigc/*
2970159451Srodrigc * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
2971159451Srodrigc * It figures out where to ask the underlying allocator to put the new extent.
2972159451Srodrigc */
2973159451SrodrigcSTATIC int
2974159451Srodrigcxfs_bmap_alloc(
2975159451Srodrigc	xfs_bmalloca_t	*ap)		/* bmap alloc argument struct */
2976159451Srodrigc{
2977159451Srodrigc	if ((ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata)
2978159451Srodrigc		return xfs_bmap_rtalloc(ap);
2979159451Srodrigc	return xfs_bmap_btalloc(ap);
2980159451Srodrigc}
2981159451Srodrigc
2982159451Srodrigc/*
2983153323Srodrigc * Transform a btree format file with only one leaf node, where the
2984153323Srodrigc * extents list will fit in the inode, into an extents format file.
2985159451Srodrigc * Since the file extents are already in-core, all we have to do is
2986153323Srodrigc * give up the space for the btree root and pitch the leaf block.
2987153323Srodrigc */
2988153323SrodrigcSTATIC int				/* error */
2989153323Srodrigcxfs_bmap_btree_to_extents(
2990153323Srodrigc	xfs_trans_t		*tp,	/* transaction pointer */
2991153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
2992153323Srodrigc	xfs_btree_cur_t		*cur,	/* btree cursor */
2993153323Srodrigc	int			*logflagsp, /* inode logging flags */
2994153323Srodrigc	int			whichfork)  /* data or attr fork */
2995153323Srodrigc{
2996153323Srodrigc	/* REFERENCED */
2997153323Srodrigc	xfs_bmbt_block_t	*cblock;/* child btree block */
2998153323Srodrigc	xfs_fsblock_t		cbno;	/* child block number */
2999153323Srodrigc	xfs_buf_t		*cbp;	/* child block's buffer */
3000153323Srodrigc	int			error;	/* error return value */
3001153323Srodrigc	xfs_ifork_t		*ifp;	/* inode fork data */
3002153323Srodrigc	xfs_mount_t		*mp;	/* mount point structure */
3003153323Srodrigc	xfs_bmbt_ptr_t		*pp;	/* ptr to block address */
3004153323Srodrigc	xfs_bmbt_block_t	*rblock;/* root btree block */
3005153323Srodrigc
3006153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3007153323Srodrigc	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3008153323Srodrigc	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
3009153323Srodrigc	rblock = ifp->if_broot;
3010159451Srodrigc	ASSERT(be16_to_cpu(rblock->bb_level) == 1);
3011159451Srodrigc	ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
3012153323Srodrigc	ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1);
3013153323Srodrigc	mp = ip->i_mount;
3014153323Srodrigc	pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes);
3015153323Srodrigc	*logflagsp = 0;
3016153323Srodrigc#ifdef DEBUG
3017153323Srodrigc	if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1)))
3018153323Srodrigc		return error;
3019153323Srodrigc#endif
3020153323Srodrigc	cbno = INT_GET(*pp, ARCH_CONVERT);
3021153323Srodrigc	if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp,
3022153323Srodrigc			XFS_BMAP_BTREE_REF)))
3023153323Srodrigc		return error;
3024153323Srodrigc	cblock = XFS_BUF_TO_BMBT_BLOCK(cbp);
3025153323Srodrigc	if ((error = xfs_btree_check_lblock(cur, cblock, 0, cbp)))
3026153323Srodrigc		return error;
3027153323Srodrigc	xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
3028153323Srodrigc	ip->i_d.di_nblocks--;
3029153323Srodrigc	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
3030153323Srodrigc	xfs_trans_binval(tp, cbp);
3031153323Srodrigc	if (cur->bc_bufs[0] == cbp)
3032153323Srodrigc		cur->bc_bufs[0] = NULL;
3033153323Srodrigc	xfs_iroot_realloc(ip, -1, whichfork);
3034153323Srodrigc	ASSERT(ifp->if_broot == NULL);
3035153323Srodrigc	ASSERT((ifp->if_flags & XFS_IFBROOT) == 0);
3036153323Srodrigc	XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
3037153323Srodrigc	*logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
3038153323Srodrigc	return 0;
3039153323Srodrigc}
3040153323Srodrigc
3041153323Srodrigc/*
3042159451Srodrigc * Called by xfs_bmapi to update file extent records and the btree
3043153323Srodrigc * after removing space (or undoing a delayed allocation).
3044153323Srodrigc */
3045153323SrodrigcSTATIC int				/* error */
3046153323Srodrigcxfs_bmap_del_extent(
3047153323Srodrigc	xfs_inode_t		*ip,	/* incore inode pointer */
3048153323Srodrigc	xfs_trans_t		*tp,	/* current transaction pointer */
3049153323Srodrigc	xfs_extnum_t		idx,	/* extent number to update/delete */
3050153323Srodrigc	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
3051153323Srodrigc	xfs_btree_cur_t		*cur,	/* if null, not a btree */
3052159451Srodrigc	xfs_bmbt_irec_t		*del,	/* data to remove from extents */
3053153323Srodrigc	int			*logflagsp, /* inode logging flags */
3054159451Srodrigc	xfs_extdelta_t		*delta, /* Change made to incore extents */
3055153323Srodrigc	int			whichfork, /* data or attr fork */
3056153323Srodrigc	int			rsvd)	/* OK to allocate reserved blocks */
3057153323Srodrigc{
3058153323Srodrigc	xfs_filblks_t		da_new;	/* new delay-alloc indirect blocks */
3059153323Srodrigc	xfs_filblks_t		da_old;	/* old delay-alloc indirect blocks */
3060153323Srodrigc	xfs_fsblock_t		del_endblock=0;	/* first block past del */
3061153323Srodrigc	xfs_fileoff_t		del_endoff;	/* first offset past del */
3062153323Srodrigc	int			delay;	/* current block is delayed allocated */
3063153323Srodrigc	int			do_fx;	/* free extent at end of routine */
3064153323Srodrigc	xfs_bmbt_rec_t		*ep;	/* current extent entry pointer */
3065153323Srodrigc	int			error;	/* error return value */
3066153323Srodrigc	int			flags;	/* inode logging flags */
3067153323Srodrigc#ifdef XFS_BMAP_TRACE
3068153323Srodrigc	static char		fname[] = "xfs_bmap_del_extent";
3069153323Srodrigc#endif
3070153323Srodrigc	xfs_bmbt_irec_t		got;	/* current extent entry */
3071153323Srodrigc	xfs_fileoff_t		got_endoff;	/* first offset past got */
3072153323Srodrigc	int			i;	/* temp state */
3073153323Srodrigc	xfs_ifork_t		*ifp;	/* inode fork pointer */
3074153323Srodrigc	xfs_mount_t		*mp;	/* mount structure */
3075153323Srodrigc	xfs_filblks_t		nblks;	/* quota/sb block count */
3076153323Srodrigc	xfs_bmbt_irec_t		new;	/* new record to be inserted */
3077153323Srodrigc	/* REFERENCED */
3078153323Srodrigc	uint			qfield;	/* quota field to update */
3079153323Srodrigc	xfs_filblks_t		temp;	/* for indirect length calculations */
3080153323Srodrigc	xfs_filblks_t		temp2;	/* for indirect length calculations */
3081153323Srodrigc
3082153323Srodrigc	XFS_STATS_INC(xs_del_exlist);
3083153323Srodrigc	mp = ip->i_mount;
3084153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3085159451Srodrigc	ASSERT((idx >= 0) && (idx < ifp->if_bytes /
3086159451Srodrigc		(uint)sizeof(xfs_bmbt_rec_t)));
3087153323Srodrigc	ASSERT(del->br_blockcount > 0);
3088159451Srodrigc	ep = xfs_iext_get_ext(ifp, idx);
3089153323Srodrigc	xfs_bmbt_get_all(ep, &got);
3090153323Srodrigc	ASSERT(got.br_startoff <= del->br_startoff);
3091153323Srodrigc	del_endoff = del->br_startoff + del->br_blockcount;
3092153323Srodrigc	got_endoff = got.br_startoff + got.br_blockcount;
3093153323Srodrigc	ASSERT(got_endoff >= del_endoff);
3094153323Srodrigc	delay = ISNULLSTARTBLOCK(got.br_startblock);
3095153323Srodrigc	ASSERT(ISNULLSTARTBLOCK(del->br_startblock) == delay);
3096153323Srodrigc	flags = 0;
3097153323Srodrigc	qfield = 0;
3098153323Srodrigc	error = 0;
3099153323Srodrigc	/*
3100153323Srodrigc	 * If deleting a real allocation, must free up the disk space.
3101153323Srodrigc	 */
3102153323Srodrigc	if (!delay) {
3103153323Srodrigc		flags = XFS_ILOG_CORE;
3104153323Srodrigc		/*
3105153323Srodrigc		 * Realtime allocation.  Free it and record di_nblocks update.
3106153323Srodrigc		 */
3107153323Srodrigc		if (whichfork == XFS_DATA_FORK &&
3108153323Srodrigc		    (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
3109153323Srodrigc			xfs_fsblock_t	bno;
3110153323Srodrigc			xfs_filblks_t	len;
3111153323Srodrigc
3112153323Srodrigc			ASSERT(do_mod(del->br_blockcount,
3113153323Srodrigc				      mp->m_sb.sb_rextsize) == 0);
3114153323Srodrigc			ASSERT(do_mod(del->br_startblock,
3115153323Srodrigc				      mp->m_sb.sb_rextsize) == 0);
3116153323Srodrigc			bno = del->br_startblock;
3117153323Srodrigc			len = del->br_blockcount;
3118153323Srodrigc			do_div(bno, mp->m_sb.sb_rextsize);
3119153323Srodrigc			do_div(len, mp->m_sb.sb_rextsize);
3120153323Srodrigc			if ((error = xfs_rtfree_extent(ip->i_transp, bno,
3121153323Srodrigc					(xfs_extlen_t)len)))
3122153323Srodrigc				goto done;
3123153323Srodrigc			do_fx = 0;
3124153323Srodrigc			nblks = len * mp->m_sb.sb_rextsize;
3125153323Srodrigc			qfield = XFS_TRANS_DQ_RTBCOUNT;
3126153323Srodrigc		}
3127153323Srodrigc		/*
3128153323Srodrigc		 * Ordinary allocation.
3129153323Srodrigc		 */
3130153323Srodrigc		else {
3131153323Srodrigc			do_fx = 1;
3132153323Srodrigc			nblks = del->br_blockcount;
3133153323Srodrigc			qfield = XFS_TRANS_DQ_BCOUNT;
3134153323Srodrigc		}
3135153323Srodrigc		/*
3136153323Srodrigc		 * Set up del_endblock and cur for later.
3137153323Srodrigc		 */
3138153323Srodrigc		del_endblock = del->br_startblock + del->br_blockcount;
3139153323Srodrigc		if (cur) {
3140153323Srodrigc			if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff,
3141153323Srodrigc					got.br_startblock, got.br_blockcount,
3142153323Srodrigc					&i)))
3143153323Srodrigc				goto done;
3144153323Srodrigc			ASSERT(i == 1);
3145153323Srodrigc		}
3146153323Srodrigc		da_old = da_new = 0;
3147153323Srodrigc	} else {
3148153323Srodrigc		da_old = STARTBLOCKVAL(got.br_startblock);
3149153323Srodrigc		da_new = 0;
3150153323Srodrigc		nblks = 0;
3151153323Srodrigc		do_fx = 0;
3152153323Srodrigc	}
3153153323Srodrigc	/*
3154153323Srodrigc	 * Set flag value to use in switch statement.
3155153323Srodrigc	 * Left-contig is 2, right-contig is 1.
3156153323Srodrigc	 */
3157153323Srodrigc	switch (((got.br_startoff == del->br_startoff) << 1) |
3158153323Srodrigc		(got_endoff == del_endoff)) {
3159153323Srodrigc	case 3:
3160153323Srodrigc		/*
3161153323Srodrigc		 * Matches the whole extent.  Delete the entry.
3162153323Srodrigc		 */
3163153323Srodrigc		xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork);
3164159451Srodrigc		xfs_iext_remove(ifp, idx, 1);
3165153323Srodrigc		ifp->if_lastex = idx;
3166153323Srodrigc		if (delay)
3167153323Srodrigc			break;
3168153323Srodrigc		XFS_IFORK_NEXT_SET(ip, whichfork,
3169153323Srodrigc			XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
3170153323Srodrigc		flags |= XFS_ILOG_CORE;
3171153323Srodrigc		if (!cur) {
3172153323Srodrigc			flags |= XFS_ILOG_FEXT(whichfork);
3173153323Srodrigc			break;
3174153323Srodrigc		}
3175153323Srodrigc		if ((error = xfs_bmbt_delete(cur, &i)))
3176153323Srodrigc			goto done;
3177153323Srodrigc		ASSERT(i == 1);
3178153323Srodrigc		break;
3179153323Srodrigc
3180153323Srodrigc	case 2:
3181153323Srodrigc		/*
3182153323Srodrigc		 * Deleting the first part of the extent.
3183153323Srodrigc		 */
3184153323Srodrigc		xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork);
3185153323Srodrigc		xfs_bmbt_set_startoff(ep, del_endoff);
3186153323Srodrigc		temp = got.br_blockcount - del->br_blockcount;
3187153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
3188153323Srodrigc		ifp->if_lastex = idx;
3189153323Srodrigc		if (delay) {
3190153323Srodrigc			temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
3191153323Srodrigc				da_old);
3192153323Srodrigc			xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
3193153323Srodrigc			xfs_bmap_trace_post_update(fname, "2", ip, idx,
3194153323Srodrigc				whichfork);
3195153323Srodrigc			da_new = temp;
3196153323Srodrigc			break;
3197153323Srodrigc		}
3198153323Srodrigc		xfs_bmbt_set_startblock(ep, del_endblock);
3199153323Srodrigc		xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork);
3200153323Srodrigc		if (!cur) {
3201153323Srodrigc			flags |= XFS_ILOG_FEXT(whichfork);
3202153323Srodrigc			break;
3203153323Srodrigc		}
3204153323Srodrigc		if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock,
3205153323Srodrigc				got.br_blockcount - del->br_blockcount,
3206153323Srodrigc				got.br_state)))
3207153323Srodrigc			goto done;
3208153323Srodrigc		break;
3209153323Srodrigc
3210153323Srodrigc	case 1:
3211153323Srodrigc		/*
3212153323Srodrigc		 * Deleting the last part of the extent.
3213153323Srodrigc		 */
3214153323Srodrigc		temp = got.br_blockcount - del->br_blockcount;
3215153323Srodrigc		xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork);
3216153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
3217153323Srodrigc		ifp->if_lastex = idx;
3218153323Srodrigc		if (delay) {
3219153323Srodrigc			temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
3220153323Srodrigc				da_old);
3221153323Srodrigc			xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
3222153323Srodrigc			xfs_bmap_trace_post_update(fname, "1", ip, idx,
3223153323Srodrigc				whichfork);
3224153323Srodrigc			da_new = temp;
3225153323Srodrigc			break;
3226153323Srodrigc		}
3227153323Srodrigc		xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork);
3228153323Srodrigc		if (!cur) {
3229153323Srodrigc			flags |= XFS_ILOG_FEXT(whichfork);
3230153323Srodrigc			break;
3231153323Srodrigc		}
3232153323Srodrigc		if ((error = xfs_bmbt_update(cur, got.br_startoff,
3233153323Srodrigc				got.br_startblock,
3234153323Srodrigc				got.br_blockcount - del->br_blockcount,
3235153323Srodrigc				got.br_state)))
3236153323Srodrigc			goto done;
3237153323Srodrigc		break;
3238153323Srodrigc
3239153323Srodrigc	case 0:
3240153323Srodrigc		/*
3241153323Srodrigc		 * Deleting the middle of the extent.
3242153323Srodrigc		 */
3243153323Srodrigc		temp = del->br_startoff - got.br_startoff;
3244153323Srodrigc		xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork);
3245153323Srodrigc		xfs_bmbt_set_blockcount(ep, temp);
3246153323Srodrigc		new.br_startoff = del_endoff;
3247153323Srodrigc		temp2 = got_endoff - del_endoff;
3248153323Srodrigc		new.br_blockcount = temp2;
3249153323Srodrigc		new.br_state = got.br_state;
3250153323Srodrigc		if (!delay) {
3251153323Srodrigc			new.br_startblock = del_endblock;
3252153323Srodrigc			flags |= XFS_ILOG_CORE;
3253153323Srodrigc			if (cur) {
3254153323Srodrigc				if ((error = xfs_bmbt_update(cur,
3255153323Srodrigc						got.br_startoff,
3256153323Srodrigc						got.br_startblock, temp,
3257153323Srodrigc						got.br_state)))
3258153323Srodrigc					goto done;
3259153323Srodrigc				if ((error = xfs_bmbt_increment(cur, 0, &i)))
3260153323Srodrigc					goto done;
3261153323Srodrigc				cur->bc_rec.b = new;
3262153323Srodrigc				error = xfs_bmbt_insert(cur, &i);
3263153323Srodrigc				if (error && error != ENOSPC)
3264153323Srodrigc					goto done;
3265153323Srodrigc				/*
3266153323Srodrigc				 * If get no-space back from btree insert,
3267153323Srodrigc				 * it tried a split, and we have a zero
3268153323Srodrigc				 * block reservation.
3269153323Srodrigc				 * Fix up our state and return the error.
3270153323Srodrigc				 */
3271153323Srodrigc				if (error == ENOSPC) {
3272153323Srodrigc					/*
3273153323Srodrigc					 * Reset the cursor, don't trust
3274153323Srodrigc					 * it after any insert operation.
3275153323Srodrigc					 */
3276153323Srodrigc					if ((error = xfs_bmbt_lookup_eq(cur,
3277153323Srodrigc							got.br_startoff,
3278153323Srodrigc							got.br_startblock,
3279153323Srodrigc							temp, &i)))
3280153323Srodrigc						goto done;
3281153323Srodrigc					ASSERT(i == 1);
3282153323Srodrigc					/*
3283153323Srodrigc					 * Update the btree record back
3284153323Srodrigc					 * to the original value.
3285153323Srodrigc					 */
3286153323Srodrigc					if ((error = xfs_bmbt_update(cur,
3287153323Srodrigc							got.br_startoff,
3288153323Srodrigc							got.br_startblock,
3289153323Srodrigc							got.br_blockcount,
3290153323Srodrigc							got.br_state)))
3291153323Srodrigc						goto done;
3292153323Srodrigc					/*
3293153323Srodrigc					 * Reset the extent record back
3294153323Srodrigc					 * to the original value.
3295153323Srodrigc					 */
3296153323Srodrigc					xfs_bmbt_set_blockcount(ep,
3297153323Srodrigc						got.br_blockcount);
3298153323Srodrigc					flags = 0;
3299153323Srodrigc					error = XFS_ERROR(ENOSPC);
3300153323Srodrigc					goto done;
3301153323Srodrigc				}
3302153323Srodrigc				ASSERT(i == 1);
3303153323Srodrigc			} else
3304153323Srodrigc				flags |= XFS_ILOG_FEXT(whichfork);
3305153323Srodrigc			XFS_IFORK_NEXT_SET(ip, whichfork,
3306153323Srodrigc				XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
3307153323Srodrigc		} else {
3308153323Srodrigc			ASSERT(whichfork == XFS_DATA_FORK);
3309153323Srodrigc			temp = xfs_bmap_worst_indlen(ip, temp);
3310153323Srodrigc			xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
3311153323Srodrigc			temp2 = xfs_bmap_worst_indlen(ip, temp2);
3312153323Srodrigc			new.br_startblock = NULLSTARTBLOCK((int)temp2);
3313153323Srodrigc			da_new = temp + temp2;
3314153323Srodrigc			while (da_new > da_old) {
3315153323Srodrigc				if (temp) {
3316153323Srodrigc					temp--;
3317153323Srodrigc					da_new--;
3318153323Srodrigc					xfs_bmbt_set_startblock(ep,
3319153323Srodrigc						NULLSTARTBLOCK((int)temp));
3320153323Srodrigc				}
3321153323Srodrigc				if (da_new == da_old)
3322153323Srodrigc					break;
3323153323Srodrigc				if (temp2) {
3324153323Srodrigc					temp2--;
3325153323Srodrigc					da_new--;
3326153323Srodrigc					new.br_startblock =
3327153323Srodrigc						NULLSTARTBLOCK((int)temp2);
3328153323Srodrigc				}
3329153323Srodrigc			}
3330153323Srodrigc		}
3331153323Srodrigc		xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork);
3332153323Srodrigc		xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL,
3333153323Srodrigc			whichfork);
3334159451Srodrigc		xfs_iext_insert(ifp, idx + 1, 1, &new);
3335153323Srodrigc		ifp->if_lastex = idx + 1;
3336153323Srodrigc		break;
3337153323Srodrigc	}
3338153323Srodrigc	/*
3339153323Srodrigc	 * If we need to, add to list of extents to delete.
3340153323Srodrigc	 */
3341153323Srodrigc	if (do_fx)
3342153323Srodrigc		xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist,
3343153323Srodrigc			mp);
3344153323Srodrigc	/*
3345153323Srodrigc	 * Adjust inode # blocks in the file.
3346153323Srodrigc	 */
3347153323Srodrigc	if (nblks)
3348153323Srodrigc		ip->i_d.di_nblocks -= nblks;
3349153323Srodrigc	/*
3350153323Srodrigc	 * Adjust quota data.
3351153323Srodrigc	 */
3352153323Srodrigc	if (qfield)
3353153323Srodrigc		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, qfield, (long)-nblks);
3354153323Srodrigc
3355153323Srodrigc	/*
3356153323Srodrigc	 * Account for change in delayed indirect blocks.
3357153323Srodrigc	 * Nothing to do for disk quota accounting here.
3358153323Srodrigc	 */
3359153323Srodrigc	ASSERT(da_old >= da_new);
3360153323Srodrigc	if (da_old > da_new)
3361153323Srodrigc		xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new),
3362153323Srodrigc			rsvd);
3363159451Srodrigc	if (delta) {
3364159451Srodrigc		/* DELTA: report the original extent. */
3365159451Srodrigc		if (delta->xed_startoff > got.br_startoff)
3366159451Srodrigc			delta->xed_startoff = got.br_startoff;
3367159451Srodrigc		if (delta->xed_blockcount < got.br_startoff+got.br_blockcount)
3368159451Srodrigc			delta->xed_blockcount = got.br_startoff +
3369159451Srodrigc							got.br_blockcount;
3370159451Srodrigc	}
3371153323Srodrigcdone:
3372153323Srodrigc	*logflagsp = flags;
3373153323Srodrigc	return error;
3374153323Srodrigc}
3375153323Srodrigc
3376153323Srodrigc/*
3377153323Srodrigc * Remove the entry "free" from the free item list.  Prev points to the
3378153323Srodrigc * previous entry, unless "free" is the head of the list.
3379153323Srodrigc */
3380153323SrodrigcSTATIC void
3381153323Srodrigcxfs_bmap_del_free(
3382153323Srodrigc	xfs_bmap_free_t		*flist,	/* free item list header */
3383153323Srodrigc	xfs_bmap_free_item_t	*prev,	/* previous item on list, if any */
3384153323Srodrigc	xfs_bmap_free_item_t	*free)	/* list item to be freed */
3385153323Srodrigc{
3386153323Srodrigc	if (prev)
3387153323Srodrigc		prev->xbfi_next = free->xbfi_next;
3388153323Srodrigc	else
3389153323Srodrigc		flist->xbf_first = free->xbfi_next;
3390153323Srodrigc	flist->xbf_count--;
3391153323Srodrigc	kmem_zone_free(xfs_bmap_free_item_zone, free);
3392153323Srodrigc}
3393153323Srodrigc
3394153323Srodrigc/*
3395153323Srodrigc * Convert an extents-format file into a btree-format file.
3396153323Srodrigc * The new file will have a root block (in the inode) and a single child block.
3397153323Srodrigc */
3398153323SrodrigcSTATIC int					/* error */
3399153323Srodrigcxfs_bmap_extents_to_btree(
3400153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
3401153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
3402153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first-block-allocated */
3403153323Srodrigc	xfs_bmap_free_t		*flist,		/* blocks freed in xaction */
3404153323Srodrigc	xfs_btree_cur_t		**curp,		/* cursor returned to caller */
3405153323Srodrigc	int			wasdel,		/* converting a delayed alloc */
3406153323Srodrigc	int			*logflagsp,	/* inode logging flags */
3407153323Srodrigc	int			whichfork)	/* data or attr fork */
3408153323Srodrigc{
3409153323Srodrigc	xfs_bmbt_block_t	*ablock;	/* allocated (child) bt block */
3410153323Srodrigc	xfs_buf_t		*abp;		/* buffer for ablock */
3411153323Srodrigc	xfs_alloc_arg_t		args;		/* allocation arguments */
3412153323Srodrigc	xfs_bmbt_rec_t		*arp;		/* child record pointer */
3413153323Srodrigc	xfs_bmbt_block_t	*block;		/* btree root block */
3414153323Srodrigc	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
3415159451Srodrigc	xfs_bmbt_rec_t		*ep;		/* extent record pointer */
3416153323Srodrigc	int			error;		/* error return value */
3417159451Srodrigc	xfs_extnum_t		i, cnt;		/* extent record index */
3418153323Srodrigc	xfs_ifork_t		*ifp;		/* inode fork pointer */
3419153323Srodrigc	xfs_bmbt_key_t		*kp;		/* root block key pointer */
3420153323Srodrigc	xfs_mount_t		*mp;		/* mount structure */
3421159451Srodrigc	xfs_extnum_t		nextents;	/* number of file extents */
3422153323Srodrigc	xfs_bmbt_ptr_t		*pp;		/* root block address pointer */
3423153323Srodrigc
3424153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3425153323Srodrigc	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS);
3426153323Srodrigc	ASSERT(ifp->if_ext_max ==
3427153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
3428153323Srodrigc	/*
3429153323Srodrigc	 * Make space in the inode incore.
3430153323Srodrigc	 */
3431153323Srodrigc	xfs_iroot_realloc(ip, 1, whichfork);
3432153323Srodrigc	ifp->if_flags |= XFS_IFBROOT;
3433153323Srodrigc	/*
3434153323Srodrigc	 * Fill in the root.
3435153323Srodrigc	 */
3436153323Srodrigc	block = ifp->if_broot;
3437159451Srodrigc	block->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
3438159451Srodrigc	block->bb_level = cpu_to_be16(1);
3439159451Srodrigc	block->bb_numrecs = cpu_to_be16(1);
3440159451Srodrigc	block->bb_leftsib = cpu_to_be64(NULLDFSBNO);
3441159451Srodrigc	block->bb_rightsib = cpu_to_be64(NULLDFSBNO);
3442153323Srodrigc	/*
3443153323Srodrigc	 * Need a cursor.  Can't allocate until bb_level is filled in.
3444153323Srodrigc	 */
3445153323Srodrigc	mp = ip->i_mount;
3446153323Srodrigc	cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
3447153323Srodrigc		whichfork);
3448153323Srodrigc	cur->bc_private.b.firstblock = *firstblock;
3449153323Srodrigc	cur->bc_private.b.flist = flist;
3450153323Srodrigc	cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
3451153323Srodrigc	/*
3452153323Srodrigc	 * Convert to a btree with two levels, one record in root.
3453153323Srodrigc	 */
3454153323Srodrigc	XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE);
3455153323Srodrigc	args.tp = tp;
3456153323Srodrigc	args.mp = mp;
3457153323Srodrigc	if (*firstblock == NULLFSBLOCK) {
3458153323Srodrigc		args.type = XFS_ALLOCTYPE_START_BNO;
3459153323Srodrigc		args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
3460153323Srodrigc	} else if (flist->xbf_low) {
3461153323Srodrigc		args.type = XFS_ALLOCTYPE_START_BNO;
3462153323Srodrigc		args.fsbno = *firstblock;
3463153323Srodrigc	} else {
3464153323Srodrigc		args.type = XFS_ALLOCTYPE_NEAR_BNO;
3465153323Srodrigc		args.fsbno = *firstblock;
3466153323Srodrigc	}
3467153323Srodrigc	args.minlen = args.maxlen = args.prod = 1;
3468153323Srodrigc	args.total = args.minleft = args.alignment = args.mod = args.isfl =
3469153323Srodrigc		args.minalignslop = 0;
3470153323Srodrigc	args.wasdel = wasdel;
3471153323Srodrigc	*logflagsp = 0;
3472153323Srodrigc	if ((error = xfs_alloc_vextent(&args))) {
3473153323Srodrigc		xfs_iroot_realloc(ip, -1, whichfork);
3474153323Srodrigc		xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
3475153323Srodrigc		return error;
3476153323Srodrigc	}
3477153323Srodrigc	/*
3478153323Srodrigc	 * Allocation can't fail, the space was reserved.
3479153323Srodrigc	 */
3480153323Srodrigc	ASSERT(args.fsbno != NULLFSBLOCK);
3481153323Srodrigc	ASSERT(*firstblock == NULLFSBLOCK ||
3482153323Srodrigc	       args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) ||
3483153323Srodrigc	       (flist->xbf_low &&
3484153323Srodrigc		args.agno > XFS_FSB_TO_AGNO(mp, *firstblock)));
3485153323Srodrigc	*firstblock = cur->bc_private.b.firstblock = args.fsbno;
3486153323Srodrigc	cur->bc_private.b.allocated++;
3487153323Srodrigc	ip->i_d.di_nblocks++;
3488153323Srodrigc	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
3489153323Srodrigc	abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
3490153323Srodrigc	/*
3491153323Srodrigc	 * Fill in the child block.
3492153323Srodrigc	 */
3493153323Srodrigc	ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
3494159451Srodrigc	ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
3495159451Srodrigc	ablock->bb_level = 0;
3496159451Srodrigc	ablock->bb_leftsib = cpu_to_be64(NULLDFSBNO);
3497159451Srodrigc	ablock->bb_rightsib = cpu_to_be64(NULLDFSBNO);
3498153323Srodrigc	arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
3499153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3500159451Srodrigc	for (cnt = i = 0; i < nextents; i++) {
3501159451Srodrigc		ep = xfs_iext_get_ext(ifp, i);
3502153323Srodrigc		if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) {
3503153323Srodrigc			arp->l0 = INT_GET(ep->l0, ARCH_CONVERT);
3504153323Srodrigc			arp->l1 = INT_GET(ep->l1, ARCH_CONVERT);
3505153323Srodrigc			arp++; cnt++;
3506153323Srodrigc		}
3507153323Srodrigc	}
3508159451Srodrigc	ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork));
3509159451Srodrigc	ablock->bb_numrecs = cpu_to_be16(cnt);
3510153323Srodrigc	/*
3511153323Srodrigc	 * Fill in the root key and pointer.
3512153323Srodrigc	 */
3513153323Srodrigc	kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
3514153323Srodrigc	arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
3515153323Srodrigc	INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
3516153323Srodrigc	pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
3517153323Srodrigc	INT_SET(*pp, ARCH_CONVERT, args.fsbno);
3518153323Srodrigc	/*
3519153323Srodrigc	 * Do all this logging at the end so that
3520153323Srodrigc	 * the root is at the right level.
3521153323Srodrigc	 */
3522153323Srodrigc	xfs_bmbt_log_block(cur, abp, XFS_BB_ALL_BITS);
3523159451Srodrigc	xfs_bmbt_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs));
3524153323Srodrigc	ASSERT(*curp == NULL);
3525153323Srodrigc	*curp = cur;
3526153323Srodrigc	*logflagsp = XFS_ILOG_CORE | XFS_ILOG_FBROOT(whichfork);
3527153323Srodrigc	return 0;
3528153323Srodrigc}
3529153323Srodrigc
3530153323Srodrigc/*
3531159451Srodrigc * Helper routine to reset inode di_forkoff field when switching
3532159451Srodrigc * attribute fork from local to extent format - we reset it where
3533159451Srodrigc * possible to make space available for inline data fork extents.
3534153323Srodrigc */
3535153323SrodrigcSTATIC void
3536159451Srodrigcxfs_bmap_forkoff_reset(
3537159451Srodrigc	xfs_mount_t	*mp,
3538159451Srodrigc	xfs_inode_t	*ip,
3539159451Srodrigc	int		whichfork)
3540153323Srodrigc{
3541159451Srodrigc	if (whichfork == XFS_ATTR_FORK &&
3542159451Srodrigc	    (ip->i_d.di_format != XFS_DINODE_FMT_DEV) &&
3543159451Srodrigc	    (ip->i_d.di_format != XFS_DINODE_FMT_UUID) &&
3544159451Srodrigc	    ((mp->m_attroffset >> 3) > ip->i_d.di_forkoff)) {
3545159451Srodrigc		ip->i_d.di_forkoff = mp->m_attroffset >> 3;
3546159451Srodrigc		ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) /
3547159451Srodrigc					(uint)sizeof(xfs_bmbt_rec_t);
3548159451Srodrigc		ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) /
3549159451Srodrigc					(uint)sizeof(xfs_bmbt_rec_t);
3550159451Srodrigc	}
3551153323Srodrigc}
3552153323Srodrigc
3553153323Srodrigc/*
3554153323Srodrigc * Convert a local file to an extents file.
3555153323Srodrigc * This code is out of bounds for data forks of regular files,
3556153323Srodrigc * since the file data needs to get logged so things will stay consistent.
3557153323Srodrigc * (The bmap-level manipulations are ok, though).
3558153323Srodrigc */
3559153323SrodrigcSTATIC int				/* error */
3560153323Srodrigcxfs_bmap_local_to_extents(
3561153323Srodrigc	xfs_trans_t	*tp,		/* transaction pointer */
3562153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3563153323Srodrigc	xfs_fsblock_t	*firstblock,	/* first block allocated in xaction */
3564153323Srodrigc	xfs_extlen_t	total,		/* total blocks needed by transaction */
3565153323Srodrigc	int		*logflagsp,	/* inode logging flags */
3566153323Srodrigc	int		whichfork)	/* data or attr fork */
3567153323Srodrigc{
3568153323Srodrigc	int		error;		/* error return value */
3569153323Srodrigc	int		flags;		/* logging flags returned */
3570153323Srodrigc#ifdef XFS_BMAP_TRACE
3571153323Srodrigc	static char	fname[] = "xfs_bmap_local_to_extents";
3572153323Srodrigc#endif
3573153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
3574153323Srodrigc
3575153323Srodrigc	/*
3576153323Srodrigc	 * We don't want to deal with the case of keeping inode data inline yet.
3577153323Srodrigc	 * So sending the data fork of a regular inode is invalid.
3578153323Srodrigc	 */
3579153323Srodrigc	ASSERT(!((ip->i_d.di_mode & S_IFMT) == S_IFREG &&
3580153323Srodrigc		 whichfork == XFS_DATA_FORK));
3581153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3582153323Srodrigc	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
3583153323Srodrigc	flags = 0;
3584153323Srodrigc	error = 0;
3585153323Srodrigc	if (ifp->if_bytes) {
3586153323Srodrigc		xfs_alloc_arg_t	args;	/* allocation arguments */
3587159451Srodrigc		xfs_buf_t	*bp;	/* buffer for extent block */
3588159451Srodrigc		xfs_bmbt_rec_t	*ep;	/* extent record pointer */
3589153323Srodrigc
3590153323Srodrigc		args.tp = tp;
3591153323Srodrigc		args.mp = ip->i_mount;
3592159451Srodrigc		ASSERT((ifp->if_flags &
3593159451Srodrigc			(XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE);
3594153323Srodrigc		/*
3595153323Srodrigc		 * Allocate a block.  We know we need only one, since the
3596153323Srodrigc		 * file currently fits in an inode.
3597153323Srodrigc		 */
3598153323Srodrigc		if (*firstblock == NULLFSBLOCK) {
3599153323Srodrigc			args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
3600153323Srodrigc			args.type = XFS_ALLOCTYPE_START_BNO;
3601153323Srodrigc		} else {
3602153323Srodrigc			args.fsbno = *firstblock;
3603153323Srodrigc			args.type = XFS_ALLOCTYPE_NEAR_BNO;
3604153323Srodrigc		}
3605153323Srodrigc		args.total = total;
3606153323Srodrigc		args.mod = args.minleft = args.alignment = args.wasdel =
3607153323Srodrigc			args.isfl = args.minalignslop = 0;
3608153323Srodrigc		args.minlen = args.maxlen = args.prod = 1;
3609153323Srodrigc		if ((error = xfs_alloc_vextent(&args)))
3610153323Srodrigc			goto done;
3611153323Srodrigc		/*
3612153323Srodrigc		 * Can't fail, the space was reserved.
3613153323Srodrigc		 */
3614153323Srodrigc		ASSERT(args.fsbno != NULLFSBLOCK);
3615153323Srodrigc		ASSERT(args.len == 1);
3616153323Srodrigc		*firstblock = args.fsbno;
3617153323Srodrigc		bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
3618153323Srodrigc		memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
3619153323Srodrigc			ifp->if_bytes);
3620153323Srodrigc		xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
3621159451Srodrigc		xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
3622153323Srodrigc		xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
3623159451Srodrigc		xfs_iext_add(ifp, 0, 1);
3624159451Srodrigc		ep = xfs_iext_get_ext(ifp, 0);
3625153323Srodrigc		xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
3626153323Srodrigc		xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
3627153323Srodrigc		XFS_IFORK_NEXT_SET(ip, whichfork, 1);
3628153323Srodrigc		ip->i_d.di_nblocks = 1;
3629153323Srodrigc		XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
3630153323Srodrigc			XFS_TRANS_DQ_BCOUNT, 1L);
3631153323Srodrigc		flags |= XFS_ILOG_FEXT(whichfork);
3632159451Srodrigc	} else {
3633153323Srodrigc		ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
3634159451Srodrigc		xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
3635159451Srodrigc	}
3636153323Srodrigc	ifp->if_flags &= ~XFS_IFINLINE;
3637153323Srodrigc	ifp->if_flags |= XFS_IFEXTENTS;
3638153323Srodrigc	XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
3639153323Srodrigc	flags |= XFS_ILOG_CORE;
3640153323Srodrigcdone:
3641153323Srodrigc	*logflagsp = flags;
3642153323Srodrigc	return error;
3643153323Srodrigc}
3644153323Srodrigc
3645159451Srodrigc/*
3646159451Srodrigc * Search the extent records for the entry containing block bno.
3647159451Srodrigc * If bno lies in a hole, point to the next entry.  If bno lies
3648159451Srodrigc * past eof, *eofp will be set, and *prevp will contain the last
3649159451Srodrigc * entry (null if none).  Else, *lastxp will be set to the index
3650159451Srodrigc * of the found entry; *gotp will contain the entry.
3651159451Srodrigc */
3652153323Srodrigcxfs_bmbt_rec_t *			/* pointer to found extent entry */
3653159451Srodrigcxfs_bmap_search_multi_extents(
3654159451Srodrigc	xfs_ifork_t	*ifp,		/* inode fork pointer */
3655153323Srodrigc	xfs_fileoff_t	bno,		/* block number searched for */
3656153323Srodrigc	int		*eofp,		/* out: end of file found */
3657153323Srodrigc	xfs_extnum_t	*lastxp,	/* out: last extent index */
3658153323Srodrigc	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */
3659153323Srodrigc	xfs_bmbt_irec_t	*prevp)		/* out: previous extent entry found */
3660153323Srodrigc{
3661159451Srodrigc	xfs_bmbt_rec_t	*ep;		/* extent record pointer */
3662159451Srodrigc	xfs_extnum_t	lastx;		/* last extent index */
3663153323Srodrigc
3664159451Srodrigc	/*
3665159451Srodrigc	 * Initialize the extent entry structure to catch access to
3666159451Srodrigc	 * uninitialized br_startblock field.
3667159451Srodrigc	 */
3668159451Srodrigc	gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL;
3669159451Srodrigc	gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL;
3670159451Srodrigc	gotp->br_state = XFS_EXT_INVALID;
3671159451Srodrigc#if XFS_BIG_BLKNOS
3672159451Srodrigc	gotp->br_startblock = 0xffffa5a5a5a5a5a5LL;
3673159451Srodrigc#else
3674159451Srodrigc	gotp->br_startblock = 0xffffa5a5;
3675159451Srodrigc#endif
3676153323Srodrigc	prevp->br_startoff = NULLFILEOFF;
3677159451Srodrigc
3678159451Srodrigc	ep = xfs_iext_bno_to_ext(ifp, bno, &lastx);
3679159451Srodrigc	if (lastx > 0) {
3680159451Srodrigc		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp);
3681159451Srodrigc	}
3682159451Srodrigc	if (lastx < (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) {
3683159451Srodrigc		xfs_bmbt_get_all(ep, gotp);
3684153323Srodrigc		*eofp = 0;
3685153323Srodrigc	} else {
3686159451Srodrigc		if (lastx > 0) {
3687159451Srodrigc			*gotp = *prevp;
3688153323Srodrigc		}
3689159451Srodrigc		*eofp = 1;
3690159451Srodrigc		ep = NULL;
3691153323Srodrigc	}
3692153323Srodrigc	*lastxp = lastx;
3693153323Srodrigc	return ep;
3694153323Srodrigc}
3695153323Srodrigc
3696153323Srodrigc/*
3697153323Srodrigc * Search the extents list for the inode, for the extent containing bno.
3698153323Srodrigc * If bno lies in a hole, point to the next entry.  If bno lies past eof,
3699153323Srodrigc * *eofp will be set, and *prevp will contain the last entry (null if none).
3700153323Srodrigc * Else, *lastxp will be set to the index of the found
3701153323Srodrigc * entry; *gotp will contain the entry.
3702153323Srodrigc */
3703153323SrodrigcSTATIC xfs_bmbt_rec_t *                 /* pointer to found extent entry */
3704153323Srodrigcxfs_bmap_search_extents(
3705153323Srodrigc	xfs_inode_t     *ip,            /* incore inode pointer */
3706153323Srodrigc	xfs_fileoff_t   bno,            /* block number searched for */
3707153323Srodrigc	int             whichfork,      /* data or attr fork */
3708153323Srodrigc	int             *eofp,          /* out: end of file found */
3709153323Srodrigc	xfs_extnum_t    *lastxp,        /* out: last extent index */
3710153323Srodrigc	xfs_bmbt_irec_t *gotp,          /* out: extent entry found */
3711153323Srodrigc	xfs_bmbt_irec_t *prevp)         /* out: previous extent entry found */
3712153323Srodrigc{
3713153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
3714159451Srodrigc	xfs_bmbt_rec_t  *ep;            /* extent record pointer */
3715159451Srodrigc	int		rt;		/* realtime flag    */
3716153323Srodrigc
3717153323Srodrigc	XFS_STATS_INC(xs_look_exlist);
3718153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3719153323Srodrigc
3720159451Srodrigc	ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
3721159451Srodrigc
3722159451Srodrigc	rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
3723159451Srodrigc	if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) {
3724159451Srodrigc                cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld "
3725159451Srodrigc			"start_block : %llx start_off : %llx blkcnt : %llx "
3726159451Srodrigc			"extent-state : %x \n",
3727159451Srodrigc			(ip->i_mount)->m_fsname, (long long)ip->i_ino,
3728159451Srodrigc			(unsigned long long)gotp->br_startblock,
3729159451Srodrigc			(unsigned long long)gotp->br_startoff,
3730159451Srodrigc			(unsigned long long)gotp->br_blockcount,
3731159451Srodrigc			gotp->br_state);
3732159451Srodrigc        }
3733159451Srodrigc        return ep;
3734153323Srodrigc}
3735153323Srodrigc
3736153323Srodrigc
3737153323Srodrigc#ifdef XFS_BMAP_TRACE
3738153323Srodrigcktrace_t	*xfs_bmap_trace_buf;
3739153323Srodrigc
3740153323Srodrigc/*
3741153323Srodrigc * Add a bmap trace buffer entry.  Base routine for the others.
3742153323Srodrigc */
3743153323SrodrigcSTATIC void
3744153323Srodrigcxfs_bmap_trace_addentry(
3745153323Srodrigc	int		opcode,		/* operation */
3746153323Srodrigc	char		*fname,		/* function name */
3747153323Srodrigc	char		*desc,		/* operation description */
3748153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3749153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(ies) */
3750153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries, 1 or 2 */
3751153323Srodrigc	xfs_bmbt_rec_t	*r1,		/* first record */
3752153323Srodrigc	xfs_bmbt_rec_t	*r2,		/* second record or null */
3753153323Srodrigc	int		whichfork)	/* data or attr fork */
3754153323Srodrigc{
3755153323Srodrigc	xfs_bmbt_rec_t	tr2;
3756153323Srodrigc
3757153323Srodrigc	ASSERT(cnt == 1 || cnt == 2);
3758153323Srodrigc	ASSERT(r1 != NULL);
3759153323Srodrigc	if (cnt == 1) {
3760153323Srodrigc		ASSERT(r2 == NULL);
3761153323Srodrigc		r2 = &tr2;
3762153323Srodrigc		memset(&tr2, 0, sizeof(tr2));
3763153323Srodrigc	} else
3764153323Srodrigc		ASSERT(r2 != NULL);
3765153323Srodrigc	ktrace_enter(xfs_bmap_trace_buf,
3766153323Srodrigc		(void *)(__psint_t)(opcode | (whichfork << 16)),
3767153323Srodrigc		(void *)fname, (void *)desc, (void *)ip,
3768153323Srodrigc		(void *)(__psint_t)idx,
3769153323Srodrigc		(void *)(__psint_t)cnt,
3770153323Srodrigc		(void *)(__psunsigned_t)(ip->i_ino >> 32),
3771153323Srodrigc		(void *)(__psunsigned_t)(unsigned)ip->i_ino,
3772153323Srodrigc		(void *)(__psunsigned_t)(r1->l0 >> 32),
3773153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r1->l0),
3774153323Srodrigc		(void *)(__psunsigned_t)(r1->l1 >> 32),
3775153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r1->l1),
3776153323Srodrigc		(void *)(__psunsigned_t)(r2->l0 >> 32),
3777153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r2->l0),
3778153323Srodrigc		(void *)(__psunsigned_t)(r2->l1 >> 32),
3779153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r2->l1)
3780153323Srodrigc		);
3781153323Srodrigc	ASSERT(ip->i_xtrace);
3782153323Srodrigc	ktrace_enter(ip->i_xtrace,
3783153323Srodrigc		(void *)(__psint_t)(opcode | (whichfork << 16)),
3784153323Srodrigc		(void *)fname, (void *)desc, (void *)ip,
3785153323Srodrigc		(void *)(__psint_t)idx,
3786153323Srodrigc		(void *)(__psint_t)cnt,
3787153323Srodrigc		(void *)(__psunsigned_t)(ip->i_ino >> 32),
3788153323Srodrigc		(void *)(__psunsigned_t)(unsigned)ip->i_ino,
3789153323Srodrigc		(void *)(__psunsigned_t)(r1->l0 >> 32),
3790153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r1->l0),
3791153323Srodrigc		(void *)(__psunsigned_t)(r1->l1 >> 32),
3792153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r1->l1),
3793153323Srodrigc		(void *)(__psunsigned_t)(r2->l0 >> 32),
3794153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r2->l0),
3795153323Srodrigc		(void *)(__psunsigned_t)(r2->l1 >> 32),
3796153323Srodrigc		(void *)(__psunsigned_t)(unsigned)(r2->l1)
3797153323Srodrigc		);
3798153323Srodrigc}
3799153323Srodrigc
3800153323Srodrigc/*
3801159451Srodrigc * Add bmap trace entry prior to a call to xfs_iext_remove.
3802153323Srodrigc */
3803153323SrodrigcSTATIC void
3804153323Srodrigcxfs_bmap_trace_delete(
3805153323Srodrigc	char		*fname,		/* function name */
3806153323Srodrigc	char		*desc,		/* operation description */
3807153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3808153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(entries) deleted */
3809153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries deleted, 1 or 2 */
3810153323Srodrigc	int		whichfork)	/* data or attr fork */
3811153323Srodrigc{
3812153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
3813153323Srodrigc
3814153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3815153323Srodrigc	xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_DELETE, fname, desc, ip, idx,
3816159451Srodrigc		cnt, xfs_iext_get_ext(ifp, idx),
3817159451Srodrigc		cnt == 2 ? xfs_iext_get_ext(ifp, idx + 1) : NULL,
3818153323Srodrigc		whichfork);
3819153323Srodrigc}
3820153323Srodrigc
3821153323Srodrigc/*
3822159451Srodrigc * Add bmap trace entry prior to a call to xfs_iext_insert, or
3823153323Srodrigc * reading in the extents list from the disk (in the btree).
3824153323Srodrigc */
3825153323SrodrigcSTATIC void
3826153323Srodrigcxfs_bmap_trace_insert(
3827153323Srodrigc	char		*fname,		/* function name */
3828153323Srodrigc	char		*desc,		/* operation description */
3829153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3830153323Srodrigc	xfs_extnum_t	idx,		/* index of entry(entries) inserted */
3831153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries inserted, 1 or 2 */
3832153323Srodrigc	xfs_bmbt_irec_t	*r1,		/* inserted record 1 */
3833153323Srodrigc	xfs_bmbt_irec_t	*r2,		/* inserted record 2 or null */
3834153323Srodrigc	int		whichfork)	/* data or attr fork */
3835153323Srodrigc{
3836153323Srodrigc	xfs_bmbt_rec_t	tr1;		/* compressed record 1 */
3837153323Srodrigc	xfs_bmbt_rec_t	tr2;		/* compressed record 2 if needed */
3838153323Srodrigc
3839153323Srodrigc	xfs_bmbt_set_all(&tr1, r1);
3840153323Srodrigc	if (cnt == 2) {
3841153323Srodrigc		ASSERT(r2 != NULL);
3842153323Srodrigc		xfs_bmbt_set_all(&tr2, r2);
3843153323Srodrigc	} else {
3844153323Srodrigc		ASSERT(cnt == 1);
3845153323Srodrigc		ASSERT(r2 == NULL);
3846153323Srodrigc	}
3847153323Srodrigc	xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_INSERT, fname, desc, ip, idx,
3848153323Srodrigc		cnt, &tr1, cnt == 2 ? &tr2 : NULL, whichfork);
3849153323Srodrigc}
3850153323Srodrigc
3851153323Srodrigc/*
3852159451Srodrigc * Add bmap trace entry after updating an extent record in place.
3853153323Srodrigc */
3854153323SrodrigcSTATIC void
3855153323Srodrigcxfs_bmap_trace_post_update(
3856153323Srodrigc	char		*fname,		/* function name */
3857153323Srodrigc	char		*desc,		/* operation description */
3858153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3859153323Srodrigc	xfs_extnum_t	idx,		/* index of entry updated */
3860153323Srodrigc	int		whichfork)	/* data or attr fork */
3861153323Srodrigc{
3862153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
3863153323Srodrigc
3864153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3865153323Srodrigc	xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_POST_UP, fname, desc, ip, idx,
3866159451Srodrigc		1, xfs_iext_get_ext(ifp, idx), NULL, whichfork);
3867153323Srodrigc}
3868153323Srodrigc
3869153323Srodrigc/*
3870159451Srodrigc * Add bmap trace entry prior to updating an extent record in place.
3871153323Srodrigc */
3872153323SrodrigcSTATIC void
3873153323Srodrigcxfs_bmap_trace_pre_update(
3874153323Srodrigc	char		*fname,		/* function name */
3875153323Srodrigc	char		*desc,		/* operation description */
3876153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3877153323Srodrigc	xfs_extnum_t	idx,		/* index of entry to be updated */
3878153323Srodrigc	int		whichfork)	/* data or attr fork */
3879153323Srodrigc{
3880153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
3881153323Srodrigc
3882153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
3883153323Srodrigc	xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_PRE_UP, fname, desc, ip, idx, 1,
3884159451Srodrigc		xfs_iext_get_ext(ifp, idx), NULL, whichfork);
3885153323Srodrigc}
3886153323Srodrigc#endif	/* XFS_BMAP_TRACE */
3887153323Srodrigc
3888153323Srodrigc/*
3889153323Srodrigc * Compute the worst-case number of indirect blocks that will be used
3890153323Srodrigc * for ip's delayed extent of length "len".
3891153323Srodrigc */
3892153323SrodrigcSTATIC xfs_filblks_t
3893153323Srodrigcxfs_bmap_worst_indlen(
3894153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
3895153323Srodrigc	xfs_filblks_t	len)		/* delayed extent length */
3896153323Srodrigc{
3897153323Srodrigc	int		level;		/* btree level number */
3898153323Srodrigc	int		maxrecs;	/* maximum record count at this level */
3899153323Srodrigc	xfs_mount_t	*mp;		/* mount structure */
3900153323Srodrigc	xfs_filblks_t	rval;		/* return value */
3901153323Srodrigc
3902153323Srodrigc	mp = ip->i_mount;
3903153323Srodrigc	maxrecs = mp->m_bmap_dmxr[0];
3904153323Srodrigc	for (level = 0, rval = 0;
3905153323Srodrigc	     level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK);
3906153323Srodrigc	     level++) {
3907153323Srodrigc		len += maxrecs - 1;
3908153323Srodrigc		do_div(len, maxrecs);
3909153323Srodrigc		rval += len;
3910153323Srodrigc		if (len == 1)
3911153323Srodrigc			return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) -
3912153323Srodrigc				level - 1;
3913153323Srodrigc		if (level == 0)
3914153323Srodrigc			maxrecs = mp->m_bmap_dmxr[1];
3915153323Srodrigc	}
3916153323Srodrigc	return rval;
3917153323Srodrigc}
3918153323Srodrigc
3919153323Srodrigc#if defined(XFS_RW_TRACE)
3920153323SrodrigcSTATIC void
3921153323Srodrigcxfs_bunmap_trace(
3922153323Srodrigc	xfs_inode_t		*ip,
3923153323Srodrigc	xfs_fileoff_t		bno,
3924153323Srodrigc	xfs_filblks_t		len,
3925153323Srodrigc	int			flags,
3926153323Srodrigc	inst_t			*ra)
3927153323Srodrigc{
3928153323Srodrigc	if (ip->i_rwtrace == NULL)
3929153323Srodrigc		return;
3930153323Srodrigc	ktrace_enter(ip->i_rwtrace,
3931159451Srodrigc		(void *)(__psint_t)XFS_BUNMAP,
3932153323Srodrigc		(void *)ip,
3933153323Srodrigc		(void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff),
3934153323Srodrigc		(void *)(__psint_t)(ip->i_d.di_size & 0xffffffff),
3935153323Srodrigc		(void *)(__psint_t)(((xfs_dfiloff_t)bno >> 32) & 0xffffffff),
3936153323Srodrigc		(void *)(__psint_t)((xfs_dfiloff_t)bno & 0xffffffff),
3937153323Srodrigc		(void *)(__psint_t)len,
3938153323Srodrigc		(void *)(__psint_t)flags,
3939153323Srodrigc		(void *)current_cpu(),
3940153323Srodrigc		(void *)ra,
3941153323Srodrigc		(void *)0,
3942153323Srodrigc		(void *)0,
3943153323Srodrigc		(void *)0,
3944153323Srodrigc		(void *)0,
3945153323Srodrigc		(void *)0,
3946153323Srodrigc		(void *)0);
3947153323Srodrigc}
3948153323Srodrigc#endif
3949153323Srodrigc
3950153323Srodrigc/*
3951153323Srodrigc * Convert inode from non-attributed to attributed.
3952153323Srodrigc * Must not be in a transaction, ip must not be locked.
3953153323Srodrigc */
3954153323Srodrigcint						/* error code */
3955153323Srodrigcxfs_bmap_add_attrfork(
3956153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
3957159451Srodrigc	int			size,		/* space new attribute needs */
3958159451Srodrigc	int			rsvd)		/* xact may use reserved blks */
3959153323Srodrigc{
3960159451Srodrigc	xfs_fsblock_t		firstblock;	/* 1st block/ag allocated */
3961159451Srodrigc	xfs_bmap_free_t		flist;		/* freed extent records */
3962159451Srodrigc	xfs_mount_t		*mp;		/* mount structure */
3963159451Srodrigc	xfs_trans_t		*tp;		/* transaction pointer */
3964159451Srodrigc	unsigned long		s;		/* spinlock spl value */
3965153323Srodrigc	int			blks;		/* space reservation */
3966159451Srodrigc	int			version = 1;	/* superblock attr version */
3967153323Srodrigc	int			committed;	/* xaction was committed */
3968159451Srodrigc	int			logflags;	/* logging flags */
3969153323Srodrigc	int			error;		/* error return value */
3970153323Srodrigc
3971159451Srodrigc	ASSERT(XFS_IFORK_Q(ip) == 0);
3972153323Srodrigc	ASSERT(ip->i_df.if_ext_max ==
3973153323Srodrigc	       XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
3974159451Srodrigc
3975153323Srodrigc	mp = ip->i_mount;
3976153323Srodrigc	ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
3977153323Srodrigc	tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK);
3978153323Srodrigc	blks = XFS_ADDAFORK_SPACE_RES(mp);
3979153323Srodrigc	if (rsvd)
3980153323Srodrigc		tp->t_flags |= XFS_TRANS_RESERVE;
3981153323Srodrigc	if ((error = xfs_trans_reserve(tp, blks, XFS_ADDAFORK_LOG_RES(mp), 0,
3982153323Srodrigc			XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
3983153323Srodrigc		goto error0;
3984153323Srodrigc	xfs_ilock(ip, XFS_ILOCK_EXCL);
3985153323Srodrigc	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, blks, 0, rsvd ?
3986153323Srodrigc			XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
3987153323Srodrigc			XFS_QMOPT_RES_REGBLKS);
3988153323Srodrigc	if (error) {
3989153323Srodrigc		xfs_iunlock(ip, XFS_ILOCK_EXCL);
3990153323Srodrigc		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
3991153323Srodrigc		return error;
3992153323Srodrigc	}
3993153323Srodrigc	if (XFS_IFORK_Q(ip))
3994153323Srodrigc		goto error1;
3995153323Srodrigc	if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) {
3996153323Srodrigc		/*
3997153323Srodrigc		 * For inodes coming from pre-6.2 filesystems.
3998153323Srodrigc		 */
3999153323Srodrigc		ASSERT(ip->i_d.di_aformat == 0);
4000153323Srodrigc		ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
4001153323Srodrigc	}
4002153323Srodrigc	ASSERT(ip->i_d.di_anextents == 0);
4003153323Srodrigc	VN_HOLD(XFS_ITOV(ip));
4004153323Srodrigc	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
4005153323Srodrigc	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
4006153323Srodrigc	switch (ip->i_d.di_format) {
4007153323Srodrigc	case XFS_DINODE_FMT_DEV:
4008153323Srodrigc		ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
4009153323Srodrigc		break;
4010153323Srodrigc	case XFS_DINODE_FMT_UUID:
4011153323Srodrigc		ip->i_d.di_forkoff = roundup(sizeof(uuid_t), 8) >> 3;
4012153323Srodrigc		break;
4013153323Srodrigc	case XFS_DINODE_FMT_LOCAL:
4014153323Srodrigc	case XFS_DINODE_FMT_EXTENTS:
4015153323Srodrigc	case XFS_DINODE_FMT_BTREE:
4016159451Srodrigc		ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
4017159451Srodrigc		if (!ip->i_d.di_forkoff)
4018159451Srodrigc			ip->i_d.di_forkoff = mp->m_attroffset >> 3;
4019159451Srodrigc		else if (mp->m_flags & XFS_MOUNT_ATTR2)
4020159451Srodrigc			version = 2;
4021153323Srodrigc		break;
4022153323Srodrigc	default:
4023153323Srodrigc		ASSERT(0);
4024153323Srodrigc		error = XFS_ERROR(EINVAL);
4025153323Srodrigc		goto error1;
4026153323Srodrigc	}
4027153323Srodrigc	ip->i_df.if_ext_max =
4028153323Srodrigc		XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
4029153323Srodrigc	ASSERT(ip->i_afp == NULL);
4030153323Srodrigc	ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
4031153323Srodrigc	ip->i_afp->if_ext_max =
4032153323Srodrigc		XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
4033153323Srodrigc	ip->i_afp->if_flags = XFS_IFEXTENTS;
4034153323Srodrigc	logflags = 0;
4035153323Srodrigc	XFS_BMAP_INIT(&flist, &firstblock);
4036153323Srodrigc	switch (ip->i_d.di_format) {
4037153323Srodrigc	case XFS_DINODE_FMT_LOCAL:
4038153323Srodrigc		error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &flist,
4039153323Srodrigc			&logflags);
4040153323Srodrigc		break;
4041153323Srodrigc	case XFS_DINODE_FMT_EXTENTS:
4042153323Srodrigc		error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock,
4043153323Srodrigc			&flist, &logflags);
4044153323Srodrigc		break;
4045153323Srodrigc	case XFS_DINODE_FMT_BTREE:
4046153323Srodrigc		error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &flist,
4047153323Srodrigc			&logflags);
4048153323Srodrigc		break;
4049153323Srodrigc	default:
4050153323Srodrigc		error = 0;
4051153323Srodrigc		break;
4052153323Srodrigc	}
4053153323Srodrigc	if (logflags)
4054153323Srodrigc		xfs_trans_log_inode(tp, ip, logflags);
4055153323Srodrigc	if (error)
4056153323Srodrigc		goto error2;
4057159451Srodrigc	if (!XFS_SB_VERSION_HASATTR(&mp->m_sb) ||
4058159451Srodrigc	   (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2)) {
4059159451Srodrigc		__int64_t sbfields = 0;
4060159451Srodrigc
4061153323Srodrigc		s = XFS_SB_LOCK(mp);
4062153323Srodrigc		if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) {
4063153323Srodrigc			XFS_SB_VERSION_ADDATTR(&mp->m_sb);
4064159451Srodrigc			sbfields |= XFS_SB_VERSIONNUM;
4065159451Srodrigc		}
4066159451Srodrigc		if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2) {
4067159451Srodrigc			XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
4068159451Srodrigc			sbfields |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
4069159451Srodrigc		}
4070159451Srodrigc		if (sbfields) {
4071153323Srodrigc			XFS_SB_UNLOCK(mp, s);
4072159451Srodrigc			xfs_mod_sb(tp, sbfields);
4073153323Srodrigc		} else
4074153323Srodrigc			XFS_SB_UNLOCK(mp, s);
4075153323Srodrigc	}
4076153323Srodrigc	if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed)))
4077153323Srodrigc		goto error2;
4078153323Srodrigc	error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL);
4079153323Srodrigc	ASSERT(ip->i_df.if_ext_max ==
4080153323Srodrigc	       XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
4081153323Srodrigc	return error;
4082153323Srodrigcerror2:
4083153323Srodrigc	xfs_bmap_cancel(&flist);
4084153323Srodrigcerror1:
4085153323Srodrigc	ASSERT(ismrlocked(&ip->i_lock,MR_UPDATE));
4086153323Srodrigc	xfs_iunlock(ip, XFS_ILOCK_EXCL);
4087153323Srodrigcerror0:
4088153323Srodrigc	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
4089153323Srodrigc	ASSERT(ip->i_df.if_ext_max ==
4090153323Srodrigc	       XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
4091153323Srodrigc	return error;
4092153323Srodrigc}
4093153323Srodrigc
4094153323Srodrigc/*
4095153323Srodrigc * Add the extent to the list of extents to be free at transaction end.
4096153323Srodrigc * The list is maintained sorted (by block number).
4097153323Srodrigc */
4098153323Srodrigc/* ARGSUSED */
4099153323Srodrigcvoid
4100153323Srodrigcxfs_bmap_add_free(
4101153323Srodrigc	xfs_fsblock_t		bno,		/* fs block number of extent */
4102153323Srodrigc	xfs_filblks_t		len,		/* length of extent */
4103153323Srodrigc	xfs_bmap_free_t		*flist,		/* list of extents */
4104153323Srodrigc	xfs_mount_t		*mp)		/* mount point structure */
4105153323Srodrigc{
4106153323Srodrigc	xfs_bmap_free_item_t	*cur;		/* current (next) element */
4107153323Srodrigc	xfs_bmap_free_item_t	*new;		/* new element */
4108153323Srodrigc	xfs_bmap_free_item_t	*prev;		/* previous element */
4109153323Srodrigc#ifdef DEBUG
4110153323Srodrigc	xfs_agnumber_t		agno;
4111153323Srodrigc	xfs_agblock_t		agbno;
4112153323Srodrigc
4113153323Srodrigc	ASSERT(bno != NULLFSBLOCK);
4114153323Srodrigc	ASSERT(len > 0);
4115153323Srodrigc	ASSERT(len <= MAXEXTLEN);
4116153323Srodrigc	ASSERT(!ISNULLSTARTBLOCK(bno));
4117153323Srodrigc	agno = XFS_FSB_TO_AGNO(mp, bno);
4118153323Srodrigc	agbno = XFS_FSB_TO_AGBNO(mp, bno);
4119153323Srodrigc	ASSERT(agno < mp->m_sb.sb_agcount);
4120153323Srodrigc	ASSERT(agbno < mp->m_sb.sb_agblocks);
4121153323Srodrigc	ASSERT(len < mp->m_sb.sb_agblocks);
4122153323Srodrigc	ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
4123153323Srodrigc#endif
4124153323Srodrigc	ASSERT(xfs_bmap_free_item_zone != NULL);
4125153323Srodrigc	new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
4126153323Srodrigc	new->xbfi_startblock = bno;
4127153323Srodrigc	new->xbfi_blockcount = (xfs_extlen_t)len;
4128153323Srodrigc	for (prev = NULL, cur = flist->xbf_first;
4129153323Srodrigc	     cur != NULL;
4130153323Srodrigc	     prev = cur, cur = cur->xbfi_next) {
4131153323Srodrigc		if (cur->xbfi_startblock >= bno)
4132153323Srodrigc			break;
4133153323Srodrigc	}
4134153323Srodrigc	if (prev)
4135153323Srodrigc		prev->xbfi_next = new;
4136153323Srodrigc	else
4137153323Srodrigc		flist->xbf_first = new;
4138153323Srodrigc	new->xbfi_next = cur;
4139153323Srodrigc	flist->xbf_count++;
4140153323Srodrigc}
4141153323Srodrigc
4142153323Srodrigc/*
4143153323Srodrigc * Compute and fill in the value of the maximum depth of a bmap btree
4144153323Srodrigc * in this filesystem.  Done once, during mount.
4145153323Srodrigc */
4146153323Srodrigcvoid
4147153323Srodrigcxfs_bmap_compute_maxlevels(
4148153323Srodrigc	xfs_mount_t	*mp,		/* file system mount structure */
4149153323Srodrigc	int		whichfork)	/* data or attr fork */
4150153323Srodrigc{
4151153323Srodrigc	int		level;		/* btree level */
4152153323Srodrigc	uint		maxblocks;	/* max blocks at this level */
4153153323Srodrigc	uint		maxleafents;	/* max leaf entries possible */
4154153323Srodrigc	int		maxrootrecs;	/* max records in root block */
4155153323Srodrigc	int		minleafrecs;	/* min records in leaf block */
4156153323Srodrigc	int		minnoderecs;	/* min records in node block */
4157153323Srodrigc	int		sz;		/* root block size */
4158153323Srodrigc
4159153323Srodrigc	/*
4160153323Srodrigc	 * The maximum number of extents in a file, hence the maximum
4161153323Srodrigc	 * number of leaf entries, is controlled by the type of di_nextents
4162153323Srodrigc	 * (a signed 32-bit number, xfs_extnum_t), or by di_anextents
4163153323Srodrigc	 * (a signed 16-bit number, xfs_aextnum_t).
4164153323Srodrigc	 */
4165159451Srodrigc	if (whichfork == XFS_DATA_FORK) {
4166159451Srodrigc		maxleafents = MAXEXTNUM;
4167159451Srodrigc		sz = (mp->m_flags & XFS_MOUNT_ATTR2) ?
4168159451Srodrigc			XFS_BMDR_SPACE_CALC(MINDBTPTRS) : mp->m_attroffset;
4169159451Srodrigc	} else {
4170159451Srodrigc		maxleafents = MAXAEXTNUM;
4171159451Srodrigc		sz = (mp->m_flags & XFS_MOUNT_ATTR2) ?
4172159451Srodrigc			XFS_BMDR_SPACE_CALC(MINABTPTRS) :
4173159451Srodrigc			mp->m_sb.sb_inodesize - mp->m_attroffset;
4174159451Srodrigc	}
4175159451Srodrigc	maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
4176153323Srodrigc	minleafrecs = mp->m_bmap_dmnr[0];
4177153323Srodrigc	minnoderecs = mp->m_bmap_dmnr[1];
4178153323Srodrigc	maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
4179153323Srodrigc	for (level = 1; maxblocks > 1; level++) {
4180153323Srodrigc		if (maxblocks <= maxrootrecs)
4181153323Srodrigc			maxblocks = 1;
4182153323Srodrigc		else
4183153323Srodrigc			maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
4184153323Srodrigc	}
4185153323Srodrigc	mp->m_bm_maxlevels[whichfork] = level;
4186153323Srodrigc}
4187153323Srodrigc
4188153323Srodrigc/*
4189153323Srodrigc * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
4190153323Srodrigc * caller.  Frees all the extents that need freeing, which must be done
4191153323Srodrigc * last due to locking considerations.  We never free any extents in
4192153323Srodrigc * the first transaction.  This is to allow the caller to make the first
4193153323Srodrigc * transaction a synchronous one so that the pointers to the data being
4194153323Srodrigc * broken in this transaction will be permanent before the data is actually
4195153323Srodrigc * freed.  This is necessary to prevent blocks from being reallocated
4196153323Srodrigc * and written to before the free and reallocation are actually permanent.
4197153323Srodrigc * We do not just make the first transaction synchronous here, because
4198153323Srodrigc * there are more efficient ways to gain the same protection in some cases
4199153323Srodrigc * (see the file truncation code).
4200153323Srodrigc *
4201153323Srodrigc * Return 1 if the given transaction was committed and a new one
4202153323Srodrigc * started, and 0 otherwise in the committed parameter.
4203153323Srodrigc */
4204153323Srodrigc/*ARGSUSED*/
4205153323Srodrigcint						/* error */
4206153323Srodrigcxfs_bmap_finish(
4207153323Srodrigc	xfs_trans_t		**tp,		/* transaction pointer addr */
4208153323Srodrigc	xfs_bmap_free_t		*flist,		/* i/o: list extents to free */
4209153323Srodrigc	xfs_fsblock_t		firstblock,	/* controlled ag for allocs */
4210153323Srodrigc	int			*committed)	/* xact committed or not */
4211153323Srodrigc{
4212153323Srodrigc	xfs_efd_log_item_t	*efd;		/* extent free data */
4213153323Srodrigc	xfs_efi_log_item_t	*efi;		/* extent free intention */
4214153323Srodrigc	int			error;		/* error return value */
4215159451Srodrigc	xfs_bmap_free_item_t	*free;		/* free extent item */
4216153323Srodrigc	unsigned int		logres;		/* new log reservation */
4217153323Srodrigc	unsigned int		logcount;	/* new log count */
4218153323Srodrigc	xfs_mount_t		*mp;		/* filesystem mount structure */
4219153323Srodrigc	xfs_bmap_free_item_t	*next;		/* next item on free list */
4220153323Srodrigc	xfs_trans_t		*ntp;		/* new transaction pointer */
4221153323Srodrigc
4222153323Srodrigc	ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
4223153323Srodrigc	if (flist->xbf_count == 0) {
4224153323Srodrigc		*committed = 0;
4225153323Srodrigc		return 0;
4226153323Srodrigc	}
4227153323Srodrigc	ntp = *tp;
4228153323Srodrigc	efi = xfs_trans_get_efi(ntp, flist->xbf_count);
4229153323Srodrigc	for (free = flist->xbf_first; free; free = free->xbfi_next)
4230153323Srodrigc		xfs_trans_log_efi_extent(ntp, efi, free->xbfi_startblock,
4231153323Srodrigc			free->xbfi_blockcount);
4232153323Srodrigc	logres = ntp->t_log_res;
4233153323Srodrigc	logcount = ntp->t_log_count;
4234153323Srodrigc	ntp = xfs_trans_dup(*tp);
4235153323Srodrigc	error = xfs_trans_commit(*tp, 0, NULL);
4236153323Srodrigc	*tp = ntp;
4237153323Srodrigc	*committed = 1;
4238153323Srodrigc	/*
4239153323Srodrigc	 * We have a new transaction, so we should return committed=1,
4240153323Srodrigc	 * even though we're returning an error.
4241153323Srodrigc	 */
4242153323Srodrigc	if (error) {
4243153323Srodrigc		return error;
4244153323Srodrigc	}
4245153323Srodrigc	if ((error = xfs_trans_reserve(ntp, 0, logres, 0, XFS_TRANS_PERM_LOG_RES,
4246153323Srodrigc			logcount)))
4247153323Srodrigc		return error;
4248153323Srodrigc	efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count);
4249153323Srodrigc	for (free = flist->xbf_first; free != NULL; free = next) {
4250153323Srodrigc		next = free->xbfi_next;
4251153323Srodrigc		if ((error = xfs_free_extent(ntp, free->xbfi_startblock,
4252153323Srodrigc				free->xbfi_blockcount))) {
4253153323Srodrigc			/*
4254153323Srodrigc			 * The bmap free list will be cleaned up at a
4255153323Srodrigc			 * higher level.  The EFI will be canceled when
4256153323Srodrigc			 * this transaction is aborted.
4257153323Srodrigc			 * Need to force shutdown here to make sure it
4258153323Srodrigc			 * happens, since this transaction may not be
4259153323Srodrigc			 * dirty yet.
4260153323Srodrigc			 */
4261153323Srodrigc			mp = ntp->t_mountp;
4262153323Srodrigc			if (!XFS_FORCED_SHUTDOWN(mp))
4263153323Srodrigc				xfs_force_shutdown(mp,
4264153323Srodrigc						   (error == EFSCORRUPTED) ?
4265153323Srodrigc						   XFS_CORRUPT_INCORE :
4266153323Srodrigc						   XFS_METADATA_IO_ERROR);
4267153323Srodrigc			return error;
4268153323Srodrigc		}
4269153323Srodrigc		xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock,
4270153323Srodrigc			free->xbfi_blockcount);
4271153323Srodrigc		xfs_bmap_del_free(flist, NULL, free);
4272153323Srodrigc	}
4273153323Srodrigc	return 0;
4274153323Srodrigc}
4275153323Srodrigc
4276153323Srodrigc/*
4277153323Srodrigc * Free up any items left in the list.
4278153323Srodrigc */
4279153323Srodrigcvoid
4280153323Srodrigcxfs_bmap_cancel(
4281153323Srodrigc	xfs_bmap_free_t		*flist)	/* list of bmap_free_items */
4282153323Srodrigc{
4283153323Srodrigc	xfs_bmap_free_item_t	*free;	/* free list item */
4284153323Srodrigc	xfs_bmap_free_item_t	*next;
4285153323Srodrigc
4286153323Srodrigc	if (flist->xbf_count == 0)
4287153323Srodrigc		return;
4288153323Srodrigc	ASSERT(flist->xbf_first != NULL);
4289153323Srodrigc	for (free = flist->xbf_first; free; free = next) {
4290153323Srodrigc		next = free->xbfi_next;
4291153323Srodrigc		xfs_bmap_del_free(flist, NULL, free);
4292153323Srodrigc	}
4293153323Srodrigc	ASSERT(flist->xbf_count == 0);
4294153323Srodrigc}
4295153323Srodrigc
4296153323Srodrigc/*
4297153323Srodrigc * Returns the file-relative block number of the first unused block(s)
4298153323Srodrigc * in the file with at least "len" logically contiguous blocks free.
4299153323Srodrigc * This is the lowest-address hole if the file has holes, else the first block
4300153323Srodrigc * past the end of file.
4301153323Srodrigc * Return 0 if the file is currently local (in-inode).
4302153323Srodrigc */
4303153323Srodrigcint						/* error */
4304153323Srodrigcxfs_bmap_first_unused(
4305153323Srodrigc	xfs_trans_t	*tp,			/* transaction pointer */
4306153323Srodrigc	xfs_inode_t	*ip,			/* incore inode */
4307153323Srodrigc	xfs_extlen_t	len,			/* size of hole to find */
4308153323Srodrigc	xfs_fileoff_t	*first_unused,		/* unused block */
4309153323Srodrigc	int		whichfork)		/* data or attr fork */
4310153323Srodrigc{
4311153323Srodrigc	xfs_bmbt_rec_t	*ep;			/* pointer to an extent entry */
4312153323Srodrigc	int		error;			/* error return value */
4313159451Srodrigc	int		idx;			/* extent record index */
4314153323Srodrigc	xfs_ifork_t	*ifp;			/* inode fork pointer */
4315153323Srodrigc	xfs_fileoff_t	lastaddr;		/* last block number seen */
4316153323Srodrigc	xfs_fileoff_t	lowest;			/* lowest useful block */
4317153323Srodrigc	xfs_fileoff_t	max;			/* starting useful block */
4318153323Srodrigc	xfs_fileoff_t	off;			/* offset for this block */
4319153323Srodrigc	xfs_extnum_t	nextents;		/* number of extent entries */
4320153323Srodrigc
4321153323Srodrigc	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE ||
4322153323Srodrigc	       XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ||
4323153323Srodrigc	       XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
4324153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
4325153323Srodrigc		*first_unused = 0;
4326153323Srodrigc		return 0;
4327153323Srodrigc	}
4328153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4329153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
4330153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
4331153323Srodrigc		return error;
4332153323Srodrigc	lowest = *first_unused;
4333153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4334159451Srodrigc	for (idx = 0, lastaddr = 0, max = lowest; idx < nextents; idx++) {
4335159451Srodrigc		ep = xfs_iext_get_ext(ifp, idx);
4336153323Srodrigc		off = xfs_bmbt_get_startoff(ep);
4337153323Srodrigc		/*
4338153323Srodrigc		 * See if the hole before this extent will work.
4339153323Srodrigc		 */
4340153323Srodrigc		if (off >= lowest + len && off - max >= len) {
4341153323Srodrigc			*first_unused = max;
4342153323Srodrigc			return 0;
4343153323Srodrigc		}
4344153323Srodrigc		lastaddr = off + xfs_bmbt_get_blockcount(ep);
4345153323Srodrigc		max = XFS_FILEOFF_MAX(lastaddr, lowest);
4346153323Srodrigc	}
4347153323Srodrigc	*first_unused = max;
4348153323Srodrigc	return 0;
4349153323Srodrigc}
4350153323Srodrigc
4351153323Srodrigc/*
4352153323Srodrigc * Returns the file-relative block number of the last block + 1 before
4353153323Srodrigc * last_block (input value) in the file.
4354159451Srodrigc * This is not based on i_size, it is based on the extent records.
4355159451Srodrigc * Returns 0 for local files, as they do not have extent records.
4356153323Srodrigc */
4357153323Srodrigcint						/* error */
4358153323Srodrigcxfs_bmap_last_before(
4359153323Srodrigc	xfs_trans_t	*tp,			/* transaction pointer */
4360153323Srodrigc	xfs_inode_t	*ip,			/* incore inode */
4361153323Srodrigc	xfs_fileoff_t	*last_block,		/* last block */
4362153323Srodrigc	int		whichfork)		/* data or attr fork */
4363153323Srodrigc{
4364153323Srodrigc	xfs_fileoff_t	bno;			/* input file offset */
4365153323Srodrigc	int		eof;			/* hit end of file */
4366153323Srodrigc	xfs_bmbt_rec_t	*ep;			/* pointer to last extent */
4367153323Srodrigc	int		error;			/* error return value */
4368153323Srodrigc	xfs_bmbt_irec_t	got;			/* current extent value */
4369153323Srodrigc	xfs_ifork_t	*ifp;			/* inode fork pointer */
4370153323Srodrigc	xfs_extnum_t	lastx;			/* last extent used */
4371153323Srodrigc	xfs_bmbt_irec_t	prev;			/* previous extent value */
4372153323Srodrigc
4373153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
4374153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
4375153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
4376153323Srodrigc	       return XFS_ERROR(EIO);
4377153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
4378153323Srodrigc		*last_block = 0;
4379153323Srodrigc		return 0;
4380153323Srodrigc	}
4381153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4382153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
4383153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
4384153323Srodrigc		return error;
4385153323Srodrigc	bno = *last_block - 1;
4386153323Srodrigc	ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
4387153323Srodrigc		&prev);
4388153323Srodrigc	if (eof || xfs_bmbt_get_startoff(ep) > bno) {
4389153323Srodrigc		if (prev.br_startoff == NULLFILEOFF)
4390153323Srodrigc			*last_block = 0;
4391153323Srodrigc		else
4392153323Srodrigc			*last_block = prev.br_startoff + prev.br_blockcount;
4393153323Srodrigc	}
4394153323Srodrigc	/*
4395153323Srodrigc	 * Otherwise *last_block is already the right answer.
4396153323Srodrigc	 */
4397153323Srodrigc	return 0;
4398153323Srodrigc}
4399153323Srodrigc
4400153323Srodrigc/*
4401153323Srodrigc * Returns the file-relative block number of the first block past eof in
4402159451Srodrigc * the file.  This is not based on i_size, it is based on the extent records.
4403159451Srodrigc * Returns 0 for local files, as they do not have extent records.
4404153323Srodrigc */
4405153323Srodrigcint						/* error */
4406153323Srodrigcxfs_bmap_last_offset(
4407153323Srodrigc	xfs_trans_t	*tp,			/* transaction pointer */
4408153323Srodrigc	xfs_inode_t	*ip,			/* incore inode */
4409153323Srodrigc	xfs_fileoff_t	*last_block,		/* last block */
4410153323Srodrigc	int		whichfork)		/* data or attr fork */
4411153323Srodrigc{
4412153323Srodrigc	xfs_bmbt_rec_t	*ep;			/* pointer to last extent */
4413153323Srodrigc	int		error;			/* error return value */
4414153323Srodrigc	xfs_ifork_t	*ifp;			/* inode fork pointer */
4415153323Srodrigc	xfs_extnum_t	nextents;		/* number of extent entries */
4416153323Srodrigc
4417153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
4418153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
4419153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
4420153323Srodrigc	       return XFS_ERROR(EIO);
4421153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
4422153323Srodrigc		*last_block = 0;
4423153323Srodrigc		return 0;
4424153323Srodrigc	}
4425153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4426153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
4427153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
4428153323Srodrigc		return error;
4429153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4430153323Srodrigc	if (!nextents) {
4431153323Srodrigc		*last_block = 0;
4432153323Srodrigc		return 0;
4433153323Srodrigc	}
4434159451Srodrigc	ep = xfs_iext_get_ext(ifp, nextents - 1);
4435153323Srodrigc	*last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep);
4436153323Srodrigc	return 0;
4437153323Srodrigc}
4438153323Srodrigc
4439153323Srodrigc/*
4440153323Srodrigc * Returns whether the selected fork of the inode has exactly one
4441153323Srodrigc * block or not.  For the data fork we check this matches di_size,
4442153323Srodrigc * implying the file's range is 0..bsize-1.
4443153323Srodrigc */
4444153323Srodrigcint					/* 1=>1 block, 0=>otherwise */
4445153323Srodrigcxfs_bmap_one_block(
4446153323Srodrigc	xfs_inode_t	*ip,		/* incore inode */
4447153323Srodrigc	int		whichfork)	/* data or attr fork */
4448153323Srodrigc{
4449153323Srodrigc	xfs_bmbt_rec_t	*ep;		/* ptr to fork's extent */
4450153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
4451153323Srodrigc	int		rval;		/* return value */
4452153323Srodrigc	xfs_bmbt_irec_t	s;		/* internal version of extent */
4453153323Srodrigc
4454153323Srodrigc#ifndef DEBUG
4455153323Srodrigc	if (whichfork == XFS_DATA_FORK)
4456153323Srodrigc		return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize;
4457153323Srodrigc#endif	/* !DEBUG */
4458153323Srodrigc	if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
4459153323Srodrigc		return 0;
4460153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
4461153323Srodrigc		return 0;
4462153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4463153323Srodrigc	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
4464159451Srodrigc	ep = xfs_iext_get_ext(ifp, 0);
4465153323Srodrigc	xfs_bmbt_get_all(ep, &s);
4466153323Srodrigc	rval = s.br_startoff == 0 && s.br_blockcount == 1;
4467153323Srodrigc	if (rval && whichfork == XFS_DATA_FORK)
4468153323Srodrigc		ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
4469153323Srodrigc	return rval;
4470153323Srodrigc}
4471153323Srodrigc
4472153323Srodrigc/*
4473153323Srodrigc * Read in the extents to if_extents.
4474153323Srodrigc * All inode fields are set up by caller, we just traverse the btree
4475153323Srodrigc * and copy the records in. If the file system cannot contain unwritten
4476153323Srodrigc * extents, the records are checked for no "state" flags.
4477153323Srodrigc */
4478153323Srodrigcint					/* error */
4479153323Srodrigcxfs_bmap_read_extents(
4480153323Srodrigc	xfs_trans_t		*tp,	/* transaction pointer */
4481153323Srodrigc	xfs_inode_t		*ip,	/* incore inode */
4482153323Srodrigc	int			whichfork) /* data or attr fork */
4483153323Srodrigc{
4484153323Srodrigc	xfs_bmbt_block_t	*block;	/* current btree block */
4485153323Srodrigc	xfs_fsblock_t		bno;	/* block # of "block" */
4486153323Srodrigc	xfs_buf_t		*bp;	/* buffer for "block" */
4487153323Srodrigc	int			error;	/* error return value */
4488153323Srodrigc	xfs_exntfmt_t		exntf;	/* XFS_EXTFMT_NOSTATE, if checking */
4489153323Srodrigc#ifdef XFS_BMAP_TRACE
4490153323Srodrigc	static char		fname[] = "xfs_bmap_read_extents";
4491153323Srodrigc#endif
4492153323Srodrigc	xfs_extnum_t		i, j;	/* index into the extents list */
4493153323Srodrigc	xfs_ifork_t		*ifp;	/* fork structure */
4494153323Srodrigc	int			level;	/* btree level, for checking */
4495153323Srodrigc	xfs_mount_t		*mp;	/* file system mount structure */
4496153323Srodrigc	xfs_bmbt_ptr_t		*pp;	/* pointer to block address */
4497153323Srodrigc	/* REFERENCED */
4498153323Srodrigc	xfs_extnum_t		room;	/* number of entries there's room for */
4499153323Srodrigc
4500153323Srodrigc	bno = NULLFSBLOCK;
4501153323Srodrigc	mp = ip->i_mount;
4502153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4503153323Srodrigc	exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE :
4504153323Srodrigc					XFS_EXTFMT_INODE(ip);
4505153323Srodrigc	block = ifp->if_broot;
4506153323Srodrigc	/*
4507153323Srodrigc	 * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
4508153323Srodrigc	 */
4509159451Srodrigc	level = be16_to_cpu(block->bb_level);
4510159451Srodrigc	ASSERT(level > 0);
4511153323Srodrigc	pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
4512153323Srodrigc	ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
4513153323Srodrigc	ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
4514153323Srodrigc	ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
4515153323Srodrigc	bno = INT_GET(*pp, ARCH_CONVERT);
4516153323Srodrigc	/*
4517153323Srodrigc	 * Go down the tree until leaf level is reached, following the first
4518153323Srodrigc	 * pointer (leftmost) at each level.
4519153323Srodrigc	 */
4520153323Srodrigc	while (level-- > 0) {
4521153323Srodrigc		if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
4522153323Srodrigc				XFS_BMAP_BTREE_REF)))
4523153323Srodrigc			return error;
4524153323Srodrigc		block = XFS_BUF_TO_BMBT_BLOCK(bp);
4525153323Srodrigc		XFS_WANT_CORRUPTED_GOTO(
4526153323Srodrigc			XFS_BMAP_SANITY_CHECK(mp, block, level),
4527153323Srodrigc			error0);
4528153323Srodrigc		if (level == 0)
4529153323Srodrigc			break;
4530153323Srodrigc		pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
4531153323Srodrigc			1, mp->m_bmap_dmxr[1]);
4532153323Srodrigc		XFS_WANT_CORRUPTED_GOTO(
4533153323Srodrigc			XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)),
4534153323Srodrigc			error0);
4535153323Srodrigc		bno = INT_GET(*pp, ARCH_CONVERT);
4536153323Srodrigc		xfs_trans_brelse(tp, bp);
4537153323Srodrigc	}
4538153323Srodrigc	/*
4539153323Srodrigc	 * Here with bp and block set to the leftmost leaf node in the tree.
4540153323Srodrigc	 */
4541159451Srodrigc	room = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4542153323Srodrigc	i = 0;
4543153323Srodrigc	/*
4544159451Srodrigc	 * Loop over all leaf nodes.  Copy information to the extent records.
4545153323Srodrigc	 */
4546153323Srodrigc	for (;;) {
4547159451Srodrigc		xfs_bmbt_rec_t	*frp, *trp;
4548153323Srodrigc		xfs_fsblock_t	nextbno;
4549153323Srodrigc		xfs_extnum_t	num_recs;
4550159451Srodrigc		xfs_extnum_t	start;
4551153323Srodrigc
4552153323Srodrigc
4553159451Srodrigc		num_recs = be16_to_cpu(block->bb_numrecs);
4554153323Srodrigc		if (unlikely(i + num_recs > room)) {
4555153323Srodrigc			ASSERT(i + num_recs <= room);
4556159451Srodrigc			xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
4557159451Srodrigc				"corrupt dinode %Lu, (btree extents).",
4558153323Srodrigc				(unsigned long long) ip->i_ino);
4559153323Srodrigc			XFS_ERROR_REPORT("xfs_bmap_read_extents(1)",
4560153323Srodrigc					 XFS_ERRLEVEL_LOW,
4561153323Srodrigc					ip->i_mount);
4562153323Srodrigc			goto error0;
4563153323Srodrigc		}
4564153323Srodrigc		XFS_WANT_CORRUPTED_GOTO(
4565153323Srodrigc			XFS_BMAP_SANITY_CHECK(mp, block, 0),
4566153323Srodrigc			error0);
4567153323Srodrigc		/*
4568153323Srodrigc		 * Read-ahead the next leaf block, if any.
4569153323Srodrigc		 */
4570159451Srodrigc		nextbno = be64_to_cpu(block->bb_rightsib);
4571153323Srodrigc		if (nextbno != NULLFSBLOCK)
4572153323Srodrigc			xfs_btree_reada_bufl(mp, nextbno, 1);
4573153323Srodrigc		/*
4574159451Srodrigc		 * Copy records into the extent records.
4575153323Srodrigc		 */
4576153323Srodrigc		frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
4577153323Srodrigc			block, 1, mp->m_bmap_dmxr[0]);
4578159451Srodrigc		start = i;
4579159451Srodrigc		for (j = 0; j < num_recs; j++, i++, frp++) {
4580159451Srodrigc			trp = xfs_iext_get_ext(ifp, i);
4581153323Srodrigc			trp->l0 = INT_GET(frp->l0, ARCH_CONVERT);
4582153323Srodrigc			trp->l1 = INT_GET(frp->l1, ARCH_CONVERT);
4583153323Srodrigc		}
4584153323Srodrigc		if (exntf == XFS_EXTFMT_NOSTATE) {
4585153323Srodrigc			/*
4586153323Srodrigc			 * Check all attribute bmap btree records and
4587153323Srodrigc			 * any "older" data bmap btree records for a
4588153323Srodrigc			 * set bit in the "extent flag" position.
4589153323Srodrigc			 */
4590159451Srodrigc			if (unlikely(xfs_check_nostate_extents(ifp,
4591159451Srodrigc					start, num_recs))) {
4592153323Srodrigc				XFS_ERROR_REPORT("xfs_bmap_read_extents(2)",
4593153323Srodrigc						 XFS_ERRLEVEL_LOW,
4594153323Srodrigc						 ip->i_mount);
4595153323Srodrigc				goto error0;
4596153323Srodrigc			}
4597153323Srodrigc		}
4598153323Srodrigc		xfs_trans_brelse(tp, bp);
4599153323Srodrigc		bno = nextbno;
4600153323Srodrigc		/*
4601153323Srodrigc		 * If we've reached the end, stop.
4602153323Srodrigc		 */
4603153323Srodrigc		if (bno == NULLFSBLOCK)
4604153323Srodrigc			break;
4605153323Srodrigc		if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
4606153323Srodrigc				XFS_BMAP_BTREE_REF)))
4607153323Srodrigc			return error;
4608153323Srodrigc		block = XFS_BUF_TO_BMBT_BLOCK(bp);
4609153323Srodrigc	}
4610159451Srodrigc	ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)));
4611153323Srodrigc	ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
4612153323Srodrigc	xfs_bmap_trace_exlist(fname, ip, i, whichfork);
4613153323Srodrigc	return 0;
4614153323Srodrigcerror0:
4615153323Srodrigc	xfs_trans_brelse(tp, bp);
4616153323Srodrigc	return XFS_ERROR(EFSCORRUPTED);
4617153323Srodrigc}
4618153323Srodrigc
4619153323Srodrigc#ifdef XFS_BMAP_TRACE
4620153323Srodrigc/*
4621159451Srodrigc * Add bmap trace insert entries for all the contents of the extent records.
4622153323Srodrigc */
4623153323Srodrigcvoid
4624153323Srodrigcxfs_bmap_trace_exlist(
4625153323Srodrigc	char		*fname,		/* function name */
4626153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
4627153323Srodrigc	xfs_extnum_t	cnt,		/* count of entries in the list */
4628153323Srodrigc	int		whichfork)	/* data or attr fork */
4629153323Srodrigc{
4630159451Srodrigc	xfs_bmbt_rec_t	*ep;		/* current extent record */
4631159451Srodrigc	xfs_extnum_t	idx;		/* extent record index */
4632153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
4633159451Srodrigc	xfs_bmbt_irec_t	s;		/* file extent record */
4634153323Srodrigc
4635153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4636159451Srodrigc	ASSERT(cnt == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)));
4637159451Srodrigc	for (idx = 0; idx < cnt; idx++) {
4638159451Srodrigc		ep = xfs_iext_get_ext(ifp, idx);
4639153323Srodrigc		xfs_bmbt_get_all(ep, &s);
4640153323Srodrigc		xfs_bmap_trace_insert(fname, "exlist", ip, idx, 1, &s, NULL,
4641153323Srodrigc			whichfork);
4642153323Srodrigc	}
4643153323Srodrigc}
4644153323Srodrigc#endif
4645153323Srodrigc
4646153323Srodrigc#ifdef DEBUG
4647153323Srodrigc/*
4648153323Srodrigc * Validate that the bmbt_irecs being returned from bmapi are valid
4649153323Srodrigc * given the callers original parameters.  Specifically check the
4650153323Srodrigc * ranges of the returned irecs to ensure that they only extent beyond
4651153323Srodrigc * the given parameters if the XFS_BMAPI_ENTIRE flag was set.
4652153323Srodrigc */
4653153323SrodrigcSTATIC void
4654153323Srodrigcxfs_bmap_validate_ret(
4655153323Srodrigc	xfs_fileoff_t		bno,
4656153323Srodrigc	xfs_filblks_t		len,
4657153323Srodrigc	int			flags,
4658153323Srodrigc	xfs_bmbt_irec_t		*mval,
4659153323Srodrigc	int			nmap,
4660153323Srodrigc	int			ret_nmap)
4661153323Srodrigc{
4662153323Srodrigc	int			i;		/* index to map values */
4663153323Srodrigc
4664153323Srodrigc	ASSERT(ret_nmap <= nmap);
4665153323Srodrigc
4666153323Srodrigc	for (i = 0; i < ret_nmap; i++) {
4667153323Srodrigc		ASSERT(mval[i].br_blockcount > 0);
4668153323Srodrigc		if (!(flags & XFS_BMAPI_ENTIRE)) {
4669153323Srodrigc			ASSERT(mval[i].br_startoff >= bno);
4670153323Srodrigc			ASSERT(mval[i].br_blockcount <= len);
4671153323Srodrigc			ASSERT(mval[i].br_startoff + mval[i].br_blockcount <=
4672153323Srodrigc			       bno + len);
4673153323Srodrigc		} else {
4674153323Srodrigc			ASSERT(mval[i].br_startoff < bno + len);
4675153323Srodrigc			ASSERT(mval[i].br_startoff + mval[i].br_blockcount >
4676153323Srodrigc			       bno);
4677153323Srodrigc		}
4678153323Srodrigc		ASSERT(i == 0 ||
4679153323Srodrigc		       mval[i - 1].br_startoff + mval[i - 1].br_blockcount ==
4680153323Srodrigc		       mval[i].br_startoff);
4681153323Srodrigc		if ((flags & XFS_BMAPI_WRITE) && !(flags & XFS_BMAPI_DELAY))
4682153323Srodrigc			ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
4683153323Srodrigc			       mval[i].br_startblock != HOLESTARTBLOCK);
4684153323Srodrigc		ASSERT(mval[i].br_state == XFS_EXT_NORM ||
4685153323Srodrigc		       mval[i].br_state == XFS_EXT_UNWRITTEN);
4686153323Srodrigc	}
4687153323Srodrigc}
4688153323Srodrigc#endif /* DEBUG */
4689153323Srodrigc
4690153323Srodrigc
4691153323Srodrigc/*
4692153323Srodrigc * Map file blocks to filesystem blocks.
4693153323Srodrigc * File range is given by the bno/len pair.
4694153323Srodrigc * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
4695153323Srodrigc * into a hole or past eof.
4696153323Srodrigc * Only allocates blocks from a single allocation group,
4697153323Srodrigc * to avoid locking problems.
4698153323Srodrigc * The returned value in "firstblock" from the first call in a transaction
4699153323Srodrigc * must be remembered and presented to subsequent calls in "firstblock".
4700153323Srodrigc * An upper bound for the number of blocks to be allocated is supplied to
4701153323Srodrigc * the first call in "total"; if no allocation group has that many free
4702153323Srodrigc * blocks then the call will fail (return NULLFSBLOCK in "firstblock").
4703153323Srodrigc */
4704153323Srodrigcint					/* error */
4705153323Srodrigcxfs_bmapi(
4706153323Srodrigc	xfs_trans_t	*tp,		/* transaction pointer */
4707153323Srodrigc	xfs_inode_t	*ip,		/* incore inode */
4708153323Srodrigc	xfs_fileoff_t	bno,		/* starting file offs. mapped */
4709153323Srodrigc	xfs_filblks_t	len,		/* length to map in file */
4710153323Srodrigc	int		flags,		/* XFS_BMAPI_... */
4711153323Srodrigc	xfs_fsblock_t	*firstblock,	/* first allocated block
4712153323Srodrigc					   controls a.g. for allocs */
4713153323Srodrigc	xfs_extlen_t	total,		/* total blocks needed */
4714153323Srodrigc	xfs_bmbt_irec_t	*mval,		/* output: map values */
4715153323Srodrigc	int		*nmap,		/* i/o: mval size/count */
4716159451Srodrigc	xfs_bmap_free_t	*flist,		/* i/o: list extents to free */
4717159451Srodrigc	xfs_extdelta_t	*delta)		/* o: change made to incore extents */
4718153323Srodrigc{
4719153323Srodrigc	xfs_fsblock_t	abno;		/* allocated block number */
4720153323Srodrigc	xfs_extlen_t	alen;		/* allocated extent length */
4721153323Srodrigc	xfs_fileoff_t	aoff;		/* allocated file offset */
4722153323Srodrigc	xfs_bmalloca_t	bma;		/* args for xfs_bmap_alloc */
4723153323Srodrigc	xfs_btree_cur_t	*cur;		/* bmap btree cursor */
4724153323Srodrigc	xfs_fileoff_t	end;		/* end of mapped file region */
4725159451Srodrigc	int		eof;		/* we've hit the end of extents */
4726159451Srodrigc	xfs_bmbt_rec_t	*ep;		/* extent record pointer */
4727153323Srodrigc	int		error;		/* error return */
4728159451Srodrigc	xfs_bmbt_irec_t	got;		/* current file extent record */
4729153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
4730153323Srodrigc	xfs_extlen_t	indlen;		/* indirect blocks length */
4731153323Srodrigc	xfs_extnum_t	lastx;		/* last useful extent number */
4732153323Srodrigc	int		logflags;	/* flags for transaction logging */
4733153323Srodrigc	xfs_extlen_t	minleft;	/* min blocks left after allocation */
4734153323Srodrigc	xfs_extlen_t	minlen;		/* min allocation size */
4735153323Srodrigc	xfs_mount_t	*mp;		/* xfs mount structure */
4736153323Srodrigc	int		n;		/* current extent index */
4737153323Srodrigc	int		nallocs;	/* number of extents alloc\'d */
4738153323Srodrigc	xfs_extnum_t	nextents;	/* number of extents in file */
4739153323Srodrigc	xfs_fileoff_t	obno;		/* old block number (offset) */
4740159451Srodrigc	xfs_bmbt_irec_t	prev;		/* previous file extent record */
4741153323Srodrigc	int		tmp_logflags;	/* temp flags holder */
4742159451Srodrigc	int		whichfork;	/* data or attr fork */
4743159451Srodrigc	char		inhole;		/* current location is hole in file */
4744153323Srodrigc	char		wasdelay;	/* old extent was delayed */
4745153323Srodrigc	char		wr;		/* this is a write request */
4746159451Srodrigc	char		rt;		/* this is a realtime file */
4747153323Srodrigc#ifdef DEBUG
4748153323Srodrigc	xfs_fileoff_t	orig_bno;	/* original block number value */
4749153323Srodrigc	int		orig_flags;	/* original flags arg value */
4750153323Srodrigc	xfs_filblks_t	orig_len;	/* original value of len arg */
4751153323Srodrigc	xfs_bmbt_irec_t	*orig_mval;	/* original value of mval */
4752153323Srodrigc	int		orig_nmap;	/* original value of *nmap */
4753153323Srodrigc
4754153323Srodrigc	orig_bno = bno;
4755153323Srodrigc	orig_len = len;
4756153323Srodrigc	orig_flags = flags;
4757153323Srodrigc	orig_mval = mval;
4758153323Srodrigc	orig_nmap = *nmap;
4759153323Srodrigc#endif
4760153323Srodrigc	ASSERT(*nmap >= 1);
4761153323Srodrigc	ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE));
4762153323Srodrigc	whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
4763153323Srodrigc		XFS_ATTR_FORK : XFS_DATA_FORK;
4764153323Srodrigc	mp = ip->i_mount;
4765153323Srodrigc	if (unlikely(XFS_TEST_ERROR(
4766153323Srodrigc	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
4767153323Srodrigc	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
4768153323Srodrigc	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
4769153323Srodrigc	     mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
4770153323Srodrigc		XFS_ERROR_REPORT("xfs_bmapi", XFS_ERRLEVEL_LOW, mp);
4771153323Srodrigc		return XFS_ERROR(EFSCORRUPTED);
4772153323Srodrigc	}
4773153323Srodrigc	if (XFS_FORCED_SHUTDOWN(mp))
4774153323Srodrigc		return XFS_ERROR(EIO);
4775159451Srodrigc	rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
4776153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
4777153323Srodrigc	ASSERT(ifp->if_ext_max ==
4778153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
4779153323Srodrigc	if ((wr = (flags & XFS_BMAPI_WRITE)) != 0)
4780153323Srodrigc		XFS_STATS_INC(xs_blk_mapw);
4781153323Srodrigc	else
4782153323Srodrigc		XFS_STATS_INC(xs_blk_mapr);
4783153323Srodrigc	/*
4784159451Srodrigc	 * IGSTATE flag is used to combine extents which
4785153323Srodrigc	 * differ only due to the state of the extents.
4786153323Srodrigc	 * This technique is used from xfs_getbmap()
4787153323Srodrigc	 * when the caller does not wish to see the
4788153323Srodrigc	 * separation (which is the default).
4789153323Srodrigc	 *
4790153323Srodrigc	 * This technique is also used when writing a
4791153323Srodrigc	 * buffer which has been partially written,
4792153323Srodrigc	 * (usually by being flushed during a chunkread),
4793153323Srodrigc	 * to ensure one write takes place. This also
4794153323Srodrigc	 * prevents a change in the xfs inode extents at
4795153323Srodrigc	 * this time, intentionally. This change occurs
4796153323Srodrigc	 * on completion of the write operation, in
4797153323Srodrigc	 * xfs_strat_comp(), where the xfs_bmapi() call
4798153323Srodrigc	 * is transactioned, and the extents combined.
4799153323Srodrigc	 */
4800159451Srodrigc	if ((flags & XFS_BMAPI_IGSTATE) && wr)	/* if writing unwritten space */
4801159451Srodrigc		wr = 0;				/* no allocations are allowed */
4802159451Srodrigc	ASSERT(wr || !(flags & XFS_BMAPI_DELAY));
4803153323Srodrigc	logflags = 0;
4804153323Srodrigc	nallocs = 0;
4805153323Srodrigc	cur = NULL;
4806153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
4807153323Srodrigc		ASSERT(wr && tp);
4808153323Srodrigc		if ((error = xfs_bmap_local_to_extents(tp, ip,
4809153323Srodrigc				firstblock, total, &logflags, whichfork)))
4810153323Srodrigc			goto error0;
4811153323Srodrigc	}
4812153323Srodrigc	if (wr && *firstblock == NULLFSBLOCK) {
4813153323Srodrigc		if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
4814159451Srodrigc			minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
4815153323Srodrigc		else
4816153323Srodrigc			minleft = 1;
4817153323Srodrigc	} else
4818153323Srodrigc		minleft = 0;
4819153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
4820153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
4821153323Srodrigc		goto error0;
4822153323Srodrigc	ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
4823153323Srodrigc		&prev);
4824153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4825153323Srodrigc	n = 0;
4826153323Srodrigc	end = bno + len;
4827153323Srodrigc	obno = bno;
4828153323Srodrigc	bma.ip = NULL;
4829159451Srodrigc	if (delta) {
4830159451Srodrigc		delta->xed_startoff = NULLFILEOFF;
4831159451Srodrigc		delta->xed_blockcount = 0;
4832159451Srodrigc	}
4833153323Srodrigc	while (bno < end && n < *nmap) {
4834153323Srodrigc		/*
4835153323Srodrigc		 * Reading past eof, act as though there's a hole
4836153323Srodrigc		 * up to end.
4837153323Srodrigc		 */
4838153323Srodrigc		if (eof && !wr)
4839153323Srodrigc			got.br_startoff = end;
4840153323Srodrigc		inhole = eof || got.br_startoff > bno;
4841159451Srodrigc		wasdelay = wr && !inhole && !(flags & XFS_BMAPI_DELAY) &&
4842153323Srodrigc			ISNULLSTARTBLOCK(got.br_startblock);
4843153323Srodrigc		/*
4844153323Srodrigc		 * First, deal with the hole before the allocated space
4845153323Srodrigc		 * that we found, if any.
4846153323Srodrigc		 */
4847153323Srodrigc		if (wr && (inhole || wasdelay)) {
4848153323Srodrigc			/*
4849153323Srodrigc			 * For the wasdelay case, we could also just
4850153323Srodrigc			 * allocate the stuff asked for in this bmap call
4851153323Srodrigc			 * but that wouldn't be as good.
4852153323Srodrigc			 */
4853159451Srodrigc			if (wasdelay && !(flags & XFS_BMAPI_EXACT)) {
4854153323Srodrigc				alen = (xfs_extlen_t)got.br_blockcount;
4855153323Srodrigc				aoff = got.br_startoff;
4856153323Srodrigc				if (lastx != NULLEXTNUM && lastx) {
4857159451Srodrigc					ep = xfs_iext_get_ext(ifp, lastx - 1);
4858153323Srodrigc					xfs_bmbt_get_all(ep, &prev);
4859153323Srodrigc				}
4860153323Srodrigc			} else if (wasdelay) {
4861153323Srodrigc				alen = (xfs_extlen_t)
4862153323Srodrigc					XFS_FILBLKS_MIN(len,
4863153323Srodrigc						(got.br_startoff +
4864153323Srodrigc						 got.br_blockcount) - bno);
4865153323Srodrigc				aoff = bno;
4866153323Srodrigc			} else {
4867153323Srodrigc				alen = (xfs_extlen_t)
4868153323Srodrigc					XFS_FILBLKS_MIN(len, MAXEXTLEN);
4869153323Srodrigc				if (!eof)
4870153323Srodrigc					alen = (xfs_extlen_t)
4871153323Srodrigc						XFS_FILBLKS_MIN(alen,
4872153323Srodrigc							got.br_startoff - bno);
4873153323Srodrigc				aoff = bno;
4874153323Srodrigc			}
4875159451Srodrigc			minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
4876159451Srodrigc			if (flags & XFS_BMAPI_DELAY) {
4877159451Srodrigc				xfs_extlen_t	extsz;
4878159451Srodrigc
4879159451Srodrigc				/* Figure out the extent size, adjust alen */
4880159451Srodrigc				if (rt) {
4881159451Srodrigc					if (!(extsz = ip->i_d.di_extsize))
4882159451Srodrigc						extsz = mp->m_sb.sb_rextsize;
4883159451Srodrigc				} else {
4884159451Srodrigc					extsz = ip->i_d.di_extsize;
4885159451Srodrigc				}
4886159451Srodrigc				if (extsz) {
4887159451Srodrigc					error = xfs_bmap_extsize_align(mp,
4888159451Srodrigc							&got, &prev, extsz,
4889159451Srodrigc							rt, eof,
4890159451Srodrigc							flags&XFS_BMAPI_DELAY,
4891159451Srodrigc							flags&XFS_BMAPI_CONVERT,
4892159451Srodrigc							&aoff, &alen);
4893159451Srodrigc					ASSERT(!error);
4894159451Srodrigc				}
4895159451Srodrigc
4896159451Srodrigc				if (rt)
4897159451Srodrigc					extsz = alen / mp->m_sb.sb_rextsize;
4898159451Srodrigc
4899153323Srodrigc				/*
4900153323Srodrigc				 * Make a transaction-less quota reservation for
4901153323Srodrigc				 * delayed allocation blocks. This number gets
4902159451Srodrigc				 * adjusted later.  We return if we haven't
4903159451Srodrigc				 * allocated blocks already inside this loop.
4904153323Srodrigc				 */
4905159451Srodrigc				if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
4906159451Srodrigc						mp, NULL, ip, (long)alen, 0,
4907159451Srodrigc						rt ? XFS_QMOPT_RES_RTBLKS :
4908159451Srodrigc						     XFS_QMOPT_RES_REGBLKS))) {
4909153323Srodrigc					if (n == 0) {
4910153323Srodrigc						*nmap = 0;
4911153323Srodrigc						ASSERT(cur == NULL);
4912159451Srodrigc						return error;
4913153323Srodrigc					}
4914153323Srodrigc					break;
4915153323Srodrigc				}
4916159451Srodrigc
4917159451Srodrigc				/*
4918159451Srodrigc				 * Split changing sb for alen and indlen since
4919159451Srodrigc				 * they could be coming from different places.
4920159451Srodrigc				 */
4921159451Srodrigc				indlen = (xfs_extlen_t)
4922159451Srodrigc					xfs_bmap_worst_indlen(ip, alen);
4923159451Srodrigc				ASSERT(indlen > 0);
4924159451Srodrigc
4925159451Srodrigc				if (rt) {
4926159451Srodrigc					error = xfs_mod_incore_sb(mp,
4927159451Srodrigc							XFS_SBS_FREXTENTS,
4928159451Srodrigc							-(extsz), (flags &
4929159451Srodrigc							XFS_BMAPI_RSVBLOCKS));
4930159451Srodrigc				} else {
4931159451Srodrigc					error = xfs_mod_incore_sb(mp,
4932159451Srodrigc							XFS_SBS_FDBLOCKS,
4933159451Srodrigc							-(alen), (flags &
4934159451Srodrigc							XFS_BMAPI_RSVBLOCKS));
4935159451Srodrigc				}
4936159451Srodrigc				if (!error) {
4937159451Srodrigc					error = xfs_mod_incore_sb(mp,
4938159451Srodrigc							XFS_SBS_FDBLOCKS,
4939159451Srodrigc							-(indlen), (flags &
4940159451Srodrigc							XFS_BMAPI_RSVBLOCKS));
4941159451Srodrigc					if (error && rt)
4942159451Srodrigc						xfs_mod_incore_sb(mp,
4943159451Srodrigc							XFS_SBS_FREXTENTS,
4944159451Srodrigc							extsz, (flags &
4945159451Srodrigc							XFS_BMAPI_RSVBLOCKS));
4946159451Srodrigc					else if (error)
4947159451Srodrigc						xfs_mod_incore_sb(mp,
4948159451Srodrigc							XFS_SBS_FDBLOCKS,
4949159451Srodrigc							alen, (flags &
4950159451Srodrigc							XFS_BMAPI_RSVBLOCKS));
4951159451Srodrigc				}
4952159451Srodrigc
4953159451Srodrigc				if (error) {
4954159451Srodrigc					if (XFS_IS_QUOTA_ON(mp))
4955159451Srodrigc						/* unreserve the blocks now */
4956159451Srodrigc						(void)
4957159451Srodrigc						XFS_TRANS_UNRESERVE_QUOTA_NBLKS(
4958159451Srodrigc							mp, NULL, ip,
4959159451Srodrigc							(long)alen, 0, rt ?
4960159451Srodrigc							XFS_QMOPT_RES_RTBLKS :
4961159451Srodrigc							XFS_QMOPT_RES_REGBLKS);
4962153323Srodrigc					break;
4963153323Srodrigc				}
4964159451Srodrigc
4965153323Srodrigc				ip->i_delayed_blks += alen;
4966153323Srodrigc				abno = NULLSTARTBLOCK(indlen);
4967153323Srodrigc			} else {
4968153323Srodrigc				/*
4969153323Srodrigc				 * If first time, allocate and fill in
4970153323Srodrigc				 * once-only bma fields.
4971153323Srodrigc				 */
4972153323Srodrigc				if (bma.ip == NULL) {
4973153323Srodrigc					bma.tp = tp;
4974153323Srodrigc					bma.ip = ip;
4975153323Srodrigc					bma.prevp = &prev;
4976153323Srodrigc					bma.gotp = &got;
4977153323Srodrigc					bma.total = total;
4978153323Srodrigc					bma.userdata = 0;
4979153323Srodrigc				}
4980153323Srodrigc				/* Indicate if this is the first user data
4981153323Srodrigc				 * in the file, or just any user data.
4982153323Srodrigc				 */
4983159451Srodrigc				if (!(flags & XFS_BMAPI_METADATA)) {
4984153323Srodrigc					bma.userdata = (aoff == 0) ?
4985153323Srodrigc						XFS_ALLOC_INITIAL_USER_DATA :
4986153323Srodrigc						XFS_ALLOC_USERDATA;
4987153323Srodrigc				}
4988153323Srodrigc				/*
4989153323Srodrigc				 * Fill in changeable bma fields.
4990153323Srodrigc				 */
4991153323Srodrigc				bma.eof = eof;
4992153323Srodrigc				bma.firstblock = *firstblock;
4993153323Srodrigc				bma.alen = alen;
4994153323Srodrigc				bma.off = aoff;
4995170124Skan				bma.conv = (flags & XFS_BMAPI_CONVERT) != 0;
4996153323Srodrigc				bma.wasdel = wasdelay;
4997153323Srodrigc				bma.minlen = minlen;
4998153323Srodrigc				bma.low = flist->xbf_low;
4999153323Srodrigc				bma.minleft = minleft;
5000153323Srodrigc				/*
5001153323Srodrigc				 * Only want to do the alignment at the
5002153323Srodrigc				 * eof if it is userdata and allocation length
5003153323Srodrigc				 * is larger than a stripe unit.
5004153323Srodrigc				 */
5005153323Srodrigc				if (mp->m_dalign && alen >= mp->m_dalign &&
5006159451Srodrigc				    (!(flags & XFS_BMAPI_METADATA)) &&
5007159451Srodrigc				    (whichfork == XFS_DATA_FORK)) {
5008153323Srodrigc					if ((error = xfs_bmap_isaeof(ip, aoff,
5009153323Srodrigc							whichfork, &bma.aeof)))
5010153323Srodrigc						goto error0;
5011153323Srodrigc				} else
5012153323Srodrigc					bma.aeof = 0;
5013153323Srodrigc				/*
5014153323Srodrigc				 * Call allocator.
5015153323Srodrigc				 */
5016153323Srodrigc				if ((error = xfs_bmap_alloc(&bma)))
5017153323Srodrigc					goto error0;
5018153323Srodrigc				/*
5019153323Srodrigc				 * Copy out result fields.
5020153323Srodrigc				 */
5021153323Srodrigc				abno = bma.rval;
5022153323Srodrigc				if ((flist->xbf_low = bma.low))
5023153323Srodrigc					minleft = 0;
5024153323Srodrigc				alen = bma.alen;
5025153323Srodrigc				aoff = bma.off;
5026153323Srodrigc				ASSERT(*firstblock == NULLFSBLOCK ||
5027153323Srodrigc				       XFS_FSB_TO_AGNO(mp, *firstblock) ==
5028153323Srodrigc				       XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
5029153323Srodrigc				       (flist->xbf_low &&
5030153323Srodrigc					XFS_FSB_TO_AGNO(mp, *firstblock) <
5031153323Srodrigc					XFS_FSB_TO_AGNO(mp, bma.firstblock)));
5032153323Srodrigc				*firstblock = bma.firstblock;
5033153323Srodrigc				if (cur)
5034153323Srodrigc					cur->bc_private.b.firstblock =
5035153323Srodrigc						*firstblock;
5036153323Srodrigc				if (abno == NULLFSBLOCK)
5037153323Srodrigc					break;
5038153323Srodrigc				if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
5039153323Srodrigc					cur = xfs_btree_init_cursor(mp,
5040153323Srodrigc						tp, NULL, 0, XFS_BTNUM_BMAP,
5041153323Srodrigc						ip, whichfork);
5042153323Srodrigc					cur->bc_private.b.firstblock =
5043153323Srodrigc						*firstblock;
5044153323Srodrigc					cur->bc_private.b.flist = flist;
5045153323Srodrigc				}
5046153323Srodrigc				/*
5047153323Srodrigc				 * Bump the number of extents we've allocated
5048153323Srodrigc				 * in this call.
5049153323Srodrigc				 */
5050153323Srodrigc				nallocs++;
5051153323Srodrigc			}
5052153323Srodrigc			if (cur)
5053153323Srodrigc				cur->bc_private.b.flags =
5054153323Srodrigc					wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0;
5055153323Srodrigc			got.br_startoff = aoff;
5056153323Srodrigc			got.br_startblock = abno;
5057153323Srodrigc			got.br_blockcount = alen;
5058153323Srodrigc			got.br_state = XFS_EXT_NORM;	/* assume normal */
5059153323Srodrigc			/*
5060153323Srodrigc			 * Determine state of extent, and the filesystem.
5061153323Srodrigc			 * A wasdelay extent has been initialized, so
5062153323Srodrigc			 * shouldn't be flagged as unwritten.
5063153323Srodrigc			 */
5064153323Srodrigc			if (wr && XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
5065153323Srodrigc				if (!wasdelay && (flags & XFS_BMAPI_PREALLOC))
5066153323Srodrigc					got.br_state = XFS_EXT_UNWRITTEN;
5067153323Srodrigc			}
5068153323Srodrigc			error = xfs_bmap_add_extent(ip, lastx, &cur, &got,
5069159451Srodrigc				firstblock, flist, &tmp_logflags, delta,
5070159451Srodrigc				whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
5071153323Srodrigc			logflags |= tmp_logflags;
5072153323Srodrigc			if (error)
5073153323Srodrigc				goto error0;
5074153323Srodrigc			lastx = ifp->if_lastex;
5075159451Srodrigc			ep = xfs_iext_get_ext(ifp, lastx);
5076153323Srodrigc			nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
5077153323Srodrigc			xfs_bmbt_get_all(ep, &got);
5078153323Srodrigc			ASSERT(got.br_startoff <= aoff);
5079153323Srodrigc			ASSERT(got.br_startoff + got.br_blockcount >=
5080153323Srodrigc				aoff + alen);
5081153323Srodrigc#ifdef DEBUG
5082159451Srodrigc			if (flags & XFS_BMAPI_DELAY) {
5083153323Srodrigc				ASSERT(ISNULLSTARTBLOCK(got.br_startblock));
5084153323Srodrigc				ASSERT(STARTBLOCKVAL(got.br_startblock) > 0);
5085153323Srodrigc			}
5086153323Srodrigc			ASSERT(got.br_state == XFS_EXT_NORM ||
5087153323Srodrigc			       got.br_state == XFS_EXT_UNWRITTEN);
5088153323Srodrigc#endif
5089153323Srodrigc			/*
5090153323Srodrigc			 * Fall down into the found allocated space case.
5091153323Srodrigc			 */
5092153323Srodrigc		} else if (inhole) {
5093153323Srodrigc			/*
5094153323Srodrigc			 * Reading in a hole.
5095153323Srodrigc			 */
5096153323Srodrigc			mval->br_startoff = bno;
5097153323Srodrigc			mval->br_startblock = HOLESTARTBLOCK;
5098153323Srodrigc			mval->br_blockcount =
5099153323Srodrigc				XFS_FILBLKS_MIN(len, got.br_startoff - bno);
5100153323Srodrigc			mval->br_state = XFS_EXT_NORM;
5101153323Srodrigc			bno += mval->br_blockcount;
5102153323Srodrigc			len -= mval->br_blockcount;
5103153323Srodrigc			mval++;
5104153323Srodrigc			n++;
5105153323Srodrigc			continue;
5106153323Srodrigc		}
5107153323Srodrigc		/*
5108153323Srodrigc		 * Then deal with the allocated space we found.
5109153323Srodrigc		 */
5110153323Srodrigc		ASSERT(ep != NULL);
5111159451Srodrigc		if (!(flags & XFS_BMAPI_ENTIRE) &&
5112159451Srodrigc		    (got.br_startoff + got.br_blockcount > obno)) {
5113153323Srodrigc			if (obno > bno)
5114153323Srodrigc				bno = obno;
5115153323Srodrigc			ASSERT((bno >= obno) || (n == 0));
5116153323Srodrigc			ASSERT(bno < end);
5117153323Srodrigc			mval->br_startoff = bno;
5118153323Srodrigc			if (ISNULLSTARTBLOCK(got.br_startblock)) {
5119159451Srodrigc				ASSERT(!wr || (flags & XFS_BMAPI_DELAY));
5120153323Srodrigc				mval->br_startblock = DELAYSTARTBLOCK;
5121153323Srodrigc			} else
5122153323Srodrigc				mval->br_startblock =
5123153323Srodrigc					got.br_startblock +
5124153323Srodrigc					(bno - got.br_startoff);
5125153323Srodrigc			/*
5126153323Srodrigc			 * Return the minimum of what we got and what we
5127153323Srodrigc			 * asked for for the length.  We can use the len
5128153323Srodrigc			 * variable here because it is modified below
5129153323Srodrigc			 * and we could have been there before coming
5130153323Srodrigc			 * here if the first part of the allocation
5131153323Srodrigc			 * didn't overlap what was asked for.
5132153323Srodrigc			 */
5133153323Srodrigc			mval->br_blockcount =
5134153323Srodrigc				XFS_FILBLKS_MIN(end - bno, got.br_blockcount -
5135153323Srodrigc					(bno - got.br_startoff));
5136153323Srodrigc			mval->br_state = got.br_state;
5137153323Srodrigc			ASSERT(mval->br_blockcount <= len);
5138153323Srodrigc		} else {
5139153323Srodrigc			*mval = got;
5140153323Srodrigc			if (ISNULLSTARTBLOCK(mval->br_startblock)) {
5141159451Srodrigc				ASSERT(!wr || (flags & XFS_BMAPI_DELAY));
5142153323Srodrigc				mval->br_startblock = DELAYSTARTBLOCK;
5143153323Srodrigc			}
5144153323Srodrigc		}
5145153323Srodrigc
5146153323Srodrigc		/*
5147153323Srodrigc		 * Check if writing previously allocated but
5148153323Srodrigc		 * unwritten extents.
5149153323Srodrigc		 */
5150153323Srodrigc		if (wr && mval->br_state == XFS_EXT_UNWRITTEN &&
5151153323Srodrigc		    ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) {
5152153323Srodrigc			/*
5153153323Srodrigc			 * Modify (by adding) the state flag, if writing.
5154153323Srodrigc			 */
5155153323Srodrigc			ASSERT(mval->br_blockcount <= len);
5156153323Srodrigc			if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
5157153323Srodrigc				cur = xfs_btree_init_cursor(mp,
5158153323Srodrigc					tp, NULL, 0, XFS_BTNUM_BMAP,
5159153323Srodrigc					ip, whichfork);
5160153323Srodrigc				cur->bc_private.b.firstblock =
5161153323Srodrigc					*firstblock;
5162153323Srodrigc				cur->bc_private.b.flist = flist;
5163153323Srodrigc			}
5164153323Srodrigc			mval->br_state = XFS_EXT_NORM;
5165153323Srodrigc			error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
5166159451Srodrigc				firstblock, flist, &tmp_logflags, delta,
5167159451Srodrigc				whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
5168153323Srodrigc			logflags |= tmp_logflags;
5169153323Srodrigc			if (error)
5170153323Srodrigc				goto error0;
5171153323Srodrigc			lastx = ifp->if_lastex;
5172159451Srodrigc			ep = xfs_iext_get_ext(ifp, lastx);
5173153323Srodrigc			nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
5174153323Srodrigc			xfs_bmbt_get_all(ep, &got);
5175153323Srodrigc			/*
5176153323Srodrigc			 * We may have combined previously unwritten
5177153323Srodrigc			 * space with written space, so generate
5178153323Srodrigc			 * another request.
5179153323Srodrigc			 */
5180153323Srodrigc			if (mval->br_blockcount < len)
5181153323Srodrigc				continue;
5182153323Srodrigc		}
5183153323Srodrigc
5184159451Srodrigc		ASSERT((flags & XFS_BMAPI_ENTIRE) ||
5185153323Srodrigc		       ((mval->br_startoff + mval->br_blockcount) <= end));
5186159451Srodrigc		ASSERT((flags & XFS_BMAPI_ENTIRE) ||
5187159451Srodrigc		       (mval->br_blockcount <= len) ||
5188153323Srodrigc		       (mval->br_startoff < obno));
5189153323Srodrigc		bno = mval->br_startoff + mval->br_blockcount;
5190153323Srodrigc		len = end - bno;
5191153323Srodrigc		if (n > 0 && mval->br_startoff == mval[-1].br_startoff) {
5192153323Srodrigc			ASSERT(mval->br_startblock == mval[-1].br_startblock);
5193153323Srodrigc			ASSERT(mval->br_blockcount > mval[-1].br_blockcount);
5194153323Srodrigc			ASSERT(mval->br_state == mval[-1].br_state);
5195153323Srodrigc			mval[-1].br_blockcount = mval->br_blockcount;
5196153323Srodrigc			mval[-1].br_state = mval->br_state;
5197153323Srodrigc		} else if (n > 0 && mval->br_startblock != DELAYSTARTBLOCK &&
5198153323Srodrigc			   mval[-1].br_startblock != DELAYSTARTBLOCK &&
5199153323Srodrigc			   mval[-1].br_startblock != HOLESTARTBLOCK &&
5200153323Srodrigc			   mval->br_startblock ==
5201153323Srodrigc			   mval[-1].br_startblock + mval[-1].br_blockcount &&
5202159451Srodrigc			   ((flags & XFS_BMAPI_IGSTATE) ||
5203159451Srodrigc				mval[-1].br_state == mval->br_state)) {
5204153323Srodrigc			ASSERT(mval->br_startoff ==
5205153323Srodrigc			       mval[-1].br_startoff + mval[-1].br_blockcount);
5206153323Srodrigc			mval[-1].br_blockcount += mval->br_blockcount;
5207153323Srodrigc		} else if (n > 0 &&
5208153323Srodrigc			   mval->br_startblock == DELAYSTARTBLOCK &&
5209153323Srodrigc			   mval[-1].br_startblock == DELAYSTARTBLOCK &&
5210153323Srodrigc			   mval->br_startoff ==
5211153323Srodrigc			   mval[-1].br_startoff + mval[-1].br_blockcount) {
5212153323Srodrigc			mval[-1].br_blockcount += mval->br_blockcount;
5213153323Srodrigc			mval[-1].br_state = mval->br_state;
5214153323Srodrigc		} else if (!((n == 0) &&
5215153323Srodrigc			     ((mval->br_startoff + mval->br_blockcount) <=
5216153323Srodrigc			      obno))) {
5217153323Srodrigc			mval++;
5218153323Srodrigc			n++;
5219153323Srodrigc		}
5220153323Srodrigc		/*
5221153323Srodrigc		 * If we're done, stop now.  Stop when we've allocated
5222153323Srodrigc		 * XFS_BMAP_MAX_NMAP extents no matter what.  Otherwise
5223153323Srodrigc		 * the transaction may get too big.
5224153323Srodrigc		 */
5225153323Srodrigc		if (bno >= end || n >= *nmap || nallocs >= *nmap)
5226153323Srodrigc			break;
5227153323Srodrigc		/*
5228153323Srodrigc		 * Else go on to the next record.
5229153323Srodrigc		 */
5230159451Srodrigc		ep = xfs_iext_get_ext(ifp, ++lastx);
5231153323Srodrigc		if (lastx >= nextents) {
5232153323Srodrigc			eof = 1;
5233153323Srodrigc			prev = got;
5234153323Srodrigc		} else
5235153323Srodrigc			xfs_bmbt_get_all(ep, &got);
5236153323Srodrigc	}
5237153323Srodrigc	ifp->if_lastex = lastx;
5238153323Srodrigc	*nmap = n;
5239153323Srodrigc	/*
5240153323Srodrigc	 * Transform from btree to extents, give it cur.
5241153323Srodrigc	 */
5242153323Srodrigc	if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
5243153323Srodrigc	    XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
5244153323Srodrigc		ASSERT(wr && cur);
5245153323Srodrigc		error = xfs_bmap_btree_to_extents(tp, ip, cur,
5246153323Srodrigc			&tmp_logflags, whichfork);
5247153323Srodrigc		logflags |= tmp_logflags;
5248153323Srodrigc		if (error)
5249153323Srodrigc			goto error0;
5250153323Srodrigc	}
5251153323Srodrigc	ASSERT(ifp->if_ext_max ==
5252153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
5253153323Srodrigc	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
5254153323Srodrigc	       XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max);
5255153323Srodrigc	error = 0;
5256159451Srodrigc	if (delta && delta->xed_startoff != NULLFILEOFF) {
5257159451Srodrigc		/* A change was actually made.
5258159451Srodrigc		 * Note that delta->xed_blockount is an offset at this
5259159451Srodrigc		 * point and needs to be converted to a block count.
5260159451Srodrigc		 */
5261159451Srodrigc		ASSERT(delta->xed_blockcount > delta->xed_startoff);
5262159451Srodrigc		delta->xed_blockcount -= delta->xed_startoff;
5263159451Srodrigc	}
5264153323Srodrigcerror0:
5265153323Srodrigc	/*
5266153323Srodrigc	 * Log everything.  Do this after conversion, there's no point in
5267159451Srodrigc	 * logging the extent records if we've converted to btree format.
5268153323Srodrigc	 */
5269153323Srodrigc	if ((logflags & XFS_ILOG_FEXT(whichfork)) &&
5270153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
5271153323Srodrigc		logflags &= ~XFS_ILOG_FEXT(whichfork);
5272153323Srodrigc	else if ((logflags & XFS_ILOG_FBROOT(whichfork)) &&
5273153323Srodrigc		 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)
5274153323Srodrigc		logflags &= ~XFS_ILOG_FBROOT(whichfork);
5275153323Srodrigc	/*
5276153323Srodrigc	 * Log whatever the flags say, even if error.  Otherwise we might miss
5277153323Srodrigc	 * detecting a case where the data is changed, there's an error,
5278153323Srodrigc	 * and it's not logged so we don't shutdown when we should.
5279153323Srodrigc	 */
5280153323Srodrigc	if (logflags) {
5281153323Srodrigc		ASSERT(tp && wr);
5282153323Srodrigc		xfs_trans_log_inode(tp, ip, logflags);
5283153323Srodrigc	}
5284153323Srodrigc	if (cur) {
5285153323Srodrigc		if (!error) {
5286153323Srodrigc			ASSERT(*firstblock == NULLFSBLOCK ||
5287153323Srodrigc			       XFS_FSB_TO_AGNO(mp, *firstblock) ==
5288153323Srodrigc			       XFS_FSB_TO_AGNO(mp,
5289153323Srodrigc				       cur->bc_private.b.firstblock) ||
5290153323Srodrigc			       (flist->xbf_low &&
5291153323Srodrigc				XFS_FSB_TO_AGNO(mp, *firstblock) <
5292153323Srodrigc				XFS_FSB_TO_AGNO(mp,
5293153323Srodrigc					cur->bc_private.b.firstblock)));
5294153323Srodrigc			*firstblock = cur->bc_private.b.firstblock;
5295153323Srodrigc		}
5296153323Srodrigc		xfs_btree_del_cursor(cur,
5297153323Srodrigc			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
5298153323Srodrigc	}
5299153323Srodrigc	if (!error)
5300153323Srodrigc		xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval,
5301153323Srodrigc			orig_nmap, *nmap);
5302153323Srodrigc	return error;
5303153323Srodrigc}
5304153323Srodrigc
5305153323Srodrigc/*
5306153323Srodrigc * Map file blocks to filesystem blocks, simple version.
5307153323Srodrigc * One block (extent) only, read-only.
5308153323Srodrigc * For flags, only the XFS_BMAPI_ATTRFORK flag is examined.
5309153323Srodrigc * For the other flag values, the effect is as if XFS_BMAPI_METADATA
5310153323Srodrigc * was set and all the others were clear.
5311153323Srodrigc */
5312153323Srodrigcint						/* error */
5313153323Srodrigcxfs_bmapi_single(
5314153323Srodrigc	xfs_trans_t	*tp,		/* transaction pointer */
5315153323Srodrigc	xfs_inode_t	*ip,		/* incore inode */
5316153323Srodrigc	int		whichfork,	/* data or attr fork */
5317153323Srodrigc	xfs_fsblock_t	*fsb,		/* output: mapped block */
5318153323Srodrigc	xfs_fileoff_t	bno)		/* starting file offs. mapped */
5319153323Srodrigc{
5320159451Srodrigc	int		eof;		/* we've hit the end of extents */
5321153323Srodrigc	int		error;		/* error return */
5322159451Srodrigc	xfs_bmbt_irec_t	got;		/* current file extent record */
5323153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
5324153323Srodrigc	xfs_extnum_t	lastx;		/* last useful extent number */
5325159451Srodrigc	xfs_bmbt_irec_t	prev;		/* previous file extent record */
5326153323Srodrigc
5327153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
5328153323Srodrigc	if (unlikely(
5329153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
5330153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)) {
5331153323Srodrigc	       XFS_ERROR_REPORT("xfs_bmapi_single", XFS_ERRLEVEL_LOW,
5332153323Srodrigc				ip->i_mount);
5333153323Srodrigc	       return XFS_ERROR(EFSCORRUPTED);
5334153323Srodrigc	}
5335153323Srodrigc	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
5336153323Srodrigc		return XFS_ERROR(EIO);
5337153323Srodrigc	XFS_STATS_INC(xs_blk_mapr);
5338153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
5339153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
5340153323Srodrigc		return error;
5341153323Srodrigc	(void)xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
5342153323Srodrigc		&prev);
5343153323Srodrigc	/*
5344153323Srodrigc	 * Reading past eof, act as though there's a hole
5345153323Srodrigc	 * up to end.
5346153323Srodrigc	 */
5347153323Srodrigc	if (eof || got.br_startoff > bno) {
5348153323Srodrigc		*fsb = NULLFSBLOCK;
5349153323Srodrigc		return 0;
5350153323Srodrigc	}
5351153323Srodrigc	ASSERT(!ISNULLSTARTBLOCK(got.br_startblock));
5352153323Srodrigc	ASSERT(bno < got.br_startoff + got.br_blockcount);
5353153323Srodrigc	*fsb = got.br_startblock + (bno - got.br_startoff);
5354153323Srodrigc	ifp->if_lastex = lastx;
5355153323Srodrigc	return 0;
5356153323Srodrigc}
5357153323Srodrigc
5358153323Srodrigc/*
5359153323Srodrigc * Unmap (remove) blocks from a file.
5360153323Srodrigc * If nexts is nonzero then the number of extents to remove is limited to
5361153323Srodrigc * that value.  If not all extents in the block range can be removed then
5362153323Srodrigc * *done is set.
5363153323Srodrigc */
5364153323Srodrigcint						/* error */
5365153323Srodrigcxfs_bunmapi(
5366153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
5367153323Srodrigc	struct xfs_inode	*ip,		/* incore inode */
5368153323Srodrigc	xfs_fileoff_t		bno,		/* starting offset to unmap */
5369153323Srodrigc	xfs_filblks_t		len,		/* length to unmap in file */
5370153323Srodrigc	int			flags,		/* misc flags */
5371153323Srodrigc	xfs_extnum_t		nexts,		/* number of extents max */
5372153323Srodrigc	xfs_fsblock_t		*firstblock,	/* first allocated block
5373153323Srodrigc						   controls a.g. for allocs */
5374153323Srodrigc	xfs_bmap_free_t		*flist,		/* i/o: list extents to free */
5375159451Srodrigc	xfs_extdelta_t		*delta,		/* o: change made to incore
5376159451Srodrigc						   extents */
5377153323Srodrigc	int			*done)		/* set if not done yet */
5378153323Srodrigc{
5379153323Srodrigc	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
5380153323Srodrigc	xfs_bmbt_irec_t		del;		/* extent being deleted */
5381153323Srodrigc	int			eof;		/* is deleting at eof */
5382159451Srodrigc	xfs_bmbt_rec_t		*ep;		/* extent record pointer */
5383153323Srodrigc	int			error;		/* error return value */
5384153323Srodrigc	xfs_extnum_t		extno;		/* extent number in list */
5385159451Srodrigc	xfs_bmbt_irec_t		got;		/* current extent record */
5386153323Srodrigc	xfs_ifork_t		*ifp;		/* inode fork pointer */
5387153323Srodrigc	int			isrt;		/* freeing in rt area */
5388153323Srodrigc	xfs_extnum_t		lastx;		/* last extent index used */
5389153323Srodrigc	int			logflags;	/* transaction logging flags */
5390153323Srodrigc	xfs_extlen_t		mod;		/* rt extent offset */
5391153323Srodrigc	xfs_mount_t		*mp;		/* mount structure */
5392159451Srodrigc	xfs_extnum_t		nextents;	/* number of file extents */
5393159451Srodrigc	xfs_bmbt_irec_t		prev;		/* previous extent record */
5394153323Srodrigc	xfs_fileoff_t		start;		/* first file offset deleted */
5395153323Srodrigc	int			tmp_logflags;	/* partial logging flags */
5396153323Srodrigc	int			wasdel;		/* was a delayed alloc extent */
5397153323Srodrigc	int			whichfork;	/* data or attribute fork */
5398153323Srodrigc	int			rsvd;		/* OK to allocate reserved blocks */
5399153323Srodrigc	xfs_fsblock_t		sum;
5400153323Srodrigc
5401153323Srodrigc	xfs_bunmap_trace(ip, bno, len, flags, (inst_t *)__return_address);
5402153323Srodrigc	whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
5403153323Srodrigc		XFS_ATTR_FORK : XFS_DATA_FORK;
5404153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
5405153323Srodrigc	if (unlikely(
5406153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
5407153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
5408153323Srodrigc		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
5409153323Srodrigc				 ip->i_mount);
5410153323Srodrigc		return XFS_ERROR(EFSCORRUPTED);
5411153323Srodrigc	}
5412153323Srodrigc	mp = ip->i_mount;
5413153323Srodrigc	if (XFS_FORCED_SHUTDOWN(mp))
5414153323Srodrigc		return XFS_ERROR(EIO);
5415153323Srodrigc	rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0;
5416153323Srodrigc	ASSERT(len > 0);
5417153323Srodrigc	ASSERT(nexts >= 0);
5418153323Srodrigc	ASSERT(ifp->if_ext_max ==
5419153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
5420153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
5421153323Srodrigc	    (error = xfs_iread_extents(tp, ip, whichfork)))
5422153323Srodrigc		return error;
5423153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
5424153323Srodrigc	if (nextents == 0) {
5425153323Srodrigc		*done = 1;
5426153323Srodrigc		return 0;
5427153323Srodrigc	}
5428153323Srodrigc	XFS_STATS_INC(xs_blk_unmap);
5429159451Srodrigc	isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
5430153323Srodrigc	start = bno;
5431153323Srodrigc	bno = start + len - 1;
5432153323Srodrigc	ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
5433153323Srodrigc		&prev);
5434159451Srodrigc	if (delta) {
5435159451Srodrigc		delta->xed_startoff = NULLFILEOFF;
5436159451Srodrigc		delta->xed_blockcount = 0;
5437159451Srodrigc	}
5438153323Srodrigc	/*
5439153323Srodrigc	 * Check to see if the given block number is past the end of the
5440153323Srodrigc	 * file, back up to the last block if so...
5441153323Srodrigc	 */
5442153323Srodrigc	if (eof) {
5443159451Srodrigc		ep = xfs_iext_get_ext(ifp, --lastx);
5444153323Srodrigc		xfs_bmbt_get_all(ep, &got);
5445153323Srodrigc		bno = got.br_startoff + got.br_blockcount - 1;
5446153323Srodrigc	}
5447153323Srodrigc	logflags = 0;
5448153323Srodrigc	if (ifp->if_flags & XFS_IFBROOT) {
5449153323Srodrigc		ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
5450153323Srodrigc		cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
5451153323Srodrigc			whichfork);
5452153323Srodrigc		cur->bc_private.b.firstblock = *firstblock;
5453153323Srodrigc		cur->bc_private.b.flist = flist;
5454153323Srodrigc		cur->bc_private.b.flags = 0;
5455153323Srodrigc	} else
5456153323Srodrigc		cur = NULL;
5457153323Srodrigc	extno = 0;
5458153323Srodrigc	while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 &&
5459153323Srodrigc	       (nexts == 0 || extno < nexts)) {
5460153323Srodrigc		/*
5461153323Srodrigc		 * Is the found extent after a hole in which bno lives?
5462153323Srodrigc		 * Just back up to the previous extent, if so.
5463153323Srodrigc		 */
5464153323Srodrigc		if (got.br_startoff > bno) {
5465153323Srodrigc			if (--lastx < 0)
5466153323Srodrigc				break;
5467159451Srodrigc			ep = xfs_iext_get_ext(ifp, lastx);
5468153323Srodrigc			xfs_bmbt_get_all(ep, &got);
5469153323Srodrigc		}
5470153323Srodrigc		/*
5471153323Srodrigc		 * Is the last block of this extent before the range
5472153323Srodrigc		 * we're supposed to delete?  If so, we're done.
5473153323Srodrigc		 */
5474153323Srodrigc		bno = XFS_FILEOFF_MIN(bno,
5475153323Srodrigc			got.br_startoff + got.br_blockcount - 1);
5476153323Srodrigc		if (bno < start)
5477153323Srodrigc			break;
5478153323Srodrigc		/*
5479153323Srodrigc		 * Then deal with the (possibly delayed) allocated space
5480153323Srodrigc		 * we found.
5481153323Srodrigc		 */
5482153323Srodrigc		ASSERT(ep != NULL);
5483153323Srodrigc		del = got;
5484153323Srodrigc		wasdel = ISNULLSTARTBLOCK(del.br_startblock);
5485153323Srodrigc		if (got.br_startoff < start) {
5486153323Srodrigc			del.br_startoff = start;
5487153323Srodrigc			del.br_blockcount -= start - got.br_startoff;
5488153323Srodrigc			if (!wasdel)
5489153323Srodrigc				del.br_startblock += start - got.br_startoff;
5490153323Srodrigc		}
5491153323Srodrigc		if (del.br_startoff + del.br_blockcount > bno + 1)
5492153323Srodrigc			del.br_blockcount = bno + 1 - del.br_startoff;
5493153323Srodrigc		sum = del.br_startblock + del.br_blockcount;
5494153323Srodrigc		if (isrt &&
5495153323Srodrigc		    (mod = do_mod(sum, mp->m_sb.sb_rextsize))) {
5496153323Srodrigc			/*
5497153323Srodrigc			 * Realtime extent not lined up at the end.
5498153323Srodrigc			 * The extent could have been split into written
5499153323Srodrigc			 * and unwritten pieces, or we could just be
5500153323Srodrigc			 * unmapping part of it.  But we can't really
5501153323Srodrigc			 * get rid of part of a realtime extent.
5502153323Srodrigc			 */
5503153323Srodrigc			if (del.br_state == XFS_EXT_UNWRITTEN ||
5504153323Srodrigc			    !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
5505153323Srodrigc				/*
5506153323Srodrigc				 * This piece is unwritten, or we're not
5507153323Srodrigc				 * using unwritten extents.  Skip over it.
5508153323Srodrigc				 */
5509153323Srodrigc				ASSERT(bno >= mod);
5510153323Srodrigc				bno -= mod > del.br_blockcount ?
5511153323Srodrigc					del.br_blockcount : mod;
5512153323Srodrigc				if (bno < got.br_startoff) {
5513153323Srodrigc					if (--lastx >= 0)
5514159451Srodrigc						xfs_bmbt_get_all(xfs_iext_get_ext(
5515159451Srodrigc							ifp, lastx), &got);
5516153323Srodrigc				}
5517153323Srodrigc				continue;
5518153323Srodrigc			}
5519153323Srodrigc			/*
5520153323Srodrigc			 * It's written, turn it unwritten.
5521153323Srodrigc			 * This is better than zeroing it.
5522153323Srodrigc			 */
5523153323Srodrigc			ASSERT(del.br_state == XFS_EXT_NORM);
5524153323Srodrigc			ASSERT(xfs_trans_get_block_res(tp) > 0);
5525153323Srodrigc			/*
5526153323Srodrigc			 * If this spans a realtime extent boundary,
5527153323Srodrigc			 * chop it back to the start of the one we end at.
5528153323Srodrigc			 */
5529153323Srodrigc			if (del.br_blockcount > mod) {
5530153323Srodrigc				del.br_startoff += del.br_blockcount - mod;
5531153323Srodrigc				del.br_startblock += del.br_blockcount - mod;
5532153323Srodrigc				del.br_blockcount = mod;
5533153323Srodrigc			}
5534153323Srodrigc			del.br_state = XFS_EXT_UNWRITTEN;
5535153323Srodrigc			error = xfs_bmap_add_extent(ip, lastx, &cur, &del,
5536159451Srodrigc				firstblock, flist, &logflags, delta,
5537159451Srodrigc				XFS_DATA_FORK, 0);
5538153323Srodrigc			if (error)
5539153323Srodrigc				goto error0;
5540153323Srodrigc			goto nodelete;
5541153323Srodrigc		}
5542153323Srodrigc		if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) {
5543153323Srodrigc			/*
5544153323Srodrigc			 * Realtime extent is lined up at the end but not
5545153323Srodrigc			 * at the front.  We'll get rid of full extents if
5546153323Srodrigc			 * we can.
5547153323Srodrigc			 */
5548153323Srodrigc			mod = mp->m_sb.sb_rextsize - mod;
5549153323Srodrigc			if (del.br_blockcount > mod) {
5550153323Srodrigc				del.br_blockcount -= mod;
5551153323Srodrigc				del.br_startoff += mod;
5552153323Srodrigc				del.br_startblock += mod;
5553153323Srodrigc			} else if ((del.br_startoff == start &&
5554153323Srodrigc				    (del.br_state == XFS_EXT_UNWRITTEN ||
5555153323Srodrigc				     xfs_trans_get_block_res(tp) == 0)) ||
5556153323Srodrigc				   !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
5557153323Srodrigc				/*
5558153323Srodrigc				 * Can't make it unwritten.  There isn't
5559153323Srodrigc				 * a full extent here so just skip it.
5560153323Srodrigc				 */
5561153323Srodrigc				ASSERT(bno >= del.br_blockcount);
5562153323Srodrigc				bno -= del.br_blockcount;
5563153323Srodrigc				if (bno < got.br_startoff) {
5564153323Srodrigc					if (--lastx >= 0)
5565153323Srodrigc						xfs_bmbt_get_all(--ep, &got);
5566153323Srodrigc				}
5567153323Srodrigc				continue;
5568153323Srodrigc			} else if (del.br_state == XFS_EXT_UNWRITTEN) {
5569153323Srodrigc				/*
5570153323Srodrigc				 * This one is already unwritten.
5571153323Srodrigc				 * It must have a written left neighbor.
5572153323Srodrigc				 * Unwrite the killed part of that one and
5573153323Srodrigc				 * try again.
5574153323Srodrigc				 */
5575153323Srodrigc				ASSERT(lastx > 0);
5576159451Srodrigc				xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
5577159451Srodrigc						lastx - 1), &prev);
5578153323Srodrigc				ASSERT(prev.br_state == XFS_EXT_NORM);
5579153323Srodrigc				ASSERT(!ISNULLSTARTBLOCK(prev.br_startblock));
5580153323Srodrigc				ASSERT(del.br_startblock ==
5581153323Srodrigc				       prev.br_startblock + prev.br_blockcount);
5582153323Srodrigc				if (prev.br_startoff < start) {
5583153323Srodrigc					mod = start - prev.br_startoff;
5584153323Srodrigc					prev.br_blockcount -= mod;
5585153323Srodrigc					prev.br_startblock += mod;
5586153323Srodrigc					prev.br_startoff = start;
5587153323Srodrigc				}
5588153323Srodrigc				prev.br_state = XFS_EXT_UNWRITTEN;
5589153323Srodrigc				error = xfs_bmap_add_extent(ip, lastx - 1, &cur,
5590153323Srodrigc					&prev, firstblock, flist, &logflags,
5591159451Srodrigc					delta, XFS_DATA_FORK, 0);
5592153323Srodrigc				if (error)
5593153323Srodrigc					goto error0;
5594153323Srodrigc				goto nodelete;
5595153323Srodrigc			} else {
5596153323Srodrigc				ASSERT(del.br_state == XFS_EXT_NORM);
5597153323Srodrigc				del.br_state = XFS_EXT_UNWRITTEN;
5598153323Srodrigc				error = xfs_bmap_add_extent(ip, lastx, &cur,
5599153323Srodrigc					&del, firstblock, flist, &logflags,
5600159451Srodrigc					delta, XFS_DATA_FORK, 0);
5601153323Srodrigc				if (error)
5602153323Srodrigc					goto error0;
5603153323Srodrigc				goto nodelete;
5604153323Srodrigc			}
5605153323Srodrigc		}
5606153323Srodrigc		if (wasdel) {
5607153323Srodrigc			ASSERT(STARTBLOCKVAL(del.br_startblock) > 0);
5608159451Srodrigc			/* Update realtime/data freespace, unreserve quota */
5609159451Srodrigc			if (isrt) {
5610159451Srodrigc				xfs_filblks_t rtexts;
5611159451Srodrigc
5612159451Srodrigc				rtexts = XFS_FSB_TO_B(mp, del.br_blockcount);
5613159451Srodrigc				do_div(rtexts, mp->m_sb.sb_rextsize);
5614159451Srodrigc				xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
5615159451Srodrigc						(int)rtexts, rsvd);
5616159451Srodrigc				(void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
5617159451Srodrigc					NULL, ip, -((long)del.br_blockcount), 0,
5618159451Srodrigc					XFS_QMOPT_RES_RTBLKS);
5619159451Srodrigc			} else {
5620159451Srodrigc				xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
5621159451Srodrigc						(int)del.br_blockcount, rsvd);
5622159451Srodrigc				(void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
5623159451Srodrigc					NULL, ip, -((long)del.br_blockcount), 0,
5624153323Srodrigc					XFS_QMOPT_RES_REGBLKS);
5625159451Srodrigc			}
5626153323Srodrigc			ip->i_delayed_blks -= del.br_blockcount;
5627153323Srodrigc			if (cur)
5628153323Srodrigc				cur->bc_private.b.flags |=
5629153323Srodrigc					XFS_BTCUR_BPRV_WASDEL;
5630153323Srodrigc		} else if (cur)
5631153323Srodrigc			cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL;
5632153323Srodrigc		/*
5633153323Srodrigc		 * If it's the case where the directory code is running
5634153323Srodrigc		 * with no block reservation, and the deleted block is in
5635153323Srodrigc		 * the middle of its extent, and the resulting insert
5636153323Srodrigc		 * of an extent would cause transformation to btree format,
5637153323Srodrigc		 * then reject it.  The calling code will then swap
5638153323Srodrigc		 * blocks around instead.
5639153323Srodrigc		 * We have to do this now, rather than waiting for the
5640153323Srodrigc		 * conversion to btree format, since the transaction
5641153323Srodrigc		 * will be dirty.
5642153323Srodrigc		 */
5643153323Srodrigc		if (!wasdel && xfs_trans_get_block_res(tp) == 0 &&
5644153323Srodrigc		    XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
5645153323Srodrigc		    XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max &&
5646153323Srodrigc		    del.br_startoff > got.br_startoff &&
5647153323Srodrigc		    del.br_startoff + del.br_blockcount <
5648153323Srodrigc		    got.br_startoff + got.br_blockcount) {
5649153323Srodrigc			error = XFS_ERROR(ENOSPC);
5650153323Srodrigc			goto error0;
5651153323Srodrigc		}
5652153323Srodrigc		error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
5653159451Srodrigc				&tmp_logflags, delta, whichfork, rsvd);
5654153323Srodrigc		logflags |= tmp_logflags;
5655153323Srodrigc		if (error)
5656153323Srodrigc			goto error0;
5657153323Srodrigc		bno = del.br_startoff - 1;
5658153323Srodrigcnodelete:
5659153323Srodrigc		lastx = ifp->if_lastex;
5660153323Srodrigc		/*
5661153323Srodrigc		 * If not done go on to the next (previous) record.
5662153323Srodrigc		 * Reset ep in case the extents array was re-alloced.
5663153323Srodrigc		 */
5664159451Srodrigc		ep = xfs_iext_get_ext(ifp, lastx);
5665153323Srodrigc		if (bno != (xfs_fileoff_t)-1 && bno >= start) {
5666153323Srodrigc			if (lastx >= XFS_IFORK_NEXTENTS(ip, whichfork) ||
5667153323Srodrigc			    xfs_bmbt_get_startoff(ep) > bno) {
5668159451Srodrigc				if (--lastx >= 0)
5669159451Srodrigc					ep = xfs_iext_get_ext(ifp, lastx);
5670153323Srodrigc			}
5671153323Srodrigc			if (lastx >= 0)
5672153323Srodrigc				xfs_bmbt_get_all(ep, &got);
5673153323Srodrigc			extno++;
5674153323Srodrigc		}
5675153323Srodrigc	}
5676153323Srodrigc	ifp->if_lastex = lastx;
5677153323Srodrigc	*done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0;
5678153323Srodrigc	ASSERT(ifp->if_ext_max ==
5679153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
5680153323Srodrigc	/*
5681153323Srodrigc	 * Convert to a btree if necessary.
5682153323Srodrigc	 */
5683153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
5684153323Srodrigc	    XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
5685153323Srodrigc		ASSERT(cur == NULL);
5686153323Srodrigc		error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist,
5687153323Srodrigc			&cur, 0, &tmp_logflags, whichfork);
5688153323Srodrigc		logflags |= tmp_logflags;
5689153323Srodrigc		if (error)
5690153323Srodrigc			goto error0;
5691153323Srodrigc	}
5692153323Srodrigc	/*
5693153323Srodrigc	 * transform from btree to extents, give it cur
5694153323Srodrigc	 */
5695153323Srodrigc	else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
5696153323Srodrigc		 XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
5697153323Srodrigc		ASSERT(cur != NULL);
5698153323Srodrigc		error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags,
5699153323Srodrigc			whichfork);
5700153323Srodrigc		logflags |= tmp_logflags;
5701153323Srodrigc		if (error)
5702153323Srodrigc			goto error0;
5703153323Srodrigc	}
5704153323Srodrigc	/*
5705153323Srodrigc	 * transform from extents to local?
5706153323Srodrigc	 */
5707153323Srodrigc	ASSERT(ifp->if_ext_max ==
5708153323Srodrigc	       XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
5709153323Srodrigc	error = 0;
5710159451Srodrigc	if (delta && delta->xed_startoff != NULLFILEOFF) {
5711159451Srodrigc		/* A change was actually made.
5712159451Srodrigc		 * Note that delta->xed_blockount is an offset at this
5713159451Srodrigc		 * point and needs to be converted to a block count.
5714159451Srodrigc		 */
5715159451Srodrigc		ASSERT(delta->xed_blockcount > delta->xed_startoff);
5716159451Srodrigc		delta->xed_blockcount -= delta->xed_startoff;
5717159451Srodrigc	}
5718153323Srodrigcerror0:
5719153323Srodrigc	/*
5720153323Srodrigc	 * Log everything.  Do this after conversion, there's no point in
5721159451Srodrigc	 * logging the extent records if we've converted to btree format.
5722153323Srodrigc	 */
5723153323Srodrigc	if ((logflags & XFS_ILOG_FEXT(whichfork)) &&
5724153323Srodrigc	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
5725153323Srodrigc		logflags &= ~XFS_ILOG_FEXT(whichfork);
5726153323Srodrigc	else if ((logflags & XFS_ILOG_FBROOT(whichfork)) &&
5727153323Srodrigc		 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)
5728153323Srodrigc		logflags &= ~XFS_ILOG_FBROOT(whichfork);
5729153323Srodrigc	/*
5730153323Srodrigc	 * Log inode even in the error case, if the transaction
5731153323Srodrigc	 * is dirty we'll need to shut down the filesystem.
5732153323Srodrigc	 */
5733153323Srodrigc	if (logflags)
5734153323Srodrigc		xfs_trans_log_inode(tp, ip, logflags);
5735153323Srodrigc	if (cur) {
5736153323Srodrigc		if (!error) {
5737153323Srodrigc			*firstblock = cur->bc_private.b.firstblock;
5738153323Srodrigc			cur->bc_private.b.allocated = 0;
5739153323Srodrigc		}
5740153323Srodrigc		xfs_btree_del_cursor(cur,
5741153323Srodrigc			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
5742153323Srodrigc	}
5743153323Srodrigc	return error;
5744153323Srodrigc}
5745153323Srodrigc
5746159451Srodrigc#undef copy_to_user
5747159451Srodrigcstatic __inline__ int
5748159451Srodrigccopy_to_user(void *dst, void *src, int len) {
5749159451Srodrigc	memcpy(dst,src,len);
5750159451Srodrigc	return 0;
5751159451Srodrigc}
5752159451Srodrigc#undef copy_from_user
5753159451Srodrigcstatic __inline__ int
5754159451Srodrigccopy_from_user(void *dst, void *src, int len) {
5755159451Srodrigc	memcpy(dst,src,len);
5756159451Srodrigc	return 0;
5757159451Srodrigc}
5758153323Srodrigc/*
5759153323Srodrigc * Fcntl interface to xfs_bmapi.
5760153323Srodrigc */
5761153323Srodrigcint						/* error code */
5762153323Srodrigcxfs_getbmap(
5763153323Srodrigc	bhv_desc_t		*bdp,		/* XFS behavior descriptor*/
5764153323Srodrigc	struct getbmap		*bmv,		/* user bmap structure */
5765159451Srodrigc	void			__user *ap,	/* pointer to user's array */
5766153323Srodrigc	int			interface)	/* interface flags */
5767153323Srodrigc{
5768153323Srodrigc	__int64_t		bmvend;		/* last block requested */
5769153323Srodrigc	int			error;		/* return value */
5770153323Srodrigc	__int64_t		fixlen;		/* length for -1 case */
5771153323Srodrigc	int			i;		/* extent number */
5772153323Srodrigc	xfs_inode_t		*ip;		/* xfs incore inode pointer */
5773153323Srodrigc	xfs_vnode_t		*vp;		/* corresponding vnode */
5774153323Srodrigc	int			lock;		/* lock state */
5775153323Srodrigc	xfs_bmbt_irec_t		*map;		/* buffer for user's data */
5776153323Srodrigc	xfs_mount_t		*mp;		/* file system mount point */
5777153323Srodrigc	int			nex;		/* # of user extents can do */
5778153323Srodrigc	int			nexleft;	/* # of user extents left */
5779153323Srodrigc	int			subnex;		/* # of bmapi's can do */
5780153323Srodrigc	int			nmap;		/* number of map entries */
5781153323Srodrigc	struct getbmap		out;		/* output structure */
5782153323Srodrigc	int			whichfork;	/* data or attr fork */
5783153323Srodrigc	int			prealloced;	/* this is a file with
5784153323Srodrigc						 * preallocated data space */
5785153323Srodrigc	int			sh_unwritten;	/* true, if unwritten */
5786153323Srodrigc						/* extents listed separately */
5787153323Srodrigc	int			bmapi_flags;	/* flags for xfs_bmapi */
5788153323Srodrigc	__int32_t		oflags;		/* getbmapx bmv_oflags field */
5789153323Srodrigc
5790153323Srodrigc	vp = BHV_TO_VNODE(bdp);
5791153323Srodrigc	ip = XFS_BHVTOI(bdp);
5792153323Srodrigc	mp = ip->i_mount;
5793153323Srodrigc
5794153323Srodrigc	whichfork = interface & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
5795153323Srodrigc	sh_unwritten = (interface & BMV_IF_PREALLOC) != 0;
5796153323Srodrigc
5797153323Srodrigc	/*	If the BMV_IF_NO_DMAPI_READ interface bit specified, do not
5798153323Srodrigc	 *	generate a DMAPI read event.  Otherwise, if the DM_EVENT_READ
5799153323Srodrigc	 *	bit is set for the file, generate a read event in order
5800153323Srodrigc	 *	that the DMAPI application may do its thing before we return
5801153323Srodrigc	 *	the extents.  Usually this means restoring user file data to
5802153323Srodrigc	 *	regions of the file that look like holes.
5803153323Srodrigc	 *
5804153323Srodrigc	 *	The "old behavior" (from XFS_IOC_GETBMAP) is to not specify
5805153323Srodrigc	 *	BMV_IF_NO_DMAPI_READ so that read events are generated.
5806153323Srodrigc	 *	If this were not true, callers of ioctl( XFS_IOC_GETBMAP )
5807153323Srodrigc	 *	could misinterpret holes in a DMAPI file as true holes,
5808153323Srodrigc	 *	when in fact they may represent offline user data.
5809153323Srodrigc	 */
5810153323Srodrigc	if (   (interface & BMV_IF_NO_DMAPI_READ) == 0
5811153323Srodrigc	    && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)
5812153323Srodrigc	    && whichfork == XFS_DATA_FORK) {
5813153323Srodrigc
5814153323Srodrigc		error = XFS_SEND_DATA(mp, DM_EVENT_READ, vp, 0, 0, 0, NULL);
5815153323Srodrigc		if (error)
5816153323Srodrigc			return XFS_ERROR(error);
5817153323Srodrigc	}
5818153323Srodrigc
5819153323Srodrigc	if (whichfork == XFS_ATTR_FORK) {
5820153323Srodrigc		if (XFS_IFORK_Q(ip)) {
5821153323Srodrigc			if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS &&
5822153323Srodrigc			    ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE &&
5823153323Srodrigc			    ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)
5824153323Srodrigc				return XFS_ERROR(EINVAL);
5825153323Srodrigc		} else if (unlikely(
5826153323Srodrigc			   ip->i_d.di_aformat != 0 &&
5827153323Srodrigc			   ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) {
5828153323Srodrigc			XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW,
5829153323Srodrigc					 ip->i_mount);
5830153323Srodrigc			return XFS_ERROR(EFSCORRUPTED);
5831153323Srodrigc		}
5832153323Srodrigc	} else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
5833153323Srodrigc		   ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
5834153323Srodrigc		   ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
5835153323Srodrigc		return XFS_ERROR(EINVAL);
5836153323Srodrigc	if (whichfork == XFS_DATA_FORK) {
5837159451Srodrigc		if ((ip->i_d.di_extsize && (ip->i_d.di_flags &
5838159451Srodrigc				(XFS_DIFLAG_REALTIME|XFS_DIFLAG_EXTSIZE))) ||
5839159451Srodrigc		    ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
5840153323Srodrigc			prealloced = 1;
5841153323Srodrigc			fixlen = XFS_MAXIOFFSET(mp);
5842153323Srodrigc		} else {
5843153323Srodrigc			prealloced = 0;
5844153323Srodrigc			fixlen = ip->i_d.di_size;
5845153323Srodrigc		}
5846153323Srodrigc	} else {
5847153323Srodrigc		prealloced = 0;
5848153323Srodrigc		fixlen = 1LL << 32;
5849153323Srodrigc	}
5850153323Srodrigc
5851153323Srodrigc	if (bmv->bmv_length == -1) {
5852153323Srodrigc		fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen));
5853153323Srodrigc		bmv->bmv_length = MAX( (__int64_t)(fixlen - bmv->bmv_offset),
5854153323Srodrigc					(__int64_t)0);
5855153323Srodrigc	} else if (bmv->bmv_length < 0)
5856153323Srodrigc		return XFS_ERROR(EINVAL);
5857153323Srodrigc	if (bmv->bmv_length == 0) {
5858153323Srodrigc		bmv->bmv_entries = 0;
5859153323Srodrigc		return 0;
5860153323Srodrigc	}
5861153323Srodrigc	nex = bmv->bmv_count - 1;
5862153323Srodrigc	if (nex <= 0)
5863153323Srodrigc		return XFS_ERROR(EINVAL);
5864153323Srodrigc	bmvend = bmv->bmv_offset + bmv->bmv_length;
5865153323Srodrigc
5866153323Srodrigc	xfs_ilock(ip, XFS_IOLOCK_SHARED);
5867153323Srodrigc
5868153323Srodrigc	if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) {
5869153323Srodrigc		/* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */
5870153323Srodrigc		XVOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error);
5871153323Srodrigc	}
5872153323Srodrigc
5873153323Srodrigc	ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0);
5874153323Srodrigc
5875153323Srodrigc	lock = xfs_ilock_map_shared(ip);
5876153323Srodrigc
5877153323Srodrigc	/*
5878153323Srodrigc	 * Don't let nex be bigger than the number of extents
5879153323Srodrigc	 * we can have assuming alternating holes and real extents.
5880153323Srodrigc	 */
5881153323Srodrigc	if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1)
5882153323Srodrigc		nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1;
5883153323Srodrigc
5884153323Srodrigc	bmapi_flags = XFS_BMAPI_AFLAG(whichfork) |
5885153323Srodrigc			((sh_unwritten) ? 0 : XFS_BMAPI_IGSTATE);
5886153323Srodrigc
5887153323Srodrigc	/*
5888153323Srodrigc	 * Allocate enough space to handle "subnex" maps at a time.
5889153323Srodrigc	 */
5890153323Srodrigc	subnex = 16;
5891153323Srodrigc	map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP);
5892153323Srodrigc
5893153323Srodrigc	bmv->bmv_entries = 0;
5894153323Srodrigc
5895153323Srodrigc	if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0) {
5896153323Srodrigc		error = 0;
5897153323Srodrigc		goto unlock_and_return;
5898153323Srodrigc	}
5899153323Srodrigc
5900153323Srodrigc	nexleft = nex;
5901153323Srodrigc
5902153323Srodrigc	do {
5903153323Srodrigc		nmap = (nexleft > subnex) ? subnex : nexleft;
5904153323Srodrigc		error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
5905153323Srodrigc				  XFS_BB_TO_FSB(mp, bmv->bmv_length),
5906159451Srodrigc				  bmapi_flags, NULL, 0, map, &nmap,
5907159451Srodrigc				  NULL, NULL);
5908153323Srodrigc		if (error)
5909153323Srodrigc			goto unlock_and_return;
5910153323Srodrigc		ASSERT(nmap <= subnex);
5911153323Srodrigc
5912153323Srodrigc		for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
5913153323Srodrigc			nexleft--;
5914153323Srodrigc			oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
5915153323Srodrigc					BMV_OF_PREALLOC : 0;
5916153323Srodrigc			out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff);
5917153323Srodrigc			out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
5918153323Srodrigc			ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
5919159451Srodrigc                        if (map[i].br_startblock == HOLESTARTBLOCK &&
5920159451Srodrigc                           ((prealloced && out.bmv_offset + out.bmv_length == bmvend) ||
5921159451Srodrigc                             whichfork == XFS_ATTR_FORK )) {
5922159451Srodrigc                                /*
5923159451Srodrigc                                 * came to hole at end of file or the end of
5924159451Srodrigc                                   attribute fork
5925159451Srodrigc                                 */
5926153323Srodrigc				goto unlock_and_return;
5927153323Srodrigc			} else {
5928153323Srodrigc				out.bmv_block =
5929153323Srodrigc				    (map[i].br_startblock == HOLESTARTBLOCK) ?
5930153323Srodrigc					-1 :
5931153323Srodrigc					XFS_FSB_TO_DB(ip, map[i].br_startblock);
5932153323Srodrigc
5933153323Srodrigc				/* return either getbmap/getbmapx structure. */
5934153323Srodrigc				if (interface & BMV_IF_EXTENDED) {
5935153323Srodrigc					struct	getbmapx	outx;
5936153323Srodrigc
5937153323Srodrigc					GETBMAP_CONVERT(out,outx);
5938153323Srodrigc					outx.bmv_oflags = oflags;
5939153323Srodrigc					outx.bmv_unused1 = outx.bmv_unused2 = 0;
5940153323Srodrigc					if (copy_to_user(ap, &outx,
5941153323Srodrigc							sizeof(outx))) {
5942153323Srodrigc						error = XFS_ERROR(EFAULT);
5943153323Srodrigc						goto unlock_and_return;
5944153323Srodrigc					}
5945153323Srodrigc				} else {
5946153323Srodrigc					if (copy_to_user(ap, &out,
5947153323Srodrigc							sizeof(out))) {
5948153323Srodrigc						error = XFS_ERROR(EFAULT);
5949153323Srodrigc						goto unlock_and_return;
5950153323Srodrigc					}
5951153323Srodrigc				}
5952153323Srodrigc				bmv->bmv_offset =
5953153323Srodrigc					out.bmv_offset + out.bmv_length;
5954153323Srodrigc				bmv->bmv_length = MAX((__int64_t)0,
5955153323Srodrigc					(__int64_t)(bmvend - bmv->bmv_offset));
5956153323Srodrigc				bmv->bmv_entries++;
5957153323Srodrigc				ap = (interface & BMV_IF_EXTENDED) ?
5958159451Srodrigc						(void __user *)
5959159451Srodrigc					((struct getbmapx __user *)ap + 1) :
5960159451Srodrigc						(void __user *)
5961159451Srodrigc					((struct getbmap __user *)ap + 1);
5962153323Srodrigc			}
5963153323Srodrigc		}
5964153323Srodrigc	} while (nmap && nexleft && bmv->bmv_length);
5965153323Srodrigc
5966153323Srodrigcunlock_and_return:
5967153323Srodrigc	xfs_iunlock_map_shared(ip, lock);
5968153323Srodrigc	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
5969153323Srodrigc
5970153323Srodrigc	kmem_free(map, subnex * sizeof(*map));
5971153323Srodrigc
5972153323Srodrigc	return error;
5973153323Srodrigc}
5974153323Srodrigc
5975153323Srodrigc/*
5976153323Srodrigc * Check the last inode extent to determine whether this allocation will result
5977153323Srodrigc * in blocks being allocated at the end of the file. When we allocate new data
5978153323Srodrigc * blocks at the end of the file which do not start at the previous data block,
5979153323Srodrigc * we will try to align the new blocks at stripe unit boundaries.
5980153323Srodrigc */
5981159451SrodrigcSTATIC int				/* error */
5982153323Srodrigcxfs_bmap_isaeof(
5983153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
5984153323Srodrigc	xfs_fileoff_t   off,		/* file offset in fsblocks */
5985153323Srodrigc	int             whichfork,	/* data or attribute fork */
5986153323Srodrigc	char		*aeof)		/* return value */
5987153323Srodrigc{
5988153323Srodrigc	int		error;		/* error return value */
5989153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
5990159451Srodrigc	xfs_bmbt_rec_t	*lastrec;	/* extent record pointer */
5991159451Srodrigc	xfs_extnum_t	nextents;	/* number of file extents */
5992159451Srodrigc	xfs_bmbt_irec_t	s;		/* expanded extent record */
5993153323Srodrigc
5994153323Srodrigc	ASSERT(whichfork == XFS_DATA_FORK);
5995153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
5996153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
5997153323Srodrigc	    (error = xfs_iread_extents(NULL, ip, whichfork)))
5998153323Srodrigc		return error;
5999153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
6000153323Srodrigc	if (nextents == 0) {
6001153323Srodrigc		*aeof = 1;
6002153323Srodrigc		return 0;
6003153323Srodrigc	}
6004153323Srodrigc	/*
6005153323Srodrigc	 * Go to the last extent
6006153323Srodrigc	 */
6007159451Srodrigc	lastrec = xfs_iext_get_ext(ifp, nextents - 1);
6008153323Srodrigc	xfs_bmbt_get_all(lastrec, &s);
6009153323Srodrigc	/*
6010153323Srodrigc	 * Check we are allocating in the last extent (for delayed allocations)
6011153323Srodrigc	 * or past the last extent for non-delayed allocations.
6012153323Srodrigc	 */
6013153323Srodrigc	*aeof = (off >= s.br_startoff &&
6014153323Srodrigc		 off < s.br_startoff + s.br_blockcount &&
6015153323Srodrigc		 ISNULLSTARTBLOCK(s.br_startblock)) ||
6016153323Srodrigc		off >= s.br_startoff + s.br_blockcount;
6017153323Srodrigc	return 0;
6018153323Srodrigc}
6019153323Srodrigc
6020153323Srodrigc/*
6021153323Srodrigc * Check if the endoff is outside the last extent. If so the caller will grow
6022153323Srodrigc * the allocation to a stripe unit boundary.
6023153323Srodrigc */
6024153323Srodrigcint					/* error */
6025153323Srodrigcxfs_bmap_eof(
6026153323Srodrigc	xfs_inode_t	*ip,		/* incore inode pointer */
6027153323Srodrigc	xfs_fileoff_t	endoff,		/* file offset in fsblocks */
6028153323Srodrigc	int		whichfork,	/* data or attribute fork */
6029153323Srodrigc	int		*eof)		/* result value */
6030153323Srodrigc{
6031153323Srodrigc	xfs_fsblock_t	blockcount;	/* extent block count */
6032153323Srodrigc	int		error;		/* error return value */
6033153323Srodrigc	xfs_ifork_t	*ifp;		/* inode fork pointer */
6034159451Srodrigc	xfs_bmbt_rec_t	*lastrec;	/* extent record pointer */
6035159451Srodrigc	xfs_extnum_t	nextents;	/* number of file extents */
6036153323Srodrigc	xfs_fileoff_t	startoff;	/* extent starting file offset */
6037153323Srodrigc
6038153323Srodrigc	ASSERT(whichfork == XFS_DATA_FORK);
6039153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
6040153323Srodrigc	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
6041153323Srodrigc	    (error = xfs_iread_extents(NULL, ip, whichfork)))
6042153323Srodrigc		return error;
6043153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
6044153323Srodrigc	if (nextents == 0) {
6045153323Srodrigc		*eof = 1;
6046153323Srodrigc		return 0;
6047153323Srodrigc	}
6048153323Srodrigc	/*
6049153323Srodrigc	 * Go to the last extent
6050153323Srodrigc	 */
6051159451Srodrigc	lastrec = xfs_iext_get_ext(ifp, nextents - 1);
6052153323Srodrigc	startoff = xfs_bmbt_get_startoff(lastrec);
6053153323Srodrigc	blockcount = xfs_bmbt_get_blockcount(lastrec);
6054153323Srodrigc	*eof = endoff >= startoff + blockcount;
6055153323Srodrigc	return 0;
6056153323Srodrigc}
6057153323Srodrigc
6058159451Srodrigc#ifdef DEBUG
6059159451Srodrigc#if 0
6060153323Srodrigc/*
6061153323Srodrigc * Check that the extents list for the inode ip is in the right order.
6062153323Srodrigc */
6063153323SrodrigcSTATIC void
6064153323Srodrigcxfs_bmap_check_extents(
6065153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
6066153323Srodrigc	int			whichfork)	/* data or attr fork */
6067153323Srodrigc{
6068153323Srodrigc	xfs_bmbt_rec_t		*ep;		/* current extent entry */
6069159451Srodrigc	xfs_extnum_t		idx;		/* extent record index */
6070153323Srodrigc	xfs_ifork_t		*ifp;		/* inode fork pointer */
6071153323Srodrigc	xfs_extnum_t		nextents;	/* number of extents in list */
6072159451Srodrigc	xfs_bmbt_rec_t		*nextp;		/* next extent entry */
6073153323Srodrigc
6074153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
6075153323Srodrigc	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
6076153323Srodrigc	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
6077159451Srodrigc	ep = xfs_iext_get_ext(ifp, 0);
6078159451Srodrigc	for (idx = 0; idx < nextents - 1; idx++) {
6079159451Srodrigc		nextp = xfs_iext_get_ext(ifp, idx + 1);
6080153323Srodrigc		xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep,
6081159451Srodrigc			(void *)(nextp));
6082159451Srodrigc		ep = nextp;
6083153323Srodrigc	}
6084153323Srodrigc}
6085159451Srodrigc#endif
6086153323Srodrigc
6087153323SrodrigcSTATIC
6088153323Srodrigcxfs_buf_t *
6089153323Srodrigcxfs_bmap_get_bp(
6090153323Srodrigc	xfs_btree_cur_t         *cur,
6091153323Srodrigc	xfs_fsblock_t		bno)
6092153323Srodrigc{
6093153323Srodrigc	int i;
6094153323Srodrigc	xfs_buf_t *bp;
6095153323Srodrigc
6096153323Srodrigc	if (!cur)
6097153323Srodrigc		return(NULL);
6098153323Srodrigc
6099153323Srodrigc	bp = NULL;
6100153323Srodrigc	for(i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
6101153323Srodrigc		bp = cur->bc_bufs[i];
6102153323Srodrigc		if (!bp) break;
6103153323Srodrigc		if (XFS_BUF_ADDR(bp) == bno)
6104153323Srodrigc			break;	/* Found it */
6105153323Srodrigc	}
6106153323Srodrigc	if (i == XFS_BTREE_MAXLEVELS)
6107153323Srodrigc		bp = NULL;
6108153323Srodrigc
6109153323Srodrigc	if (!bp) { /* Chase down all the log items to see if the bp is there */
6110153323Srodrigc		xfs_log_item_chunk_t    *licp;
6111153323Srodrigc		xfs_trans_t		*tp;
6112153323Srodrigc
6113153323Srodrigc		tp = cur->bc_tp;
6114153323Srodrigc		licp = &tp->t_items;
6115153323Srodrigc		while (!bp && licp != NULL) {
6116153323Srodrigc			if (XFS_LIC_ARE_ALL_FREE(licp)) {
6117153323Srodrigc				licp = licp->lic_next;
6118153323Srodrigc				continue;
6119153323Srodrigc			}
6120153323Srodrigc			for (i = 0; i < licp->lic_unused; i++) {
6121153323Srodrigc				xfs_log_item_desc_t	*lidp;
6122153323Srodrigc				xfs_log_item_t		*lip;
6123153323Srodrigc				xfs_buf_log_item_t	*bip;
6124153323Srodrigc				xfs_buf_t		*lbp;
6125153323Srodrigc
6126153323Srodrigc				if (XFS_LIC_ISFREE(licp, i)) {
6127153323Srodrigc					continue;
6128153323Srodrigc				}
6129153323Srodrigc
6130153323Srodrigc				lidp = XFS_LIC_SLOT(licp, i);
6131153323Srodrigc				lip = lidp->lid_item;
6132153323Srodrigc				if (lip->li_type != XFS_LI_BUF)
6133153323Srodrigc					continue;
6134153323Srodrigc
6135153323Srodrigc				bip = (xfs_buf_log_item_t *)lip;
6136153323Srodrigc				lbp = bip->bli_buf;
6137153323Srodrigc
6138153323Srodrigc				if (XFS_BUF_ADDR(lbp) == bno) {
6139153323Srodrigc					bp = lbp;
6140153323Srodrigc					break; /* Found it */
6141153323Srodrigc				}
6142153323Srodrigc			}
6143153323Srodrigc			licp = licp->lic_next;
6144153323Srodrigc		}
6145153323Srodrigc	}
6146153323Srodrigc	return(bp);
6147153323Srodrigc}
6148153323Srodrigc
6149159451SrodrigcSTATIC void
6150153323Srodrigcxfs_check_block(
6151153323Srodrigc	xfs_bmbt_block_t        *block,
6152153323Srodrigc	xfs_mount_t		*mp,
6153153323Srodrigc	int			root,
6154153323Srodrigc	short			sz)
6155153323Srodrigc{
6156153323Srodrigc	int			i, j, dmxr;
6157153323Srodrigc	xfs_bmbt_ptr_t		*pp, *thispa;	/* pointer to block address */
6158153323Srodrigc	xfs_bmbt_key_t		*prevp, *keyp;
6159153323Srodrigc
6160159451Srodrigc	ASSERT(be16_to_cpu(block->bb_level) > 0);
6161153323Srodrigc
6162153323Srodrigc	prevp = NULL;
6163159451Srodrigc	for( i = 1; i <= be16_to_cpu(block->bb_numrecs); i++) {
6164153323Srodrigc		dmxr = mp->m_bmap_dmxr[0];
6165153323Srodrigc
6166153323Srodrigc		if (root) {
6167153323Srodrigc			keyp = XFS_BMAP_BROOT_KEY_ADDR(block, i, sz);
6168153323Srodrigc		} else {
6169153323Srodrigc			keyp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize,
6170153323Srodrigc				xfs_bmbt, block, i, dmxr);
6171153323Srodrigc		}
6172153323Srodrigc
6173153323Srodrigc		if (prevp) {
6174153323Srodrigc			xfs_btree_check_key(XFS_BTNUM_BMAP, prevp, keyp);
6175153323Srodrigc		}
6176153323Srodrigc		prevp = keyp;
6177153323Srodrigc
6178153323Srodrigc		/*
6179153323Srodrigc		 * Compare the block numbers to see if there are dups.
6180153323Srodrigc		 */
6181153323Srodrigc
6182153323Srodrigc		if (root) {
6183153323Srodrigc			pp = XFS_BMAP_BROOT_PTR_ADDR(block, i, sz);
6184153323Srodrigc		} else {
6185153323Srodrigc			pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
6186153323Srodrigc				xfs_bmbt, block, i, dmxr);
6187153323Srodrigc		}
6188159451Srodrigc		for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) {
6189153323Srodrigc			if (root) {
6190153323Srodrigc				thispa = XFS_BMAP_BROOT_PTR_ADDR(block, j, sz);
6191153323Srodrigc			} else {
6192153323Srodrigc				thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
6193153323Srodrigc					xfs_bmbt, block, j, dmxr);
6194153323Srodrigc			}
6195153323Srodrigc			if (INT_GET(*thispa, ARCH_CONVERT) ==
6196153323Srodrigc			    INT_GET(*pp, ARCH_CONVERT)) {
6197153323Srodrigc				cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
6198153323Srodrigc					__FUNCTION__, j, i,
6199153323Srodrigc					INT_GET(*thispa, ARCH_CONVERT));
6200153323Srodrigc				panic("%s: ptrs are equal in node\n",
6201153323Srodrigc					__FUNCTION__);
6202153323Srodrigc			}
6203153323Srodrigc		}
6204153323Srodrigc	}
6205153323Srodrigc}
6206153323Srodrigc
6207153323Srodrigc/*
6208153323Srodrigc * Check that the extents for the inode ip are in the right order in all
6209153323Srodrigc * btree leaves.
6210153323Srodrigc */
6211153323Srodrigc
6212153323SrodrigcSTATIC void
6213153323Srodrigcxfs_bmap_check_leaf_extents(
6214153323Srodrigc	xfs_btree_cur_t		*cur,	/* btree cursor or null */
6215153323Srodrigc	xfs_inode_t		*ip,		/* incore inode pointer */
6216153323Srodrigc	int			whichfork)	/* data or attr fork */
6217153323Srodrigc{
6218153323Srodrigc	xfs_bmbt_block_t	*block;	/* current btree block */
6219153323Srodrigc	xfs_fsblock_t		bno;	/* block # of "block" */
6220153323Srodrigc	xfs_buf_t		*bp;	/* buffer for "block" */
6221153323Srodrigc	int			error;	/* error return value */
6222159451Srodrigc	xfs_extnum_t		i=0, j;	/* index into the extents list */
6223153323Srodrigc	xfs_ifork_t		*ifp;	/* fork structure */
6224153323Srodrigc	int			level;	/* btree level, for checking */
6225153323Srodrigc	xfs_mount_t		*mp;	/* file system mount structure */
6226153323Srodrigc	xfs_bmbt_ptr_t		*pp;	/* pointer to block address */
6227159451Srodrigc	xfs_bmbt_rec_t		*ep;	/* pointer to current extent */
6228159451Srodrigc	xfs_bmbt_rec_t		*lastp; /* pointer to previous extent */
6229159451Srodrigc	xfs_bmbt_rec_t		*nextp;	/* pointer to next extent */
6230153323Srodrigc	int			bp_release = 0;
6231153323Srodrigc
6232153323Srodrigc	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) {
6233153323Srodrigc		return;
6234153323Srodrigc	}
6235153323Srodrigc
6236153323Srodrigc	bno = NULLFSBLOCK;
6237153323Srodrigc	mp = ip->i_mount;
6238153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
6239153323Srodrigc	block = ifp->if_broot;
6240153323Srodrigc	/*
6241153323Srodrigc	 * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
6242153323Srodrigc	 */
6243159451Srodrigc	level = be16_to_cpu(block->bb_level);
6244159451Srodrigc	ASSERT(level > 0);
6245153323Srodrigc	xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
6246153323Srodrigc	pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
6247153323Srodrigc	ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
6248153323Srodrigc	ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
6249153323Srodrigc	ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
6250153323Srodrigc	bno = INT_GET(*pp, ARCH_CONVERT);
6251153323Srodrigc	/*
6252153323Srodrigc	 * Go down the tree until leaf level is reached, following the first
6253153323Srodrigc	 * pointer (leftmost) at each level.
6254153323Srodrigc	 */
6255153323Srodrigc	while (level-- > 0) {
6256153323Srodrigc		/* See if buf is in cur first */
6257153323Srodrigc		bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
6258153323Srodrigc		if (bp) {
6259153323Srodrigc			bp_release = 0;
6260153323Srodrigc		} else {
6261153323Srodrigc			bp_release = 1;
6262153323Srodrigc		}
6263153323Srodrigc		if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
6264153323Srodrigc				XFS_BMAP_BTREE_REF)))
6265153323Srodrigc			goto error_norelse;
6266153323Srodrigc		block = XFS_BUF_TO_BMBT_BLOCK(bp);
6267153323Srodrigc		XFS_WANT_CORRUPTED_GOTO(
6268153323Srodrigc			XFS_BMAP_SANITY_CHECK(mp, block, level),
6269153323Srodrigc			error0);
6270153323Srodrigc		if (level == 0)
6271153323Srodrigc			break;
6272153323Srodrigc
6273153323Srodrigc		/*
6274153323Srodrigc		 * Check this block for basic sanity (increasing keys and
6275153323Srodrigc		 * no duplicate blocks).
6276153323Srodrigc		 */
6277153323Srodrigc
6278153323Srodrigc		xfs_check_block(block, mp, 0, 0);
6279153323Srodrigc		pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
6280153323Srodrigc			1, mp->m_bmap_dmxr[1]);
6281153323Srodrigc		XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0);
6282153323Srodrigc		bno = INT_GET(*pp, ARCH_CONVERT);
6283153323Srodrigc		if (bp_release) {
6284153323Srodrigc			bp_release = 0;
6285153323Srodrigc			xfs_trans_brelse(NULL, bp);
6286153323Srodrigc		}
6287153323Srodrigc	}
6288153323Srodrigc
6289153323Srodrigc	/*
6290153323Srodrigc	 * Here with bp and block set to the leftmost leaf node in the tree.
6291153323Srodrigc	 */
6292153323Srodrigc	i = 0;
6293153323Srodrigc
6294153323Srodrigc	/*
6295153323Srodrigc	 * Loop over all leaf nodes checking that all extents are in the right order.
6296153323Srodrigc	 */
6297153323Srodrigc	lastp = NULL;
6298153323Srodrigc	for (;;) {
6299153323Srodrigc		xfs_fsblock_t	nextbno;
6300153323Srodrigc		xfs_extnum_t	num_recs;
6301153323Srodrigc
6302153323Srodrigc
6303159451Srodrigc		num_recs = be16_to_cpu(block->bb_numrecs);
6304153323Srodrigc
6305153323Srodrigc		/*
6306153323Srodrigc		 * Read-ahead the next leaf block, if any.
6307153323Srodrigc		 */
6308153323Srodrigc
6309159451Srodrigc		nextbno = be64_to_cpu(block->bb_rightsib);
6310153323Srodrigc
6311153323Srodrigc		/*
6312153323Srodrigc		 * Check all the extents to make sure they are OK.
6313153323Srodrigc		 * If we had a previous block, the last entry should
6314153323Srodrigc		 * conform with the first entry in this one.
6315153323Srodrigc		 */
6316153323Srodrigc
6317159451Srodrigc		ep = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
6318153323Srodrigc			block, 1, mp->m_bmap_dmxr[0]);
6319159451Srodrigc		for (j = 1; j < num_recs; j++) {
6320159451Srodrigc			nextp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
6321159451Srodrigc				block, j + 1, mp->m_bmap_dmxr[0]);
6322153323Srodrigc			if (lastp) {
6323153323Srodrigc				xfs_btree_check_rec(XFS_BTNUM_BMAP,
6324153323Srodrigc					(void *)lastp, (void *)ep);
6325153323Srodrigc			}
6326153323Srodrigc			xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep,
6327159451Srodrigc				(void *)(nextp));
6328159451Srodrigc			lastp = ep;
6329159451Srodrigc			ep = nextp;
6330153323Srodrigc		}
6331153323Srodrigc
6332153323Srodrigc		i += num_recs;
6333153323Srodrigc		if (bp_release) {
6334153323Srodrigc			bp_release = 0;
6335153323Srodrigc			xfs_trans_brelse(NULL, bp);
6336153323Srodrigc		}
6337153323Srodrigc		bno = nextbno;
6338153323Srodrigc		/*
6339153323Srodrigc		 * If we've reached the end, stop.
6340153323Srodrigc		 */
6341153323Srodrigc		if (bno == NULLFSBLOCK)
6342153323Srodrigc			break;
6343153323Srodrigc
6344153323Srodrigc		bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
6345153323Srodrigc		if (bp) {
6346153323Srodrigc			bp_release = 0;
6347153323Srodrigc		} else {
6348153323Srodrigc			bp_release = 1;
6349153323Srodrigc		}
6350153323Srodrigc		if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
6351153323Srodrigc				XFS_BMAP_BTREE_REF)))
6352153323Srodrigc			goto error_norelse;
6353153323Srodrigc		block = XFS_BUF_TO_BMBT_BLOCK(bp);
6354153323Srodrigc	}
6355153323Srodrigc	if (bp_release) {
6356153323Srodrigc		bp_release = 0;
6357153323Srodrigc		xfs_trans_brelse(NULL, bp);
6358153323Srodrigc	}
6359153323Srodrigc	return;
6360153323Srodrigc
6361153323Srodrigcerror0:
6362153323Srodrigc	cmn_err(CE_WARN, "%s: at error0", __FUNCTION__);
6363153323Srodrigc	if (bp_release)
6364153323Srodrigc		xfs_trans_brelse(NULL, bp);
6365153323Srodrigcerror_norelse:
6366153323Srodrigc	cmn_err(CE_WARN, "%s: BAD after btree leaves for %d extents",
6367159451Srodrigc		__FUNCTION__, i);
6368153323Srodrigc	panic("%s: CORRUPTED BTREE OR SOMETHING", __FUNCTION__);
6369153323Srodrigc	return;
6370153323Srodrigc}
6371153323Srodrigc#endif
6372153323Srodrigc
6373153323Srodrigc/*
6374153323Srodrigc * Count fsblocks of the given fork.
6375153323Srodrigc */
6376153323Srodrigcint						/* error */
6377153323Srodrigcxfs_bmap_count_blocks(
6378153323Srodrigc	xfs_trans_t		*tp,		/* transaction pointer */
6379153323Srodrigc	xfs_inode_t		*ip,		/* incore inode */
6380153323Srodrigc	int			whichfork,	/* data or attr fork */
6381153323Srodrigc	int			*count)		/* out: count of blocks */
6382153323Srodrigc{
6383153323Srodrigc	xfs_bmbt_block_t	*block;	/* current btree block */
6384153323Srodrigc	xfs_fsblock_t		bno;	/* block # of "block" */
6385153323Srodrigc	xfs_ifork_t		*ifp;	/* fork structure */
6386153323Srodrigc	int			level;	/* btree level, for checking */
6387153323Srodrigc	xfs_mount_t		*mp;	/* file system mount structure */
6388153323Srodrigc	xfs_bmbt_ptr_t		*pp;	/* pointer to block address */
6389153323Srodrigc
6390153323Srodrigc	bno = NULLFSBLOCK;
6391153323Srodrigc	mp = ip->i_mount;
6392153323Srodrigc	ifp = XFS_IFORK_PTR(ip, whichfork);
6393153323Srodrigc	if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) {
6394159451Srodrigc		if (unlikely(xfs_bmap_count_leaves(ifp, 0,
6395153323Srodrigc			ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t),
6396153323Srodrigc			count) < 0)) {
6397153323Srodrigc			XFS_ERROR_REPORT("xfs_bmap_count_blocks(1)",
6398153323Srodrigc					 XFS_ERRLEVEL_LOW, mp);
6399153323Srodrigc			return XFS_ERROR(EFSCORRUPTED);
6400153323Srodrigc		}
6401153323Srodrigc		return 0;
6402153323Srodrigc	}
6403153323Srodrigc
6404153323Srodrigc	/*
6405153323Srodrigc	 * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
6406153323Srodrigc	 */
6407153323Srodrigc	block = ifp->if_broot;
6408159451Srodrigc	level = be16_to_cpu(block->bb_level);
6409159451Srodrigc	ASSERT(level > 0);
6410153323Srodrigc	pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
6411153323Srodrigc	ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
6412153323Srodrigc	ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
6413153323Srodrigc	ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
6414153323Srodrigc	bno = INT_GET(*pp, ARCH_CONVERT);
6415153323Srodrigc
6416159451Srodrigc	if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
6417153323Srodrigc		XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
6418153323Srodrigc				 mp);
6419153323Srodrigc		return XFS_ERROR(EFSCORRUPTED);
6420153323Srodrigc	}
6421153323Srodrigc
6422153323Srodrigc	return 0;
6423153323Srodrigc}
6424153323Srodrigc
6425153323Srodrigc/*
6426153323Srodrigc * Recursively walks each level of a btree
6427153323Srodrigc * to count total fsblocks is use.
6428153323Srodrigc */
6429153323Srodrigcint                                     /* error */
6430153323Srodrigcxfs_bmap_count_tree(
6431153323Srodrigc	xfs_mount_t     *mp,            /* file system mount point */
6432153323Srodrigc	xfs_trans_t     *tp,            /* transaction pointer */
6433159451Srodrigc	xfs_ifork_t	*ifp,		/* inode fork pointer */
6434153323Srodrigc	xfs_fsblock_t   blockno,	/* file system block number */
6435153323Srodrigc	int             levelin,	/* level in btree */
6436153323Srodrigc	int		*count)		/* Count of blocks */
6437153323Srodrigc{
6438153323Srodrigc	int			error;
6439153323Srodrigc	xfs_buf_t		*bp, *nbp;
6440153323Srodrigc	int			level = levelin;
6441153323Srodrigc	xfs_bmbt_ptr_t          *pp;
6442153323Srodrigc	xfs_fsblock_t           bno = blockno;
6443153323Srodrigc	xfs_fsblock_t		nextbno;
6444153323Srodrigc	xfs_bmbt_block_t        *block, *nextblock;
6445153323Srodrigc	int			numrecs;
6446153323Srodrigc
6447153323Srodrigc	if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF)))
6448153323Srodrigc		return error;
6449153323Srodrigc	*count += 1;
6450153323Srodrigc	block = XFS_BUF_TO_BMBT_BLOCK(bp);
6451153323Srodrigc
6452153323Srodrigc	if (--level) {
6453153323Srodrigc		/* Not at node above leafs, count this level of nodes */
6454159451Srodrigc		nextbno = be64_to_cpu(block->bb_rightsib);
6455153323Srodrigc		while (nextbno != NULLFSBLOCK) {
6456153323Srodrigc			if ((error = xfs_btree_read_bufl(mp, tp, nextbno,
6457153323Srodrigc				0, &nbp, XFS_BMAP_BTREE_REF)))
6458153323Srodrigc				return error;
6459153323Srodrigc			*count += 1;
6460153323Srodrigc			nextblock = XFS_BUF_TO_BMBT_BLOCK(nbp);
6461159451Srodrigc			nextbno = be64_to_cpu(nextblock->bb_rightsib);
6462153323Srodrigc			xfs_trans_brelse(tp, nbp);
6463153323Srodrigc		}
6464153323Srodrigc
6465153323Srodrigc		/* Dive to the next level */
6466153323Srodrigc		pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
6467153323Srodrigc			xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
6468153323Srodrigc		bno = INT_GET(*pp, ARCH_CONVERT);
6469153323Srodrigc		if (unlikely((error =
6470159451Srodrigc		     xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
6471153323Srodrigc			xfs_trans_brelse(tp, bp);
6472153323Srodrigc			XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
6473153323Srodrigc					 XFS_ERRLEVEL_LOW, mp);
6474153323Srodrigc			return XFS_ERROR(EFSCORRUPTED);
6475153323Srodrigc		}
6476153323Srodrigc		xfs_trans_brelse(tp, bp);
6477153323Srodrigc	} else {
6478153323Srodrigc		/* count all level 1 nodes and their leaves */
6479153323Srodrigc		for (;;) {
6480159451Srodrigc			nextbno = be64_to_cpu(block->bb_rightsib);
6481159451Srodrigc			numrecs = be16_to_cpu(block->bb_numrecs);
6482159451Srodrigc			if (unlikely(xfs_bmap_disk_count_leaves(ifp, mp,
6483159451Srodrigc					0, block, numrecs, count) < 0)) {
6484153323Srodrigc				xfs_trans_brelse(tp, bp);
6485153323Srodrigc				XFS_ERROR_REPORT("xfs_bmap_count_tree(2)",
6486153323Srodrigc						 XFS_ERRLEVEL_LOW, mp);
6487153323Srodrigc				return XFS_ERROR(EFSCORRUPTED);
6488153323Srodrigc			}
6489153323Srodrigc			xfs_trans_brelse(tp, bp);
6490153323Srodrigc			if (nextbno == NULLFSBLOCK)
6491153323Srodrigc				break;
6492153323Srodrigc			bno = nextbno;
6493153323Srodrigc			if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
6494153323Srodrigc				XFS_BMAP_BTREE_REF)))
6495153323Srodrigc				return error;
6496153323Srodrigc			*count += 1;
6497153323Srodrigc			block = XFS_BUF_TO_BMBT_BLOCK(bp);
6498153323Srodrigc		}
6499153323Srodrigc	}
6500153323Srodrigc	return 0;
6501153323Srodrigc}
6502153323Srodrigc
6503153323Srodrigc/*
6504159451Srodrigc * Count leaf blocks given a range of extent records.
6505153323Srodrigc */
6506153323Srodrigcint
6507153323Srodrigcxfs_bmap_count_leaves(
6508159451Srodrigc	xfs_ifork_t		*ifp,
6509159451Srodrigc	xfs_extnum_t		idx,
6510153323Srodrigc	int			numrecs,
6511153323Srodrigc	int			*count)
6512153323Srodrigc{
6513153323Srodrigc	int		b;
6514159451Srodrigc	xfs_bmbt_rec_t	*frp;
6515153323Srodrigc
6516159451Srodrigc	for (b = 0; b < numrecs; b++) {
6517159451Srodrigc		frp = xfs_iext_get_ext(ifp, idx + b);
6518159451Srodrigc		*count += xfs_bmbt_get_blockcount(frp);
6519159451Srodrigc	}
6520159451Srodrigc	return 0;
6521159451Srodrigc}
6522159451Srodrigc
6523159451Srodrigc/*
6524159451Srodrigc * Count leaf blocks given a range of extent records originally
6525159451Srodrigc * in btree format.
6526159451Srodrigc */
6527159451Srodrigcint
6528159451Srodrigcxfs_bmap_disk_count_leaves(
6529159451Srodrigc	xfs_ifork_t		*ifp,
6530159451Srodrigc	xfs_mount_t		*mp,
6531159451Srodrigc	xfs_extnum_t		idx,
6532159451Srodrigc	xfs_bmbt_block_t	*block,
6533159451Srodrigc	int			numrecs,
6534159451Srodrigc	int			*count)
6535159451Srodrigc{
6536159451Srodrigc	int		b;
6537159451Srodrigc	xfs_bmbt_rec_t	*frp;
6538159451Srodrigc
6539159451Srodrigc	for (b = 1; b <= numrecs; b++) {
6540159451Srodrigc		frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize,
6541159451Srodrigc			xfs_bmbt, block, idx + b, mp->m_bmap_dmxr[0]);
6542153323Srodrigc		*count += xfs_bmbt_disk_get_blockcount(frp);
6543159451Srodrigc	}
6544153323Srodrigc	return 0;
6545153323Srodrigc}
6546153323Srodrigc
6547153323Srodrigc
6548