xfs_bmap.c 178 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3
 * All Rights Reserved.
Linus Torvalds's avatar
Linus Torvalds committed
4
 *
5
6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
Linus Torvalds's avatar
Linus Torvalds committed
7
8
 * published by the Free Software Foundation.
 *
9
10
11
12
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
Linus Torvalds's avatar
Linus Torvalds committed
13
 *
14
15
16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Linus Torvalds's avatar
Linus Torvalds committed
17
18
 */
#include "xfs.h"
19
#include "xfs_fs.h"
Linus Torvalds's avatar
Linus Torvalds committed
20
#include "xfs_types.h"
21
#include "xfs_bit.h"
Linus Torvalds's avatar
Linus Torvalds committed
22
#include "xfs_log.h"
23
#include "xfs_inum.h"
Linus Torvalds's avatar
Linus Torvalds committed
24
25
26
27
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
28
#include "xfs_da_btree.h"
Linus Torvalds's avatar
Linus Torvalds committed
29
#include "xfs_bmap_btree.h"
30
#include "xfs_alloc_btree.h"
Linus Torvalds's avatar
Linus Torvalds committed
31
32
33
#include "xfs_ialloc_btree.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
34
35
#include "xfs_btree.h"
#include "xfs_mount.h"
Linus Torvalds's avatar
Linus Torvalds committed
36
#include "xfs_itable.h"
37
#include "xfs_inode_item.h"
Linus Torvalds's avatar
Linus Torvalds committed
38
39
40
41
42
#include "xfs_extfree_item.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
43
#include "xfs_attr_leaf.h"
Linus Torvalds's avatar
Linus Torvalds committed
44
45
46
47
#include "xfs_rw.h"
#include "xfs_quota.h"
#include "xfs_trans_space.h"
#include "xfs_buf_item.h"
48
#include "xfs_filestream.h"
49
#include "xfs_vnodeops.h"
Christoph Hellwig's avatar
Christoph Hellwig committed
50
#include "xfs_trace.h"
Linus Torvalds's avatar
Linus Torvalds committed
51
52
53
54
55
56
57
58


kmem_zone_t		*xfs_bmap_free_item_zone;

/*
 * Prototypes for internal bmap routines.
 */

59
60
61
62
63
64
65
66
67
68
#ifdef DEBUG
STATIC void
xfs_bmap_check_leaf_extents(
	struct xfs_btree_cur	*cur,
	struct xfs_inode	*ip,
	int			whichfork);
#else
#define xfs_bmap_check_leaf_extents(cur, ip, whichfork)		do { } while (0)
#endif

Linus Torvalds's avatar
Linus Torvalds committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

/*
 * Called from xfs_bmap_add_attrfork to handle extents format files.
 */
STATIC int					/* error */
xfs_bmap_add_attrfork_extents(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first block allocated */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags);	/* inode logging flags */

/*
 * Called from xfs_bmap_add_attrfork to handle local format files.
 */
STATIC int					/* error */
xfs_bmap_add_attrfork_local(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first block allocated */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags);	/* inode logging flags */

/*
 * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
 * It figures out where to ask the underlying allocator to put the new extent.
 */
STATIC int				/* error */
xfs_bmap_alloc(
	xfs_bmalloca_t		*ap);	/* bmap alloc argument struct */

/*
 * Transform a btree format file with only one leaf node, where the
 * extents list will fit in the inode, into an extents format file.
103
 * Since the file extents are already in-core, all we have to do is
Linus Torvalds's avatar
Linus Torvalds committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
 * give up the space for the btree root and pitch the leaf block.
 */
STATIC int				/* error */
xfs_bmap_btree_to_extents(
	xfs_trans_t		*tp,	/* transaction pointer */
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_btree_cur_t		*cur,	/* btree cursor */
	int			*logflagsp, /* inode logging flags */
	int			whichfork); /* data or attr fork */

/*
 * Remove the entry "free" from the free item list.  Prev points to the
 * previous entry, unless "free" is the head of the list.
 */
STATIC void
xfs_bmap_del_free(
	xfs_bmap_free_t		*flist,	/* free item list header */
	xfs_bmap_free_item_t	*prev,	/* previous item on list, if any */
	xfs_bmap_free_item_t	*free);	/* list item to be freed */

/*
 * Convert an extents-format file into a btree-format file.
 * The new file will have a root block (in the inode) and a single child block.
 */
STATIC int					/* error */
xfs_bmap_extents_to_btree(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first-block-allocated */
	xfs_bmap_free_t		*flist,		/* blocks freed in xaction */
	xfs_btree_cur_t		**curp,		/* cursor returned to caller */
	int			wasdel,		/* converting a delayed alloc */
	int			*logflagsp,	/* inode logging flags */
	int			whichfork);	/* data or attr fork */

/*
 * Convert a local file to an extents file.
 * This code is sort of bogus, since the file data needs to get
 * logged so it won't be lost.  The bmap-level manipulations are ok, though.
 */
STATIC int				/* error */
xfs_bmap_local_to_extents(
	xfs_trans_t	*tp,		/* transaction pointer */
	xfs_inode_t	*ip,		/* incore inode pointer */
	xfs_fsblock_t	*firstblock,	/* first block allocated in xaction */
	xfs_extlen_t	total,		/* total blocks needed by transaction */
	int		*logflagsp,	/* inode logging flags */
	int		whichfork);	/* data or attr fork */

/*
 * Search the extents list for the inode, for the extent containing bno.
 * If bno lies in a hole, point to the next entry.  If bno lies past eof,
 * *eofp will be set, and *prevp will contain the last entry (null if none).
 * Else, *lastxp will be set to the index of the found
 * entry; *gotp will contain the entry.
 */
160
STATIC xfs_bmbt_rec_host_t *		/* pointer to found extent entry */
Linus Torvalds's avatar
Linus Torvalds committed
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
xfs_bmap_search_extents(
	xfs_inode_t	*ip,		/* incore inode pointer */
	xfs_fileoff_t	bno,		/* block number searched for */
	int		whichfork,	/* data or attr fork */
	int		*eofp,		/* out: end of file found */
	xfs_extnum_t	*lastxp,	/* out: last extent index */
	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */
	xfs_bmbt_irec_t	*prevp);	/* out: previous extent entry found */

/*
 * Compute the worst-case number of indirect blocks that will be used
 * for ip's delayed extent of length "len".
 */
STATIC xfs_filblks_t
xfs_bmap_worst_indlen(
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_filblks_t		len);	/* delayed extent length */

#ifdef DEBUG
/*
 * Perform various validation checks on the values being returned
 * from xfs_bmapi().
 */
STATIC void
xfs_bmap_validate_ret(
	xfs_fileoff_t		bno,
	xfs_filblks_t		len,
	int			flags,
	xfs_bmbt_irec_t		*mval,
	int			nmap,
	int			ret_nmap);
#else
#define	xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap)
#endif /* DEBUG */

STATIC int
xfs_bmap_count_tree(
	xfs_mount_t     *mp,
	xfs_trans_t     *tp,
200
	xfs_ifork_t	*ifp,
Linus Torvalds's avatar
Linus Torvalds committed
201
202
203
204
	xfs_fsblock_t   blockno,
	int             levelin,
	int		*count);

205
STATIC void
Linus Torvalds's avatar
Linus Torvalds committed
206
xfs_bmap_count_leaves(
207
208
	xfs_ifork_t		*ifp,
	xfs_extnum_t		idx,
Linus Torvalds's avatar
Linus Torvalds committed
209
210
211
	int			numrecs,
	int			*count);

212
STATIC void
213
xfs_bmap_disk_count_leaves(
214
	struct xfs_mount	*mp,
215
	struct xfs_btree_block	*block,
216
217
218
	int			numrecs,
	int			*count);

Linus Torvalds's avatar
Linus Torvalds committed
219
220
221
222
/*
 * Bmap internal routines.
 */

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
STATIC int				/* error */
xfs_bmbt_lookup_eq(
	struct xfs_btree_cur	*cur,
	xfs_fileoff_t		off,
	xfs_fsblock_t		bno,
	xfs_filblks_t		len,
	int			*stat)	/* success/failure */
{
	cur->bc_rec.b.br_startoff = off;
	cur->bc_rec.b.br_startblock = bno;
	cur->bc_rec.b.br_blockcount = len;
	return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
}

STATIC int				/* error */
xfs_bmbt_lookup_ge(
	struct xfs_btree_cur	*cur,
	xfs_fileoff_t		off,
	xfs_fsblock_t		bno,
	xfs_filblks_t		len,
	int			*stat)	/* success/failure */
{
	cur->bc_rec.b.br_startoff = off;
	cur->bc_rec.b.br_startblock = bno;
	cur->bc_rec.b.br_blockcount = len;
	return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
}

251
/*
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
 * Check if the inode needs to be converted to btree format.
 */
static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork)
{
	return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
		XFS_IFORK_NEXTENTS(ip, whichfork) >
			XFS_IFORK_MAXEXT(ip, whichfork);
}

/*
 * Check if the inode should be converted to extent format.
 */
