xfs_iomap.c revision 159451
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