📄 xfs_iomap.c
字号:
/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_alloc.h"#include "xfs_dmapi.h"#include "xfs_quota.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_ialloc.h"#include "xfs_btree.h"#include "xfs_bmap.h"#include "xfs_rtalloc.h"#include "xfs_error.h"#include "xfs_itable.h"#include "xfs_rw.h"#include "xfs_acl.h"#include "xfs_attr.h"#include "xfs_buf_item.h"#include "xfs_trans_space.h"#include "xfs_utils.h"#include "xfs_iomap.h"#if defined(XFS_RW_TRACE)voidxfs_iomap_enter_trace( int tag, xfs_iocore_t *io, xfs_off_t offset, ssize_t count){ xfs_inode_t *ip = XFS_IO_INODE(io); if (!ip->i_rwtrace) return; ktrace_enter(ip->i_rwtrace, (void *)((unsigned long)tag), (void *)ip, (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)count), (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), (void *)((unsigned long)(io->io_new_size & 0xffffffff)), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL);}voidxfs_iomap_map_trace( int tag, xfs_iocore_t *io, xfs_off_t offset, ssize_t count, xfs_iomap_t *iomapp, xfs_bmbt_irec_t *imapp, int flags){ xfs_inode_t *ip = XFS_IO_INODE(io); if (!ip->i_rwtrace) return; ktrace_enter(ip->i_rwtrace, (void *)((unsigned long)tag), (void *)ip, (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)count), (void *)((unsigned long)flags), (void *)((unsigned long)((iomapp->iomap_offset >> 32) & 0xffffffff)), (void *)((unsigned long)(iomapp->iomap_offset & 0xffffffff)), (void *)((unsigned long)(iomapp->iomap_delta)), (void *)((unsigned long)(iomapp->iomap_bsize)), (void *)((unsigned long)(iomapp->iomap_bn)), (void *)(__psint_t)(imapp->br_startoff), (void *)((unsigned long)(imapp->br_blockcount)), (void *)(__psint_t)(imapp->br_startblock));}#else#define xfs_iomap_enter_trace(tag, io, offset, count)#define xfs_iomap_map_trace(tag, io, offset, count, iomapp, imapp, flags)#endif#define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ << mp->m_writeio_log)#define XFS_STRAT_WRITE_IMAPS 2#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAPSTATIC intxfs_imap_to_bmap( xfs_iocore_t *io, xfs_off_t offset, xfs_bmbt_irec_t *imap, xfs_iomap_t *iomapp, int imaps, /* Number of imap entries */ int iomaps, /* Number of iomap entries */ int flags){ xfs_mount_t *mp; int pbm; xfs_fsblock_t start_block; mp = io->io_mount; for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) { iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff); iomapp->iomap_delta = offset - iomapp->iomap_offset; iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); iomapp->iomap_flags = flags; if (io->io_flags & XFS_IOCORE_RT) { iomapp->iomap_flags |= IOMAP_REALTIME; iomapp->iomap_target = mp->m_rtdev_targp; } else { iomapp->iomap_target = mp->m_ddev_targp; } start_block = imap->br_startblock; if (start_block == HOLESTARTBLOCK) { iomapp->iomap_bn = IOMAP_DADDR_NULL; iomapp->iomap_flags |= IOMAP_HOLE; } else if (start_block == DELAYSTARTBLOCK) { iomapp->iomap_bn = IOMAP_DADDR_NULL; iomapp->iomap_flags |= IOMAP_DELAY; } else { iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block); if (ISUNWRITTEN(imap)) iomapp->iomap_flags |= IOMAP_UNWRITTEN; } offset += iomapp->iomap_bsize - iomapp->iomap_delta; } return pbm; /* Return the number filled */}intxfs_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);}STATIC intxfs_iomap_eof_align_last_fsb( xfs_mount_t *mp, xfs_iocore_t *io, xfs_fsize_t isize, xfs_extlen_t extsize, xfs_fileoff_t *last_fsb){ xfs_fileoff_t new_last_fsb = 0; xfs_extlen_t align; int eof, error; if (io->io_flags & XFS_IOCORE_RT) ; /* * If mounted with the "-o swalloc" option, roundup the allocation * request to a stripe width boundary if the file size is >= * stripe width and we are allocating past the allocation eof. */ else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) && (isize >= XFS_FSB_TO_B(mp, mp->m_swidth))) new_last_fsb = roundup_64(*last_fsb, mp->m_swidth); /* * Roundup the allocation request to a stripe unit (m_dalign) boundary * if the file size is >= stripe unit size, and we are allocating past * the allocation eof. */ else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign))) new_last_fsb = roundup_64(*last_fsb, mp->m_dalign); /* * Always round up the allocation request to an extent boundary * (when file on a real-time subvolume or has di_extsize hint). */ if (extsize) { if (new_last_fsb) align = roundup_64(new_last_fsb, extsize); else align = extsize; new_last_fsb = roundup_64(*last_fsb, align); } if (new_last_fsb) { error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); if (error) return error; if (eof) *last_fsb = new_last_fsb; } return 0;}STATIC intxfs_flush_space( xfs_inode_t *ip, int *fsynced, int *ioflags){ switch (*fsynced) { case 0: if (ip->i_delayed_blks) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_flush_inode(ip); xfs_ilock(ip, XFS_ILOCK_EXCL); *fsynced = 1; } else { *ioflags |= BMAPI_SYNC; *fsynced = 2; } return 0; case 1: *fsynced = 2; *ioflags |= BMAPI_SYNC; return 0; case 2: xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_flush_device(ip); xfs_ilock(ip, XFS_ILOCK_EXCL); *fsynced = 3; return 0; } return 1;}STATIC intxfs_cmn_err_fsblock_zero( xfs_inode_t *ip, xfs_bmbt_irec_t *imap){ xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount, "Access to block zero in inode %llu " "start_block: %llx start_off: %llx " "blkcnt: %llx extent-state: %x\n", (unsigned long long)ip->i_ino, (unsigned long long)imap->br_startblock, (unsigned long long)imap->br_startoff, (unsigned long long)imap->br_blockcount, imap->br_state); return EFSCORRUPTED;}intxfs_iomap_write_direct( xfs_inode_t *ip, xfs_off_t offset, size_t count, int flags, xfs_bmbt_irec_t *ret_imap, int *nmaps, int found){ xfs_mount_t *mp = ip->i_mount; xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb; xfs_fileoff_t last_fsb; xfs_filblks_t count_fsb, resaligned; xfs_fsblock_t firstfsb; xfs_extlen_t extsz, temp; xfs_fsize_t isize; int nimaps; int bmapi_flag; int quota_flag; int rt; xfs_trans_t *tp; xfs_bmbt_irec_t imap; xfs_bmap_free_t free_list; uint qblocks, resblks, resrtextents; int committed; int error; /* * Make sure that the dquots are there. This doesn't hold * the ilock across a disk read. */ error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED); if (error) return XFS_ERROR(error); rt = XFS_IS_REALTIME_INODE(ip); extsz = xfs_get_extsz_hint(ip); isize = ip->i_size; if (io->io_new_size > isize) isize = io->io_new_size; offset_fsb = XFS_B_TO_FSBT(mp, offset); last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); if ((offset + count) > isize) { error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz, &last_fsb); if (error) goto error_out; } else { if (found && (ret_imap->br_startblock == HOLESTARTBLOCK)) last_fsb = MIN(last_fsb, (xfs_fileoff_t) ret_imap->br_blockcount + ret_imap->br_startoff); } count_fsb = last_fsb - offset_fsb; ASSERT(count_fsb > 0); resaligned = count_fsb; if (unlikely(extsz)) { if ((temp = do_mod(offset_fsb, extsz))) resaligned += temp; if ((temp = do_mod(resaligned, extsz))) resaligned += extsz - temp; } if (unlikely(rt)) { resrtextents = qblocks = resaligned;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -