aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r--fs/xfs/xfs_bmap_util.c174
1 files changed, 85 insertions, 89 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 64731ef3324d..2f1e30d39a35 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -133,7 +133,7 @@ xfs_bmap_finish(
133 mp = ntp->t_mountp; 133 mp = ntp->t_mountp;
134 if (!XFS_FORCED_SHUTDOWN(mp)) 134 if (!XFS_FORCED_SHUTDOWN(mp))
135 xfs_force_shutdown(mp, 135 xfs_force_shutdown(mp,
136 (error == EFSCORRUPTED) ? 136 (error == -EFSCORRUPTED) ?
137 SHUTDOWN_CORRUPT_INCORE : 137 SHUTDOWN_CORRUPT_INCORE :
138 SHUTDOWN_META_IO_ERROR); 138 SHUTDOWN_META_IO_ERROR);
139 return error; 139 return error;
@@ -365,7 +365,7 @@ xfs_bmap_count_tree(
365 xfs_trans_brelse(tp, bp); 365 xfs_trans_brelse(tp, bp);
366 XFS_ERROR_REPORT("xfs_bmap_count_tree(1)", 366 XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
367 XFS_ERRLEVEL_LOW, mp); 367 XFS_ERRLEVEL_LOW, mp);
368 return XFS_ERROR(EFSCORRUPTED); 368 return -EFSCORRUPTED;
369 } 369 }
370 xfs_trans_brelse(tp, bp); 370 xfs_trans_brelse(tp, bp);
371 } else { 371 } else {
@@ -425,14 +425,14 @@ xfs_bmap_count_blocks(
425 ASSERT(level > 0); 425 ASSERT(level > 0);
426 pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); 426 pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
427 bno = be64_to_cpu(*pp); 427 bno = be64_to_cpu(*pp);
428 ASSERT(bno != NULLDFSBNO); 428 ASSERT(bno != NULLFSBLOCK);
429 ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); 429 ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
430 ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); 430 ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
431 431
432 if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) { 432 if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
433 XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW, 433 XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
434 mp); 434 mp);
435 return XFS_ERROR(EFSCORRUPTED); 435 return -EFSCORRUPTED;
436 } 436 }
437 437
438 return 0; 438 return 0;
@@ -524,13 +524,13 @@ xfs_getbmap(
524 if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && 524 if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS &&
525 ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE && 525 ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE &&
526 ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) 526 ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)
527 return XFS_ERROR(EINVAL); 527 return -EINVAL;
528 } else if (unlikely( 528 } else if (unlikely(
529 ip->i_d.di_aformat != 0 && 529 ip->i_d.di_aformat != 0 &&
530 ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) { 530 ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) {
531 XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW, 531 XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW,
532 ip->i_mount); 532 ip->i_mount);
533 return XFS_ERROR(EFSCORRUPTED); 533 return -EFSCORRUPTED;
534 } 534 }
535 535
536 prealloced = 0; 536 prealloced = 0;
@@ -539,7 +539,7 @@ xfs_getbmap(
539 if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && 539 if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
540 ip->i_d.di_format != XFS_DINODE_FMT_BTREE && 540 ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
541 ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) 541 ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
542 return XFS_ERROR(EINVAL); 542 return -EINVAL;
543 543
544 if (xfs_get_extsz_hint(ip) || 544 if (xfs_get_extsz_hint(ip) ||
545 ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ 545 ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
@@ -559,26 +559,26 @@ xfs_getbmap(
559 bmv->bmv_entries = 0; 559 bmv->bmv_entries = 0;
560 return 0; 560 return 0;
561 } else if (bmv->bmv_length < 0) { 561 } else if (bmv->bmv_length < 0) {
562 return XFS_ERROR(EINVAL); 562 return -EINVAL;
563 } 563 }
564 564
565 nex = bmv->bmv_count - 1; 565 nex = bmv->bmv_count - 1;
566 if (nex <= 0) 566 if (nex <= 0)
567 return XFS_ERROR(EINVAL); 567 return -EINVAL;
568 bmvend = bmv->bmv_offset + bmv->bmv_length; 568 bmvend = bmv->bmv_offset + bmv->bmv_length;
569 569
570 570
571 if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) 571 if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
572 return XFS_ERROR(ENOMEM); 572 return -ENOMEM;
573 out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0); 573 out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0);
574 if (!out) 574 if (!out)
575 return XFS_ERROR(ENOMEM); 575 return -ENOMEM;
576 576
577 xfs_ilock(ip, XFS_IOLOCK_SHARED); 577 xfs_ilock(ip, XFS_IOLOCK_SHARED);
578 if (whichfork == XFS_DATA_FORK) { 578 if (whichfork == XFS_DATA_FORK) {
579 if (!(iflags & BMV_IF_DELALLOC) && 579 if (!(iflags & BMV_IF_DELALLOC) &&
580 (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size)) { 580 (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size)) {
581 error = -filemap_write_and_wait(VFS_I(ip)->i_mapping); 581 error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
582 if (error) 582 if (error)
583 goto out_unlock_iolock; 583 goto out_unlock_iolock;
584 584
@@ -611,7 +611,7 @@ xfs_getbmap(
611 /* 611 /*
612 * Allocate enough space to handle "subnex" maps at a time. 612 * Allocate enough space to handle "subnex" maps at a time.
613 */ 613 */
614 error = ENOMEM; 614 error = -ENOMEM;
615 subnex = 16; 615 subnex = 16;
616 map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS); 616 map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);
617 if (!map) 617 if (!map)
@@ -809,7 +809,7 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
809 * have speculative prealloc/delalloc blocks to remove. 809 * have speculative prealloc/delalloc blocks to remove.
810 */ 810 */
811 if (VFS_I(ip)->i_size == 0 && 811 if (VFS_I(ip)->i_size == 0 &&
812 VN_CACHED(VFS_I(ip)) == 0 && 812 VFS_I(ip)->i_mapping->nrpages == 0 &&
813 ip->i_delayed_blks == 0) 813 ip->i_delayed_blks == 0)
814 return false; 814 return false;
815 815
@@ -882,7 +882,7 @@ xfs_free_eofblocks(
882 if (need_iolock) { 882 if (need_iolock) {
883 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { 883 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
884 xfs_trans_cancel(tp, 0); 884 xfs_trans_cancel(tp, 0);
885 return EAGAIN; 885 return -EAGAIN;
886 } 886 }
887 } 887 }
888 888
@@ -955,14 +955,14 @@ xfs_alloc_file_space(
955 trace_xfs_alloc_file_space(ip); 955 trace_xfs_alloc_file_space(ip);
956 956
957 if (XFS_FORCED_SHUTDOWN(mp)) 957 if (XFS_FORCED_SHUTDOWN(mp))
958 return XFS_ERROR(EIO); 958 return -EIO;
959 959
960 error = xfs_qm_dqattach(ip, 0); 960 error = xfs_qm_dqattach(ip, 0);
961 if (error) 961 if (error)
962 return error; 962 return error;
963 963
964 if (len <= 0) 964 if (len <= 0)
965 return XFS_ERROR(EINVAL); 965 return -EINVAL;
966 966
967 rt = XFS_IS_REALTIME_INODE(ip); 967 rt = XFS_IS_REALTIME_INODE(ip);
968 extsz = xfs_get_extsz_hint(ip); 968 extsz = xfs_get_extsz_hint(ip);
@@ -1028,7 +1028,7 @@ xfs_alloc_file_space(
1028 /* 1028 /*
1029 * Free the transaction structure. 1029 * Free the transaction structure.
1030 */ 1030 */
1031 ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); 1031 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1032 xfs_trans_cancel(tp, 0); 1032 xfs_trans_cancel(tp, 0);
1033 break; 1033 break;
1034 } 1034 }
@@ -1065,7 +1065,7 @@ xfs_alloc_file_space(
1065 allocated_fsb = imapp->br_blockcount; 1065 allocated_fsb = imapp->br_blockcount;
1066 1066
1067 if (nimaps == 0) { 1067 if (nimaps == 0) {
1068 error = XFS_ERROR(ENOSPC); 1068 error = -ENOSPC;
1069 break; 1069 break;
1070 } 1070 }
1071 1071
@@ -1126,7 +1126,7 @@ xfs_zero_remaining_bytes(
1126 mp->m_rtdev_targp : mp->m_ddev_targp, 1126 mp->m_rtdev_targp : mp->m_ddev_targp,
1127 BTOBB(mp->m_sb.sb_blocksize), 0); 1127 BTOBB(mp->m_sb.sb_blocksize), 0);
1128 if (!bp) 1128 if (!bp)
1129 return XFS_ERROR(ENOMEM); 1129 return -ENOMEM;
1130 1130
1131 xfs_buf_unlock(bp); 1131 xfs_buf_unlock(bp);
1132 1132
@@ -1158,7 +1158,7 @@ xfs_zero_remaining_bytes(
1158 XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock)); 1158 XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
1159 1159
1160 if (XFS_FORCED_SHUTDOWN(mp)) { 1160 if (XFS_FORCED_SHUTDOWN(mp)) {
1161 error = XFS_ERROR(EIO); 1161 error = -EIO;
1162 break; 1162 break;
1163 } 1163 }
1164 xfs_buf_iorequest(bp); 1164 xfs_buf_iorequest(bp);
@@ -1176,7 +1176,7 @@ xfs_zero_remaining_bytes(
1176 XFS_BUF_WRITE(bp); 1176 XFS_BUF_WRITE(bp);
1177 1177
1178 if (XFS_FORCED_SHUTDOWN(mp)) { 1178 if (XFS_FORCED_SHUTDOWN(mp)) {
1179 error = XFS_ERROR(EIO); 1179 error = -EIO;
1180 break; 1180 break;
1181 } 1181 }
1182 xfs_buf_iorequest(bp); 1182 xfs_buf_iorequest(bp);
@@ -1234,7 +1234,7 @@ xfs_free_file_space(
1234 1234
1235 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); 1235 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
1236 ioffset = offset & ~(rounding - 1); 1236 ioffset = offset & ~(rounding - 1);
1237 error = -filemap_write_and_wait_range(VFS_I(ip)->i_mapping, 1237 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
1238 ioffset, -1); 1238 ioffset, -1);
1239 if (error) 1239 if (error)
1240 goto out; 1240 goto out;
@@ -1315,7 +1315,7 @@ xfs_free_file_space(
1315 /* 1315 /*
1316 * Free the transaction structure. 1316 * Free the transaction structure.
1317 */ 1317 */
1318 ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); 1318 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1319 xfs_trans_cancel(tp, 0); 1319 xfs_trans_cancel(tp, 0);
1320 break; 1320 break;
1321 } 1321 }
@@ -1557,14 +1557,14 @@ xfs_swap_extents_check_format(
1557 /* Should never get a local format */ 1557 /* Should never get a local format */
1558 if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL || 1558 if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
1559 tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) 1559 tip->i_d.di_format == XFS_DINODE_FMT_LOCAL)
1560 return EINVAL; 1560 return -EINVAL;
1561 1561
1562 /* 1562 /*
1563 * if the target inode has less extents that then temporary inode then 1563 * if the target inode has less extents that then temporary inode then
1564 * why did userspace call us? 1564 * why did userspace call us?
1565 */ 1565 */
1566 if (ip->i_d.di_nextents < tip->i_d.di_nextents) 1566 if (ip->i_d.di_nextents < tip->i_d.di_nextents)
1567 return EINVAL; 1567 return -EINVAL;
1568 1568
1569 /* 1569 /*
1570 * if the target inode is in extent form and the temp inode is in btree 1570 * if the target inode is in extent form and the temp inode is in btree
@@ -1573,19 +1573,19 @@ xfs_swap_extents_check_format(
1573 */ 1573 */
1574 if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && 1574 if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1575 tip->i_d.di_format == XFS_DINODE_FMT_BTREE) 1575 tip->i_d.di_format == XFS_DINODE_FMT_BTREE)
1576 return EINVAL; 1576 return -EINVAL;
1577 1577
1578 /* Check temp in extent form to max in target */ 1578 /* Check temp in extent form to max in target */
1579 if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && 1579 if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1580 XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > 1580 XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) >
1581 XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) 1581 XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
1582 return EINVAL; 1582 return -EINVAL;
1583 1583
1584 /* Check target in extent form to max in temp */ 1584 /* Check target in extent form to max in temp */
1585 if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && 1585 if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
1586 XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > 1586 XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) >
1587 XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) 1587 XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
1588 return EINVAL; 1588 return -EINVAL;
1589 1589
1590 /* 1590 /*
1591 * If we are in a btree format, check that the temp root block will fit 1591 * If we are in a btree format, check that the temp root block will fit
@@ -1599,26 +1599,50 @@ xfs_swap_extents_check_format(
1599 if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) { 1599 if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
1600 if (XFS_IFORK_BOFF(ip) && 1600 if (XFS_IFORK_BOFF(ip) &&
1601 XFS_BMAP_BMDR_SPACE(tip->i_df.if_broot) > XFS_IFORK_BOFF(ip)) 1601 XFS_BMAP_BMDR_SPACE(tip->i_df.if_broot) > XFS_IFORK_BOFF(ip))
1602 return EINVAL; 1602 return -EINVAL;
1603 if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= 1603 if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <=
1604 XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) 1604 XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
1605 return EINVAL; 1605 return -EINVAL;
1606 } 1606 }
1607 1607
1608 /* Reciprocal target->temp btree format checks */ 1608 /* Reciprocal target->temp btree format checks */
1609 if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { 1609 if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
1610 if (XFS_IFORK_BOFF(tip) && 1610 if (XFS_IFORK_BOFF(tip) &&
1611 XFS_BMAP_BMDR_SPACE(ip->i_df.if_broot) > XFS_IFORK_BOFF(tip)) 1611 XFS_BMAP_BMDR_SPACE(ip->i_df.if_broot) > XFS_IFORK_BOFF(tip))
1612 return EINVAL; 1612 return -EINVAL;
1613 if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= 1613 if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <=
1614 XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) 1614 XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
1615 return EINVAL; 1615 return -EINVAL;
1616 } 1616 }
1617 1617
1618 return 0; 1618 return 0;
1619} 1619}
1620 1620
1621int 1621int
1622xfs_swap_extent_flush(
1623 struct xfs_inode *ip)
1624{
1625 int error;
1626
1627 error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
1628 if (error)
1629 return error;
1630 truncate_pagecache_range(VFS_I(ip), 0, -1);
1631
1632 /* Verify O_DIRECT for ftmp */
1633 if (VFS_I(ip)->i_mapping->nrpages)
1634 return -EINVAL;
1635
1636 /*
1637 * Don't try to swap extents on mmap()d files because we can't lock
1638 * out races against page faults safely.
1639 */
1640 if (mapping_mapped(VFS_I(ip)->i_mapping))
1641 return -EBUSY;
1642 return 0;
1643}
1644
1645int
1622xfs_swap_extents( 1646xfs_swap_extents(
1623 xfs_inode_t *ip, /* target inode */ 1647 xfs_inode_t *ip, /* target inode */
1624 xfs_inode_t *tip, /* tmp inode */ 1648 xfs_inode_t *tip, /* tmp inode */
@@ -1633,51 +1657,57 @@ xfs_swap_extents(
1633 int aforkblks = 0; 1657 int aforkblks = 0;
1634 int taforkblks = 0; 1658 int taforkblks = 0;
1635 __uint64_t tmp; 1659 __uint64_t tmp;
1660 int lock_flags;
1636 1661
1637 tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); 1662 tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
1638 if (!tempifp) { 1663 if (!tempifp) {
1639 error = XFS_ERROR(ENOMEM); 1664 error = -ENOMEM;
1640 goto out; 1665 goto out;
1641 } 1666 }
1642 1667
1643 /* 1668 /*
1644 * we have to do two separate lock calls here to keep lockdep 1669 * Lock up the inodes against other IO and truncate to begin with.
1645 * happy. If we try to get all the locks in one call, lock will 1670 * Then we can ensure the inodes are flushed and have no page cache
1646 * report false positives when we drop the ILOCK and regain them 1671 * safely. Once we have done this we can take the ilocks and do the rest
1647 * below. 1672 * of the checks.
1648 */ 1673 */
1674 lock_flags = XFS_IOLOCK_EXCL;
1649 xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); 1675 xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
1650 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1651 1676
1652 /* Verify that both files have the same format */ 1677 /* Verify that both files have the same format */
1653 if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { 1678 if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
1654 error = XFS_ERROR(EINVAL); 1679 error = -EINVAL;
1655 goto out_unlock; 1680 goto out_unlock;
1656 } 1681 }
1657 1682
1658 /* Verify both files are either real-time or non-realtime */ 1683 /* Verify both files are either real-time or non-realtime */
1659 if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) { 1684 if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
1660 error = XFS_ERROR(EINVAL); 1685 error = -EINVAL;
1661 goto out_unlock; 1686 goto out_unlock;
1662 } 1687 }
1663 1688
1664 error = -filemap_write_and_wait(VFS_I(tip)->i_mapping); 1689 error = xfs_swap_extent_flush(ip);
1690 if (error)
1691 goto out_unlock;
1692 error = xfs_swap_extent_flush(tip);
1665 if (error) 1693 if (error)
1666 goto out_unlock; 1694 goto out_unlock;
1667 truncate_pagecache_range(VFS_I(tip), 0, -1);
1668 1695
1669 /* Verify O_DIRECT for ftmp */ 1696 tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
1670 if (VN_CACHED(VFS_I(tip)) != 0) { 1697 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
1671 error = XFS_ERROR(EINVAL); 1698 if (error) {
1699 xfs_trans_cancel(tp, 0);
1672 goto out_unlock; 1700 goto out_unlock;
1673 } 1701 }
1702 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1703 lock_flags |= XFS_ILOCK_EXCL;
1674 1704
1675 /* Verify all data are being swapped */ 1705 /* Verify all data are being swapped */
1676 if (sxp->sx_offset != 0 || 1706 if (sxp->sx_offset != 0 ||
1677 sxp->sx_length != ip->i_d.di_size || 1707 sxp->sx_length != ip->i_d.di_size ||
1678 sxp->sx_length != tip->i_d.di_size) { 1708 sxp->sx_length != tip->i_d.di_size) {
1679 error = XFS_ERROR(EFAULT); 1709 error = -EFAULT;
1680 goto out_unlock; 1710 goto out_trans_cancel;
1681 } 1711 }
1682 1712
1683 trace_xfs_swap_extent_before(ip, 0); 1713 trace_xfs_swap_extent_before(ip, 0);
@@ -1689,7 +1719,7 @@ xfs_swap_extents(
1689 xfs_notice(mp, 1719 xfs_notice(mp,
1690 "%s: inode 0x%llx format is incompatible for exchanging.", 1720 "%s: inode 0x%llx format is incompatible for exchanging.",
1691 __func__, ip->i_ino); 1721 __func__, ip->i_ino);
1692 goto out_unlock; 1722 goto out_trans_cancel;
1693 } 1723 }
1694 1724
1695 /* 1725 /*
@@ -1703,43 +1733,9 @@ xfs_swap_extents(
1703 (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) || 1733 (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) ||
1704 (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || 1734 (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
1705 (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { 1735 (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
1706 error = XFS_ERROR(EBUSY); 1736 error = -EBUSY;
1707 goto out_unlock; 1737 goto out_trans_cancel;
1708 }
1709
1710 /* We need to fail if the file is memory mapped. Once we have tossed
1711 * all existing pages, the page fault will have no option
1712 * but to go to the filesystem for pages. By making the page fault call
1713 * vop_read (or write in the case of autogrow) they block on the iolock
1714 * until we have switched the extents.
1715 */
1716 if (VN_MAPPED(VFS_I(ip))) {
1717 error = XFS_ERROR(EBUSY);
1718 goto out_unlock;
1719 }
1720
1721 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1722 xfs_iunlock(tip, XFS_ILOCK_EXCL);
1723
1724 /*
1725 * There is a race condition here since we gave up the
1726 * ilock. However, the data fork will not change since
1727 * we have the iolock (locked for truncation too) so we
1728 * are safe. We don't really care if non-io related
1729 * fields change.
1730 */
1731 truncate_pagecache_range(VFS_I(ip), 0, -1);
1732
1733 tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
1734 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
1735 if (error) {
1736 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1737 xfs_iunlock(tip, XFS_IOLOCK_EXCL);
1738 xfs_trans_cancel(tp, 0);
1739 goto out;
1740 } 1738 }
1741 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1742
1743 /* 1739 /*
1744 * Count the number of extended attribute blocks 1740 * Count the number of extended attribute blocks
1745 */ 1741 */
@@ -1757,8 +1753,8 @@ xfs_swap_extents(
1757 goto out_trans_cancel; 1753 goto out_trans_cancel;
1758 } 1754 }
1759 1755
1760 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 1756 xfs_trans_ijoin(tp, ip, lock_flags);
1761 xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 1757 xfs_trans_ijoin(tp, tip, lock_flags);
1762 1758
1763 /* 1759 /*
1764 * Before we've swapped the forks, lets set the owners of the forks 1760 * Before we've swapped the forks, lets set the owners of the forks
@@ -1887,8 +1883,8 @@ out:
1887 return error; 1883 return error;
1888 1884
1889out_unlock: 1885out_unlock:
1890 xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 1886 xfs_iunlock(ip, lock_flags);
1891 xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 1887 xfs_iunlock(tip, lock_flags);
1892 goto out; 1888 goto out;
1893 1889
1894out_trans_cancel: 1890out_trans_cancel: