Blame view

fs/xfs/xfs_iomap.c 19.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
3e57ecf64   Olaf Weber   [XFS] Add paramet...
2
   * Copyright (c) 2000-2006 Silicon Graphics, Inc.
7b7187698   Nathan Scott   [XFS] Update lice...
3
   * All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
7b7187698   Nathan Scott   [XFS] Update lice...
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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   * published by the Free Software Foundation.
   *
7b7187698   Nathan Scott   [XFS] Update lice...
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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
   *
7b7187698   Nathan Scott   [XFS] Update lice...
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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include "xfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include "xfs_fs.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
20
  #include "xfs_bit.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include "xfs_log.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
22
  #include "xfs_inum.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include "xfs_trans.h"
  #include "xfs_sb.h"
  #include "xfs_ag.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include "xfs_alloc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  #include "xfs_quota.h"
  #include "xfs_mount.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include "xfs_bmap_btree.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
30
  #include "xfs_alloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include "xfs_ialloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  #include "xfs_dinode.h"
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
34
  #include "xfs_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #include "xfs_bmap.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
  #include "xfs_rtalloc.h"
  #include "xfs_error.h"
  #include "xfs_itable.h"
  #include "xfs_rw.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
  #include "xfs_attr.h"
  #include "xfs_buf_item.h"
  #include "xfs_trans_space.h"
  #include "xfs_utils.h"
  #include "xfs_iomap.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
45
  #include "xfs_trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
  
  #define XFS_WRITEIO_ALIGN(mp,off)	(((off) >> mp->m_writeio_log) \
  						<< mp->m_writeio_log)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #define XFS_WRITE_IMAPS		XFS_BMAP_MAX_NMAP
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  STATIC int
dd9f438e3   Nathan Scott   [XFS] Implement t...
52
53
  xfs_iomap_eof_align_last_fsb(
  	xfs_mount_t	*mp,
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
54
  	xfs_inode_t	*ip,
dd9f438e3   Nathan Scott   [XFS] Implement t...
55
56
57
58
59
60
  	xfs_extlen_t	extsize,
  	xfs_fileoff_t	*last_fsb)
  {
  	xfs_fileoff_t	new_last_fsb = 0;
  	xfs_extlen_t	align;
  	int		eof, error;
71ddabb94   Eric Sandeen   [XFS] optimize XF...
61
  	if (XFS_IS_REALTIME_INODE(ip))
dd9f438e3   Nathan Scott   [XFS] Implement t...
62
63
64
65
66
67
68
  		;
  	/*
  	 * If mounted with the "-o swalloc" option, roundup the allocation
  	 * request to a stripe width boundary if the file size is >=
  	 * stripe width and we are allocating past the allocation eof.
  	 */
  	else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
9f6c92b9c   Lachlan McIlroy   [XFS] Fix specula...
69
  	        (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_swidth)))
dd9f438e3   Nathan Scott   [XFS] Implement t...
70
71
72
73
74
75
  		new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
  	/*
  	 * Roundup the allocation request to a stripe unit (m_dalign) boundary
  	 * if the file size is >= stripe unit size, and we are allocating past
  	 * the allocation eof.
  	 */
9f6c92b9c   Lachlan McIlroy   [XFS] Fix specula...
76
  	else if (mp->m_dalign && (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_dalign)))
dd9f438e3   Nathan Scott   [XFS] Implement t...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  		new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
  
  	/*
  	 * Always round up the allocation request to an extent boundary
  	 * (when file on a real-time subvolume or has di_extsize hint).
  	 */
  	if (extsize) {
  		if (new_last_fsb)
  			align = roundup_64(new_last_fsb, extsize);
  		else
  			align = extsize;
  		new_last_fsb = roundup_64(*last_fsb, align);
  	}
  
  	if (new_last_fsb) {
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
92
  		error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof);
dd9f438e3   Nathan Scott   [XFS] Implement t...
93
94
95
96
97
98
99
100
101
  		if (error)
  			return error;
  		if (eof)
  			*last_fsb = new_last_fsb;
  	}
  	return 0;
  }
  
  STATIC int
6d4a8ecb3   Dave Chinner   xfs: rename xfs_c...
102
  xfs_alert_fsblock_zero(
572d95f49   Nathan Scott   [XFS] Improve err...
103
104
105
  	xfs_inode_t	*ip,
  	xfs_bmbt_irec_t	*imap)
  {
6a19d9393   Dave Chinner   xfs: convert xfs_...
106
  	xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
572d95f49   Nathan Scott   [XFS] Improve err...
107
108
109
110
111
112
113
114
115
116
117
  			"Access to block zero in inode %llu "
  			"start_block: %llx start_off: %llx "
  			"blkcnt: %llx extent-state: %x
  ",
  		(unsigned long long)ip->i_ino,
  		(unsigned long long)imap->br_startblock,
  		(unsigned long long)imap->br_startoff,
  		(unsigned long long)imap->br_blockcount,
  		imap->br_state);
  	return EFSCORRUPTED;
  }
a206c817c   Christoph Hellwig   xfs: kill xfs_iomap
118
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  xfs_iomap_write_direct(
  	xfs_inode_t	*ip,
f403b7f45   Nathan Scott   [XFS] Cleanup use...
121
  	xfs_off_t	offset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  	size_t		count,
3070451ee   Christoph Hellwig   xfs: reduce stack...
123
  	xfs_bmbt_irec_t *imap,
405f80429   Christoph Hellwig   xfs: cleanup the ...
124
  	int		nmaps)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
  {
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  	xfs_fileoff_t	offset_fsb;
  	xfs_fileoff_t	last_fsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
129
  	xfs_filblks_t	count_fsb, resaligned;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	xfs_fsblock_t	firstfsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
131
  	xfs_extlen_t	extsz, temp;
0116d9356   Eric Sandeen   [XFS] Remove dead...
132
  	int		nimaps;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  	int		bmapi_flag;
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
134
  	int		quota_flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  	int		rt;
  	xfs_trans_t	*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	xfs_bmap_free_t free_list;
dd9f438e3   Nathan Scott   [XFS] Implement t...
138
  	uint		qblocks, resblks, resrtextents;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	int		committed;
dd9f438e3   Nathan Scott   [XFS] Implement t...
140
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
  
  	/*
  	 * Make sure that the dquots are there. This doesn't hold
  	 * the ilock across a disk read.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
146
  	error = xfs_qm_dqattach_locked(ip, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  	if (error)
  		return XFS_ERROR(error);
dd9f438e3   Nathan Scott   [XFS] Implement t...
149
  	rt = XFS_IS_REALTIME_INODE(ip);
957d0ebed   David Chinner   [XFS] Cleanup ino...
150
  	extsz = xfs_get_extsz_hint(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151

957d0ebed   David Chinner   [XFS] Cleanup ino...
152
153
  	offset_fsb = XFS_B_TO_FSBT(mp, offset);
  	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
9f6c92b9c   Lachlan McIlroy   [XFS] Fix specula...
154
155
  	if ((offset + count) > ip->i_size) {
  		error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
dd9f438e3   Nathan Scott   [XFS] Implement t...
156
157
  		if (error)
  			goto error_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	} else {
405f80429   Christoph Hellwig   xfs: cleanup the ...
159
  		if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
dd9f438e3   Nathan Scott   [XFS] Implement t...
160
  			last_fsb = MIN(last_fsb, (xfs_fileoff_t)
3070451ee   Christoph Hellwig   xfs: reduce stack...
161
162
  					imap->br_blockcount +
  					imap->br_startoff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  	}
dd9f438e3   Nathan Scott   [XFS] Implement t...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  	count_fsb = last_fsb - offset_fsb;
  	ASSERT(count_fsb > 0);
  
  	resaligned = count_fsb;
  	if (unlikely(extsz)) {
  		if ((temp = do_mod(offset_fsb, extsz)))
  			resaligned += temp;
  		if ((temp = do_mod(resaligned, extsz)))
  			resaligned += extsz - temp;
  	}
  
  	if (unlikely(rt)) {
  		resrtextents = qblocks = resaligned;
  		resrtextents /= mp->m_sb.sb_rextsize;
84e1e99f1   David Chinner   [XFS] Prevent ENO...
178
179
180
181
  		resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
  		quota_flag = XFS_QMOPT_RES_RTBLKS;
  	} else {
  		resrtextents = 0;
dd9f438e3   Nathan Scott   [XFS] Implement t...
182
  		resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
84e1e99f1   David Chinner   [XFS] Prevent ENO...
183
184
  		quota_flag = XFS_QMOPT_RES_REGBLKS;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  
  	/*
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
187
  	 * Allocate and setup the transaction
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  	 */
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	error = xfs_trans_reserve(tp, resblks,
d52b44d07   Nathan Scott   [XFS] Fix regress...
192
  			XFS_WRITE_LOG_RES(mp), resrtextents,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  			XFS_TRANS_PERM_LOG_RES,
  			XFS_WRITE_LOG_COUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  	/*
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
196
  	 * Check for running out of space, note: need lock to return
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
  	 */
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  		xfs_trans_cancel(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	if (error)
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
202
  		goto error_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
204
  	error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
dd9f438e3   Nathan Scott   [XFS] Implement t...
205
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  		goto error1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

ddc3415ab   Christoph Hellwig   xfs: simplify xfs...
208
  	xfs_trans_ijoin(tp, ip, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209

c0dc7828a   Dave Chinner   xfs: rename xfs_b...
210
  	bmapi_flag = 0;
405f80429   Christoph Hellwig   xfs: cleanup the ...
211
  	if (offset < ip->i_size || extsz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
  		bmapi_flag |= XFS_BMAPI_PREALLOC;
  
  	/*
3070451ee   Christoph Hellwig   xfs: reduce stack...
215
216
  	 * From this point onwards we overwrite the imap pointer that the
  	 * caller gave to us.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
218
  	xfs_bmap_init(&free_list, &firstfsb);
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
219
  	nimaps = 1;
c0dc7828a   Dave Chinner   xfs: rename xfs_b...
220
221
  	error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag,
  				&firstfsb, 0, imap, &nimaps, &free_list);
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
222
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  		goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  
  	/*
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
226
  	 * Complete the transaction
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	 */
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
228
  	error = xfs_bmap_finish(&tp, &free_list, &committed);
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
229
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  		goto error0;
1c72bf900   Eric Sandeen   [XFS] The last ar...
231
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
232
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  		goto error_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

06d10dd9c   Nathan Scott   [XFS] Merge fixes...
235
236
237
  	/*
  	 * Copy any maps to caller's array and return any error.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	if (nimaps == 0) {
572d95f49   Nathan Scott   [XFS] Improve err...
239
240
241
  		error = ENOSPC;
  		goto error_out;
  	}
3070451ee   Christoph Hellwig   xfs: reduce stack...
242
  	if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) {
6d4a8ecb3   Dave Chinner   xfs: rename xfs_c...
243
  		error = xfs_alert_fsblock_zero(ip, imap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  		goto error_out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	return 0;
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
247
  error0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	xfs_bmap_cancel(&free_list);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
249
  	xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250

06d10dd9c   Nathan Scott   [XFS] Merge fixes...
251
  error1:	/* Just cancel transaction */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
  
  error_out:
  	return XFS_ERROR(error);
  }
dd9f438e3   Nathan Scott   [XFS] Implement t...
257
  /*
8de2bf937   Dave Chinner   xfs: remove xfs_f...
258
259
260
   * If the caller is doing a write at the end of the file, then extend the
   * allocation out to the file system's write iosize.  We clean up any extra
   * space left over when the file is closed in xfs_inactive().
055388a31   Dave Chinner   xfs: dynamic spec...
261
262
263
   *
   * If we find we already have delalloc preallocation beyond EOF, don't do more
   * preallocation as it it not needed.
dd9f438e3   Nathan Scott   [XFS] Implement t...
264
265
266
267
   */
  STATIC int
  xfs_iomap_eof_want_preallocate(
  	xfs_mount_t	*mp,
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
268
  	xfs_inode_t	*ip,
dd9f438e3   Nathan Scott   [XFS] Implement t...
269
270
  	xfs_off_t	offset,
  	size_t		count,
dd9f438e3   Nathan Scott   [XFS] Implement t...
271
272
273
274
275
276
277
278
  	xfs_bmbt_irec_t *imap,
  	int		nimaps,
  	int		*prealloc)
  {
  	xfs_fileoff_t   start_fsb;
  	xfs_filblks_t   count_fsb;
  	xfs_fsblock_t	firstblock;
  	int		n, error, imaps;
055388a31   Dave Chinner   xfs: dynamic spec...
279
  	int		found_delalloc = 0;
dd9f438e3   Nathan Scott   [XFS] Implement t...
280
281
  
  	*prealloc = 0;
8de2bf937   Dave Chinner   xfs: remove xfs_f...
282
  	if ((offset + count) <= ip->i_size)
dd9f438e3   Nathan Scott   [XFS] Implement t...
283
284
285
286
287
288
289
290
291
292
  		return 0;
  
  	/*
  	 * If there are any real blocks past eof, then don't
  	 * do any speculative allocation.
  	 */
  	start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1)));
  	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
  	while (count_fsb > 0) {
  		imaps = nimaps;
3ddb8fa98   Nathan Scott   [XFS] Sort out co...
293
  		firstblock = NULLFSBLOCK;
5c8ed2021   Dave Chinner   xfs: introduce xf...
294
295
  		error = xfs_bmapi_read(ip, start_fsb, count_fsb, imap, &imaps,
  				       0);
dd9f438e3   Nathan Scott   [XFS] Implement t...
296
297
298
299
300
301
302
303
  		if (error)
  			return error;
  		for (n = 0; n < imaps; n++) {
  			if ((imap[n].br_startblock != HOLESTARTBLOCK) &&
  			    (imap[n].br_startblock != DELAYSTARTBLOCK))
  				return 0;
  			start_fsb += imap[n].br_blockcount;
  			count_fsb -= imap[n].br_blockcount;
055388a31   Dave Chinner   xfs: dynamic spec...
304
305
306
  
  			if (imap[n].br_startblock == DELAYSTARTBLOCK)
  				found_delalloc = 1;
dd9f438e3   Nathan Scott   [XFS] Implement t...
307
308
  		}
  	}
055388a31   Dave Chinner   xfs: dynamic spec...
309
310
  	if (!found_delalloc)
  		*prealloc = 1;
dd9f438e3   Nathan Scott   [XFS] Implement t...
311
312
  	return 0;
  }
055388a31   Dave Chinner   xfs: dynamic spec...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
  /*
   * If we don't have a user specified preallocation size, dynamically increase
   * the preallocation size as the size of the file grows. Cap the maximum size
   * at a single extent or less if the filesystem is near full. The closer the
   * filesystem is to full, the smaller the maximum prealocation.
   */
  STATIC xfs_fsblock_t
  xfs_iomap_prealloc_size(
  	struct xfs_mount	*mp,
  	struct xfs_inode	*ip)
  {
  	xfs_fsblock_t		alloc_blocks = 0;
  
  	if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) {
  		int shift = 0;
  		int64_t freesp;
b8fc82630   Dave Chinner   xfs: speculative ...
329
330
331
332
333
334
  		/*
  		 * rounddown_pow_of_two() returns an undefined result
  		 * if we pass in alloc_blocks = 0. Hence the "+ 1" to
  		 * ensure we always pass in a non-zero value.
  		 */
  		alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
055388a31   Dave Chinner   xfs: dynamic spec...
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
  		alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
  					rounddown_pow_of_two(alloc_blocks));
  
  		xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
  		freesp = mp->m_sb.sb_fdblocks;
  		if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) {
  			shift = 2;
  			if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT])
  				shift++;
  			if (freesp < mp->m_low_space[XFS_LOWSP_3_PCNT])
  				shift++;
  			if (freesp < mp->m_low_space[XFS_LOWSP_2_PCNT])
  				shift++;
  			if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT])
  				shift++;
  		}
  		if (shift)
  			alloc_blocks >>= shift;
  	}
  
  	if (alloc_blocks < mp->m_writeio_blocks)
  		alloc_blocks = mp->m_writeio_blocks;
  
  	return alloc_blocks;
  }
