Loading fs/xfs/xfs_bmap_util.c +137 −115 Original line number Diff line number Diff line Loading @@ -1184,69 +1184,72 @@ xfs_zero_remaining_bytes( return error; } int xfs_free_file_space( static int xfs_unmap_extent( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) xfs_fileoff_t startoffset_fsb, xfs_filblks_t len_fsb, int *done) { int done; xfs_fileoff_t endoffset_fsb; int error; struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_bmap_free free_list; xfs_fsblock_t firstfsb; xfs_bmap_free_t free_list; xfs_bmbt_irec_t imap; xfs_off_t ioffset; xfs_off_t iendoffset; xfs_extlen_t mod=0; xfs_mount_t *mp; int nimap; uint resblks; xfs_off_t rounding; int rt; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); int error; mp = ip->i_mount; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); if (error) { ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); return error; } trace_xfs_free_file_space(ip); xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot, ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS); if (error) goto out_trans_cancel; error = xfs_qm_dqattach(ip, 0); xfs_trans_ijoin(tp, ip, 0); xfs_bmap_init(&free_list, &firstfsb); error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb, &free_list, done); if (error) return error; goto out_bmap_cancel; error = 0; if (len <= 0) /* if nothing being freed */ error = xfs_bmap_finish(&tp, &free_list, NULL); if (error) goto out_bmap_cancel; error = xfs_trans_commit(tp); out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; rt = XFS_IS_REALTIME_INODE(ip); startoffset_fsb = XFS_B_TO_FSB(mp, offset); endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); /* wait for the completion of any pending DIOs */ inode_dio_wait(VFS_I(ip)); out_bmap_cancel: xfs_bmap_cancel(&free_list); out_trans_cancel: xfs_trans_cancel(tp); goto out_unlock; } rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); ioffset = round_down(offset, rounding); iendoffset = round_up(offset + len, rounding) - 1; error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset, iendoffset); if (error) goto out; truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset); static int xfs_adjust_extent_unmap_boundaries( struct xfs_inode *ip, xfs_fileoff_t *startoffset_fsb, xfs_fileoff_t *endoffset_fsb) { struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec imap; int nimap, error; xfs_extlen_t mod = 0; /* * Need to zero the stuff we're not freeing, on disk. * If it's a realtime file & can't use unwritten extents then we * actually need to zero the extent edges. Otherwise xfs_bunmapi * will take care of it for us. */ if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { nimap = 1; error = xfs_bmapi_read(ip, startoffset_fsb, 1, &imap, &nimap, 0); error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0); if (error) goto out; ASSERT(nimap == 0 || nimap == 1); return error; if (nimap && imap.br_startblock != HOLESTARTBLOCK) { xfs_daddr_t block; Loading @@ -1254,21 +1257,90 @@ xfs_free_file_space( block = imap.br_startblock; mod = do_div(block, mp->m_sb.sb_rextsize); if (mod) startoffset_fsb += mp->m_sb.sb_rextsize - mod; *startoffset_fsb += mp->m_sb.sb_rextsize - mod; } nimap = 1; error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1, &imap, &nimap, 0); error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0); if (error) goto out; ASSERT(nimap == 0 || nimap == 1); return error; if (nimap && imap.br_startblock != HOLESTARTBLOCK) { ASSERT(imap.br_startblock != DELAYSTARTBLOCK); mod++; if (mod && (mod != mp->m_sb.sb_rextsize)) endoffset_fsb -= mod; if (mod && mod != mp->m_sb.sb_rextsize) *endoffset_fsb -= mod; } return 0; } static int xfs_flush_unmap_range( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) { struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); xfs_off_t rounding, start, end; int error; /* wait for the completion of any pending DIOs */ inode_dio_wait(inode); rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); start = round_down(offset, rounding); end = round_up(offset + len, rounding) - 1; error = filemap_write_and_wait_range(inode->i_mapping, start, end); if (error) return error; truncate_pagecache_range(inode, start, end); return 0; } int xfs_free_file_space( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) { struct xfs_mount *mp = ip->i_mount; xfs_fileoff_t startoffset_fsb; xfs_fileoff_t endoffset_fsb; int done, error; trace_xfs_free_file_space(ip); error = xfs_qm_dqattach(ip, 0); if (error) return error; if (len <= 0) /* if nothing being freed */ return 0; error = xfs_flush_unmap_range(ip, offset, len); if (error) return error; startoffset_fsb = XFS_B_TO_FSB(mp, offset); endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); /* * Need to zero the stuff we're not freeing, on disk. If it's a RT file * and we can't use unwritten extents then we actually need to ensure * to zero the whole extent, otherwise we just need to take of block * boundaries, and xfs_bunmapi will handle the rest. */ if (XFS_IS_REALTIME_INODE(ip) && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb, &endoffset_fsb); if (error) return error; } if ((done = (endoffset_fsb <= startoffset_fsb))) /* * One contiguous piece to clear Loading @@ -1288,62 +1360,12 @@ xfs_free_file_space( offset + len - 1); } /* * free file space until done or until there is an error */ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); while (!error && !done) { /* * allocate and setup the transaction. Allow this * transaction to dip into the reserve blocks to ensure * the freeing of the space succeeds at ENOSPC. */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); if (error) { ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); break; error = xfs_unmap_extent(ip, startoffset_fsb, endoffset_fsb - startoffset_fsb, &done); } xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot, ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS); if (error) goto error1; xfs_trans_ijoin(tp, ip, 0); /* * issue the bunmapi() call to free the blocks */ xfs_bmap_init(&free_list, &firstfsb); error = xfs_bunmapi(tp, ip, startoffset_fsb, endoffset_fsb - startoffset_fsb, 0, 2, &firstfsb, &free_list, &done); if (error) goto error0; /* * complete the transaction */ error = xfs_bmap_finish(&tp, &free_list, NULL); if (error) goto error0; error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); } out: return error; error0: xfs_bmap_cancel(&free_list); error1: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); goto out; } /* Loading Loading
fs/xfs/xfs_bmap_util.c +137 −115 Original line number Diff line number Diff line Loading @@ -1184,69 +1184,72 @@ xfs_zero_remaining_bytes( return error; } int xfs_free_file_space( static int xfs_unmap_extent( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) xfs_fileoff_t startoffset_fsb, xfs_filblks_t len_fsb, int *done) { int done; xfs_fileoff_t endoffset_fsb; int error; struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_bmap_free free_list; xfs_fsblock_t firstfsb; xfs_bmap_free_t free_list; xfs_bmbt_irec_t imap; xfs_off_t ioffset; xfs_off_t iendoffset; xfs_extlen_t mod=0; xfs_mount_t *mp; int nimap; uint resblks; xfs_off_t rounding; int rt; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); int error; mp = ip->i_mount; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); if (error) { ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); return error; } trace_xfs_free_file_space(ip); xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot, ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS); if (error) goto out_trans_cancel; error = xfs_qm_dqattach(ip, 0); xfs_trans_ijoin(tp, ip, 0); xfs_bmap_init(&free_list, &firstfsb); error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb, &free_list, done); if (error) return error; goto out_bmap_cancel; error = 0; if (len <= 0) /* if nothing being freed */ error = xfs_bmap_finish(&tp, &free_list, NULL); if (error) goto out_bmap_cancel; error = xfs_trans_commit(tp); out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; rt = XFS_IS_REALTIME_INODE(ip); startoffset_fsb = XFS_B_TO_FSB(mp, offset); endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); /* wait for the completion of any pending DIOs */ inode_dio_wait(VFS_I(ip)); out_bmap_cancel: xfs_bmap_cancel(&free_list); out_trans_cancel: xfs_trans_cancel(tp); goto out_unlock; } rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); ioffset = round_down(offset, rounding); iendoffset = round_up(offset + len, rounding) - 1; error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset, iendoffset); if (error) goto out; truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset); static int xfs_adjust_extent_unmap_boundaries( struct xfs_inode *ip, xfs_fileoff_t *startoffset_fsb, xfs_fileoff_t *endoffset_fsb) { struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec imap; int nimap, error; xfs_extlen_t mod = 0; /* * Need to zero the stuff we're not freeing, on disk. * If it's a realtime file & can't use unwritten extents then we * actually need to zero the extent edges. Otherwise xfs_bunmapi * will take care of it for us. */ if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { nimap = 1; error = xfs_bmapi_read(ip, startoffset_fsb, 1, &imap, &nimap, 0); error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0); if (error) goto out; ASSERT(nimap == 0 || nimap == 1); return error; if (nimap && imap.br_startblock != HOLESTARTBLOCK) { xfs_daddr_t block; Loading @@ -1254,21 +1257,90 @@ xfs_free_file_space( block = imap.br_startblock; mod = do_div(block, mp->m_sb.sb_rextsize); if (mod) startoffset_fsb += mp->m_sb.sb_rextsize - mod; *startoffset_fsb += mp->m_sb.sb_rextsize - mod; } nimap = 1; error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1, &imap, &nimap, 0); error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0); if (error) goto out; ASSERT(nimap == 0 || nimap == 1); return error; if (nimap && imap.br_startblock != HOLESTARTBLOCK) { ASSERT(imap.br_startblock != DELAYSTARTBLOCK); mod++; if (mod && (mod != mp->m_sb.sb_rextsize)) endoffset_fsb -= mod; if (mod && mod != mp->m_sb.sb_rextsize) *endoffset_fsb -= mod; } return 0; } static int xfs_flush_unmap_range( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) { struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); xfs_off_t rounding, start, end; int error; /* wait for the completion of any pending DIOs */ inode_dio_wait(inode); rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); start = round_down(offset, rounding); end = round_up(offset + len, rounding) - 1; error = filemap_write_and_wait_range(inode->i_mapping, start, end); if (error) return error; truncate_pagecache_range(inode, start, end); return 0; } int xfs_free_file_space( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t len) { struct xfs_mount *mp = ip->i_mount; xfs_fileoff_t startoffset_fsb; xfs_fileoff_t endoffset_fsb; int done, error; trace_xfs_free_file_space(ip); error = xfs_qm_dqattach(ip, 0); if (error) return error; if (len <= 0) /* if nothing being freed */ return 0; error = xfs_flush_unmap_range(ip, offset, len); if (error) return error; startoffset_fsb = XFS_B_TO_FSB(mp, offset); endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); /* * Need to zero the stuff we're not freeing, on disk. If it's a RT file * and we can't use unwritten extents then we actually need to ensure * to zero the whole extent, otherwise we just need to take of block * boundaries, and xfs_bunmapi will handle the rest. */ if (XFS_IS_REALTIME_INODE(ip) && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb, &endoffset_fsb); if (error) return error; } if ((done = (endoffset_fsb <= startoffset_fsb))) /* * One contiguous piece to clear Loading @@ -1288,62 +1360,12 @@ xfs_free_file_space( offset + len - 1); } /* * free file space until done or until there is an error */ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); while (!error && !done) { /* * allocate and setup the transaction. Allow this * transaction to dip into the reserve blocks to ensure * the freeing of the space succeeds at ENOSPC. */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); if (error) { ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); break; error = xfs_unmap_extent(ip, startoffset_fsb, endoffset_fsb - startoffset_fsb, &done); } xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot, ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS); if (error) goto error1; xfs_trans_ijoin(tp, ip, 0); /* * issue the bunmapi() call to free the blocks */ xfs_bmap_init(&free_list, &firstfsb); error = xfs_bunmapi(tp, ip, startoffset_fsb, endoffset_fsb - startoffset_fsb, 0, 2, &firstfsb, &free_list, &done); if (error) goto error0; /* * complete the transaction */ error = xfs_bmap_finish(&tp, &free_list, NULL); if (error) goto error0; error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); } out: return error; error0: xfs_bmap_cancel(&free_list); error1: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); goto out; } /* Loading