static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork)
{
	return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
		XFS_IFORK_NEXTENTS(ip, whichfork) <=
			XFS_IFORK_MAXEXT(ip, whichfork);
}

/*
 * Update the record referred to by cur to the value given
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
 * by [off, bno, len, state].
 * This either works (return 0) or gets an EFSCORRUPTED error.
 */
STATIC int
xfs_bmbt_update(
	struct xfs_btree_cur	*cur,
	xfs_fileoff_t		off,
	xfs_fsblock_t		bno,
	xfs_filblks_t		len,
	xfs_exntst_t		state)
{
	union xfs_btree_rec	rec;

	xfs_bmbt_disk_set_allf(&rec.bmbt, off, bno, len, state);
	return xfs_btree_update(cur, &rec);
}
289

Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
 * Called from xfs_bmap_add_attrfork to handle btree format files.
 */
STATIC int					/* error */
xfs_bmap_add_attrfork_btree(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first block allocated */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags)		/* inode logging flags */
{
	xfs_btree_cur_t		*cur;		/* btree cursor */
	int			error;		/* error return value */
	xfs_mount_t		*mp;		/* file system mount struct */
	int			stat;		/* newroot status */

	mp = ip->i_mount;
	if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))
		*flags |= XFS_ILOG_DBROOT;
	else {
310
		cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
Linus Torvalds's avatar
Linus Torvalds committed
311
312
313
314
		cur->bc_private.b.flist = flist;
		cur->bc_private.b.firstblock = *firstblock;
		if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
			goto error0;
315
316
		/* must be at least one entry */
		XFS_WANT_CORRUPTED_GOTO(stat == 1, error0);
317
		if ((error = xfs_btree_new_iroot(cur, flags, &stat)))
Linus Torvalds's avatar
Linus Torvalds committed
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
			goto error0;
		if (stat == 0) {
			xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
			return XFS_ERROR(ENOSPC);
		}
		*firstblock = cur->bc_private.b.firstblock;
		cur->bc_private.b.allocated = 0;
		xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
	}
	return 0;
error0:
	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
	return error;
}

/*
 * Called from xfs_bmap_add_attrfork to handle extents format files.
 */
STATIC int					/* error */
xfs_bmap_add_attrfork_extents(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first block allocated */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags)		/* inode logging flags */
{
	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
	int			error;		/* error return value */

	if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip))
		return 0;
	cur = NULL;
	error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0,
		flags, XFS_DATA_FORK);
	if (cur) {
		cur->bc_private.b.allocated = 0;
		xfs_btree_del_cursor(cur,
			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
	}
	return error;
}

/*
 * Called from xfs_bmap_add_attrfork to handle local format files.
 */
STATIC int					/* error */
xfs_bmap_add_attrfork_local(
	xfs_trans_t		*tp,		/* transaction pointer */
	xfs_inode_t		*ip,		/* incore inode pointer */
	xfs_fsblock_t		*firstblock,	/* first block allocated */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags)		/* inode logging flags */
{
	xfs_da_args_t		dargs;		/* args for dir/attr code */
	int			error;		/* error return value */
	xfs_mount_t		*mp;		/* mount structure pointer */

	if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
		return 0;
377
	if (S_ISDIR(ip->i_d.di_mode)) {
Linus Torvalds's avatar
Linus Torvalds committed
378
379
380
381
382
383
384
385
		mp = ip->i_mount;
		memset(&dargs, 0, sizeof(dargs));
		dargs.dp = ip;
		dargs.firstblock = firstblock;
		dargs.flist = flist;
		dargs.total = mp->m_dirblkfsbs;
		dargs.whichfork = XFS_DATA_FORK;
		dargs.trans = tp;
386
		error = xfs_dir2_sf_to_block(&dargs);
Linus Torvalds's avatar
Linus Torvalds committed
387
388
389
390
391
392
393
	} else
		error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
			XFS_DATA_FORK);
	return error;
}

/*
394
 * Convert a delayed allocation to a real allocation.
Linus Torvalds's avatar
Linus Torvalds committed
395
396
397
 */
STATIC int				/* error */
xfs_bmap_add_extent_delay_real(
398
	struct xfs_bmalloca	*bma)
Linus Torvalds's avatar
Linus Torvalds committed
399
{
400
	struct xfs_bmbt_irec	*new = &bma->got;
Linus Torvalds's avatar
Linus Torvalds committed
401
	int			diff;	/* temp value */
402
	xfs_bmbt_rec_host_t	*ep;	/* extent entry for idx */
Linus Torvalds's avatar
Linus Torvalds committed
403
404
	int			error;	/* error return value */
	int			i;	/* temp state */
405
	xfs_ifork_t		*ifp;	/* inode fork pointer */
Linus Torvalds's avatar
Linus Torvalds committed
406
407
408
409
410
	xfs_fileoff_t		new_endoff;	/* end offset of new entry */
	xfs_bmbt_irec_t		r[3];	/* neighbor extent entries */
					/* left is 0, right is 1, prev is 2 */
	int			rval=0;	/* return value (logging flags) */
	int			state = 0;/* state bits, accessed thru macros */
411
412
413
414
	xfs_filblks_t		da_new; /* new count del alloc blocks used */
	xfs_filblks_t		da_old; /* old count del alloc blocks used */
	xfs_filblks_t		temp=0;	/* value for da_new calculations */
	xfs_filblks_t		temp2=0;/* value for da_new calculations */
Linus Torvalds's avatar
Linus Torvalds committed
415
416
	int			tmp_rval;	/* partial logging flags */

417
	ifp = XFS_IFORK_PTR(bma->ip, XFS_DATA_FORK);
418

419
420
	ASSERT(bma->idx >= 0);
	ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
421
	ASSERT(!isnullstartblock(new->br_startblock));
422
423
	ASSERT(!bma->cur ||
	       (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
424
425
426

	XFS_STATS_INC(xs_add_exlist);

Linus Torvalds's avatar
Linus Torvalds committed
427
428
429
430
431
432
433
#define	LEFT		r[0]
#define	RIGHT		r[1]
#define	PREV		r[2]

	/*
	 * Set up a bunch of variables to make the tests simpler.
	 */
434
	ep = xfs_iext_get_ext(ifp, bma->idx);
Linus Torvalds's avatar
Linus Torvalds committed
435
436
437
438
	xfs_bmbt_get_all(ep, &PREV);
	new_endoff = new->br_startoff + new->br_blockcount;
	ASSERT(PREV.br_startoff <= new->br_startoff);
	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
439

440
441
442
	da_old = startblockval(PREV.br_startblock);
	da_new = 0;

Linus Torvalds's avatar
Linus Torvalds committed
443
444
445
446
	/*
	 * Set flags determining what part of the previous delayed allocation
	 * extent is being replaced by a real allocation.
	 */
447
448
449
450
451
	if (PREV.br_startoff == new->br_startoff)
		state |= BMAP_LEFT_FILLING;
	if (PREV.br_startoff + PREV.br_blockcount == new_endoff)
		state |= BMAP_RIGHT_FILLING;

Linus Torvalds's avatar
Linus Torvalds committed
452
453
454
455
	/*
	 * Check and set flags if this segment has a left neighbor.
	 * Don't set contiguous if the combined extent would be too large.
	 */
456
	if (bma->idx > 0) {
457
		state |= BMAP_LEFT_VALID;
458
		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &LEFT);
459
460
461

		if (isnullstartblock(LEFT.br_startblock))
			state |= BMAP_LEFT_DELAY;
Linus Torvalds's avatar
Linus Torvalds committed
462
	}
463
464
465
466
467
468
469
470

	if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) &&
	    LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&
	    LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&
	    LEFT.br_state == new->br_state &&
	    LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN)
		state |= BMAP_LEFT_CONTIG;

Linus Torvalds's avatar
Linus Torvalds committed
471
472
473
474
475
	/*
	 * Check and set flags if this segment has a right neighbor.
	 * Don't set contiguous if the combined extent would be too large.
	 * Also check for all-three-contiguous being too large.
	 */
476
	if (bma->idx < bma->ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
477
		state |= BMAP_RIGHT_VALID;
478
		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx + 1), &RIGHT);
479
480
481

		if (isnullstartblock(RIGHT.br_startblock))
			state |= BMAP_RIGHT_DELAY;
Linus Torvalds's avatar
Linus Torvalds committed
482
	}
483
484
485
486
487
488
489
490
491
492
493
494
495
496

	if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) &&
	    new_endoff == RIGHT.br_startoff &&
	    new->br_startblock + new->br_blockcount == RIGHT.br_startblock &&
	    new->br_state == RIGHT.br_state &&
	    new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&
	    ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
		       BMAP_RIGHT_FILLING)) !=
		      (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
		       BMAP_RIGHT_FILLING) ||
	     LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount
			<= MAXEXTLEN))
		state |= BMAP_RIGHT_CONTIG;

Linus Torvalds's avatar
Linus Torvalds committed
497
498
499
500
	error = 0;
	/*
	 * Switch out based on the FILLING and CONTIG state bits.
	 */
501
502
503
504
	switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG |
			 BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) {
	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG |
	     BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
505
506
507
508
		/*
		 * Filling in all of a previously delayed allocation extent.
		 * The left and right neighbors are both contiguous with new.
		 */
509
510
511
		bma->idx--;
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
Linus Torvalds's avatar
Linus Torvalds committed
512
513
			LEFT.br_blockcount + PREV.br_blockcount +
			RIGHT.br_blockcount);
514
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
515

516
517
518
		xfs_iext_remove(bma->ip, bma->idx + 1, 2, state);
		bma->ip->i_d.di_nextents--;
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
519
520
521
			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
		else {
			rval = XFS_ILOG_CORE;
522
			error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
523
					RIGHT.br_startblock,
524
525
					RIGHT.br_blockcount, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
526
				goto done;
527
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
528
529
			error = xfs_btree_delete(bma->cur, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
530
				goto done;
531
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
532
533
			error = xfs_btree_decrement(bma->cur, 0, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
534
				goto done;
535
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
536
			error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
537
538
539
					LEFT.br_startblock,
					LEFT.br_blockcount +
					PREV.br_blockcount +
540
541
					RIGHT.br_blockcount, LEFT.br_state);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
545
				goto done;
		}
		break;

546
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
547
548
549
550
		/*
		 * Filling in all of a previously delayed allocation extent.
		 * The left neighbor is contiguous, the right is not.
		 */
551
		bma->idx--;
Christoph Hellwig's avatar
Christoph Hellwig committed
552

553
554
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
Linus Torvalds's avatar
Linus Torvalds committed
555
			LEFT.br_blockcount + PREV.br_blockcount);
556
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
557

558
559
		xfs_iext_remove(bma->ip, bma->idx + 1, 1, state);
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
560
561
562
			rval = XFS_ILOG_DEXT;
		else {
			rval = 0;
563
			error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
564
					LEFT.br_startblock, LEFT.br_blockcount,
565
566
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
567
				goto done;
568
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
569
			error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
570
571
					LEFT.br_startblock,
					LEFT.br_blockcount +
572
573
					PREV.br_blockcount, LEFT.br_state);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
574
575
576
577
				goto done;
		}
		break;

578
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
579
580
581
582
		/*
		 * Filling in all of a previously delayed allocation extent.
		 * The right neighbor is contiguous, the left is not.
		 */
583
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
584
585
586
		xfs_bmbt_set_startblock(ep, new->br_startblock);
		xfs_bmbt_set_blockcount(ep,
			PREV.br_blockcount + RIGHT.br_blockcount);
587
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
588

589
590
		xfs_iext_remove(bma->ip, bma->idx + 1, 1, state);
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
591
592
593
			rval = XFS_ILOG_DEXT;
		else {
			rval = 0;
594
			error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
595
					RIGHT.br_startblock,
596
597
					RIGHT.br_blockcount, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
598
				goto done;
599
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
600
			error = xfs_bmbt_update(bma->cur, PREV.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
601
602
					new->br_startblock,
					PREV.br_blockcount +
603
604
					RIGHT.br_blockcount, PREV.br_state);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
605
606
607
608
				goto done;
		}
		break;

609
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
Linus Torvalds's avatar
Linus Torvalds committed
610
611
612
613
614
		/*
		 * Filling in all of a previously delayed allocation extent.
		 * Neither the left nor right neighbors are contiguous with
		 * the new one.
		 */
615
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
616
		xfs_bmbt_set_startblock(ep, new->br_startblock);
617
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
618

619
620
		bma->ip->i_d.di_nextents++;
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
621
622
623
			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
		else {
			rval = XFS_ILOG_CORE;
624
			error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
625
					new->br_startblock, new->br_blockcount,
626
627
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
628
				goto done;
629
			XFS_WANT_CORRUPTED_GOTO(i == 0, done);
630
631
632
			bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
			error = xfs_btree_insert(bma->cur, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
633
				goto done;
634
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
Linus Torvalds's avatar
Linus Torvalds committed
635
636
637
		}
		break;

638
	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
639
640
641
642
		/*
		 * Filling in the first part of a previous delayed allocation.
		 * The left neighbor is contiguous.
		 */
643
644
		trace_xfs_bmap_pre_update(bma->ip, bma->idx - 1, state, _THIS_IP_);
		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx - 1),
Linus Torvalds's avatar
Linus Torvalds committed
645
646
647
			LEFT.br_blockcount + new->br_blockcount);
		xfs_bmbt_set_startoff(ep,
			PREV.br_startoff + new->br_blockcount);
