aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2014-05-19 18:56:00 -0400
committerDave Chinner <david@fromorbit.com>2014-05-19 18:56:00 -0400
commit0d907a3bb4a77cffebebd17c323e898048301aa3 (patch)
treec093289c9ab443935ce10e138ab49efacb2c283f
parent2d6dcc6d7e95cc83046b2f97e179e6bbb7921245 (diff)
parent376c2f3a5f0706868b08ccf043bf3532936a03b1 (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.c49
-rw-r--r--fs/xfs/xfs_bmap_util.c2
-rw-r--r--fs/xfs/xfs_da_btree.c41
-rw-r--r--fs/xfs/xfs_ialloc.c10
-rw-r--r--fs/xfs/xfs_ialloc.h2
-rw-r--r--fs/xfs/xfs_log.h19
-rw-r--r--fs/xfs/xfs_log_cil.c7
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;
2669out_free: 2628out_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 */
55static inline void 66static inline void
56xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) 67xlog_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