diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 174 |
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 | ||
1621 | int | 1621 | int |
1622 | xfs_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 | |||
1645 | int | ||
1622 | xfs_swap_extents( | 1646 | xfs_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 | ||
1889 | out_unlock: | 1885 | out_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 | ||
1894 | out_trans_cancel: | 1890 | out_trans_cancel: |