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"
19153323Srodrigc#include "xfs_fs.h"
20159451Srodrigc#include "xfs_bit.h"
21159451Srodrigc#include "xfs_log.h"
22153323Srodrigc#include "xfs_inum.h"
23153323Srodrigc#include "xfs_trans.h"
24153323Srodrigc#include "xfs_sb.h"
25153323Srodrigc#include "xfs_ag.h"
26153323Srodrigc#include "xfs_dir.h"
27153323Srodrigc#include "xfs_dir2.h"
28153323Srodrigc#include "xfs_alloc.h"
29153323Srodrigc#include "xfs_dmapi.h"
30153323Srodrigc#include "xfs_quota.h"
31153323Srodrigc#include "xfs_mount.h"
32159451Srodrigc#include "xfs_bmap_btree.h"
33153323Srodrigc#include "xfs_alloc_btree.h"
34153323Srodrigc#include "xfs_ialloc_btree.h"
35153323Srodrigc#include "xfs_dir_sf.h"
36153323Srodrigc#include "xfs_dir2_sf.h"
37159451Srodrigc#include "xfs_attr_sf.h"
38153323Srodrigc#include "xfs_dinode.h"
39153323Srodrigc#include "xfs_inode.h"
40159451Srodrigc#include "xfs_ialloc.h"
41159451Srodrigc#include "xfs_btree.h"
42153323Srodrigc#include "xfs_bmap.h"
43153323Srodrigc#include "xfs_rtalloc.h"
44153323Srodrigc#include "xfs_error.h"
45153323Srodrigc#include "xfs_itable.h"
46153323Srodrigc#include "xfs_rw.h"
47153323Srodrigc#include "xfs_acl.h"
48153323Srodrigc#include "xfs_cap.h"
49153323Srodrigc#include "xfs_mac.h"
50153323Srodrigc#include "xfs_attr.h"
51153323Srodrigc#include "xfs_buf_item.h"
52153323Srodrigc#include "xfs_trans_space.h"
53153323Srodrigc#include "xfs_utils.h"
54153323Srodrigc#include "xfs_iomap.h"
55153323Srodrigc
56153323Srodrigc#if defined(XFS_RW_TRACE)
57153323Srodrigcvoid
58153323Srodrigcxfs_iomap_enter_trace(
59153323Srodrigc	int		tag,
60153323Srodrigc	xfs_iocore_t	*io,
61153323Srodrigc	xfs_off_t	offset,
62153323Srodrigc	ssize_t		count)
63153323Srodrigc{
64153323Srodrigc	xfs_inode_t	*ip = XFS_IO_INODE(io);
65153323Srodrigc
66153323Srodrigc	if (!ip->i_rwtrace)
67153323Srodrigc		return;
68153323Srodrigc
69153323Srodrigc	ktrace_enter(ip->i_rwtrace,
70153323Srodrigc		(void *)((unsigned long)tag),
71153323Srodrigc		(void *)ip,
72153323Srodrigc		(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
73153323Srodrigc		(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
74153323Srodrigc		(void *)((unsigned long)((offset >> 32) & 0xffffffff)),
75153323Srodrigc		(void *)((unsigned long)(offset & 0xffffffff)),
76153323Srodrigc		(void *)((unsigned long)count),
77153323Srodrigc		(void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)),
78153323Srodrigc		(void *)((unsigned long)(io->io_new_size & 0xffffffff)),
79159451Srodrigc		(void *)((unsigned long)current_pid()),
80153323Srodrigc		(void *)NULL,
81153323Srodrigc		(void *)NULL,
82153323Srodrigc		(void *)NULL,
83153323Srodrigc		(void *)NULL,
84153323Srodrigc		(void *)NULL,
85153323Srodrigc		(void *)NULL);
86153323Srodrigc}
87153323Srodrigc
88153323Srodrigcvoid
89153323Srodrigcxfs_iomap_map_trace(
90153323Srodrigc	int		tag,
91153323Srodrigc	xfs_iocore_t	*io,
92153323Srodrigc	xfs_off_t	offset,
93153323Srodrigc	ssize_t		count,
94153323Srodrigc	xfs_iomap_t	*iomapp,
95153323Srodrigc	xfs_bmbt_irec_t	*imapp,
96153323Srodrigc	int		flags)
97153323Srodrigc{
98153323Srodrigc	xfs_inode_t	*ip = XFS_IO_INODE(io);
99153323Srodrigc
100153323Srodrigc	if (!ip->i_rwtrace)
101153323Srodrigc		return;
102153323Srodrigc
103153323Srodrigc	ktrace_enter(ip->i_rwtrace,
104153323Srodrigc		(void *)((unsigned long)tag),
105153323Srodrigc		(void *)ip,
106153323Srodrigc		(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
107153323Srodrigc		(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
108153323Srodrigc		(void *)((unsigned long)((offset >> 32) & 0xffffffff)),
109153323Srodrigc		(void *)((unsigned long)(offset & 0xffffffff)),
110153323Srodrigc		(void *)((unsigned long)count),
111153323Srodrigc		(void *)((unsigned long)flags),
112153323Srodrigc		(void *)((unsigned long)((iomapp->iomap_offset >> 32) & 0xffffffff)),
113153323Srodrigc		(void *)((unsigned long)(iomapp->iomap_offset & 0xffffffff)),
114153323Srodrigc		(void *)((unsigned long)(iomapp->iomap_delta)),
115153323Srodrigc		(void *)((unsigned long)(iomapp->iomap_bsize)),
116153323Srodrigc		(void *)((unsigned long)(iomapp->iomap_bn)),
117153323Srodrigc		(void *)(__psint_t)(imapp->br_startoff),
118153323Srodrigc		(void *)((unsigned long)(imapp->br_blockcount)),
119153323Srodrigc		(void *)(__psint_t)(imapp->br_startblock));
120153323Srodrigc}
121153323Srodrigc#else
122153323Srodrigc#define xfs_iomap_enter_trace(tag, io, offset, count)
123153323Srodrigc#define xfs_iomap_map_trace(tag, io, offset, count, iomapp, imapp, flags)
124153323Srodrigc#endif
125153323Srodrigc
126153323Srodrigc#define XFS_WRITEIO_ALIGN(mp,off)	(((off) >> mp->m_writeio_log) \
127153323Srodrigc						<< mp->m_writeio_log)
128153323Srodrigc#define XFS_STRAT_WRITE_IMAPS	2
129153323Srodrigc#define XFS_WRITE_IMAPS		XFS_BMAP_MAX_NMAP
130153323Srodrigc
131153323SrodrigcSTATIC int
132153323Srodrigcxfs_imap_to_bmap(
133153323Srodrigc	xfs_iocore_t	*io,
134153323Srodrigc	xfs_off_t	offset,
135153323Srodrigc	xfs_bmbt_irec_t *imap,
136153323Srodrigc	xfs_iomap_t	*iomapp,
137153323Srodrigc	int		imaps,			/* Number of imap entries */
138153323Srodrigc	int		iomaps,			/* Number of iomap entries */
139153323Srodrigc	int		flags)
140153323Srodrigc{
141153323Srodrigc	xfs_mount_t	*mp;
142153323Srodrigc	xfs_fsize_t	nisize;
143153323Srodrigc	int		pbm;
144153323Srodrigc	xfs_fsblock_t	start_block;
145153323Srodrigc
146153323Srodrigc	mp = io->io_mount;
147153323Srodrigc	nisize = XFS_SIZE(mp, io);
148153323Srodrigc	if (io->io_new_size > nisize)
149153323Srodrigc		nisize = io->io_new_size;
150153323Srodrigc
151153323Srodrigc	for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) {
152153323Srodrigc		iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
153153323Srodrigc		iomapp->iomap_delta = offset - iomapp->iomap_offset;
154153323Srodrigc		iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
155153323Srodrigc		iomapp->iomap_flags = flags;
156153323Srodrigc
157159451Srodrigc		if (io->io_flags & XFS_IOCORE_RT) {
158159451Srodrigc			iomapp->iomap_flags |= IOMAP_REALTIME;
159159451Srodrigc			iomapp->iomap_target = mp->m_rtdev_targp;
160159451Srodrigc		} else {
161159451Srodrigc			iomapp->iomap_target = mp->m_ddev_targp;
162159451Srodrigc		}
163153323Srodrigc		start_block = imap->br_startblock;
164153323Srodrigc		if (start_block == HOLESTARTBLOCK) {
165153323Srodrigc			iomapp->iomap_bn = IOMAP_DADDR_NULL;
166159451Srodrigc			iomapp->iomap_flags |= IOMAP_HOLE;
167153323Srodrigc		} else if (start_block == DELAYSTARTBLOCK) {
168153323Srodrigc			iomapp->iomap_bn = IOMAP_DADDR_NULL;
169159451Srodrigc			iomapp->iomap_flags |= IOMAP_DELAY;
170153323Srodrigc		} else {
171153323Srodrigc			iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block);
172153323Srodrigc			if (ISUNWRITTEN(imap))
173153323Srodrigc				iomapp->iomap_flags |= IOMAP_UNWRITTEN;
174153323Srodrigc		}
175153323Srodrigc
176153323Srodrigc		if ((iomapp->iomap_offset + iomapp->iomap_bsize) >= nisize) {
177153323Srodrigc			iomapp->iomap_flags |= IOMAP_EOF;
178153323Srodrigc		}
179153323Srodrigc
180153323Srodrigc		offset += iomapp->iomap_bsize - iomapp->iomap_delta;
181153323Srodrigc	}
182153323Srodrigc	return pbm;	/* Return the number filled */
183153323Srodrigc}
184153323Srodrigc
185153323Srodrigcint
186153323Srodrigcxfs_iomap(
187153323Srodrigc	xfs_iocore_t	*io,
188153323Srodrigc	xfs_off_t	offset,
189153323Srodrigc	ssize_t		count,
190153323Srodrigc	int		flags,
191153323Srodrigc	xfs_iomap_t	*iomapp,
192153323Srodrigc	int		*niomaps)
193153323Srodrigc{
194153323Srodrigc	xfs_mount_t	*mp = io->io_mount;
195153323Srodrigc	xfs_fileoff_t	offset_fsb, end_fsb;
196153323Srodrigc	int		error = 0;
197153323Srodrigc	int		lockmode = 0;
198153323Srodrigc	xfs_bmbt_irec_t	imap;
199153323Srodrigc	int		nimaps = 1;
200153323Srodrigc	int		bmapi_flags = 0;
201153323Srodrigc	int		iomap_flags = 0;
202153323Srodrigc
203153323Srodrigc	if (XFS_FORCED_SHUTDOWN(mp))
204153323Srodrigc		return XFS_ERROR(EIO);
205153323Srodrigc
206153323Srodrigc	switch (flags &
207153323Srodrigc		(BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE |
208153323Srodrigc		 BMAPI_UNWRITTEN | BMAPI_DEVICE)) {
209153323Srodrigc	case BMAPI_READ:
210153323Srodrigc		xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count);
211153323Srodrigc		lockmode = XFS_LCK_MAP_SHARED(mp, io);
212153323Srodrigc		bmapi_flags = XFS_BMAPI_ENTIRE;
213153323Srodrigc		break;
214153323Srodrigc	case BMAPI_WRITE:
215153323Srodrigc		xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count);
216153323Srodrigc		lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
217159451Srodrigc		if (flags & BMAPI_IGNSTATE)
218159451Srodrigc			bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE;
219153323Srodrigc		XFS_ILOCK(mp, io, lockmode);
220153323Srodrigc		break;
221153323Srodrigc	case BMAPI_ALLOCATE:
222153323Srodrigc		xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count);
223153323Srodrigc		lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD;
224153323Srodrigc		bmapi_flags = XFS_BMAPI_ENTIRE;
225153323Srodrigc		/* Attempt non-blocking lock */
226153323Srodrigc		if (flags & BMAPI_TRYLOCK) {
227153323Srodrigc			if (!XFS_ILOCK_NOWAIT(mp, io, lockmode))
228153323Srodrigc				return XFS_ERROR(EAGAIN);
229153323Srodrigc		} else {
230153323Srodrigc			XFS_ILOCK(mp, io, lockmode);
231153323Srodrigc		}
232153323Srodrigc		break;
233153323Srodrigc	case BMAPI_UNWRITTEN:
234153323Srodrigc		goto phase2;
235153323Srodrigc	case BMAPI_DEVICE:
236153323Srodrigc		lockmode = XFS_LCK_MAP_SHARED(mp, io);
237153323Srodrigc		iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ?
238153323Srodrigc			mp->m_rtdev_targp : mp->m_ddev_targp;
239153323Srodrigc		error = 0;
240153323Srodrigc		*niomaps = 1;
241153323Srodrigc		goto out;
242153323Srodrigc	default:
243153323Srodrigc		panic("unrecognized bmapi flags");
244153323Srodrigc	}
245153323Srodrigc
246153323Srodrigc	ASSERT(offset <= mp->m_maxioffset);
247153323Srodrigc	if ((xfs_fsize_t)offset + count > mp->m_maxioffset)
248153323Srodrigc		count = mp->m_maxioffset - offset;
249153323Srodrigc	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
250153323Srodrigc	offset_fsb = XFS_B_TO_FSBT(mp, offset);
251153323Srodrigc
252153323Srodrigc	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
253153323Srodrigc			(xfs_filblks_t)(end_fsb - offset_fsb),
254153323Srodrigc			bmapi_flags,  NULL, 0, &imap,
255159451Srodrigc			&nimaps, NULL, NULL);
256153323Srodrigc
257153323Srodrigc	if (error)
258153323Srodrigc		goto out;
259153323Srodrigc
260153323Srodrigcphase2:
261153323Srodrigc	switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) {
262153323Srodrigc	case BMAPI_WRITE:
263153323Srodrigc		/* If we found an extent, return it */
264159451Srodrigc		if (nimaps &&
265159451Srodrigc		    (imap.br_startblock != HOLESTARTBLOCK) &&
266159451Srodrigc		    (imap.br_startblock != DELAYSTARTBLOCK)) {
267153323Srodrigc			xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,
268153323Srodrigc					offset, count, iomapp, &imap, flags);
269153323Srodrigc			break;
270153323Srodrigc		}
271153323Srodrigc
272153323Srodrigc		if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) {
273153323Srodrigc			error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset,
274153323Srodrigc					count, flags, &imap, &nimaps, nimaps);
275153323Srodrigc		} else {
276153323Srodrigc			error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count,
277153323Srodrigc					flags, &imap, &nimaps);
278153323Srodrigc		}
279153323Srodrigc		if (!error) {
280153323Srodrigc			xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io,
281153323Srodrigc					offset, count, iomapp, &imap, flags);
282153323Srodrigc		}
283153323Srodrigc		iomap_flags = IOMAP_NEW;
284153323Srodrigc		break;
285153323Srodrigc	case BMAPI_ALLOCATE:
286153323Srodrigc		/* If we found an extent, return it */
287153323Srodrigc		XFS_IUNLOCK(mp, io, lockmode);
288153323Srodrigc		lockmode = 0;
289153323Srodrigc
290153323Srodrigc		if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) {
291153323Srodrigc			xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,
292153323Srodrigc					offset, count, iomapp, &imap, flags);
293153323Srodrigc			break;
294153323Srodrigc		}
295153323Srodrigc
296159451Srodrigc		error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count,
297159451Srodrigc						 &imap, &nimaps);
298153323Srodrigc		break;
299153323Srodrigc	case BMAPI_UNWRITTEN:
300153323Srodrigc		lockmode = 0;
301153323Srodrigc		error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count);
302153323Srodrigc		nimaps = 0;
303153323Srodrigc		break;
304153323Srodrigc	}
305153323Srodrigc
306153323Srodrigc	if (nimaps) {
307153323Srodrigc		*niomaps = xfs_imap_to_bmap(io, offset, &imap,
308153323Srodrigc					    iomapp, nimaps, *niomaps, iomap_flags);
309153323Srodrigc	} else if (niomaps) {
310153323Srodrigc		*niomaps = 0;
311153323Srodrigc	}
312153323Srodrigc
313153323Srodrigcout:
314153323Srodrigc	if (lockmode)
315153323Srodrigc		XFS_IUNLOCK(mp, io, lockmode);
316153323Srodrigc	return XFS_ERROR(error);
317153323Srodrigc}
318153323Srodrigc
319153323SrodrigcSTATIC int
320159451Srodrigcxfs_iomap_eof_align_last_fsb(
321159451Srodrigc	xfs_mount_t	*mp,
322159451Srodrigc	xfs_iocore_t	*io,
323159451Srodrigc	xfs_fsize_t	isize,
324159451Srodrigc	xfs_extlen_t	extsize,
325159451Srodrigc	xfs_fileoff_t	*last_fsb)
326159451Srodrigc{
327159451Srodrigc	xfs_fileoff_t	new_last_fsb = 0;
328159451Srodrigc	xfs_extlen_t	align;
329159451Srodrigc	int		eof, error;
330159451Srodrigc
331159451Srodrigc	if (io->io_flags & XFS_IOCORE_RT)
332159451Srodrigc		;
333159451Srodrigc	/*
334159451Srodrigc	 * If mounted with the "-o swalloc" option, roundup the allocation
335159451Srodrigc	 * request to a stripe width boundary if the file size is >=
336159451Srodrigc	 * stripe width and we are allocating past the allocation eof.
337159451Srodrigc	 */
338159451Srodrigc	else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
339159451Srodrigc	        (isize >= XFS_FSB_TO_B(mp, mp->m_swidth)))
340159451Srodrigc		new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
341159451Srodrigc	/*
342159451Srodrigc	 * Roundup the allocation request to a stripe unit (m_dalign) boundary
343159451Srodrigc	 * if the file size is >= stripe unit size, and we are allocating past
344159451Srodrigc	 * the allocation eof.
345159451Srodrigc	 */
346159451Srodrigc	else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)))
347159451Srodrigc		new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
348159451Srodrigc
349159451Srodrigc	/*
350159451Srodrigc	 * Always round up the allocation request to an extent boundary
351159451Srodrigc	 * (when file on a real-time subvolume or has di_extsize hint).
352159451Srodrigc	 */
353159451Srodrigc	if (extsize) {
354159451Srodrigc		if (new_last_fsb)
355159451Srodrigc			align = roundup_64(new_last_fsb, extsize);
356159451Srodrigc		else
357159451Srodrigc			align = extsize;
358159451Srodrigc		new_last_fsb = roundup_64(*last_fsb, align);
359159451Srodrigc	}
360159451Srodrigc
361159451Srodrigc	if (new_last_fsb) {
362159451Srodrigc		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
363159451Srodrigc		if (error)
364159451Srodrigc			return error;
365159451Srodrigc		if (eof)
366159451Srodrigc			*last_fsb = new_last_fsb;
367159451Srodrigc	}
368159451Srodrigc	return 0;
369159451Srodrigc}
370159451Srodrigc
371159451SrodrigcSTATIC int
372153323Srodrigcxfs_flush_space(
373153323Srodrigc	xfs_inode_t	*ip,
374153323Srodrigc	int		*fsynced,
375153323Srodrigc	int		*ioflags)
376153323Srodrigc{
377153323Srodrigc	switch (*fsynced) {
378153323Srodrigc	case 0:
379153323Srodrigc		if (ip->i_delayed_blks) {
380153323Srodrigc			xfs_iunlock(ip, XFS_ILOCK_EXCL);
381153323Srodrigc			xfs_flush_inode(ip);
382153323Srodrigc			xfs_ilock(ip, XFS_ILOCK_EXCL);
383153323Srodrigc			*fsynced = 1;
384153323Srodrigc		} else {
385153323Srodrigc			*ioflags |= BMAPI_SYNC;
386153323Srodrigc			*fsynced = 2;
387153323Srodrigc		}
388153323Srodrigc		return 0;
389153323Srodrigc	case 1:
390153323Srodrigc		*fsynced = 2;
391153323Srodrigc		*ioflags |= BMAPI_SYNC;
392153323Srodrigc		return 0;
393153323Srodrigc	case 2:
394153323Srodrigc		xfs_iunlock(ip, XFS_ILOCK_EXCL);
395153323Srodrigc		xfs_flush_device(ip);
396153323Srodrigc		xfs_ilock(ip, XFS_ILOCK_EXCL);
397153323Srodrigc		*fsynced = 3;
398153323Srodrigc		return 0;
399153323Srodrigc	}
400153323Srodrigc	return 1;
401153323Srodrigc}
402153323Srodrigc
403153323Srodrigcint
404153323Srodrigcxfs_iomap_write_direct(
405153323Srodrigc	xfs_inode_t	*ip,
406153323Srodrigc	xfs_off_t	offset,
407153323Srodrigc	size_t		count,
408153323Srodrigc	int		flags,
409153323Srodrigc	xfs_bmbt_irec_t *ret_imap,
410153323Srodrigc	int		*nmaps,
411153323Srodrigc	int		found)
412153323Srodrigc{
413153323Srodrigc	xfs_mount_t	*mp = ip->i_mount;
414153323Srodrigc	xfs_iocore_t	*io = &ip->i_iocore;
415153323Srodrigc	xfs_fileoff_t	offset_fsb;
416153323Srodrigc	xfs_fileoff_t	last_fsb;
417159451Srodrigc	xfs_filblks_t	count_fsb, resaligned;
418159451Srodrigc	xfs_fsblock_t	firstfsb;
419159451Srodrigc	xfs_extlen_t	extsz, temp;
420153323Srodrigc	xfs_fsize_t	isize;
421159451Srodrigc	int		nimaps;
422153323Srodrigc	int		bmapi_flag;
423159451Srodrigc	int		quota_flag;
424153323Srodrigc	int		rt;
425153323Srodrigc	xfs_trans_t	*tp;
426159451Srodrigc	xfs_bmbt_irec_t imap;
427153323Srodrigc	xfs_bmap_free_t free_list;
428159451Srodrigc	uint		qblocks, resblks, resrtextents;
429153323Srodrigc	int		committed;
430159451Srodrigc	int		error;
431153323Srodrigc
432153323Srodrigc	/*
433153323Srodrigc	 * Make sure that the dquots are there. This doesn't hold
434153323Srodrigc	 * the ilock across a disk read.
435153323Srodrigc	 */
436153323Srodrigc	error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
437153323Srodrigc	if (error)
438153323Srodrigc		return XFS_ERROR(error);
439153323Srodrigc
440159451Srodrigc	rt = XFS_IS_REALTIME_INODE(ip);
441159451Srodrigc	if (unlikely(rt)) {
442159451Srodrigc		if (!(extsz = ip->i_d.di_extsize))
443159451Srodrigc			extsz = mp->m_sb.sb_rextsize;
444159451Srodrigc	} else {
445159451Srodrigc		extsz = ip->i_d.di_extsize;
446159451Srodrigc	}
447153323Srodrigc
448153323Srodrigc	isize = ip->i_d.di_size;
449153323Srodrigc	if (io->io_new_size > isize)
450153323Srodrigc		isize = io->io_new_size;
451153323Srodrigc
452159451Srodrigc  	offset_fsb = XFS_B_TO_FSBT(mp, offset);
453159451Srodrigc  	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
454159451Srodrigc	if ((offset + count) > isize) {
455159451Srodrigc		error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
456159451Srodrigc							&last_fsb);
457159451Srodrigc		if (error)
458159451Srodrigc			goto error_out;
459159451Srodrigc	} else {
460159451Srodrigc		if (found && (ret_imap->br_startblock == HOLESTARTBLOCK))
461159451Srodrigc			last_fsb = MIN(last_fsb, (xfs_fileoff_t)
462159451Srodrigc					ret_imap->br_blockcount +
463159451Srodrigc					ret_imap->br_startoff);
464159451Srodrigc	}
465153323Srodrigc	count_fsb = last_fsb - offset_fsb;
466159451Srodrigc	ASSERT(count_fsb > 0);
467153323Srodrigc
468159451Srodrigc	resaligned = count_fsb;
469159451Srodrigc	if (unlikely(extsz)) {
470159451Srodrigc		if ((temp = do_mod(offset_fsb, extsz)))
471159451Srodrigc			resaligned += temp;
472159451Srodrigc		if ((temp = do_mod(resaligned, extsz)))
473159451Srodrigc			resaligned += extsz - temp;
474153323Srodrigc	}
475153323Srodrigc
476159451Srodrigc	if (unlikely(rt)) {
477159451Srodrigc		resrtextents = qblocks = resaligned;
478159451Srodrigc		resrtextents /= mp->m_sb.sb_rextsize;
479159451Srodrigc  		resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
480159451Srodrigc  		quota_flag = XFS_QMOPT_RES_RTBLKS;
481159451Srodrigc  	} else {
482159451Srodrigc  		resrtextents = 0;
483159451Srodrigc		resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
484159451Srodrigc  		quota_flag = XFS_QMOPT_RES_REGBLKS;
485159451Srodrigc  	}
486153323Srodrigc
487153323Srodrigc	/*
488159451Srodrigc	 * Allocate and setup the transaction
489153323Srodrigc	 */
490153323Srodrigc	xfs_iunlock(ip, XFS_ILOCK_EXCL);
491153323Srodrigc	tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
492153323Srodrigc	error = xfs_trans_reserve(tp, resblks,
493159451Srodrigc			XFS_WRITE_LOG_RES(mp), resrtextents,
494153323Srodrigc			XFS_TRANS_PERM_LOG_RES,
495153323Srodrigc			XFS_WRITE_LOG_COUNT);
496153323Srodrigc	/*
497159451Srodrigc	 * Check for running out of space, note: need lock to return
498153323Srodrigc	 */
499153323Srodrigc	if (error)
500153323Srodrigc		xfs_trans_cancel(tp, 0);
501153323Srodrigc	xfs_ilock(ip, XFS_ILOCK_EXCL);
502159451Srodrigc	if (error)
503159451Srodrigc		goto error_out;
504153323Srodrigc
505159451Srodrigc	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
506159451Srodrigc					      qblocks, 0, quota_flag);
507153323Srodrigc	if (error)
508153323Srodrigc		goto error1;
509153323Srodrigc
510153323Srodrigc	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
511153323Srodrigc	xfs_trans_ihold(tp, ip);
512153323Srodrigc
513159451Srodrigc	bmapi_flag = XFS_BMAPI_WRITE;
514159451Srodrigc	if ((flags & BMAPI_DIRECT) && (offset < ip->i_d.di_size || extsz))
515153323Srodrigc		bmapi_flag |= XFS_BMAPI_PREALLOC;
516153323Srodrigc
517153323Srodrigc	/*
518159451Srodrigc	 * Issue the xfs_bmapi() call to allocate the blocks
519153323Srodrigc	 */
520153323Srodrigc	XFS_BMAP_INIT(&free_list, &firstfsb);
521159451Srodrigc	nimaps = 1;
522159451Srodrigc	error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag,
523159451Srodrigc		&firstfsb, 0, &imap, &nimaps, &free_list, NULL);
524159451Srodrigc	if (error)
525153323Srodrigc		goto error0;
526153323Srodrigc
527153323Srodrigc	/*
528159451Srodrigc	 * Complete the transaction
529153323Srodrigc	 */
530153323Srodrigc	error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
531159451Srodrigc	if (error)
532153323Srodrigc		goto error0;
533153323Srodrigc	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
534159451Srodrigc	if (error)
535153323Srodrigc		goto error_out;
536153323Srodrigc
537159451Srodrigc	/*
538159451Srodrigc	 * Copy any maps to caller's array and return any error.
539159451Srodrigc	 */
540153323Srodrigc	if (nimaps == 0) {
541153323Srodrigc		error = (ENOSPC);
542153323Srodrigc		goto error_out;
543153323Srodrigc	}
544153323Srodrigc
545159451Srodrigc	*ret_imap = imap;
546153323Srodrigc	*nmaps = 1;
547159451Srodrigc	if ( !(io->io_flags & XFS_IOCORE_RT)  && !ret_imap->br_startblock) {
548159451Srodrigc                cmn_err(CE_PANIC,"Access to block zero:  fs <%s> inode: %lld "
549159451Srodrigc                        "start_block : %llx start_off : %llx blkcnt : %llx "
550159451Srodrigc                        "extent-state : %x \n",
551159451Srodrigc                        (ip->i_mount)->m_fsname,
552159451Srodrigc                        (long long)ip->i_ino,
553159451Srodrigc                        (unsigned long long)ret_imap->br_startblock,
554159451Srodrigc			(unsigned long long)ret_imap->br_startoff,
555159451Srodrigc                        (unsigned long long)ret_imap->br_blockcount,
556159451Srodrigc			ret_imap->br_state);
557159451Srodrigc        }
558153323Srodrigc	return 0;
559153323Srodrigc
560159451Srodrigcerror0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
561153323Srodrigc	xfs_bmap_cancel(&free_list);
562159451Srodrigc	XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
563153323Srodrigc
564159451Srodrigcerror1:	/* Just cancel transaction */
565153323Srodrigc	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
566153323Srodrigc	*nmaps = 0;	/* nothing set-up here */
567153323Srodrigc
568153323Srodrigcerror_out:
569153323Srodrigc	return XFS_ERROR(error);
570153323Srodrigc}
571153323Srodrigc
572159451Srodrigc/*
573159451Srodrigc * If the caller is doing a write at the end of the file,
574159451Srodrigc * then extend the allocation out to the file system's write
575159451Srodrigc * iosize.  We clean up any extra space left over when the
576159451Srodrigc * file is closed in xfs_inactive().
577159451Srodrigc *
578159451Srodrigc * For sync writes, we are flushing delayed allocate space to
579159451Srodrigc * try to make additional space available for allocation near
580159451Srodrigc * the filesystem full boundary - preallocation hurts in that
581159451Srodrigc * situation, of course.
582159451Srodrigc */
583159451SrodrigcSTATIC int
584159451Srodrigcxfs_iomap_eof_want_preallocate(
585159451Srodrigc	xfs_mount_t	*mp,
586159451Srodrigc	xfs_iocore_t	*io,
587159451Srodrigc	xfs_fsize_t	isize,
588159451Srodrigc	xfs_off_t	offset,
589159451Srodrigc	size_t		count,
590159451Srodrigc	int		ioflag,
591159451Srodrigc	xfs_bmbt_irec_t *imap,
592159451Srodrigc	int		nimaps,
593159451Srodrigc	int		*prealloc)
594159451Srodrigc{
595159451Srodrigc	xfs_fileoff_t   start_fsb;
596159451Srodrigc	xfs_filblks_t   count_fsb;
597159451Srodrigc	xfs_fsblock_t	firstblock;
598159451Srodrigc	int		n, error, imaps;
599159451Srodrigc
600159451Srodrigc	*prealloc = 0;
601159451Srodrigc	if ((ioflag & BMAPI_SYNC) || (offset + count) <= isize)
602159451Srodrigc		return 0;
603159451Srodrigc
604159451Srodrigc	/*
605159451Srodrigc	 * If there are any real blocks past eof, then don't
606159451Srodrigc	 * do any speculative allocation.
607159451Srodrigc	 */
608159451Srodrigc	start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1)));
609159451Srodrigc	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
610159451Srodrigc	while (count_fsb > 0) {
611159451Srodrigc		imaps = nimaps;
612159451Srodrigc		firstblock = NULLFSBLOCK;
613159451Srodrigc		error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0,
614159451Srodrigc				  &firstblock, 0, imap, &imaps, NULL, NULL);
615159451Srodrigc		if (error)
616159451Srodrigc			return error;
617159451Srodrigc		for (n = 0; n < imaps; n++) {
618159451Srodrigc			if ((imap[n].br_startblock != HOLESTARTBLOCK) &&
619159451Srodrigc			    (imap[n].br_startblock != DELAYSTARTBLOCK))
620159451Srodrigc				return 0;
621159451Srodrigc			start_fsb += imap[n].br_blockcount;
622159451Srodrigc			count_fsb -= imap[n].br_blockcount;
623159451Srodrigc		}
624159451Srodrigc	}
625159451Srodrigc	*prealloc = 1;
626159451Srodrigc	return 0;
627159451Srodrigc}
628159451Srodrigc
629153323Srodrigcint
630153323Srodrigcxfs_iomap_write_delay(
631153323Srodrigc	xfs_inode_t	*ip,
632153323Srodrigc	xfs_off_t	offset,
633153323Srodrigc	size_t		count,
634153323Srodrigc	int		ioflag,
635153323Srodrigc	xfs_bmbt_irec_t *ret_imap,
636153323Srodrigc	int		*nmaps)
637153323Srodrigc{
638153323Srodrigc	xfs_mount_t	*mp = ip->i_mount;
639153323Srodrigc	xfs_iocore_t	*io = &ip->i_iocore;
640153323Srodrigc	xfs_fileoff_t	offset_fsb;
641153323Srodrigc	xfs_fileoff_t	last_fsb;
642159451Srodrigc	xfs_off_t	aligned_offset;
643159451Srodrigc	xfs_fileoff_t	ioalign;
644159451Srodrigc	xfs_fsblock_t	firstblock;
645159451Srodrigc	xfs_extlen_t	extsz;
646153323Srodrigc	xfs_fsize_t	isize;
647153323Srodrigc	int		nimaps;
648159451Srodrigc	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
649159451Srodrigc	int		prealloc, fsynced = 0;
650153323Srodrigc	int		error;
651153323Srodrigc
652153323Srodrigc	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
653153323Srodrigc
654153323Srodrigc	/*
655153323Srodrigc	 * Make sure that the dquots are there. This doesn't hold
656153323Srodrigc	 * the ilock across a disk read.
657153323Srodrigc	 */
658153323Srodrigc	error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
659153323Srodrigc	if (error)
660153323Srodrigc		return XFS_ERROR(error);
661153323Srodrigc
662159451Srodrigc	if (XFS_IS_REALTIME_INODE(ip)) {
663159451Srodrigc		if (!(extsz = ip->i_d.di_extsize))
664159451Srodrigc			extsz = mp->m_sb.sb_rextsize;
665159451Srodrigc	} else {
666159451Srodrigc		extsz = ip->i_d.di_extsize;
667159451Srodrigc	}
668159451Srodrigc
669159451Srodrigc	offset_fsb = XFS_B_TO_FSBT(mp, offset);
670159451Srodrigc
671153323Srodrigcretry:
672153323Srodrigc	isize = ip->i_d.di_size;
673159451Srodrigc	if (io->io_new_size > isize)
674153323Srodrigc		isize = io->io_new_size;
675153323Srodrigc
676159451Srodrigc	error = xfs_iomap_eof_want_preallocate(mp, io, isize, offset, count,
677159451Srodrigc				ioflag, imap, XFS_WRITE_IMAPS, &prealloc);
678159451Srodrigc	if (error)
679159451Srodrigc		return error;
680153323Srodrigc
681159451Srodrigc	if (prealloc) {
682153323Srodrigc		aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
683153323Srodrigc		ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
684159451Srodrigc		last_fsb = ioalign + mp->m_writeio_blocks;
685159451Srodrigc	} else {
686159451Srodrigc		last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
687153323Srodrigc	}
688153323Srodrigc
689159451Srodrigc	if (prealloc || extsz) {
690159451Srodrigc		error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
691159451Srodrigc							&last_fsb);
692159451Srodrigc		if (error)
693153323Srodrigc			return error;
694153323Srodrigc	}
695153323Srodrigc
696159451Srodrigc	nimaps = XFS_WRITE_IMAPS;
697159451Srodrigc	firstblock = NULLFSBLOCK;
698159451Srodrigc	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
699153323Srodrigc			  (xfs_filblks_t)(last_fsb - offset_fsb),
700153323Srodrigc			  XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
701153323Srodrigc			  XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
702159451Srodrigc			  &nimaps, NULL, NULL);
703159451Srodrigc	if (error && (error != ENOSPC))
704153323Srodrigc		return XFS_ERROR(error);
705159451Srodrigc
706153323Srodrigc	/*
707153323Srodrigc	 * If bmapi returned us nothing, and if we didn't get back EDQUOT,
708159451Srodrigc	 * then we must have run out of space - flush delalloc, and retry..
709153323Srodrigc	 */
710153323Srodrigc	if (nimaps == 0) {
711153323Srodrigc		xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE,
712153323Srodrigc					io, offset, count);
713153323Srodrigc		if (xfs_flush_space(ip, &fsynced, &ioflag))
714153323Srodrigc			return XFS_ERROR(ENOSPC);
715153323Srodrigc
716153323Srodrigc		error = 0;
717153323Srodrigc		goto retry;
718153323Srodrigc	}
719153323Srodrigc
720159451Srodrigc	if (!(io->io_flags & XFS_IOCORE_RT)  && !ret_imap->br_startblock) {
721159451Srodrigc		cmn_err(CE_PANIC,"Access to block zero:  fs <%s> inode: %lld "
722159451Srodrigc                        "start_block : %llx start_off : %llx blkcnt : %llx "
723159451Srodrigc                        "extent-state : %x \n",
724159451Srodrigc                        (ip->i_mount)->m_fsname,
725159451Srodrigc                        (long long)ip->i_ino,
726159451Srodrigc                        (unsigned long long)ret_imap->br_startblock,
727159451Srodrigc			(unsigned long long)ret_imap->br_startoff,
728159451Srodrigc                        (unsigned long long)ret_imap->br_blockcount,
729159451Srodrigc			ret_imap->br_state);
730159451Srodrigc	}
731159451Srodrigc
732153323Srodrigc	*ret_imap = imap[0];
733153323Srodrigc	*nmaps = 1;
734159451Srodrigc
735153323Srodrigc	return 0;
736153323Srodrigc}
737153323Srodrigc
738153323Srodrigc/*
739153323Srodrigc * Pass in a delayed allocate extent, convert it to real extents;
740153323Srodrigc * return to the caller the extent we create which maps on top of
741153323Srodrigc * the originating callers request.
742153323Srodrigc *
743153323Srodrigc * Called without a lock on the inode.
744153323Srodrigc */
745153323Srodrigcint
746153323Srodrigcxfs_iomap_write_allocate(
747153323Srodrigc	xfs_inode_t	*ip,
748159451Srodrigc	xfs_off_t	offset,
749159451Srodrigc	size_t		count,
750153323Srodrigc	xfs_bmbt_irec_t *map,
751153323Srodrigc	int		*retmap)
752153323Srodrigc{
753153323Srodrigc	xfs_mount_t	*mp = ip->i_mount;
754159451Srodrigc	xfs_iocore_t    *io = &ip->i_iocore;
755153323Srodrigc	xfs_fileoff_t	offset_fsb, last_block;
756153323Srodrigc	xfs_fileoff_t	end_fsb, map_start_fsb;
757153323Srodrigc	xfs_fsblock_t	first_block;
758153323Srodrigc	xfs_bmap_free_t	free_list;
759153323Srodrigc	xfs_filblks_t	count_fsb;
760153323Srodrigc	xfs_bmbt_irec_t	imap[XFS_STRAT_WRITE_IMAPS];
761153323Srodrigc	xfs_trans_t	*tp;
762153323Srodrigc	int		i, nimaps, committed;
763153323Srodrigc	int		error = 0;
764153323Srodrigc	int		nres;
765153323Srodrigc
766153323Srodrigc	*retmap = 0;
767153323Srodrigc
768153323Srodrigc	/*
769153323Srodrigc	 * Make sure that the dquots are there.
770153323Srodrigc	 */
771153323Srodrigc	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
772153323Srodrigc		return XFS_ERROR(error);
773153323Srodrigc
774159451Srodrigc	offset_fsb = XFS_B_TO_FSBT(mp, offset);
775153323Srodrigc	count_fsb = map->br_blockcount;
776159451Srodrigc	map_start_fsb = map->br_startoff;
777153323Srodrigc
778153323Srodrigc	XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
779153323Srodrigc
780153323Srodrigc	while (count_fsb != 0) {
781153323Srodrigc		/*
782153323Srodrigc		 * Set up a transaction with which to allocate the
783153323Srodrigc		 * backing store for the file.  Do allocations in a
784153323Srodrigc		 * loop until we get some space in the range we are
785153323Srodrigc		 * interested in.  The other space that might be allocated
786153323Srodrigc		 * is in the delayed allocation extent on which we sit
787153323Srodrigc		 * but before our buffer starts.
788153323Srodrigc		 */
789153323Srodrigc
790153323Srodrigc		nimaps = 0;
791153323Srodrigc		while (nimaps == 0) {
792153323Srodrigc			tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
793153323Srodrigc			nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
794153323Srodrigc			error = xfs_trans_reserve(tp, nres,
795153323Srodrigc					XFS_WRITE_LOG_RES(mp),
796153323Srodrigc					0, XFS_TRANS_PERM_LOG_RES,
797153323Srodrigc					XFS_WRITE_LOG_COUNT);
798153323Srodrigc			if (error == ENOSPC) {
799153323Srodrigc				error = xfs_trans_reserve(tp, 0,
800153323Srodrigc						XFS_WRITE_LOG_RES(mp),
801153323Srodrigc						0,
802153323Srodrigc						XFS_TRANS_PERM_LOG_RES,
803153323Srodrigc						XFS_WRITE_LOG_COUNT);
804153323Srodrigc			}
805153323Srodrigc			if (error) {
806153323Srodrigc				xfs_trans_cancel(tp, 0);
807153323Srodrigc				return XFS_ERROR(error);
808153323Srodrigc			}
809153323Srodrigc			xfs_ilock(ip, XFS_ILOCK_EXCL);
810153323Srodrigc			xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
811153323Srodrigc			xfs_trans_ihold(tp, ip);
812153323Srodrigc
813153323Srodrigc			XFS_BMAP_INIT(&free_list, &first_block);
814153323Srodrigc
815153323Srodrigc			nimaps = XFS_STRAT_WRITE_IMAPS;
816153323Srodrigc			/*
817153323Srodrigc			 * Ensure we don't go beyond eof - it is possible
818153323Srodrigc			 * the extents changed since we did the read call,
819153323Srodrigc			 * we dropped the ilock in the interim.
820153323Srodrigc			 */
821153323Srodrigc
822153323Srodrigc			end_fsb = XFS_B_TO_FSB(mp, ip->i_d.di_size);
823153323Srodrigc			xfs_bmap_last_offset(NULL, ip, &last_block,
824153323Srodrigc				XFS_DATA_FORK);
825153323Srodrigc			last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
826153323Srodrigc			if ((map_start_fsb + count_fsb) > last_block) {
827153323Srodrigc				count_fsb = last_block - map_start_fsb;
828153323Srodrigc				if (count_fsb == 0) {
829153323Srodrigc					error = EAGAIN;
830153323Srodrigc					goto trans_cancel;
831153323Srodrigc				}
832153323Srodrigc			}
833153323Srodrigc
834153323Srodrigc			/* Go get the actual blocks */
835159451Srodrigc			error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb,
836153323Srodrigc					XFS_BMAPI_WRITE, &first_block, 1,
837159451Srodrigc					imap, &nimaps, &free_list, NULL);
838153323Srodrigc			if (error)
839153323Srodrigc				goto trans_cancel;
840153323Srodrigc
841153323Srodrigc			error = xfs_bmap_finish(&tp, &free_list,
842153323Srodrigc					first_block, &committed);
843153323Srodrigc			if (error)
844153323Srodrigc				goto trans_cancel;
845153323Srodrigc
846153323Srodrigc			error = xfs_trans_commit(tp,
847153323Srodrigc					XFS_TRANS_RELEASE_LOG_RES, NULL);
848153323Srodrigc			if (error)
849153323Srodrigc				goto error0;
850153323Srodrigc
851153323Srodrigc			xfs_iunlock(ip, XFS_ILOCK_EXCL);
852153323Srodrigc		}
853153323Srodrigc
854153323Srodrigc		/*
855153323Srodrigc		 * See if we were able to allocate an extent that
856153323Srodrigc		 * covers at least part of the callers request
857153323Srodrigc		 */
858153323Srodrigc
859153323Srodrigc		for (i = 0; i < nimaps; i++) {
860159451Srodrigc			if (!(io->io_flags & XFS_IOCORE_RT)  &&
861159451Srodrigc			    !imap[i].br_startblock) {
862159451Srodrigc				cmn_err(CE_PANIC,"Access to block zero:  "
863159451Srodrigc					"fs <%s> inode: %lld "
864159451Srodrigc					"start_block : %llx start_off : %llx "
865159451Srodrigc					"blkcnt : %llx extent-state : %x \n",
866159451Srodrigc					(ip->i_mount)->m_fsname,
867159451Srodrigc					(long long)ip->i_ino,
868159451Srodrigc					(unsigned long long)
869159451Srodrigc						imap[i].br_startblock,
870159451Srodrigc					(unsigned long long)
871159451Srodrigc						imap[i].br_startoff,
872159451Srodrigc					(unsigned long long)
873159451Srodrigc				        	imap[i].br_blockcount,
874159451Srodrigc					imap[i].br_state);
875159451Srodrigc                        }
876159451Srodrigc			if ((offset_fsb >= imap[i].br_startoff) &&
877159451Srodrigc			    (offset_fsb < (imap[i].br_startoff +
878159451Srodrigc					   imap[i].br_blockcount))) {
879153323Srodrigc				*map = imap[i];
880153323Srodrigc				*retmap = 1;
881153323Srodrigc				XFS_STATS_INC(xs_xstrat_quick);
882153323Srodrigc				return 0;
883153323Srodrigc			}
884153323Srodrigc			count_fsb -= imap[i].br_blockcount;
885153323Srodrigc		}
886153323Srodrigc
887153323Srodrigc		/* So far we have not mapped the requested part of the
888153323Srodrigc		 * file, just surrounding data, try again.
889153323Srodrigc		 */
890153323Srodrigc		nimaps--;
891159451Srodrigc		map_start_fsb = imap[nimaps].br_startoff +
892159451Srodrigc				imap[nimaps].br_blockcount;
893153323Srodrigc	}
894153323Srodrigc
895153323Srodrigctrans_cancel:
896153323Srodrigc	xfs_bmap_cancel(&free_list);
897153323Srodrigc	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
898153323Srodrigcerror0:
899153323Srodrigc	xfs_iunlock(ip, XFS_ILOCK_EXCL);
900153323Srodrigc	return XFS_ERROR(error);
901153323Srodrigc}
902153323Srodrigc
903153323Srodrigcint
904153323Srodrigcxfs_iomap_write_unwritten(
905153323Srodrigc	xfs_inode_t	*ip,
906153323Srodrigc	xfs_off_t	offset,
907153323Srodrigc	size_t		count)
908153323Srodrigc{
909153323Srodrigc	xfs_mount_t	*mp = ip->i_mount;
910159451Srodrigc	xfs_iocore_t    *io = &ip->i_iocore;
911153323Srodrigc	xfs_fileoff_t	offset_fsb;
912153323Srodrigc	xfs_filblks_t	count_fsb;
913153323Srodrigc	xfs_filblks_t	numblks_fsb;
914159451Srodrigc	xfs_fsblock_t	firstfsb;
915159451Srodrigc	int		nimaps;
916159451Srodrigc	xfs_trans_t	*tp;
917159451Srodrigc	xfs_bmbt_irec_t imap;
918159451Srodrigc	xfs_bmap_free_t free_list;
919159451Srodrigc	uint		resblks;
920153323Srodrigc	int		committed;
921153323Srodrigc	int		error;
922153323Srodrigc
923153323Srodrigc	xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN,
924153323Srodrigc				&ip->i_iocore, offset, count);
925153323Srodrigc
926153323Srodrigc	offset_fsb = XFS_B_TO_FSBT(mp, offset);
927159451Srodrigc	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
928159451Srodrigc	count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb);
929153323Srodrigc
930159451Srodrigc	resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
931159451Srodrigc
932153323Srodrigc	do {
933153323Srodrigc		/*
934153323Srodrigc		 * set up a transaction to convert the range of extents
935153323Srodrigc		 * from unwritten to real. Do allocations in a loop until
936153323Srodrigc		 * we have covered the range passed in.
937153323Srodrigc		 */
938153323Srodrigc
939153323Srodrigc		tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
940159451Srodrigc		error = xfs_trans_reserve(tp, resblks,
941153323Srodrigc				XFS_WRITE_LOG_RES(mp), 0,
942153323Srodrigc				XFS_TRANS_PERM_LOG_RES,
943153323Srodrigc				XFS_WRITE_LOG_COUNT);
944153323Srodrigc		if (error) {
945153323Srodrigc			xfs_trans_cancel(tp, 0);
946153323Srodrigc			goto error0;
947153323Srodrigc		}
948153323Srodrigc
949153323Srodrigc		xfs_ilock(ip, XFS_ILOCK_EXCL);
950153323Srodrigc		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
951153323Srodrigc		xfs_trans_ihold(tp, ip);
952153323Srodrigc
953153323Srodrigc		/*
954153323Srodrigc		 * Modify the unwritten extent state of the buffer.
955153323Srodrigc		 */
956153323Srodrigc		XFS_BMAP_INIT(&free_list, &firstfsb);
957153323Srodrigc		nimaps = 1;
958159451Srodrigc		error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb,
959159451Srodrigc				  XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
960159451Srodrigc				  1, &imap, &nimaps, &free_list, NULL);
961153323Srodrigc		if (error)
962153323Srodrigc			goto error_on_bmapi_transaction;
963153323Srodrigc
964153323Srodrigc		error = xfs_bmap_finish(&(tp), &(free_list),
965153323Srodrigc				firstfsb, &committed);
966153323Srodrigc		if (error)
967153323Srodrigc			goto error_on_bmapi_transaction;
968153323Srodrigc
969153323Srodrigc		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
970153323Srodrigc		xfs_iunlock(ip, XFS_ILOCK_EXCL);
971153323Srodrigc		if (error)
972153323Srodrigc			goto error0;
973153323Srodrigc
974159451Srodrigc		if ( !(io->io_flags & XFS_IOCORE_RT)  && !imap.br_startblock) {
975159451Srodrigc			cmn_err(CE_PANIC,"Access to block zero:  fs <%s> "
976159451Srodrigc				"inode: %lld start_block : %llx start_off : "
977159451Srodrigc				"%llx blkcnt : %llx extent-state : %x \n",
978159451Srodrigc				(ip->i_mount)->m_fsname,
979159451Srodrigc				(long long)ip->i_ino,
980159451Srodrigc				(unsigned long long)imap.br_startblock,
981159451Srodrigc				(unsigned long long)imap.br_startoff,
982159451Srodrigc				(unsigned long long)imap.br_blockcount,
983159451Srodrigc				imap.br_state);
984159451Srodrigc        	}
985159451Srodrigc
986153323Srodrigc		if ((numblks_fsb = imap.br_blockcount) == 0) {
987153323Srodrigc			/*
988153323Srodrigc			 * The numblks_fsb value should always get
989153323Srodrigc			 * smaller, otherwise the loop is stuck.
990153323Srodrigc			 */
991153323Srodrigc			ASSERT(imap.br_blockcount);
992153323Srodrigc			break;
993153323Srodrigc		}
994153323Srodrigc		offset_fsb += numblks_fsb;
995153323Srodrigc		count_fsb -= numblks_fsb;
996153323Srodrigc	} while (count_fsb > 0);
997153323Srodrigc
998153323Srodrigc	return 0;
999153323Srodrigc
1000153323Srodrigcerror_on_bmapi_transaction:
1001153323Srodrigc	xfs_bmap_cancel(&free_list);
1002153323Srodrigc	xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
1003153323Srodrigc	xfs_iunlock(ip, XFS_ILOCK_EXCL);
1004153323Srodrigcerror0:
1005153323Srodrigc	return XFS_ERROR(error);
1006153323Srodrigc}
1007