diff options
| -rw-r--r-- | fs/xfs/xfs_aops.c | 49 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap_util.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_da_btree.c | 41 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc.c | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_log.h | 19 | ||||
| -rw-r--r-- | fs/xfs/xfs_log_cil.c | 7 |
7 files changed, 66 insertions, 64 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 0479c32c5eb1..d1b99b692ccb 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
| @@ -982,7 +982,32 @@ xfs_vm_writepage( | |||
| 982 | offset = i_size_read(inode); | 982 | offset = i_size_read(inode); |
| 983 | end_index = offset >> PAGE_CACHE_SHIFT; | 983 | end_index = offset >> PAGE_CACHE_SHIFT; |
| 984 | last_index = (offset - 1) >> PAGE_CACHE_SHIFT; | 984 | last_index = (offset - 1) >> PAGE_CACHE_SHIFT; |
| 985 | if (page->index >= end_index) { | 985 | |
| 986 | /* | ||
| 987 | * The page index is less than the end_index, adjust the end_offset | ||
| 988 | * to the highest offset that this page should represent. | ||
| 989 | * ----------------------------------------------------- | ||
| 990 | * | file mapping | <EOF> | | ||
| 991 | * ----------------------------------------------------- | ||
| 992 | * | Page ... | Page N-2 | Page N-1 | Page N | | | ||
| 993 | * ^--------------------------------^----------|-------- | ||
| 994 | * | desired writeback range | see else | | ||
| 995 | * ---------------------------------^------------------| | ||
| 996 | */ | ||
| 997 | if (page->index < end_index) | ||
| 998 | end_offset = (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT; | ||
| 999 | else { | ||
| 1000 | /* | ||
| 1001 | * Check whether the page to write out is beyond or straddles | ||
| 1002 | * i_size or not. | ||
| 1003 | * ------------------------------------------------------- | ||
| 1004 | * | file mapping | <EOF> | | ||
| 1005 | * ------------------------------------------------------- | ||
| 1006 | * | Page ... | Page N-2 | Page N-1 | Page N | Beyond | | ||
| 1007 | * ^--------------------------------^-----------|--------- | ||
| 1008 | * | | Straddles | | ||
| 1009 | * ---------------------------------^-----------|--------| | ||
| 1010 | */ | ||
| 986 | unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1); | 1011 | unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1); |
| 987 | 1012 | ||
| 988 | /* | 1013 | /* |
| @@ -990,24 +1015,36 @@ xfs_vm_writepage( | |||
| 990 | * truncate operation that is in progress. We must redirty the | 1015 | * truncate operation that is in progress. We must redirty the |
| 991 | * page so that reclaim stops reclaiming it. Otherwise | 1016 | * page so that reclaim stops reclaiming it. Otherwise |
| 992 | * xfs_vm_releasepage() is called on it and gets confused. | 1017 | * xfs_vm_releasepage() is called on it and gets confused. |
| 1018 | * | ||
| 1019 | * Note that the end_index is unsigned long, it would overflow | ||
| 1020 | * if the given offset is greater than 16TB on 32-bit system | ||
| 1021 | * and if we do check the page is fully outside i_size or not | ||
| 1022 | * via "if (page->index >= end_index + 1)" as "end_index + 1" | ||
| 1023 | * will be evaluated to 0. Hence this page will be redirtied | ||
| 1024 | * and be written out repeatedly which would result in an | ||
| 1025 | * infinite loop, the user program that perform this operation | ||
| 1026 | * will hang. Instead, we can verify this situation by checking | ||
| 1027 | * if the page to write is totally beyond the i_size or if it's | ||
| 1028 | * offset is just equal to the EOF. | ||
| 993 | */ | 1029 | */ |
| 994 | if (page->index >= end_index + 1 || offset_into_page == 0) | 1030 | if (page->index > end_index || |
| 1031 | (page->index == end_index && offset_into_page == 0)) | ||
| 995 | goto redirty; | 1032 | goto redirty; |
| 996 | 1033 | ||
| 997 | /* | 1034 | /* |
| 998 | * The page straddles i_size. It must be zeroed out on each | 1035 | * The page straddles i_size. It must be zeroed out on each |
| 999 | * and every writepage invocation because it may be mmapped. | 1036 | * and every writepage invocation because it may be mmapped. |
| 1000 | * "A file is mapped in multiples of the page size. For a file | 1037 | * "A file is mapped in multiples of the page size. For a file |
| 1001 | * that is not a multiple of the page size, the remaining | 1038 | * that is not a multiple of the page size, the remaining |
| 1002 | * memory is zeroed when mapped, and writes to that region are | 1039 | * memory is zeroed when mapped, and writes to that region are |
| 1003 | * not written out to the file." | 1040 | * not written out to the file." |
| 1004 | */ | 1041 | */ |
| 1005 | zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE); | 1042 | zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE); |
| 1043 | |||
| 1044 | /* Adjust the end_offset to the end of file */ | ||
| 1045 | end_offset = offset; | ||
| 1006 | } | 1046 | } |
| 1007 | 1047 | ||
| 1008 | end_offset = min_t(unsigned long long, | ||
| 1009 | (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, | ||
| 1010 | offset); | ||
| 1011 | len = 1 << inode->i_blkbits; | 1048 | len = 1 << inode->i_blkbits; |
| 1012 | 1049 | ||
| 1013 | bh = head = page_buffers(page); | 1050 | bh = head = page_buffers(page); |
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 296160b8e78c..057f671811d6 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
| @@ -1519,7 +1519,6 @@ xfs_collapse_file_space( | |||
| 1519 | 1519 | ||
| 1520 | while (!error && !done) { | 1520 | while (!error && !done) { |
| 1521 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 1521 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
| 1522 | tp->t_flags |= XFS_TRANS_RESERVE; | ||
| 1523 | /* | 1522 | /* |
| 1524 | * We would need to reserve permanent block for transaction. | 1523 | * We would need to reserve permanent block for transaction. |
| 1525 | * This will come into picture when after shifting extent into | 1524 | * This will come into picture when after shifting extent into |
| @@ -1529,7 +1528,6 @@ xfs_collapse_file_space( | |||
| 1529 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, | 1528 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, |
| 1530 | XFS_DIOSTRAT_SPACE_RES(mp, 0), 0); | 1529 | XFS_DIOSTRAT_SPACE_RES(mp, 0), 0); |
| 1531 | if (error) { | 1530 | if (error) { |
| 1532 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); | ||
| 1533 | xfs_trans_cancel(tp, 0); | 1531 | xfs_trans_cancel(tp, 0); |
| 1534 | break; | 1532 | break; |
| 1535 | } | 1533 | } |
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 9eec594cc25a..4db5102d403a 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
| @@ -2624,47 +2624,6 @@ xfs_da_read_buf( | |||
| 2624 | xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF); | 2624 | xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF); |
| 2625 | else | 2625 | else |
| 2626 | xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF); | 2626 | xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF); |
| 2627 | |||
| 2628 | /* | ||
| 2629 | * This verification code will be moved to a CRC verification callback | ||
| 2630 | * function so just leave it here unchanged until then. | ||
| 2631 | */ | ||
| 2632 | { | ||
| 2633 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; | ||
| 2634 | xfs_dir2_free_t *free = bp->b_addr; | ||
| 2635 | xfs_da_blkinfo_t *info = bp->b_addr; | ||
| 2636 | uint magic, magic1; | ||
| 2637 | struct xfs_mount *mp = dp->i_mount; | ||
| 2638 | |||
| 2639 | magic = be16_to_cpu(info->magic); | ||
| 2640 | magic1 = be32_to_cpu(hdr->magic); | ||
| 2641 | if (unlikely( | ||
| 2642 | XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) && | ||
| 2643 | (magic != XFS_DA3_NODE_MAGIC) && | ||
| 2644 | (magic != XFS_ATTR_LEAF_MAGIC) && | ||
| 2645 | (magic != XFS_ATTR3_LEAF_MAGIC) && | ||
| 2646 | (magic != XFS_DIR2_LEAF1_MAGIC) && | ||
| 2647 | (magic != XFS_DIR3_LEAF1_MAGIC) && | ||
| 2648 | (magic != XFS_DIR2_LEAFN_MAGIC) && | ||
| 2649 | (magic != XFS_DIR3_LEAFN_MAGIC) && | ||
| 2650 | (magic1 != XFS_DIR2_BLOCK_MAGIC) && | ||
| 2651 | (magic1 != XFS_DIR3_BLOCK_MAGIC) && | ||
| 2652 | (magic1 != XFS_DIR2_DATA_MAGIC) && | ||
| 2653 | (magic1 != XFS_DIR3_DATA_MAGIC) && | ||
| 2654 | (free->hdr.magic != | ||
| 2655 | cpu_to_be32(XFS_DIR2_FREE_MAGIC)) && | ||
| 2656 | (free->hdr.magic != | ||
| 2657 | cpu_to_be32(XFS_DIR3_FREE_MAGIC)), | ||
| 2658 | mp, XFS_ERRTAG_DA_READ_BUF, | ||
| 2659 | XFS_RANDOM_DA_READ_BUF))) { | ||
| 2660 | trace_xfs_da_btree_corrupt(bp, _RET_IP_); | ||
| 2661 | XFS_CORRUPTION_ERROR("xfs_da_do_buf(2)", | ||
| 2662 | XFS_ERRLEVEL_LOW, mp, info); | ||
| 2663 | error = XFS_ERROR(EFSCORRUPTED); | ||
| 2664 | xfs_trans_brelse(trans, bp); | ||
| 2665 | goto out_free; | ||
| 2666 | } | ||
| 2667 | } | ||
| 2668 | *bpp = bp; | 2627 | *bpp = bp; |
| 2669 | out_free: | 2628 | out_free: |
| 2670 | if (mapp != &map) | 2629 | if (mapp != &map) |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 6ac0c2986c32..1313df7ff0d8 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
| @@ -1437,7 +1437,7 @@ xfs_difree_inobt( | |||
| 1437 | struct xfs_buf *agbp, | 1437 | struct xfs_buf *agbp, |
| 1438 | xfs_agino_t agino, | 1438 | xfs_agino_t agino, |
| 1439 | struct xfs_bmap_free *flist, | 1439 | struct xfs_bmap_free *flist, |
| 1440 | int *delete, | 1440 | int *deleted, |
| 1441 | xfs_ino_t *first_ino, | 1441 | xfs_ino_t *first_ino, |
| 1442 | struct xfs_inobt_rec_incore *orec) | 1442 | struct xfs_inobt_rec_incore *orec) |
| 1443 | { | 1443 | { |
| @@ -1497,7 +1497,7 @@ xfs_difree_inobt( | |||
| 1497 | if (!(mp->m_flags & XFS_MOUNT_IKEEP) && | 1497 | if (!(mp->m_flags & XFS_MOUNT_IKEEP) && |
| 1498 | (rec.ir_freecount == mp->m_ialloc_inos)) { | 1498 | (rec.ir_freecount == mp->m_ialloc_inos)) { |
| 1499 | 1499 | ||
| 1500 | *delete = 1; | 1500 | *deleted = 1; |
| 1501 | *first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); | 1501 | *first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); |
| 1502 | 1502 | ||
| 1503 | /* | 1503 | /* |
| @@ -1525,7 +1525,7 @@ xfs_difree_inobt( | |||
| 1525 | XFS_AGINO_TO_AGBNO(mp, rec.ir_startino)), | 1525 | XFS_AGINO_TO_AGBNO(mp, rec.ir_startino)), |
| 1526 | mp->m_ialloc_blks, flist, mp); | 1526 | mp->m_ialloc_blks, flist, mp); |
| 1527 | } else { | 1527 | } else { |
| 1528 | *delete = 0; | 1528 | *deleted = 0; |
| 1529 | 1529 | ||
| 1530 | error = xfs_inobt_update(cur, &rec); | 1530 | error = xfs_inobt_update(cur, &rec); |
| 1531 | if (error) { | 1531 | if (error) { |
| @@ -1662,7 +1662,7 @@ xfs_difree( | |||
| 1662 | struct xfs_trans *tp, /* transaction pointer */ | 1662 | struct xfs_trans *tp, /* transaction pointer */ |
| 1663 | xfs_ino_t inode, /* inode to be freed */ | 1663 | xfs_ino_t inode, /* inode to be freed */ |
| 1664 | struct xfs_bmap_free *flist, /* extents to free */ | 1664 | struct xfs_bmap_free *flist, /* extents to free */ |
| 1665 | int *delete,/* set if inode cluster was deleted */ | 1665 | int *deleted,/* set if inode cluster was deleted */ |
| 1666 | xfs_ino_t *first_ino)/* first inode in deleted cluster */ | 1666 | xfs_ino_t *first_ino)/* first inode in deleted cluster */ |
| 1667 | { | 1667 | { |
| 1668 | /* REFERENCED */ | 1668 | /* REFERENCED */ |
| @@ -1714,7 +1714,7 @@ xfs_difree( | |||
| 1714 | /* | 1714 | /* |
| 1715 | * Fix up the inode allocation btree. | 1715 | * Fix up the inode allocation btree. |
| 1716 | */ | 1716 | */ |
| 1717 | error = xfs_difree_inobt(mp, tp, agbp, agino, flist, delete, first_ino, | 1717 | error = xfs_difree_inobt(mp, tp, agbp, agino, flist, deleted, first_ino, |
| 1718 | &rec); | 1718 | &rec); |
| 1719 | if (error) | 1719 | if (error) |
| 1720 | goto error0; | 1720 | goto error0; |
diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h index 812365d17e67..95ad1c002d60 100644 --- a/fs/xfs/xfs_ialloc.h +++ b/fs/xfs/xfs_ialloc.h | |||
| @@ -90,7 +90,7 @@ xfs_difree( | |||
| 90 | struct xfs_trans *tp, /* transaction pointer */ | 90 | struct xfs_trans *tp, /* transaction pointer */ |
| 91 | xfs_ino_t inode, /* inode to be freed */ | 91 | xfs_ino_t inode, /* inode to be freed */ |
| 92 | struct xfs_bmap_free *flist, /* extents to free */ | 92 | struct xfs_bmap_free *flist, /* extents to free */ |
| 93 | int *delete, /* set if inode cluster was deleted */ | 93 | int *deleted, /* set if inode cluster was deleted */ |
| 94 | xfs_ino_t *first_ino); /* first inode in deleted cluster */ | 94 | xfs_ino_t *first_ino); /* first inode in deleted cluster */ |
| 95 | 95 | ||
| 96 | /* | 96 | /* |
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index 2c4004475e71..84e0deb95abd 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h | |||
| @@ -24,7 +24,8 @@ struct xfs_log_vec { | |||
| 24 | struct xfs_log_iovec *lv_iovecp; /* iovec array */ | 24 | struct xfs_log_iovec *lv_iovecp; /* iovec array */ |
| 25 | struct xfs_log_item *lv_item; /* owner */ | 25 | struct xfs_log_item *lv_item; /* owner */ |
| 26 | char *lv_buf; /* formatted buffer */ | 26 | char *lv_buf; /* formatted buffer */ |
| 27 | int lv_buf_len; /* size of formatted buffer */ | 27 | int lv_bytes; /* accounted space in buffer */ |
| 28 | int lv_buf_len; /* aligned size of buffer */ | ||
| 28 | int lv_size; /* size of allocated lv */ | 29 | int lv_size; /* size of allocated lv */ |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| @@ -52,15 +53,21 @@ xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, | |||
| 52 | return vec->i_addr; | 53 | return vec->i_addr; |
| 53 | } | 54 | } |
| 54 | 55 | ||
| 56 | /* | ||
| 57 | * We need to make sure the next buffer is naturally aligned for the biggest | ||
| 58 | * basic data type we put into it. We already accounted for this padding when | ||
| 59 | * sizing the buffer. | ||
| 60 | * | ||
| 61 | * However, this padding does not get written into the log, and hence we have to | ||
| 62 | * track the space used by the log vectors separately to prevent log space hangs | ||
| 63 | * due to inaccurate accounting (i.e. a leak) of the used log space through the | ||
| 64 | * CIL context ticket. | ||
| 65 | */ | ||
| 55 | static inline void | 66 | static inline void |
| 56 | xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) | 67 | xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) |
| 57 | { | 68 | { |
| 58 | /* | ||
| 59 | * We need to make sure the next buffer is naturally aligned for the | ||
| 60 | * biggest basic data type we put into it. We already accounted for | ||
| 61 | * this when sizing the buffer. | ||
| 62 | */ | ||
| 63 | lv->lv_buf_len += round_up(len, sizeof(uint64_t)); | 69 | lv->lv_buf_len += round_up(len, sizeof(uint64_t)); |
| 70 | lv->lv_bytes += len; | ||
| 64 | vec->i_len = len; | 71 | vec->i_len = len; |
| 65 | } | 72 | } |
| 66 | 73 | ||
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 039c873e6fb2..b3425b34e3d5 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c | |||
| @@ -97,7 +97,7 @@ xfs_cil_prepare_item( | |||
| 97 | { | 97 | { |
| 98 | /* Account for the new LV being passed in */ | 98 | /* Account for the new LV being passed in */ |
| 99 | if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { | 99 | if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { |
| 100 | *diff_len += lv->lv_buf_len; | 100 | *diff_len += lv->lv_bytes; |
| 101 | *diff_iovecs += lv->lv_niovecs; | 101 | *diff_iovecs += lv->lv_niovecs; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| @@ -111,7 +111,7 @@ xfs_cil_prepare_item( | |||
| 111 | else if (old_lv != lv) { | 111 | else if (old_lv != lv) { |
| 112 | ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED); | 112 | ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED); |
| 113 | 113 | ||
| 114 | *diff_len -= old_lv->lv_buf_len; | 114 | *diff_len -= old_lv->lv_bytes; |
| 115 | *diff_iovecs -= old_lv->lv_niovecs; | 115 | *diff_iovecs -= old_lv->lv_niovecs; |
| 116 | kmem_free(old_lv); | 116 | kmem_free(old_lv); |
| 117 | } | 117 | } |
| @@ -239,7 +239,7 @@ xlog_cil_insert_format_items( | |||
| 239 | * that the space reservation accounting is correct. | 239 | * that the space reservation accounting is correct. |
| 240 | */ | 240 | */ |
| 241 | *diff_iovecs -= lv->lv_niovecs; | 241 | *diff_iovecs -= lv->lv_niovecs; |
| 242 | *diff_len -= lv->lv_buf_len; | 242 | *diff_len -= lv->lv_bytes; |
| 243 | } else { | 243 | } else { |
| 244 | /* allocate new data chunk */ | 244 | /* allocate new data chunk */ |
| 245 | lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); | 245 | lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); |
| @@ -259,6 +259,7 @@ xlog_cil_insert_format_items( | |||
| 259 | 259 | ||
| 260 | /* The allocated data region lies beyond the iovec region */ | 260 | /* The allocated data region lies beyond the iovec region */ |
| 261 | lv->lv_buf_len = 0; | 261 | lv->lv_buf_len = 0; |
| 262 | lv->lv_bytes = 0; | ||
| 262 | lv->lv_buf = (char *)lv + buf_size - nbytes; | 263 | lv->lv_buf = (char *)lv + buf_size - nbytes; |
| 263 | ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); | 264 | ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); |
| 264 | 265 | ||
