int xfs_iomap( xfs_inode_t *ip, xfs_off_t offset, ssize_t count, int flags, xfs_iomap_t *iomapp, int *niomaps) { xfs_mount_t *mp = ip->i_mount; xfs_fileoff_t offset_fsb, end_fsb; int error = 0; int lockmode = 0; xfs_bmbt_irec_t imap; int nimaps = 1; int bmapi_flags = 0; int iomap_flags = 0; ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); switch (flags & (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE)) { case BMAPI_READ: xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, ip, offset, count); lockmode = xfs_ilock_map_shared(ip); bmapi_flags = XFS_BMAPI_ENTIRE; break; case BMAPI_WRITE: xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, ip, offset, count); lockmode = XFS_ILOCK_EXCL; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; xfs_ilock(ip, lockmode); break; case BMAPI_ALLOCATE: xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, ip, offset, count); lockmode = XFS_ILOCK_SHARED; bmapi_flags = XFS_BMAPI_ENTIRE; /* Attempt non-blocking lock */ if (flags & BMAPI_TRYLOCK) { if (!xfs_ilock_nowait(ip, lockmode)) return XFS_ERROR(EAGAIN); } else { xfs_ilock(ip, lockmode); } break; default: BUG(); } ASSERT(offset <= mp->m_maxioffset); if ((xfs_fsize_t)offset + count > mp->m_maxioffset) count = mp->m_maxioffset - offset; end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); offset_fsb = XFS_B_TO_FSBT(mp, offset); error = xfs_bmapi(NULL, ip, offset_fsb, (xfs_filblks_t)(end_fsb - offset_fsb), bmapi_flags, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) goto out; switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)) { case BMAPI_WRITE: /* If we found an extent, return it */ if (nimaps && (imap.br_startblock != HOLESTARTBLOCK) && (imap.br_startblock != DELAYSTARTBLOCK)) { xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, offset, count, iomapp, &imap, flags); break; } if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) { error = xfs_iomap_write_direct(ip, offset, count, flags, &imap, &nimaps, nimaps); } else { error = xfs_iomap_write_delay(ip, offset, count, flags, &imap, &nimaps); } if (!error) { xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, ip, offset, count, iomapp, &imap, flags); } iomap_flags = IOMAP_NEW; break; case BMAPI_ALLOCATE: /* If we found an extent, return it */ xfs_iunlock(ip, lockmode); lockmode = 0; if (nimaps && !isnullstartblock(imap.br_startblock)) { xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, offset, count, iomapp, &imap, flags); break; } error = xfs_iomap_write_allocate(ip, offset, count, &imap, &nimaps); break; } if (nimaps) { *niomaps = xfs_imap_to_bmap(ip, offset, &imap, iomapp, nimaps, *niomaps, iomap_flags); } else if (niomaps) { *niomaps = 0; } out: if (lockmode) xfs_iunlock(ip, lockmode); return XFS_ERROR(error); }
int xfs_iomap( xfs_iocore_t *io, xfs_off_t offset, ssize_t count, int flags, xfs_iomap_t *iomapp, int *niomaps) { xfs_mount_t *mp = io->io_mount; xfs_fileoff_t offset_fsb, end_fsb; int error = 0; int lockmode = 0; xfs_bmbt_irec_t imap; int nimaps = 1; int bmapi_flags = 0; int iomap_flags = 0; if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); switch (flags & (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE | BMAPI_UNWRITTEN | BMAPI_DEVICE)) { case BMAPI_READ: xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); lockmode = XFS_LCK_MAP_SHARED(mp, io); bmapi_flags = XFS_BMAPI_ENTIRE; break; case BMAPI_WRITE: xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; XFS_ILOCK(mp, io, lockmode); break; case BMAPI_ALLOCATE: xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count); lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD; bmapi_flags = XFS_BMAPI_ENTIRE; /* Attempt non-blocking lock */ if (flags & BMAPI_TRYLOCK) { if (!XFS_ILOCK_NOWAIT(mp, io, lockmode)) return XFS_ERROR(EAGAIN); } else { XFS_ILOCK(mp, io, lockmode); } break; case BMAPI_UNWRITTEN: goto phase2; case BMAPI_DEVICE: lockmode = XFS_LCK_MAP_SHARED(mp, io); iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ? mp->m_rtdev_targp : mp->m_ddev_targp; error = 0; *niomaps = 1; goto out; default: BUG(); } ASSERT(offset <= mp->m_maxioffset); if ((xfs_fsize_t)offset + count > mp->m_maxioffset) count = mp->m_maxioffset - offset; end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); offset_fsb = XFS_B_TO_FSBT(mp, offset); error = XFS_BMAPI(mp, NULL, io, offset_fsb, (xfs_filblks_t)(end_fsb - offset_fsb), bmapi_flags, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) goto out; phase2: switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { case BMAPI_WRITE: /* If we found an extent, return it */ if (nimaps && (imap.br_startblock != HOLESTARTBLOCK) && (imap.br_startblock != DELAYSTARTBLOCK)) { xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, offset, count, iomapp, &imap, flags); break; } if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) { error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset, count, flags, &imap, &nimaps, nimaps); } else { error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, &imap, &nimaps); } if (!error) { xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io, offset, count, iomapp, &imap, flags); } iomap_flags = IOMAP_NEW; break; case BMAPI_ALLOCATE: /* If we found an extent, return it */ XFS_IUNLOCK(mp, io, lockmode); lockmode = 0; if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) { xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, offset, count, iomapp, &imap, flags); break; } error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, &imap, &nimaps); break; case BMAPI_UNWRITTEN: lockmode = 0; error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count); nimaps = 0; break; } if (nimaps) { *niomaps = xfs_imap_to_bmap(io, offset, &imap, iomapp, nimaps, *niomaps, iomap_flags); } else if (niomaps) { *niomaps = 0; } out: if (lockmode) XFS_IUNLOCK(mp, io, lockmode); return XFS_ERROR(error); }