648
		trace_xfs_bmap_post_update(bma->ip, bma->idx - 1, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
649

Linus Torvalds's avatar
Linus Torvalds committed
650
		temp = PREV.br_blockcount - new->br_blockcount;
651
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
652
		xfs_bmbt_set_blockcount(ep, temp);
653
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
654
655
656
			rval = XFS_ILOG_DEXT;
		else {
			rval = 0;
657
			error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
658
					LEFT.br_startblock, LEFT.br_blockcount,
659
660
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
661
				goto done;
662
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
663
			error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
664
665
666
					LEFT.br_startblock,
					LEFT.br_blockcount +
					new->br_blockcount,
667
668
					LEFT.br_state);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
669
670
				goto done;
		}
671
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
672
			startblockval(PREV.br_startblock));
673
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
674
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
675

676
		bma->idx--;
Linus Torvalds's avatar
Linus Torvalds committed
677
678
		break;

679
	case BMAP_LEFT_FILLING:
Linus Torvalds's avatar
Linus Torvalds committed
680
681
682
683
		/*
		 * Filling in the first part of a previous delayed allocation.
		 * The left neighbor is not contiguous.
		 */
684
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
685
686
687
		xfs_bmbt_set_startoff(ep, new_endoff);
		temp = PREV.br_blockcount - new->br_blockcount;
		xfs_bmbt_set_blockcount(ep, temp);
688
689
690
		xfs_iext_insert(bma->ip, bma->idx, 1, new, state);
		bma->ip->i_d.di_nextents++;
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
691
692
693
			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
		else {
			rval = XFS_ILOG_CORE;
694
			error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
695
					new->br_startblock, new->br_blockcount,
696
697
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
698
				goto done;
699
			XFS_WANT_CORRUPTED_GOTO(i == 0, done);
700
701
702
			bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
			error = xfs_btree_insert(bma->cur, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
703
				goto done;
704
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
Linus Torvalds's avatar
Linus Torvalds committed
705
		}
706
707

		if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
708
709
710
			error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
					bma->firstblock, bma->flist,
					&bma->cur, 1, &tmp_rval, XFS_DATA_FORK);
Linus Torvalds's avatar
Linus Torvalds committed
711
712
713
714
			rval |= tmp_rval;
			if (error)
				goto done;
		}
715
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
716
			startblockval(PREV.br_startblock) -
717
718
			(bma->cur ? bma->cur->bc_private.b.allocated : 0));
		ep = xfs_iext_get_ext(ifp, bma->idx + 1);
719
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
720
		trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
721
722
		break;

723
	case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
724
725
726
727
728
		/*
		 * Filling in the last part of a previous delayed allocation.
		 * The right neighbor is contiguous with the new allocation.
		 */
		temp = PREV.br_blockcount - new->br_blockcount;
729
		trace_xfs_bmap_pre_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
730
		xfs_bmbt_set_blockcount(ep, temp);
731
		xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx + 1),
732
			new->br_startoff, new->br_startblock,
Linus Torvalds's avatar
Linus Torvalds committed
733
734
			new->br_blockcount + RIGHT.br_blockcount,
			RIGHT.br_state);
735
736
		trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
737
738
739
			rval = XFS_ILOG_DEXT;
		else {
			rval = 0;
740
			error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
741
					RIGHT.br_startblock,
742
743
					RIGHT.br_blockcount, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
744
				goto done;
745
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
746
			error = xfs_bmbt_update(bma->cur, new->br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
					new->br_startblock,
					new->br_blockcount +
					RIGHT.br_blockcount,
750
751
					RIGHT.br_state);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
752
753
				goto done;
		}
Christoph Hellwig's avatar
Christoph Hellwig committed
754

755
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
756
			startblockval(PREV.br_startblock));
757
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
758
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
759
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
760

761
		bma->idx++;
Linus Torvalds's avatar
Linus Torvalds committed
762
763
		break;

764
	case BMAP_RIGHT_FILLING:
Linus Torvalds's avatar
Linus Torvalds committed
765
766
767
768
769
		/*
		 * Filling in the last part of a previous delayed allocation.
		 * The right neighbor is not contiguous.
		 */
		temp = PREV.br_blockcount - new->br_blockcount;
770
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
Linus Torvalds's avatar
Linus Torvalds committed
771
		xfs_bmbt_set_blockcount(ep, temp);
772
773
774
		xfs_iext_insert(bma->ip, bma->idx + 1, 1, new, state);
		bma->ip->i_d.di_nextents++;
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
775
776
777
			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
		else {
			rval = XFS_ILOG_CORE;
778
			error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
779
					new->br_startblock, new->br_blockcount,
780
781
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
782
				goto done;
783
			XFS_WANT_CORRUPTED_GOTO(i == 0, done);
784
785
786
			bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
			error = xfs_btree_insert(bma->cur, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
787
				goto done;
788
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
Linus Torvalds's avatar
Linus Torvalds committed
789
		}
790
791

		if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
792
793
794
			error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
				bma->firstblock, bma->flist, &bma->cur, 1,
				&tmp_rval, XFS_DATA_FORK);
