diff options
author | Dave Chinner <david@fromorbit.com> | 2014-05-19 18:56:00 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2014-05-19 18:56:00 -0400 |
commit | 0d907a3bb4a77cffebebd17c323e898048301aa3 (patch) | |
tree | c093289c9ab443935ce10e138ab49efacb2c283f | |
parent | 2d6dcc6d7e95cc83046b2f97e179e6bbb7921245 (diff) | |
parent | 376c2f3a5f0706868b08ccf043bf3532936a03b1 (diff) |
Merge branch 'xfs-misc-fixes-2-for-3.16' into for-next
Conflicts:
fs/xfs/xfs_ialloc.c
-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 | ||