a206c817c   Christoph Hellwig   xfs: kill xfs_iomap
360
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  xfs_iomap_write_delay(
  	xfs_inode_t	*ip,
f403b7f45   Nathan Scott   [XFS] Cleanup use...
363
  	xfs_off_t	offset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	size_t		count,
405f80429   Christoph Hellwig   xfs: cleanup the ...
365
  	xfs_bmbt_irec_t *ret_imap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  {
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  	xfs_fileoff_t	offset_fsb;
  	xfs_fileoff_t	last_fsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
370
371
  	xfs_off_t	aligned_offset;
  	xfs_fileoff_t	ioalign;
dd9f438e3   Nathan Scott   [XFS] Implement t...
372
  	xfs_extlen_t	extsz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	int		nimaps;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
8de2bf937   Dave Chinner   xfs: remove xfs_f...
375
  	int		prealloc, flushed = 0;
dd9f438e3   Nathan Scott   [XFS] Implement t...
376
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377

579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
378
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
383
  
  	/*
  	 * Make sure that the dquots are there. This doesn't hold
  	 * the ilock across a disk read.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
384
  	error = xfs_qm_dqattach_locked(ip, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
  	if (error)
  		return XFS_ERROR(error);
957d0ebed   David Chinner   [XFS] Cleanup ino...
387
  	extsz = xfs_get_extsz_hint(ip);
dd9f438e3   Nathan Scott   [XFS] Implement t...
388
  	offset_fsb = XFS_B_TO_FSBT(mp, offset);
055388a31   Dave Chinner   xfs: dynamic spec...
389

9f6c92b9c   Lachlan McIlroy   [XFS] Fix specula...
390
  	error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count,
405f80429   Christoph Hellwig   xfs: cleanup the ...
391
  				imap, XFS_WRITE_IMAPS, &prealloc);
dd9f438e3   Nathan Scott   [XFS] Implement t...
392
393
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394

8de2bf937   Dave Chinner   xfs: remove xfs_f...
395
  retry:
dd9f438e3   Nathan Scott   [XFS] Implement t...
396
  	if (prealloc) {
055388a31   Dave Chinner   xfs: dynamic spec...
397
  		xfs_fsblock_t	alloc_blocks = xfs_iomap_prealloc_size(mp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
  		aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
  		ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
055388a31   Dave Chinner   xfs: dynamic spec...
400
  		last_fsb = ioalign + alloc_blocks;
dd9f438e3   Nathan Scott   [XFS] Implement t...
401
402
  	} else {
  		last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404

dd9f438e3   Nathan Scott   [XFS] Implement t...
405
  	if (prealloc || extsz) {
9f6c92b9c   Lachlan McIlroy   [XFS] Fix specula...
406
  		error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
dd9f438e3   Nathan Scott   [XFS] Implement t...
407
  		if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  	}
dd9f438e3   Nathan Scott   [XFS] Implement t...
410
411
  
  	nimaps = XFS_WRITE_IMAPS;
4403280aa   Christoph Hellwig   xfs: introduce xf...
412
413
  	error = xfs_bmapi_delay(ip, offset_fsb, last_fsb - offset_fsb,
  				imap, &nimaps, XFS_BMAPI_ENTIRE);
055388a31   Dave Chinner   xfs: dynamic spec...
414
415
416
417
418
419
  	switch (error) {
  	case 0:
  	case ENOSPC:
  	case EDQUOT:
  		break;
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  		return XFS_ERROR(error);
055388a31   Dave Chinner   xfs: dynamic spec...
421
  	}
dd9f438e3   Nathan Scott   [XFS] Implement t...
422

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	/*
055388a31   Dave Chinner   xfs: dynamic spec...
424
425
426
427
  	 * If bmapi returned us nothing, we got either ENOSPC or EDQUOT.  For
  	 * ENOSPC, * flush all other inodes with delalloc blocks to free up
  	 * some of the excess reserved metadata space. For both cases, retry
  	 * without EOF preallocation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
  	 */
  	if (nimaps == 0) {
0b1b213fc   Christoph Hellwig   xfs: event tracin...
430
  		trace_xfs_delalloc_enospc(ip, offset, count);
8de2bf937   Dave Chinner   xfs: remove xfs_f...
431
  		if (flushed)
055388a31   Dave Chinner   xfs: dynamic spec...
432
  			return XFS_ERROR(error ? error : ENOSPC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433

055388a31   Dave Chinner   xfs: dynamic spec...
434
435
436
437
438
  		if (error == ENOSPC) {
  			xfs_iunlock(ip, XFS_ILOCK_EXCL);
  			xfs_flush_inodes(ip);
  			xfs_ilock(ip, XFS_ILOCK_EXCL);
  		}
8de2bf937   Dave Chinner   xfs: remove xfs_f...
439
440
  
  		flushed = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  		error = 0;
8de2bf937   Dave Chinner   xfs: remove xfs_f...
442
  		prealloc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  		goto retry;
  	}
86c4d6230   David Chinner   [XFS] Fix check f...
445
  	if (!(imap[0].br_startblock || XFS_IS_REALTIME_INODE(ip)))
6d4a8ecb3   Dave Chinner   xfs: rename xfs_c...
446
  		return xfs_alert_fsblock_zero(ip, &imap[0]);
dd9f438e3   Nathan Scott   [XFS] Implement t...
447
448
  
  	*ret_imap = imap[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
  	return 0;
  }
  
  /*
   * Pass in a delayed allocate extent, convert it to real extents;
   * return to the caller the extent we create which maps on top of
   * the originating callers request.
   *
   * Called without a lock on the inode.
e4143a1cf   David Chinner   [XFS] Fix transac...
458
459
460
   *
   * We no longer bother to look at the incoming map - all we have to
   * guarantee is that whatever we allocate fills the required range.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
   */
a206c817c   Christoph Hellwig   xfs: kill xfs_iomap
462
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
  xfs_iomap_write_allocate(
  	xfs_inode_t	*ip,
f403b7f45   Nathan Scott   [XFS] Cleanup use...
465
  	xfs_off_t	offset,
24e17b5fb   Nathan Scott   [XFS] Use the rig...
466
  	size_t		count,
405f80429   Christoph Hellwig   xfs: cleanup the ...
467
  	xfs_bmbt_irec_t *imap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  {
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
  	xfs_fileoff_t	offset_fsb, last_block;
  	xfs_fileoff_t	end_fsb, map_start_fsb;
  	xfs_fsblock_t	first_block;
  	xfs_bmap_free_t	free_list;
  	xfs_filblks_t	count_fsb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  	xfs_trans_t	*tp;
e4143a1cf   David Chinner   [XFS] Fix transac...
476
  	int		nimaps, committed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  	int		error = 0;
  	int		nres;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  	/*
  	 * Make sure that the dquots are there.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
482
483
  	error = xfs_qm_dqattach(ip, 0);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  		return XFS_ERROR(error);
24e17b5fb   Nathan Scott   [XFS] Use the rig...
485
  	offset_fsb = XFS_B_TO_FSBT(mp, offset);
3070451ee   Christoph Hellwig   xfs: reduce stack...
486
487
  	count_fsb = imap->br_blockcount;
  	map_start_fsb = imap->br_startoff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  
  	XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
  
  	while (count_fsb != 0) {
  		/*
  		 * Set up a transaction with which to allocate the
  		 * backing store for the file.  Do allocations in a
  		 * loop until we get some space in the range we are
  		 * interested in.  The other space that might be allocated
  		 * is in the delayed allocation extent on which we sit
  		 * but before our buffer starts.
  		 */
  
  		nimaps = 0;
  		while (nimaps == 0) {
  			tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
84e1e99f1   David Chinner   [XFS] Prevent ENO...
504
  			tp->t_flags |= XFS_TRANS_RESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
  			nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
  			error = xfs_trans_reserve(tp, nres,
  					XFS_WRITE_LOG_RES(mp),
  					0, XFS_TRANS_PERM_LOG_RES,
  					XFS_WRITE_LOG_COUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
  			if (error) {
  				xfs_trans_cancel(tp, 0);
  				return XFS_ERROR(error);
  			}
  			xfs_ilock(ip, XFS_ILOCK_EXCL);
ddc3415ab   Christoph Hellwig   xfs: simplify xfs...
515
  			xfs_trans_ijoin(tp, ip, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

9d87c3192   Eric Sandeen   [XFS] Remove the ...
517
  			xfs_bmap_init(&free_list, &first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  			/*
e4143a1cf   David Chinner   [XFS] Fix transac...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  			 * it is possible that the extents have changed since
  			 * we did the read call as we dropped the ilock for a
  			 * while. We have to be careful about truncates or hole
  			 * punchs here - we are not allowed to allocate
  			 * non-delalloc blocks here.
  			 *
  			 * The only protection against truncation is the pages
  			 * for the range we are being asked to convert are
  			 * locked and hence a truncate will block on them
  			 * first.
  			 *
  			 * As a result, if we go beyond the range we really
  			 * need and hit an delalloc extent boundary followed by
  			 * a hole while we have excess blocks in the map, we
  			 * will fill the hole incorrectly and overrun the
  			 * transaction reservation.
  			 *
  			 * Using a single map prevents this as we are forced to
  			 * check each map we look for overlap with the desired
  			 * range and abort as soon as we find it. Also, given
  			 * that we only return a single map, having one beyond
  			 * what we can return is probably a bit silly.
  			 *
  			 * We also need to check that we don't go beyond EOF;
  			 * this is a truncate optimisation as a truncate sets
  			 * the new file size before block on the pages we
  			 * currently have locked under writeback. Because they
  			 * are about to be tossed, we don't need to write them
  			 * back....
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  			 */
e4143a1cf   David Chinner   [XFS] Fix transac...
550
  			nimaps = 1;
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
551
  			end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
7c9ef85c5   David Chinner   [XFS] Catch error...
552
553
554
555
  			error = xfs_bmap_last_offset(NULL, ip, &last_block,
  							XFS_DATA_FORK);
  			if (error)
  				goto trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
559
560
561
562
563
  			last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
  			if ((map_start_fsb + count_fsb) > last_block) {
  				count_fsb = last_block - map_start_fsb;
  				if (count_fsb == 0) {
  					error = EAGAIN;
  					goto trans_cancel;
  				}
  			}
3070451ee   Christoph Hellwig   xfs: reduce stack...
564
  			/*
3070451ee   Christoph Hellwig   xfs: reduce stack...
565
566
567
  			 * From this point onwards we overwrite the imap
  			 * pointer that the caller gave to us.
  			 */
c0dc7828a   Dave Chinner   xfs: rename xfs_b...
568
569
570
  			error = xfs_bmapi_write(tp, ip, map_start_fsb,
  						count_fsb, 0, &first_block, 1,
  						imap, &nimaps, &free_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
  			if (error)
  				goto trans_cancel;
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
573
  			error = xfs_bmap_finish(&tp, &free_list, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
  			if (error)
  				goto trans_cancel;
1c72bf900   Eric Sandeen   [XFS] The last ar...
576
  			error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
582
583
584
585
586
  			if (error)
  				goto error0;
  
  			xfs_iunlock(ip, XFS_ILOCK_EXCL);
  		}
  
  		/*
  		 * See if we were able to allocate an extent that
  		 * covers at least part of the callers request
  		 */
3070451ee   Christoph Hellwig   xfs: reduce stack...
587
  		if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
6d4a8ecb3   Dave Chinner   xfs: rename xfs_c...
588
  			return xfs_alert_fsblock_zero(ip, imap);
86c4d6230   David Chinner   [XFS] Fix check f...
589

3070451ee   Christoph Hellwig   xfs: reduce stack...
590
591
592
  		if ((offset_fsb >= imap->br_startoff) &&
  		    (offset_fsb < (imap->br_startoff +
  				   imap->br_blockcount))) {
e4143a1cf   David Chinner   [XFS] Fix transac...
593
594
  			XFS_STATS_INC(xs_xstrat_quick);
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  		}
e4143a1cf   David Chinner   [XFS] Fix transac...
596
597
  		/*
  		 * So far we have not mapped the requested part of the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
  		 * file, just surrounding data, try again.
  		 */
3070451ee   Christoph Hellwig   xfs: reduce stack...
600
601
  		count_fsb -= imap->br_blockcount;
  		map_start_fsb = imap->br_startoff + imap->br_blockcount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
607
608
609
610
611
612
613
614
  	}
  
  trans_cancel:
  	xfs_bmap_cancel(&free_list);
  	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
  error0:
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	return XFS_ERROR(error);
  }
  
  int
  xfs_iomap_write_unwritten(
  	xfs_inode_t	*ip,
f403b7f45   Nathan Scott   [XFS] Cleanup use...
615
  	xfs_off_t	offset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
  	size_t		count)
  {
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
  	xfs_fileoff_t	offset_fsb;
  	xfs_filblks_t	count_fsb;
  	xfs_filblks_t	numblks_fsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
622
623
624
625
626
627
  	xfs_fsblock_t	firstfsb;
  	int		nimaps;
  	xfs_trans_t	*tp;
  	xfs_bmbt_irec_t imap;
  	xfs_bmap_free_t free_list;
  	uint		resblks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
  	int		committed;
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630

0b1b213fc   Christoph Hellwig   xfs: event tracin...
631
  	trace_xfs_unwritten_convert(ip, offset, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
  
  	offset_fsb = XFS_B_TO_FSBT(mp, offset);
  	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
  	count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb);
4ddd8bb1d   Lachlan McIlroy   [XFS] use minleft...
636
637
638
639
640
641
642
643
644
645
  	/*
  	 * Reserve enough blocks in this transaction for two complete extent
  	 * btree splits.  We may be converting the middle part of an unwritten
  	 * extent and in this case we will insert two new extents in the btree
  	 * each of which could cause a full split.
  	 *
  	 * This reservation amount will be used in the first call to
  	 * xfs_bmbt_split() to select an AG with enough space to satisfy the
  	 * rest of the operation.
  	 */
dd9f438e3   Nathan Scott   [XFS] Implement t...
646
  	resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647

dd9f438e3   Nathan Scott   [XFS] Implement t...
648
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
  		/*
  		 * set up a transaction to convert the range of extents
  		 * from unwritten to real. Do allocations in a loop until
  		 * we have covered the range passed in.
80641dc66   Christoph Hellwig   xfs: I/O completi...
653
654
655
656
657
658
  		 *
  		 * Note that we open code the transaction allocation here
  		 * to pass KM_NOFS--we can't risk to recursing back into
  		 * the filesystem here as we might be asked to write out
  		 * the same inode that we complete here and might deadlock
  		 * on the iolock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  		 */
80641dc66   Christoph Hellwig   xfs: I/O completi...
660
661
  		xfs_wait_for_freeze(mp, SB_FREEZE_TRANS);
  		tp = _xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE, KM_NOFS);
84e1e99f1   David Chinner   [XFS] Prevent ENO...
662
  		tp->t_flags |= XFS_TRANS_RESERVE;
dd9f438e3   Nathan Scott   [XFS] Implement t...
663
  		error = xfs_trans_reserve(tp, resblks,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
  				XFS_WRITE_LOG_RES(mp), 0,
  				XFS_TRANS_PERM_LOG_RES,
  				XFS_WRITE_LOG_COUNT);
  		if (error) {
  			xfs_trans_cancel(tp, 0);
572d95f49   Nathan Scott   [XFS] Improve err...
669
  			return XFS_ERROR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
  		}
  
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
ddc3415ab   Christoph Hellwig   xfs: simplify xfs...
673
  		xfs_trans_ijoin(tp, ip, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
  
  		/*
  		 * Modify the unwritten extent state of the buffer.
  		 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
678
  		xfs_bmap_init(&free_list, &firstfsb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  		nimaps = 1;
c0dc7828a   Dave Chinner   xfs: rename xfs_b...
680
681
  		error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
  				  XFS_BMAPI_CONVERT, &firstfsb,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
682
  				  1, &imap, &nimaps, &free_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  		if (error)
  			goto error_on_bmapi_transaction;
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
685
  		error = xfs_bmap_finish(&(tp), &(free_list), &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
  		if (error)
  			goto error_on_bmapi_transaction;
1c72bf900   Eric Sandeen   [XFS] The last ar...
688
  		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
  		xfs_iunlock(ip, XFS_ILOCK_EXCL);
  		if (error)
572d95f49   Nathan Scott   [XFS] Improve err...
691
  			return XFS_ERROR(error);
86c4d6230   David Chinner   [XFS] Fix check f...
692
  		if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip)))
6d4a8ecb3   Dave Chinner   xfs: rename xfs_c...
693
  			return xfs_alert_fsblock_zero(ip, &imap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  
  		if ((numblks_fsb = imap.br_blockcount) == 0) {
  			/*
  			 * The numblks_fsb value should always get
  			 * smaller, otherwise the loop is stuck.
  			 */
  			ASSERT(imap.br_blockcount);
  			break;
  		}
  		offset_fsb += numblks_fsb;
  		count_fsb -= numblks_fsb;
  	} while (count_fsb > 0);
  
  	return 0;
  
  error_on_bmapi_transaction:
  	xfs_bmap_cancel(&free_list);
  	xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
  	return XFS_ERROR(error);
  }