Linus Torvalds's avatar
Linus Torvalds committed
795
796
797
798
			rval |= tmp_rval;
			if (error)
				goto done;
		}
799
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
800
			startblockval(PREV.br_startblock) -
801
802
			(bma->cur ? bma->cur->bc_private.b.allocated : 0));
		ep = xfs_iext_get_ext(ifp, bma->idx);
803
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
804
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
805

806
		bma->idx++;
Linus Torvalds's avatar
Linus Torvalds committed
807
808
809
810
811
812
813
		break;

	case 0:
		/*
		 * Filling in the middle part of a previous delayed allocation.
		 * Contiguity is impossible here.
		 * This case is avoided almost all the time.
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
		 *
		 * We start with a delayed allocation:
		 *
		 * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+
		 *  PREV @ idx
		 *
	         * and we are allocating:
		 *                     +rrrrrrrrrrrrrrrrr+
		 *			      new
		 *
		 * and we set it up for insertion as:
		 * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+
		 *                            new
		 *  PREV @ idx          LEFT              RIGHT
		 *                      inserted at idx + 1
Linus Torvalds's avatar
Linus Torvalds committed
829
830
831
		 */
		temp = new->br_startoff - PREV.br_startoff;
		temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
832
		trace_xfs_bmap_pre_update(bma->ip, bma->idx, 0, _THIS_IP_);
833
834
835
836
		xfs_bmbt_set_blockcount(ep, temp);	/* truncate PREV */
		LEFT = *new;
		RIGHT.br_state = PREV.br_state;
		RIGHT.br_startblock = nullstartblock(
837
				(int)xfs_bmap_worst_indlen(bma->ip, temp2));
838
839
840
		RIGHT.br_startoff = new_endoff;
		RIGHT.br_blockcount = temp2;
		/* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
841
842
843
		xfs_iext_insert(bma->ip, bma->idx + 1, 2, &LEFT, state);
		bma->ip->i_d.di_nextents++;
		if (bma->cur == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
844
845
846
			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
		else {
			rval = XFS_ILOG_CORE;
847
			error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
Linus Torvalds's avatar
Linus Torvalds committed
848
					new->br_startblock, new->br_blockcount,
849
850
					&i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
851
				goto done;
852
			XFS_WANT_CORRUPTED_GOTO(i == 0, done);
853
854
855
			bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
			error = xfs_btree_insert(bma->cur, &i);
			if (error)
Linus Torvalds's avatar
Linus Torvalds committed
856
				goto done;
857
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
Linus Torvalds's avatar
Linus Torvalds committed
858
		}
859
860

		if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
861
862
863
			error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
					bma->firstblock, bma->flist, &bma->cur,
					1, &tmp_rval, XFS_DATA_FORK);
Linus Torvalds's avatar
Linus Torvalds committed
864
865
866
867
			rval |= tmp_rval;
			if (error)
				goto done;
		}
868
869
		temp = xfs_bmap_worst_indlen(bma->ip, temp);
		temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
870
		diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
871
			(bma->cur ? bma->cur->bc_private.b.allocated : 0));
872
		if (diff > 0) {
873
			error = xfs_icsb_modify_counters(bma->ip->i_mount,
874
875
876
877
878
					XFS_SBS_FDBLOCKS,
					-((int64_t)diff), 0);
			ASSERT(!error);
			if (error)
				goto done;
Linus Torvalds's avatar
Linus Torvalds committed
879
		}
880

881
		ep = xfs_iext_get_ext(ifp, bma->idx);
882
		xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
883
884
885
		trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
		trace_xfs_bmap_pre_update(bma->ip, bma->idx + 2, state, _THIS_IP_);
		xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, bma->idx + 2),
886
			nullstartblock((int)temp2));
887
		trace_xfs_bmap_post_update(bma->ip, bma->idx + 2, state, _THIS_IP_);
Christoph Hellwig's avatar
Christoph Hellwig committed
888

889
		bma->idx++;
890
		da_new = temp + temp2;
Linus Torvalds's avatar
Linus Torvalds committed
891
892
		break;

893
894
895
896
897
898
899
	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
	case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
	case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG:
	case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
	case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
	case BMAP_LEFT_CONTIG:
	case BMAP_RIGHT_CONTIG:
Linus Torvalds's avatar
Linus Torvalds committed
900
901
902
903
904
		/*
		 * These cases are all impossible.
		 */
		ASSERT(0);
	}
