2 * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
38 #include "xfs_trans.h"
43 #include "xfs_alloc.h"
44 #include "xfs_dmapi.h"
45 #include "xfs_quota.h"
46 #include "xfs_mount.h"
47 #include "xfs_alloc_btree.h"
48 #include "xfs_bmap_btree.h"
49 #include "xfs_ialloc_btree.h"
50 #include "xfs_btree.h"
51 #include "xfs_ialloc.h"
52 #include "xfs_attr_sf.h"
53 #include "xfs_dir_sf.h"
54 #include "xfs_dir2_sf.h"
55 #include "xfs_dinode.h"
56 #include "xfs_inode.h"
59 #include "xfs_rtalloc.h"
60 #include "xfs_error.h"
61 #include "xfs_itable.h"
67 #include "xfs_buf_item.h"
68 #include "xfs_trans_space.h"
69 #include "xfs_utils.h"
71 #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \
73 #define XFS_STRAT_WRITE_IMAPS 2
74 #define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
81 xfs_bmbt_irec_t *imap,
82 page_buf_bmap_t *pbmapp,
83 int imaps, /* Number of imap entries */
84 int pbmaps) /* Number of pbmap entries */
89 xfs_fsblock_t start_block;
92 nisize = XFS_SIZE(mp, io);
93 if (io->io_new_size > nisize)
94 nisize = io->io_new_size;
96 for (pbm = 0; imaps && pbm < pbmaps; imaps--, pbmapp++, imap++, pbm++) {
97 pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ?
98 mp->m_rtdev_targp : mp->m_ddev_targp;
99 pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
100 pbmapp->pbm_delta = offset - pbmapp->pbm_offset;
101 pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
102 pbmapp->pbm_flags = 0;
104 start_block = imap->br_startblock;
105 if (start_block == HOLESTARTBLOCK) {
106 pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
107 pbmapp->pbm_flags = PBMF_HOLE;
108 } else if (start_block == DELAYSTARTBLOCK) {
109 pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
110 pbmapp->pbm_flags = PBMF_DELAY;
112 pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block);
113 if (ISUNWRITTEN(imap))
114 pbmapp->pbm_flags |= PBMF_UNWRITTEN;
117 if ((pbmapp->pbm_offset + pbmapp->pbm_bsize) >= nisize) {
118 pbmapp->pbm_flags |= PBMF_EOF;
122 pbmapp->pbm_flags |= PBMF_NEW;
124 offset += pbmapp->pbm_bsize - pbmapp->pbm_delta;
126 return pbm; /* Return the number filled */
135 page_buf_bmap_t *pbmapp,
138 xfs_mount_t *mp = io->io_mount;
139 xfs_fileoff_t offset_fsb, end_fsb;
143 xfs_bmbt_irec_t imap;
147 if (XFS_FORCED_SHUTDOWN(mp))
148 return -XFS_ERROR(EIO);
151 (BMAP_READ | BMAP_WRITE | BMAP_ALLOCATE |
152 BMAP_UNWRITTEN | BMAP_DEVICE)) {
154 lockmode = XFS_LCK_MAP_SHARED(mp, io);
155 bmap_flags = XFS_BMAPI_ENTIRE;
156 if (flags & BMAP_IGNSTATE)
157 bmap_flags |= XFS_BMAPI_IGSTATE;
160 lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
162 XFS_ILOCK(mp, io, lockmode);
165 lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD;
166 bmap_flags = XFS_BMAPI_ENTIRE;
167 /* Attempt non-blocking lock */
168 if (flags & BMAP_TRYLOCK) {
169 if (!XFS_ILOCK_NOWAIT(mp, io, lockmode))
170 return XFS_ERROR(EAGAIN);
172 XFS_ILOCK(mp, io, lockmode);
178 lockmode = XFS_LCK_MAP_SHARED(mp, io);
179 pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ?
180 mp->m_rtdev_targp : mp->m_ddev_targp;
188 ASSERT(offset <= mp->m_maxioffset);
189 if ((xfs_fsize_t)offset + count > mp->m_maxioffset)
190 count = mp->m_maxioffset - offset;
191 end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
192 offset_fsb = XFS_B_TO_FSBT(mp, offset);
194 error = XFS_BMAPI(mp, NULL, io, offset_fsb,
195 (xfs_filblks_t)(end_fsb - offset_fsb) ,
196 bmap_flags, NULL, 0, &imap,
203 switch (flags & (BMAP_WRITE|BMAP_ALLOCATE|BMAP_UNWRITTEN)) {
205 /* If we found an extent, return it */
206 if (nimaps && (imap.br_startblock != HOLESTARTBLOCK))
209 if (flags & (BMAP_DIRECT|BMAP_MMAP)) {
210 error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset,
211 count, flags, &imap, &nimaps, nimaps);
213 error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count,
214 flags, &imap, &nimaps);
219 /* If we found an extent, return it */
220 XFS_IUNLOCK(mp, io, lockmode);
223 if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock))
226 error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps);
230 error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count);
236 *npbmaps = _xfs_imap_to_bmap(io, offset, new, &imap,
237 pbmapp, nimaps, *npbmaps);
238 } else if (npbmaps) {
244 XFS_IUNLOCK(mp, io, lockmode);
245 return XFS_ERROR(error);
254 vnode_t *vp = XFS_ITOV(ip);
258 if (ip->i_delayed_blks) {
259 xfs_iunlock(ip, XFS_ILOCK_EXCL);
260 filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
261 xfs_ilock(ip, XFS_ILOCK_EXCL);
264 *ioflags |= BMAP_SYNC;
270 *ioflags |= BMAP_SYNC;
273 xfs_iunlock(ip, XFS_ILOCK_EXCL);
274 sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
275 xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
276 XFS_LOG_FORCE|XFS_LOG_SYNC);
277 xfs_ilock(ip, XFS_ILOCK_EXCL);
285 xfs_iomap_write_direct(
290 xfs_bmbt_irec_t *ret_imap,
294 xfs_mount_t *mp = ip->i_mount;
295 xfs_iocore_t *io = &ip->i_iocore;
296 xfs_fileoff_t offset_fsb;
297 xfs_fileoff_t last_fsb;
298 xfs_filblks_t count_fsb;
300 xfs_fsblock_t firstfsb;
306 xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
307 xfs_bmap_free_t free_list;
309 xfs_filblks_t datablocks;
315 * Make sure that the dquots are there. This doesn't hold
316 * the ilock across a disk read.
319 error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
321 return XFS_ERROR(error);
323 maps = min(XFS_WRITE_IMAPS, *nmaps);
326 isize = ip->i_d.di_size;
327 aeof = (offset + count) > isize;
329 if (io->io_new_size > isize)
330 isize = io->io_new_size;
332 offset_fsb = XFS_B_TO_FSBT(mp, offset);
333 last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
334 count_fsb = last_fsb - offset_fsb;
335 if (found && (ret_imap->br_startblock == HOLESTARTBLOCK)) {
336 xfs_fileoff_t map_last_fsb;
338 map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff;
340 if (map_last_fsb < last_fsb) {
341 last_fsb = map_last_fsb;
342 count_fsb = last_fsb - offset_fsb;
344 ASSERT(count_fsb > 0);
348 * determine if reserving space on
349 * the data or realtime partition.
351 if ((rt = XFS_IS_REALTIME_INODE(ip))) {
352 int sbrtextsize, iprtextsize;
354 sbrtextsize = mp->m_sb.sb_rextsize;
356 ip->i_d.di_extsize ? ip->i_d.di_extsize : sbrtextsize;
357 numrtextents = (count_fsb + iprtextsize - 1);
358 do_div(numrtextents, sbrtextsize);
361 datablocks = count_fsb;
366 * allocate and setup the transaction
368 xfs_iunlock(ip, XFS_ILOCK_EXCL);
369 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
371 resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
373 error = xfs_trans_reserve(tp, resblks,
374 XFS_WRITE_LOG_RES(mp), numrtextents,
375 XFS_TRANS_PERM_LOG_RES,
376 XFS_WRITE_LOG_COUNT);
379 * check for running out of space
383 * Free the transaction structure.
385 xfs_trans_cancel(tp, 0);
387 xfs_ilock(ip, XFS_ILOCK_EXCL);
390 goto error_out; /* Don't return in above if .. trans ..,
391 need lock to return */
393 if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) {
399 bmapi_flag = XFS_BMAPI_WRITE;
400 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
401 xfs_trans_ihold(tp, ip);
403 if (!(flags & BMAP_MMAP) && (offset < ip->i_d.di_size || rt))
404 bmapi_flag |= XFS_BMAPI_PREALLOC;
407 * issue the bmapi() call to allocate the blocks
409 XFS_BMAP_INIT(&free_list, &firstfsb);
411 error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
412 bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list);
418 * complete the transaction
421 error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
426 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
431 /* copy any maps to caller's array and return any error. */
441 error0: /* Cancel bmap, unlock inode, and cancel trans */
442 xfs_bmap_cancel(&free_list);
444 error1: /* Just cancel transaction */
445 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
446 *nmaps = 0; /* nothing set-up here */
449 return XFS_ERROR(error);
453 xfs_iomap_write_delay(
458 xfs_bmbt_irec_t *ret_imap,
461 xfs_mount_t *mp = ip->i_mount;
462 xfs_iocore_t *io = &ip->i_iocore;
463 xfs_fileoff_t offset_fsb;
464 xfs_fileoff_t last_fsb;
466 xfs_fsblock_t firstblock;
469 xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
473 ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
476 * Make sure that the dquots are there. This doesn't hold
477 * the ilock across a disk read.
480 error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
482 return XFS_ERROR(error);
485 isize = ip->i_d.di_size;
486 if (io->io_new_size > isize) {
487 isize = io->io_new_size;
491 offset_fsb = XFS_B_TO_FSBT(mp, offset);
492 last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
494 * If the caller is doing a write at the end of the file,
495 * then extend the allocation (and the buffer used for the write)
496 * out to the file system's write iosize. We clean up any extra
497 * space left over when the file is closed in xfs_inactive().
499 * We don't bother with this for sync writes, because we need
500 * to minimize the amount we write for good performance.
502 if (!(ioflag & BMAP_SYNC) && ((offset + count) > ip->i_d.di_size)) {
503 xfs_off_t aligned_offset;
505 xfs_fileoff_t ioalign;
507 iosize = mp->m_writeio_blocks;
508 aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
509 ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
510 last_fsb = ioalign + iosize;
514 nimaps = XFS_WRITE_IMAPS;
515 firstblock = NULLFSBLOCK;
518 * roundup the allocation request to m_dalign boundary if file size
519 * is greater that 512K and we are allocating past the allocation eof
521 if (mp->m_dalign && (isize >= mp->m_dalign) && aeof) {
523 xfs_fileoff_t new_last_fsb;
524 new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
525 error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof);
530 last_fsb = new_last_fsb;
534 error = xfs_bmapi(NULL, ip, offset_fsb,
535 (xfs_filblks_t)(last_fsb - offset_fsb),
536 XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
537 XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
540 * This can be EDQUOT, if nimaps == 0
542 if (error && (error != ENOSPC)) {
543 return XFS_ERROR(error);
546 * If bmapi returned us nothing, and if we didn't get back EDQUOT,
547 * then we must have run out of space.
551 if (xfs_flush_space(ip, &fsynced, &ioflag))
552 return XFS_ERROR(ENOSPC);
564 * Pass in a delayed allocate extent, convert it to real extents;
565 * return to the caller the extent we create which maps on top of
566 * the originating callers request.
568 * Called without a lock on the inode.
571 xfs_iomap_write_allocate(
573 xfs_bmbt_irec_t *map,
576 xfs_mount_t *mp = ip->i_mount;
577 xfs_fileoff_t offset_fsb, last_block;
578 xfs_fileoff_t end_fsb, map_start_fsb;
579 xfs_fsblock_t first_block;
580 xfs_bmap_free_t free_list;
581 xfs_filblks_t count_fsb;
582 xfs_bmbt_irec_t imap[XFS_STRAT_WRITE_IMAPS];
584 int i, nimaps, committed;
591 * Make sure that the dquots are there.
594 if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
595 return XFS_ERROR(error);
597 offset_fsb = map->br_startoff;
598 count_fsb = map->br_blockcount;
599 map_start_fsb = offset_fsb;
601 XFS_STATS_ADD(xfsstats.xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
603 while (count_fsb != 0) {
605 * Set up a transaction with which to allocate the
606 * backing store for the file. Do allocations in a
607 * loop until we get some space in the range we are
608 * interested in. The other space that might be allocated
609 * is in the delayed allocation extent on which we sit
610 * but before our buffer starts.
614 while (nimaps == 0) {
615 tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
616 nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
617 error = xfs_trans_reserve(tp, nres,
618 XFS_WRITE_LOG_RES(mp),
619 0, XFS_TRANS_PERM_LOG_RES,
620 XFS_WRITE_LOG_COUNT);
622 if (error == ENOSPC) {
623 error = xfs_trans_reserve(tp, 0,
624 XFS_WRITE_LOG_RES(mp),
626 XFS_TRANS_PERM_LOG_RES,
627 XFS_WRITE_LOG_COUNT);
630 xfs_trans_cancel(tp, 0);
631 return XFS_ERROR(error);
633 xfs_ilock(ip, XFS_ILOCK_EXCL);
634 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
635 xfs_trans_ihold(tp, ip);
637 XFS_BMAP_INIT(&free_list, &first_block);
639 nimaps = XFS_STRAT_WRITE_IMAPS;
641 * Ensure we don't go beyond eof - it is possible
642 * the extents changed since we did the read call,
643 * we dropped the ilock in the interim.
646 end_fsb = XFS_B_TO_FSB(mp, ip->i_d.di_size);
647 xfs_bmap_last_offset(NULL, ip, &last_block,
649 last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
650 if ((map_start_fsb + count_fsb) > last_block) {
651 count_fsb = last_block - map_start_fsb;
652 if (count_fsb == 0) {
658 /* Go get the actual blocks */
659 error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb,
660 XFS_BMAPI_WRITE, &first_block, 1,
661 imap, &nimaps, &free_list);
666 error = xfs_bmap_finish(&tp, &free_list,
667 first_block, &committed);
672 error = xfs_trans_commit(tp,
673 XFS_TRANS_RELEASE_LOG_RES, NULL);
678 xfs_iunlock(ip, XFS_ILOCK_EXCL);
682 * See if we were able to allocate an extent that
683 * covers at least part of the callers request
686 for (i = 0; i < nimaps; i++) {
687 if ((map->br_startoff >= imap[i].br_startoff) &&
688 (map->br_startoff < (imap[i].br_startoff +
689 imap[i].br_blockcount))) {
692 XFS_STATS_INC(xfsstats.xs_xstrat_quick);
695 count_fsb -= imap[i].br_blockcount;
698 /* So far we have not mapped the requested part of the
699 * file, just surrounding data, try again.
702 offset_fsb = imap[nimaps].br_startoff +
703 imap[nimaps].br_blockcount;
704 map_start_fsb = offset_fsb;
708 xfs_bmap_cancel(&free_list);
709 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
711 xfs_iunlock(ip, XFS_ILOCK_EXCL);
712 return XFS_ERROR(error);
716 xfs_iomap_write_unwritten(
721 xfs_mount_t *mp = ip->i_mount;
723 xfs_fileoff_t offset_fsb;
724 xfs_filblks_t count_fsb;
725 xfs_filblks_t numblks_fsb;
726 xfs_bmbt_irec_t imap;
731 xfs_fsblock_t firstfsb;
732 xfs_bmap_free_t free_list;
734 offset_fsb = XFS_B_TO_FSBT(mp, offset);
735 count_fsb = XFS_B_TO_FSB(mp, count);
738 nres = XFS_DIOSTRAT_SPACE_RES(mp, 0);
741 * set up a transaction to convert the range of extents
742 * from unwritten to real. Do allocations in a loop until
743 * we have covered the range passed in.
746 tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
747 error = xfs_trans_reserve(tp, nres,
748 XFS_WRITE_LOG_RES(mp), 0,
749 XFS_TRANS_PERM_LOG_RES,
750 XFS_WRITE_LOG_COUNT);
752 xfs_trans_cancel(tp, 0);
756 xfs_ilock(ip, XFS_ILOCK_EXCL);
757 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
758 xfs_trans_ihold(tp, ip);
761 * Modify the unwritten extent state of the buffer.
763 XFS_BMAP_INIT(&free_list, &firstfsb);
765 error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
766 XFS_BMAPI_WRITE, &firstfsb,
767 1, &imap, &nimaps, &free_list);
769 goto error_on_bmapi_transaction;
771 error = xfs_bmap_finish(&(tp), &(free_list),
772 firstfsb, &committed);
774 goto error_on_bmapi_transaction;
776 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
777 xfs_iunlock(ip, XFS_ILOCK_EXCL);
781 if ((numblks_fsb = imap.br_blockcount) == 0) {
783 * The numblks_fsb value should always get
784 * smaller, otherwise the loop is stuck.
786 ASSERT(imap.br_blockcount);
789 offset_fsb += numblks_fsb;
790 count_fsb -= numblks_fsb;
791 } while (count_fsb > 0);
795 error_on_bmapi_transaction:
796 xfs_bmap_cancel(&free_list);
797 xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
798 xfs_iunlock(ip, XFS_ILOCK_EXCL);
800 return XFS_ERROR(error);