905
906

	/* convert to a btree if necessary */
907
	if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
908
909
		int	tmp_logflags;	/* partial log flag return val */

910
911
912
		ASSERT(bma->cur == NULL);
		error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
				bma->firstblock, bma->flist, &bma->cur,
913
				da_old > 0, &tmp_logflags, XFS_DATA_FORK);
914
		bma->logflags |= tmp_logflags;
915
916
917
918
919
920
921
		if (error)
			goto done;
	}

	/* adjust for changes in reserved delayed indirect blocks */
	if (da_old || da_new) {
		temp = da_new;
922
923
		if (bma->cur)
			temp += bma->cur->bc_private.b.allocated;
924
925
		ASSERT(temp <= da_old);
		if (temp < da_old)
926
927
928
			xfs_icsb_modify_counters(bma->ip->i_mount,
					XFS_SBS_FDBLOCKS,
					(int64_t)(da_old - temp), 0);
929
930
931
	}

	/* clear out the allocated field, done with it now in any case. */
932
933
934
935
	if (bma->cur)
		bma->cur->bc_private.b.allocated = 0;

	xfs_bmap_check_leaf_extents(bma->cur, bma->ip, XFS_DATA_FORK);
Linus Torvalds's avatar
Linus Torvalds committed
936
done:
937
	bma->logflags |= rval;
Linus Torvalds's avatar
Linus Torvalds committed
938
939
940
941
942
943
944
	return error;
#undef	LEFT
#undef	RIGHT
#undef	PREV
}

/*
945
 * Convert an unwritten allocation to a real allocation or vice versa.
Linus Torvalds's avatar
Linus Torvalds committed
946
947
948
 */
STATIC int				/* error */
xfs_bmap_add_extent_unwritten_real(
949
	struct xfs_trans	*tp,
Linus Torvalds's avatar
Linus Torvalds committed
950
	xfs_inode_t		*ip,	/* incore inode pointer */
Christoph Hellwig's avatar
Christoph Hellwig committed
951
	xfs_extnum_t		*idx,	/* extent number to update/insert */
Linus Torvalds's avatar
Linus Torvalds committed
952
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
953
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
954
955
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
956
	int			*logflagsp) /* inode logging flags */
Linus Torvalds's avatar
Linus Torvalds committed
957
958
{
	xfs_btree_cur_t		*cur;	/* btree cursor */
959
	xfs_bmbt_rec_host_t	*ep;	/* extent entry for idx */
Linus Torvalds's avatar
Linus Torvalds committed
960
961
	int			error;	/* error return value */
	int			i;	/* temp state */
962
	xfs_ifork_t		*ifp;	/* inode fork pointer */
Linus Torvalds's avatar
Linus Torvalds committed
963
964
965
966
967
968
969
970
	xfs_fileoff_t		new_endoff;	/* end offset of new entry */
	xfs_exntst_t		newext;	/* new extent state */
	xfs_exntst_t		oldext;	/* old extent state */
	xfs_bmbt_irec_t		r[3];	/* neighbor extent entries */
					/* left is 0, right is 1, prev is 2 */
	int			rval=0;	/* return value (logging flags) */
	int			state = 0;/* state bits, accessed thru macros */

971
972
973
974
975
976
977
978
979
980
981
	*logflagsp = 0;

	cur = *curp;
	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);

	ASSERT(*idx >= 0);
	ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
	ASSERT(!isnullstartblock(new->br_startblock));

	XFS_STATS_INC(xs_add_exlist);

Linus Torvalds's avatar
Linus Torvalds committed
982
983
984
#define	LEFT		r[0]
#define	RIGHT		r[1]
#define	PREV		r[2]
985

Linus Torvalds's avatar
Linus Torvalds committed
986
987
988
989
	/*
	 * Set up a bunch of variables to make the tests simpler.
	 */
	error = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
990
	ep = xfs_iext_get_ext(ifp, *idx);
Linus Torvalds's avatar
Linus Torvalds committed
991
992
993
994
995
996
997
998
	xfs_bmbt_get_all(ep, &PREV);
	newext = new->br_state;
	oldext = (newext == XFS_EXT_UNWRITTEN) ?
		XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
	ASSERT(PREV.br_state == oldext);
	new_endoff = new->br_startoff + new->br_blockcount;
	ASSERT(PREV.br_startoff <= new->br_startoff);
	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
999

Linus Torvalds's avatar
Linus Torvalds committed
1000
	/*
For faster browsing, not all history is shown. View entire blame