4.9.3-stable review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 183/206 xfs: remove prev argument to xfs_bmapi_reserve_delalloc
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
commit 65c5f419788d623a0410eca1866134f5e4628594 upstream.
We can easily lookup the previous extent for the cases where we need it, which saves the callers from looking it up for us later in the series.
--- fs/xfs/libxfs/xfs_bmap.c | 8 ++++++-- fs/xfs/libxfs/xfs_bmap.h | 3 +-- fs/xfs/xfs_iomap.c | 3 +-- fs/xfs/xfs_reflink.c | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +6 -2
@@ -4250,7 +4250,6 @@ xfs_bmapi_reserve_delalloc(xfs_fileoff_t aoff, xfs_filblks_t len, struct xfs_bmbt_irec *got, - struct xfs_bmbt_irec *prev, xfs_extnum_t *lastx, int eof) {
@@ -4272,7 +4271,12 @@ xfs_bmapi_reserve_delalloc(else extsz =xfs_get_extsz_hint (ip);if (extsz) { - error =xfs_bmap_extsize_align (mp, got, prev, extsz, rt, eof, +struct xfs_bmbt_irec prev; + +if (!xfs_iext_get_extent (ifp, *lastx -1 , &prev)) + prev.br_startoff =NULLFILEOFF ; + + error =xfs_bmap_extsize_align (mp, got, &prev, extsz, rt, eof,1 ,0 , &aoff, &alen);ASSERT (!error); }
fs/xfs/libxfs/xfs_bmap.h +1 -2
@@ -243,8 +243,7 @@ struct xfs_bmbt_rec_host * struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp);int xfs_bmapi_reserve_delalloc (struct xfs_inode *ip,int whichfork,xfs_fileoff_t aoff,xfs_filblks_t len, -struct xfs_bmbt_irec *got,struct xfs_bmbt_irec *prev, -xfs_extnum_t *lastx,int eof); +struct xfs_bmbt_irec *got,xfs_extnum_t *lastx,int eof);enum xfs_bmap_intent_type {XFS_BMAP_MAP =1 ,
fs/xfs/xfs_iomap.c +1 -2
@@ -622,8 +622,7 @@ xfs_file_iomap_begin_delay( retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_DATA_FORK , offset_fsb, - end_fsb - offset_fsb, &got, - &prev, &idx, eof); + end_fsb - offset_fsb, &got, &idx, eof);switch (error) {case 0 :break ;
fs/xfs/xfs_reflink.c +1 -1
@@ -293,7 +293,7 @@ xfs_reflink_reserve_cow( retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_COW_FORK , imap->br_startoff, - end_fsb - imap->br_startoff, &got, &prev, &idx, eof); + end_fsb - imap->br_startoff, &got, &idx, eof);switch (error) {case 0 :break ;
Greg Kroah-Hartman
maintainerPATCH 184/206 xfs: track preallocation separately in xfs_bmapi_reserve_delalloc()
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Foster <[email protected]>
commit 974ae922efd93b07b6cdf989ae959883f6f05fd8 upstream.
Speculative preallocation is currently processed entirely by the callers of xfs_bmapi_reserve_delalloc(). The caller determines how much preallocation to include, adjusts the extent length and passes down the resulting request.
While this works fine for post-eof speculative preallocation, it is not as reliable for COW fork preallocation. COW fork preallocation is implemented via the cowextszhint, which aligns the start offset as well as the length of the extent. Further, it is difficult for the caller to accurately identify when preallocation occurs because the returned extent could have been merged with neighboring extents in the fork.
To simplify this situation and facilitate further COW fork preallocation enhancements, update xfs_bmapi_reserve_delalloc() to take a separate preallocation parameter to incorporate into the allocation request. The preallocation blocks value is tacked onto the end of the request and adjusted to accommodate neighboring extents and extent size limits. Since xfs_bmapi_reserve_delalloc() now knows precisely how much preallocation was included in the allocation, it can also tag the inodes appropriately to support preallocation reclaim.
Note that xfs_bmapi_reserve_delalloc() callers are not yet updated to use the preallocation mechanism. This patch should not change behavior outside of correctly tagging reflink inodes when start offset preallocation occurs (which the caller does not handle correctly).
--- fs/xfs/libxfs/xfs_bmap.c | 23 +++++++++++++++++++++-- fs/xfs/libxfs/xfs_bmap.h | 2 +- fs/xfs/xfs_iomap.c | 2 +- fs/xfs/xfs_reflink.c | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +21 -2
@@ -50,6 +50,7 @@#include "xfs_ag_resv.h" #include "xfs_refcount.h" #include "xfs_rmap_btree.h" +#include "xfs_icache.h" kmem_zone_t *xfs_bmap_free_item_zone;
@@ -4247,8 +4248,9 @@ intxfs_bmapi_reserve_delalloc ( struct xfs_inode *ip, int whichfork, - xfs_fileoff_t aoff, + xfs_fileoff_t off, xfs_filblks_t len, + xfs_filblks_t prealloc, struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof)
@@ -4260,10 +4262,17 @@ xfs_bmapi_reserve_delalloc(char rt =XFS_IS_REALTIME_INODE (ip);xfs_extlen_t extsz;int error; +xfs_fileoff_t aoff = off; - alen =XFS_FILBLKS_MIN (len,MAXEXTLEN ); +/* +* Cap the alloc length. Keep track of prealloc so we know whether to +* tag the inode before we return. +*/ + alen =XFS_FILBLKS_MIN (len + prealloc,MAXEXTLEN );if (!eof) alen =XFS_FILBLKS_MIN (alen, got->br_startoff - aoff); +if (prealloc && alen >= len) + prealloc = alen - len;/* Figure out the extent size, adjust alen */ if (whichfork ==XFS_COW_FORK )
@@ -4329,6 +4338,16 @@ xfs_bmapi_reserve_delalloc(*/ xfs_bmbt_get_all (xfs_iext_get_ext (ifp, *lastx), got); +/* +* Tag the inode if blocks were preallocated. Note that COW fork +* preallocation can occur at the start or end of the extent, even when +* prealloc == 0, so we must also check the aligned offset and length. +*/ +if (whichfork ==XFS_DATA_FORK && prealloc) +xfs_inode_set_eofblocks_tag (ip); +if (whichfork ==XFS_COW_FORK && (prealloc || aoff < off || alen > len)) +xfs_inode_set_cowblocks_tag (ip); +ASSERT (got->br_startoff <= aoff);ASSERT (got->br_startoff + got->br_blockcount >= aoff + alen);ASSERT (isnullstartblock (got->br_startblock));
fs/xfs/libxfs/xfs_bmap.h +1 -1
@@ -242,7 +242,7 @@ struct xfs_bmbt_rec_host * int fork, int *eofp, xfs_extnum_t *lastxp, struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp);int xfs_bmapi_reserve_delalloc (struct xfs_inode *ip,int whichfork, -xfs_fileoff_t aoff,xfs_filblks_t len, +xfs_fileoff_t off,xfs_filblks_t len,xfs_filblks_t prealloc,struct xfs_bmbt_irec *got,xfs_extnum_t *lastx,int eof);enum xfs_bmap_intent_type {
fs/xfs/xfs_iomap.c +1 -1
@@ -622,7 +622,7 @@ xfs_file_iomap_begin_delay( retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_DATA_FORK , offset_fsb, - end_fsb - offset_fsb, &got, &idx, eof); + end_fsb - offset_fsb,0 , &got, &idx, eof);switch (error) {case 0 :break ;
fs/xfs/xfs_reflink.c +1 -1
@@ -293,7 +293,7 @@ xfs_reflink_reserve_cow( retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_COW_FORK , imap->br_startoff, - end_fsb - imap->br_startoff, &got, &idx, eof); + end_fsb - imap->br_startoff,0 , &got, &idx, eof);switch (error) {case 0 :break ;
Greg Kroah-Hartman
maintainerPATCH 185/206 xfs: use new extent lookup helpers in __xfs_reflink_reserve_cow
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
commit 2755fc4438501c8c28e7783df890e889f6772bee upstream.
--- fs/xfs/xfs_reflink.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
fs/xfs/xfs_reflink.c +7 -5
@@ -243,10 +243,11 @@ xfs_reflink_reserve_cow(struct xfs_bmbt_irec *imap, bool *shared) { - struct xfs_bmbt_irec got, prev; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); +struct xfs_bmbt_irec got;xfs_fileoff_t end_fsb, orig_end_fsb; -int eof =0 , error =0 ; -bool trimmed; +int error =0 ; +bool eof = false, trimmed;xfs_extnum_t idx;xfs_extlen_t align;
@@ -258,8 +259,9 @@ xfs_reflink_reserve_cow(* extent list is generally faster than going out to the shared extent * tree. */ -xfs_bmap_search_extents (ip, imap->br_startoff,XFS_COW_FORK , &eof, &idx, - &got, &prev); + +if (!xfs_iext_lookup_extent (ip, ifp, imap->br_startoff, &idx, &got)) + eof = true;if (!eof && got.br_startoff <= imap->br_startoff) {trace_xfs_reflink_cow_found (ip, imap);xfs_trim_extent (imap, got.br_startoff, got.br_blockcount);
Greg Kroah-Hartman
maintainerPATCH 186/206 xfs: clean up cow fork reservation and tag inodes correctly
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Foster <[email protected]>
commit 0260d8ff5f76617e3a55a1c471383ecb4404c3ad upstream.
COW fork reservation is implemented via delayed allocation. The code is modeled after the traditional delalloc allocation code, but is slightly different in terms of how preallocation occurs. Rather than post-eof speculative preallocation, COW fork preallocation is implemented via a COW extent size hint that is designed to minimize fragmentation as a reflinked file is split over time.
xfs_reflink_reserve_cow() still uses logic that is oriented towards dealing with post-eof speculative preallocation, however, and is stale or not necessarily correct. First, the EOF alignment to the COW extent size hint is implemented in xfs_bmapi_reserve_delalloc() (which does so correctly by aligning the start and end offsets) and so is not necessary in xfs_reflink_reserve_cow(). The backoff and retry logic on ENOSPC is also ineffective for the same reason, as xfs_bmapi_reserve_delalloc() will simply perform the same allocation request on the retry. Finally, since the COW extent size hint aligns the start and end offset of the range to allocate, the end_fsb != orig_end_fsb logic is not sufficient. Indeed, if a write request happens to end on an aligned offset, it is possible that we do not tag the inode for COW preallocation even though xfs_bmapi_reserve_delalloc() may have preallocated at the start offset.
Kill the unnecessary, duplicate code in xfs_reflink_reserve_cow(). Remove the inode tag logic as well since xfs_bmapi_reserve_delalloc() has been updated to tag the inode correctly.
--- fs/xfs/xfs_reflink.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-)
fs/xfs/xfs_reflink.c +3 -26
@@ -245,11 +245,9 @@ xfs_reflink_reserve_cow( {struct xfs_ifork *ifp =XFS_IFORK_PTR (ip,XFS_COW_FORK );struct xfs_bmbt_irec got; -xfs_fileoff_t end_fsb, orig_end_fsb;int error =0 ;bool eof = false, trimmed;xfs_extnum_t idx; -xfs_extlen_t align;/* * Search the COW fork extent list first. This serves two purposes:
@@ -287,33 +285,12 @@ xfs_reflink_reserve_cow(if (error)return error; - end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount; - - align =xfs_eof_alignment (ip,xfs_get_cowextsz_hint (ip)); -if (align) - end_fsb =roundup_64 (end_fsb, align); - -retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_COW_FORK , imap->br_startoff, - end_fsb - imap->br_startoff,0 , &got, &idx, eof); -switch (error) { -case 0 : -break ; -case -ENOSPC : -case -EDQUOT : -/* retry without any preallocation */ + imap->br_blockcount,0 , &got, &idx, eof); +if (error == -ENOSPC || error == -EDQUOT )trace_xfs_reflink_cow_enospc (ip, imap); -if (end_fsb != orig_end_fsb) { - end_fsb = orig_end_fsb; - goto retry; - } -/*FALLTHRU*/ -default : +if (error)return error; - } - -if (end_fsb != orig_end_fsb) -xfs_inode_set_cowblocks_tag (ip);trace_xfs_reflink_cow_alloc (ip, &got);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 187/206 xfs: use new extent lookup helpers xfs_file_iomap_begin_delay
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
commit 656152e552e5cbe0c11ad261b524376217c2fb13 upstream.
And only lookup the previous extent inside xfs_iomap_prealloc_size if we actually need it.
--- fs/xfs/xfs_iomap.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
fs/xfs/xfs_iomap.c +9 -11
@@ -395,11 +395,12 @@ xfs_iomap_prealloc_size(struct xfs_inode *ip, loff_t offset, loff_t count, - xfs_extnum_t idx, - struct xfs_bmbt_irec *prev) + xfs_extnum_t idx) { struct xfs_mount *mp = ip->i_mount; +struct xfs_ifork *ifp =XFS_IFORK_PTR (ip,XFS_DATA_FORK );xfs_fileoff_t offset_fsb =XFS_B_TO_FSBT (mp, offset); +struct xfs_bmbt_irec prev;int shift =0 ;int64_t freesp;xfs_fsblock_t qblocks;
@@ -419,8 +420,8 @@ xfs_iomap_prealloc_size(*/ if ((mp->m_flags &XFS_MOUNT_DFLT_IOSIZE ) ||XFS_ISIZE (ip) <XFS_FSB_TO_B (mp, mp->m_dalign) || - idx ==0 || - prev->br_startoff + prev->br_blockcount < offset_fsb) + !xfs_iext_get_extent (ifp, idx -1 , &prev) || + prev.br_startoff + prev.br_blockcount < offset_fsb)return mp->m_writeio_blocks;/*
@@ -439,8 +440,8 @@ xfs_iomap_prealloc_size(* always extends to MAXEXTLEN rather than falling short due to things * like stripe unit/width alignment of real extents. */ -if (prev->br_blockcount <= (MAXEXTLEN >>1 )) - alloc_blocks = prev->br_blockcount <<1 ; +if (prev.br_blockcount <= (MAXEXTLEN >>1 )) + alloc_blocks = prev.br_blockcount <<1 ;else alloc_blocks =XFS_B_TO_FSB (mp, offset);if (!alloc_blocks)
@@ -538,7 +539,6 @@ xfs_file_iomap_begin_delay(xfs_fileoff_t end_fsb, orig_end_fsb;int error =0 , eof =0 ;struct xfs_bmbt_irec got; -struct xfs_bmbt_irec prev;xfs_extnum_t idx;ASSERT (!XFS_IS_REALTIME_INODE (ip));
@@ -563,8 +563,7 @@ xfs_file_iomap_begin_delay( goto out_unlock; } -xfs_bmap_search_extents (ip, offset_fsb,XFS_DATA_FORK , &eof, &idx, - &got, &prev); + eof = !xfs_iext_lookup_extent (ip, ifp, offset_fsb, &idx, &got);if (!eof && got.br_startoff <= offset_fsb) {if (xfs_is_reflink_inode (ip)) {bool shared;
@@ -601,8 +600,7 @@ xfs_file_iomap_begin_delay(if (eof) {xfs_fsblock_t prealloc_blocks; - prealloc_blocks = -xfs_iomap_prealloc_size (ip, offset, count, idx, &prev); + prealloc_blocks =xfs_iomap_prealloc_size (ip, offset, count, idx);if (prealloc_blocks) {xfs_extlen_t align;xfs_off_t end_offset;
Greg Kroah-Hartman
maintainerPATCH 188/206 xfs: pass post-eof speculative prealloc blocks to bmapi
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Foster <[email protected]>
commit f782088c9e5d08e9494c63e68b4e85716df3e5f8 upstream.
xfs_file_iomap_begin_delay() implements post-eof speculative preallocation by extending the block count of the requested delayed allocation. Now that xfs_bmapi_reserve_delalloc() has been updated to handle prealloc blocks separately and tag the inode, update xfs_file_iomap_begin_delay() to use the new parameter and rely on the former to tag the inode.
Note that this patch does not change behavior.
--- fs/xfs/xfs_iomap.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-)
fs/xfs/xfs_iomap.c +13 -20
@@ -536,10 +536,11 @@ xfs_file_iomap_begin_delay(xfs_fileoff_t offset_fsb =XFS_B_TO_FSBT (mp, offset);xfs_fileoff_t maxbytes_fsb =XFS_B_TO_FSB (mp, mp->m_super->s_maxbytes); -xfs_fileoff_t end_fsb, orig_end_fsb; +xfs_fileoff_t end_fsb;int error =0 , eof =0 ;struct xfs_bmbt_irec got;xfs_extnum_t idx; +xfs_fsblock_t prealloc_blocks =0 ;ASSERT (!XFS_IS_REALTIME_INODE (ip));ASSERT (!xfs_get_extsz_hint (ip));
@@ -594,33 +595,32 @@ xfs_file_iomap_begin_delay(* the lower level functions are updated. */ count =min_t (loff_t, count,1024 *PAGE_SIZE ); - end_fsb = orig_end_fsb = -min (XFS_B_TO_FSB (mp, offset + count), maxbytes_fsb); + end_fsb =min (XFS_B_TO_FSB (mp, offset + count), maxbytes_fsb);if (eof) { -xfs_fsblock_t prealloc_blocks; - prealloc_blocks =xfs_iomap_prealloc_size (ip, offset, count, idx);if (prealloc_blocks) {xfs_extlen_t align;xfs_off_t end_offset; +xfs_fileoff_t p_end_fsb; end_offset =XFS_WRITEIO_ALIGN (mp, offset + count -1 ); - end_fsb =XFS_B_TO_FSBT (mp, end_offset) + - prealloc_blocks; + p_end_fsb =XFS_B_TO_FSBT (mp, end_offset) + + prealloc_blocks; align =xfs_eof_alignment (ip,0 );if (align) - end_fsb =roundup_64 (end_fsb, align); + p_end_fsb =roundup_64 (p_end_fsb, align); - end_fsb =min (end_fsb, maxbytes_fsb); -ASSERT (end_fsb > offset_fsb); + p_end_fsb =min (p_end_fsb, maxbytes_fsb); +ASSERT (p_end_fsb > offset_fsb); + prealloc_blocks = p_end_fsb - end_fsb; } } retry: error =xfs_bmapi_reserve_delalloc (ip,XFS_DATA_FORK , offset_fsb, - end_fsb - offset_fsb,0 , &got, &idx, eof); + end_fsb - offset_fsb, prealloc_blocks, &got, &idx, eof);switch (error) {case 0 :break ;
@@ -628,8 +628,8 @@ retry:case -EDQUOT :/* retry without any preallocation */ trace_xfs_delalloc_enospc (ip, offset, count); -if (end_fsb != orig_end_fsb) { - end_fsb = orig_end_fsb; +if (prealloc_blocks) { + prealloc_blocks =0 ; goto retry; }/*FALLTHRU*/
@@ -637,13 +637,6 @@ retry: goto out_unlock; } -/* -* Tag the inode as speculatively preallocated so we can reclaim this -* space on demand, if necessary. -*/ -if (end_fsb != orig_end_fsb) -xfs_inode_set_eofblocks_tag (ip); -trace_xfs_iomap_alloc (ip, offset, count,0 , &got); done:if (isnullstartblock (got.br_startblock))
Greg Kroah-Hartman
maintainerPATCH 189/206 xfs: Move AGI buffer type setting to xfs_read_agi
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Sandeen <[email protected]>
commit 200237d6746faaeaf7f4ff4abbf13f3917cee60a upstream.
We've missed properly setting the buffer type for an AGI transaction in 3 spots now, so just move it into xfs_read_agi() and set it if we are in a transaction to avoid the problem in the future.
This is similar to how it is done in i.e. the dir3 and attr3 read functions.
--- fs/xfs/libxfs/xfs_ialloc.c | 4 ++-- fs/xfs/xfs_inode.c | 2 -- fs/xfs/xfs_log_recover.c | 1 - 3 files changed, 2 insertions(+), 5 deletions(-)
fs/xfs/libxfs/xfs_ialloc.c +2 -2
@@ -2450,8 +2450,6 @@ xfs_ialloc_log_agi(ASSERT (agi->agi_magicnum ==cpu_to_be32 (XFS_AGI_MAGIC ));#endif -xfs_trans_buf_set_type (tp, bp,XFS_BLFT_AGI_BUF ); -/* * Compute byte offsets for the first and last fields in the first * region and log the agi buffer. This only logs up through
@@ -2592,6 +2590,8 @@ xfs_read_agi( XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops);if (error)return error; +if (tp) +xfs_trans_buf_set_type (tp, *bpp,XFS_BLFT_AGI_BUF );xfs_buf_set_ref (*bpp,XFS_AGI_REF );return 0 ;
fs/xfs/xfs_inode.c +0 -2
@@ -2041,7 +2041,6 @@ xfs_iunlink( agi->agi_unlinked[bucket_index] =cpu_to_be32 (agino); offset = offsetof(xfs_agi_t , agi_unlinked) + (sizeof (xfs_agino_t) * bucket_index); -xfs_trans_buf_set_type (tp, agibp,XFS_BLFT_AGI_BUF );xfs_trans_log_buf (tp, agibp, offset, (offset +sizeof (xfs_agino_t) -1 ));return 0 ;
@@ -2133,7 +2132,6 @@ xfs_iunlink_remove( agi->agi_unlinked[bucket_index] =cpu_to_be32 (next_agino); offset = offsetof(xfs_agi_t , agi_unlinked) + (sizeof (xfs_agino_t) * bucket_index); -xfs_trans_buf_set_type (tp, agibp,XFS_BLFT_AGI_BUF );xfs_trans_log_buf (tp, agibp, offset, (offset +sizeof (xfs_agino_t) -1 )); }else {
fs/xfs/xfs_log_recover.c +0 -1
@@ -4929,7 +4929,6 @@ xlog_recover_clear_agi_bucket( agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); offset = offsetof(xfs_agi_t , agi_unlinked) + (sizeof (xfs_agino_t) * bucket); -xfs_trans_buf_set_type (tp, agibp,XFS_BLFT_AGI_BUF );xfs_trans_log_buf (tp, agibp, offset, (offset +sizeof (xfs_agino_t) -1 ));
Greg Kroah-Hartman
maintainerPATCH 190/206 xfs: pass state not whichfork to trace_xfs_extlist
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Sandeen <[email protected]>
commit 7710517fc37b1899722707883b54694ea710b3c0 upstream.
When xfs_bmap_trace_exlist called trace_xfs_extlist, it sent in the "whichfork" var instead of the bmap "state" as expected (even though state was already set up for this purpose).
As a result, the xfs_bmap_class in tracing code used "whichfork" not state in xfs_iext_state_to_fork(), and got the wrong ifork pointer. It all goes downhill from there, including an ASSERT when ifp_bytes is empty by the time it reaches xfs_iext_get_ext():
XFS: Assertion failed: idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)
--- fs/xfs/libxfs/xfs_bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/libxfs/xfs_bmap.c +1 -1
@@ -531,7 +531,7 @@ xfs_bmap_trace_exlist( ifp =XFS_IFORK_PTR (ip, whichfork);ASSERT (cnt ==xfs_iext_count (ifp));for (idx =0 ; idx < cnt; idx++) -trace_xfs_extlist (ip, idx, whichfork, caller_ip); +trace_xfs_extlist (ip, idx, state, caller_ip); }/*
Greg Kroah-Hartman
maintainerPATCH 191/206 xfs: handle cow fork in xfs_bmap_trace_exlist
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Sandeen <[email protected]>
commit c44a1f22626c153976289e1cd67bdcdfefc16e1f upstream.
By inspection, xfs_bmap_trace_exlist isn't handling cow forks, and will trace the data fork instead.
Fix this by setting state appropriately if whichfork == XFS_COW_FORK.
()___()
< @ @ >
| |
{o_o}
(|)
--- fs/xfs/libxfs/xfs_bmap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_bmap.c +3 -1
@@ -518,7 +518,7 @@ voidxfs_bmap_trace_exlist ( xfs_inode_t *ip,/* incore inode pointer */ xfs_extnum_t cnt, /* count of entries in the list */ - int whichfork, /* data or attr fork */ + int whichfork, /* data or attr or cow fork */ unsigned long caller_ip) {xfs_extnum_t idx;/* extent record index */
@@ -527,6 +527,8 @@ xfs_bmap_trace_exlist(if (whichfork ==XFS_ATTR_FORK ) state |=BMAP_ATTRFORK ; +else if (whichfork ==XFS_COW_FORK ) + state |=BMAP_COWFORK ; ifp =XFS_IFORK_PTR (ip, whichfork);ASSERT (cnt ==xfs_iext_count (ifp));
Greg Kroah-Hartman
maintainerPATCH 192/206 xfs: forbid AG btrees with level == 0
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit d2a047f31e86941fa896e0e3271536d50aba415e upstream.
There is no such thing as a zero-level AG btree since even a single-node zero-records btree has one level. Btree cursor constructors read cur_nlevels straight from disk and then access things like cur_bufs[cur_nlevels - 1] which is /really/ bad if cur_nlevels is zero! Therefore, strengthen the verifiers to prevent this possibility.
--- fs/xfs/libxfs/xfs_alloc.c | 10 +++++++--- fs/xfs/libxfs/xfs_ialloc.c | 9 ++++++++- 2 files changed, 15 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_alloc.c +7 -3
@@ -2455,12 +2455,15 @@ xfs_agf_verify( be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))return false; -if (be32_to_cpu (agf->agf_levels[XFS_BTNUM_BNO ]) >XFS_BTREE_MAXLEVELS || +if (be32_to_cpu (agf->agf_levels[XFS_BTNUM_BNO ]) <1 || +be32_to_cpu (agf->agf_levels[XFS_BTNUM_CNT ]) <1 || +be32_to_cpu (agf->agf_levels[XFS_BTNUM_BNO ]) >XFS_BTREE_MAXLEVELS ||be32_to_cpu (agf->agf_levels[XFS_BTNUM_CNT ]) >XFS_BTREE_MAXLEVELS )return false;if (xfs_sb_version_hasrmapbt (&mp->m_sb) && -be32_to_cpu (agf->agf_levels[XFS_BTNUM_RMAP ]) >XFS_BTREE_MAXLEVELS ) + (be32_to_cpu (agf->agf_levels[XFS_BTNUM_RMAP ]) <1 || +be32_to_cpu (agf->agf_levels[XFS_BTNUM_RMAP ]) >XFS_BTREE_MAXLEVELS ))return false;/*
@@ -2477,7 +2480,8 @@ xfs_agf_verify(return false;if (xfs_sb_version_hasreflink (&mp->m_sb) && -be32_to_cpu (agf->agf_refcount_level) >XFS_BTREE_MAXLEVELS ) + (be32_to_cpu (agf->agf_refcount_level) <1 || +be32_to_cpu (agf->agf_refcount_level) >XFS_BTREE_MAXLEVELS ))return false;return true;;
fs/xfs/libxfs/xfs_ialloc.c +8 -1
@@ -2510,8 +2510,15 @@ xfs_agi_verify(if (!XFS_AGI_GOOD_VERSION (be32_to_cpu (agi->agi_versionnum)))return false; -if (be32_to_cpu (agi->agi_level) >XFS_BTREE_MAXLEVELS ) +if (be32_to_cpu (agi->agi_level) <1 || +be32_to_cpu (agi->agi_level) >XFS_BTREE_MAXLEVELS )return false; + +if (xfs_sb_version_hasfinobt (&mp->m_sb) && + (be32_to_cpu (agi->agi_free_level) <1 || +be32_to_cpu (agi->agi_free_level) >XFS_BTREE_MAXLEVELS )) +return false; +/* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't
Greg Kroah-Hartman
maintainerPATCH 193/206 xfs: check for bogus values in btree block headers
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit bb3be7e7c1c18e1b141d4cadeb98cc89ecf78099 upstream.
When we're reading a btree block, make sure that what we retrieved matches the owner and level; and has a plausible number of records.
--- fs/xfs/libxfs/xfs_btree.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
fs/xfs/libxfs/xfs_btree.c +20 -0
@@ -1769,8 +1769,28 @@ xfs_btree_lookup_get_block(if (error)return error; +/* Check the inode owner since the verifiers don't. */ +if (xfs_sb_version_hascrc (&cur->bc_mp->m_sb) && + (cur->bc_flags &XFS_BTREE_LONG_PTRS ) && +be64_to_cpu ((*blkp)->bb_u.l.bb_owner) != + cur->bc_private.b.ip->i_ino) + goto out_bad; + +/* Did we get the level we were looking for? */ +if (be16_to_cpu ((*blkp)->bb_level) != level) + goto out_bad; + +/* Check that internal nodes have at least one record. */ +if (level !=0 &&be16_to_cpu ((*blkp)->bb_numrecs) ==0 ) + goto out_bad; +xfs_btree_setbuf (cur, level, bp);return 0 ; + +out_bad: + *blkp =NULL ; +xfs_trans_brelse (cur->bc_tp, bp); +return -EFSCORRUPTED ; }/*
Greg Kroah-Hartman
maintainerPATCH 194/206 xfs: complain if we dont get nextents bmap records
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 356a3225222e5bc4df88aef3419fb6424f18ab69 upstream.
When reading into memory all extents of a btree-format inode fork, complain if the number of extents we find is not the same as the number of extents reported in the inode core. This is needed to stop an IO action from accessing the garbage areas of the in-core fork.
[dchinner: removed redundant assert]
--- fs/xfs/libxfs/xfs_bmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_bmap.c +2 -1
@@ -1377,8 +1377,9 @@ xfs_bmap_read_extents(return error; block =XFS_BUF_TO_BLOCK (bp); } +if (i !=XFS_IFORK_NEXTENTS (ip, whichfork)) +return -EFSCORRUPTED ;ASSERT (i ==xfs_iext_count (ifp)); -ASSERT (i ==XFS_IFORK_NEXTENTS (ip, whichfork));XFS_BMAP_TRACE_EXLIST (ip, i, whichfork);return 0 ; error0:
Greg Kroah-Hartman
maintainerPATCH 195/206 xfs: dont crash if reading a directory results in an unexpected hole
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 96a3aefb8ffde23180130460b0b2407b328eb727 upstream.
In xfs_dir3_data_read, we can encounter the situation where err == 0 and *bpp == NULL if the given bno offset happens to be a hole; this leads to a crash if we try to set the buffer type after the _da_read_buf call. Holes can happen due to corrupt or malicious entries in the bmbt data, so be a little more careful when we're handling buffers.
--- fs/xfs/libxfs/xfs_dir2_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/libxfs/xfs_dir2_data.c +1 -1
@@ -329,7 +329,7 @@ xfs_dir3_data_read( err =xfs_da_read_buf (tp, dp, bno, mapped_bno, bpp,XFS_DATA_FORK , &xfs_dir3_data_buf_ops); -if (!err && tp) +if (!err && tp && *bpp)xfs_trans_buf_set_type (tp, *bpp,XFS_BLFT_DIR_DATA_BUF );return err; }
Greg Kroah-Hartman
maintainerPATCH 196/206 xfs: error out if trying to add attrs and anextents > 0
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 0f352f8ee8412bd9d34fb2a6411241da61175c0e upstream.
We shouldn't assert if somehow we end up trying to add an attr fork to an inode that apparently already has attr extents because this is an indication of on-disk corruption. Instead, return an error code to userspace.
--- fs/xfs/libxfs/xfs_bmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_bmap.c +4 -1
@@ -1153,6 +1153,10 @@ xfs_bmap_add_attrfork( goto trans_cancel;if (XFS_IFORK_Q (ip)) goto trans_cancel; +if (ip->i_d.di_anextents !=0 ) { + error = -EFSCORRUPTED ; + goto trans_cancel; + }if (ip->i_d.di_aformat !=XFS_DINODE_FMT_EXTENTS ) {/* * For inodes coming from pre-6.2 filesystems.
@@ -1160,7 +1164,6 @@ xfs_bmap_add_attrfork(ASSERT (ip->i_d.di_aformat ==0 ); ip->i_d.di_aformat =XFS_DINODE_FMT_EXTENTS ; } -ASSERT (ip->i_d.di_anextents ==0 );xfs_trans_ijoin (tp, ip,0 );xfs_trans_log_inode (tp, ip,XFS_ILOG_CORE );
Greg Kroah-Hartman
maintainerPATCH 197/206 xfs: dont allow di_size with high bit set
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit ef388e2054feedaeb05399ed654bdb06f385d294 upstream.
The on-disk field di_size is used to set i_size, which is a signed integer of loff_t. If the high bit of di_size is set, we'll end up with a negative i_size, which will cause all sorts of problems. Since the VFS won't let us create a file with such length, we should catch them here in the verifier too.
--- fs/xfs/libxfs/xfs_inode_buf.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/xfs/libxfs/xfs_inode_buf.c +8 -0
@@ -392,6 +392,14 @@ xfs_dinode_verify(if (dip->di_magic !=cpu_to_be16 (XFS_DINODE_MAGIC ))return false; +/* don't allow invalid i_size */ +if (be64_to_cpu (dip->di_size) & (1ULL <<63 )) +return false; + +/* No zero-length symlinks. */ +if (S_ISLNK (be16_to_cpu (dip->di_mode)) && dip->di_size ==0 ) +return false; +/* only version 3 or greater inodes are extensively verified here */ if (dip->di_version <3 )return true;
Greg Kroah-Hartman
maintainerPATCH 198/206 xfs: dont cap maximum dedupe request length
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 1bb33a98702d8360947f18a44349df75ba555d5d upstream.
After various discussions on linux-fsdevel, it has been decided that it is not necessary to cap the length of a dedupe request, and that correctly-written userspace client programs will be able to absorb the change. Therefore, remove the length clamping behavior.
--- fs/xfs/xfs_file.c | 9 --------- 1 file changed, 9 deletions(-)
fs/xfs/xfs_file.c +0 -9
@@ -939,7 +939,6 @@ xfs_file_clone_range( len, false); } -#define XFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) STATIC ssize_t xfs_file_dedupe_range( struct file *src_file,
@@ -950,14 +949,6 @@ xfs_file_dedupe_range( {int error; -/* -* Limit the total length we will dedupe for each operation. -* This is intended to bound the total time spent in this -* ioctl to something sane. -*/ -if (len >XFS_MAX_DEDUPE_LEN ) - len =XFS_MAX_DEDUPE_LEN ; - error =xfs_reflink_remap_range (src_file, loff, dst_file, dst_loff, len, true);if (error)
Greg Kroah-Hartman
maintainerPATCH 199/206 xfs: ignore leaf attr ichdr.count in verifier during log replay
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Sandeen <[email protected]>
commit 2e1d23370e75d7d89350d41b4ab58c7f6a0e26b2 upstream.
When we create a new attribute, we first create a shortform attribute, and try to fit the new attribute into it.
If that fails, we copy the (empty) attribute into a leaf attribute, and do the copy again. Thus there can be a transient state where we have an empty leaf attribute.
If we encounter this during log replay, the verifier will fail. So add a test to ignore this part of the leaf attr verification during log replay.
Thanks as usual to dchinner for spotting the problem.
--- fs/xfs/libxfs/xfs_attr_leaf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_attr_leaf.c +7 -1
@@ -253,6 +253,7 @@ xfs_attr3_leaf_verify( {struct xfs_mount *mp = bp->b_target->bt_mount;struct xfs_attr_leafblock *leaf = bp->b_addr; +struct xfs_perag *pag = bp->b_pag;struct xfs_attr3_icleaf_hdr ichdr;xfs_attr3_leaf_hdr_from_disk (mp->m_attr_geo, &ichdr, leaf);
@@ -273,7 +274,12 @@ xfs_attr3_leaf_verify(if (ichdr.magic !=XFS_ATTR_LEAF_MAGIC )return false; } -if (ichdr.count ==0 ) +/* +* In recovery there is a transient state where count == 0 is valid +* because we may have transitioned an empty shortform attr to a leaf +* if the attr didn't fit in shortform. +*/ +if (pag && pag->pagf_init && ichdr.count ==0 )return false;/* XXX: need to range check rest of attr header values */
Greg Kroah-Hartman
maintainerPATCH 200/206 xfs: use GPF_NOFS when allocating btree cursors
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit b24a978c377be5f14e798cb41238e66fe51aab2f upstream.
Use NOFS for allocating btree cursors, since they can be called under the ilock.
--- fs/xfs/libxfs/xfs_alloc_btree.c | 2 +- fs/xfs/libxfs/xfs_bmap_btree.c | 2 +- fs/xfs/libxfs/xfs_ialloc_btree.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_alloc_btree.c +1 -1
@@ -421,7 +421,7 @@ xfs_allocbt_init_cursor(ASSERT (btnum ==XFS_BTNUM_BNO || btnum ==XFS_BTNUM_CNT ); - cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_SLEEP ); + cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_NOFS ); cur->bc_tp = tp; cur->bc_mp = mp;
fs/xfs/libxfs/xfs_bmap_btree.c +1 -1
@@ -796,7 +796,7 @@ xfs_bmbt_init_cursor(struct xfs_btree_cur *cur;ASSERT (whichfork !=XFS_COW_FORK ); - cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_SLEEP ); + cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_NOFS ); cur->bc_tp = tp; cur->bc_mp = mp;
fs/xfs/libxfs/xfs_ialloc_btree.c +1 -1
@@ -357,7 +357,7 @@ xfs_inobt_init_cursor(struct xfs_agi *agi =XFS_BUF_TO_AGI (agbp);struct xfs_btree_cur *cur; - cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_SLEEP ); + cur =kmem_zone_zalloc (xfs_btree_cur_zone,KM_NOFS ); cur->bc_tp = tp; cur->bc_mp = mp;
Greg Kroah-Hartman
maintainerPATCH 201/206 xfs: fix double-cleanup when CUI recovery fails
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 7a21272b088894070391a94fdd1c67014020fa1d upstream.
Dan Carpenter reported a double-free of rcur if _defer_finish fails while we're recovering CUI items. Fix the error recovery to prevent this.
--- fs/xfs/xfs_refcount_item.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/xfs/xfs_refcount_item.c +2 -1
@@ -526,13 +526,14 @@ xfs_cui_recover(xfs_refcount_finish_one_cleanup (tp, rcur, error); error =xfs_defer_finish (&tp, &dfops,NULL );if (error) - goto abort_error; + goto abort_defer;set_bit (XFS_CUI_RECOVERED , &cuip->cui_flags); error =xfs_trans_commit (tp);return error; abort_error:xfs_refcount_finish_one_cleanup (tp, rcur, error); +abort_defer:xfs_defer_cancel (&dfops);xfs_trans_cancel (tp);return error;
Greg Kroah-Hartman
maintainerPATCH 202/206 xfs: use the actual AG length when reserving blocks
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
commit 20e73b000bcded44a91b79429d8fa743247602ad upstream.
We need to use the actual AG length when making per-AG reservations, since we could otherwise end up reserving more blocks out of the last AG than there are actual blocks.
--- fs/xfs/libxfs/xfs_ag_resv.c | 3 +++ fs/xfs/libxfs/xfs_refcount_btree.c | 9 ++++++--- fs/xfs/libxfs/xfs_refcount_btree.h | 3 ++- fs/xfs/libxfs/xfs_rmap_btree.c | 14 +++++++------- fs/xfs/libxfs/xfs_rmap_btree.h | 3 ++- fs/xfs/xfs_fsops.c | 14 ++++++++++++++ 6 files changed, 34 insertions(+), 12 deletions(-)
fs/xfs/libxfs/xfs_ag_resv.c +3 -0
@@ -256,6 +256,9 @@ xfs_ag_resv_init( goto out; } +ASSERT (xfs_perag_resv (pag,XFS_AG_RESV_METADATA )->ar_reserved + +xfs_perag_resv (pag,XFS_AG_RESV_AGFL )->ar_reserved <= + pag->pagf_freeblks + pag->pagf_flcount); out:return error; }
fs/xfs/libxfs/xfs_refcount_btree.c +6 -3
@@ -408,13 +408,14 @@ xfs_refcountbt_calc_size(*/ xfs_extlen_t xfs_refcountbt_max_size ( -struct xfs_mount *mp) +struct xfs_mount *mp, +xfs_agblock_t agblocks) {/* Bail out if we're uninitialized, which can happen in mkfs. */ if (mp->m_refc_mxr[0 ] ==0 )return 0 ; -return xfs_refcountbt_calc_size (mp, mp->m_sb.sb_agblocks); +return xfs_refcountbt_calc_size (mp, agblocks); }/*
@@ -429,22 +430,24 @@ xfs_refcountbt_calc_reserves( {struct xfs_buf *agbp;struct xfs_agf *agf; +xfs_agblock_t agblocks;xfs_extlen_t tree_len;int error;if (!xfs_sb_version_hasreflink (&mp->m_sb))return 0 ; - *ask +=xfs_refcountbt_max_size (mp); error =xfs_alloc_read_agf (mp,NULL , agno,0 , &agbp);if (error)return error; agf =XFS_BUF_TO_AGF (agbp); + agblocks =be32_to_cpu (agf->agf_length); tree_len =be32_to_cpu (agf->agf_refcount_blocks);xfs_buf_relse (agbp); + *ask +=xfs_refcountbt_max_size (mp, agblocks); *used += tree_len;return error;
fs/xfs/libxfs/xfs_refcount_btree.h +2 -1
@@ -66,7 +66,8 @@ extern void xfs_refcountbt_compute_maxleextern xfs_extlen_t xfs_refcountbt_calc_size (struct xfs_mount *mp,unsigned long long len); -extern xfs_extlen_t xfs_refcountbt_max_size (struct xfs_mount *mp); +extern xfs_extlen_t xfs_refcountbt_max_size (struct xfs_mount *mp, +xfs_agblock_t agblocks);extern int xfs_refcountbt_calc_reserves (struct xfs_mount *mp,xfs_agnumber_t agno,xfs_extlen_t *ask,xfs_extlen_t *used);
fs/xfs/libxfs/xfs_rmap_btree.c +7 -7
@@ -549,13 +549,14 @@ xfs_rmapbt_calc_size(*/ xfs_extlen_t xfs_rmapbt_max_size ( -struct xfs_mount *mp) +struct xfs_mount *mp, +xfs_agblock_t agblocks) {/* Bail out if we're uninitialized, which can happen in mkfs. */ if (mp->m_rmap_mxr[0 ] ==0 )return 0 ; -return xfs_rmapbt_calc_size (mp, mp->m_sb.sb_agblocks); +return xfs_rmapbt_calc_size (mp, agblocks); }/*
@@ -570,25 +571,24 @@ xfs_rmapbt_calc_reserves( {struct xfs_buf *agbp;struct xfs_agf *agf; -xfs_extlen_t pool_len; +xfs_agblock_t agblocks;xfs_extlen_t tree_len;int error;if (!xfs_sb_version_hasrmapbt (&mp->m_sb))return 0 ; -/* Reserve 1% of the AG or enough for 1 block per record. */ - pool_len =max (mp->m_sb.sb_agblocks /100 ,xfs_rmapbt_max_size (mp)); - *ask += pool_len; - error =xfs_alloc_read_agf (mp,NULL , agno,0 , &agbp);if (error)return error; agf =XFS_BUF_TO_AGF (agbp); + agblocks =be32_to_cpu (agf->agf_length); tree_len =be32_to_cpu (agf->agf_rmap_blocks);xfs_buf_relse (agbp); +/* Reserve 1% of the AG or enough for 1 block per record. */ + *ask +=max (agblocks /100 ,xfs_rmapbt_max_size (mp, agblocks)); *used += tree_len;return error;
fs/xfs/libxfs/xfs_rmap_btree.h +2 -1
@@ -60,7 +60,8 @@ extern void xfs_rmapbt_compute_maxlevelsextern xfs_extlen_t xfs_rmapbt_calc_size (struct xfs_mount *mp,unsigned long long len); -extern xfs_extlen_t xfs_rmapbt_max_size (struct xfs_mount *mp); +extern xfs_extlen_t xfs_rmapbt_max_size (struct xfs_mount *mp, +xfs_agblock_t agblocks);extern int xfs_rmapbt_calc_reserves (struct xfs_mount *mp,xfs_agnumber_t agno,xfs_extlen_t *ask,xfs_extlen_t *used);
fs/xfs/xfs_fsops.c +14 -0
@@ -631,6 +631,20 @@ xfs_growfs_data_private(xfs_set_low_space_thresholds (mp); mp->m_alloc_set_aside =xfs_alloc_set_aside (mp); +/* +* If we expanded the last AG, free the per-AG reservation +* so we can reinitialize it with the new size. +*/ +if (new) { +struct xfs_perag *pag; + + pag =xfs_perag_get (mp, agno); + error =xfs_ag_resv_free (pag); +xfs_perag_put (pag); +if (error) + goto out; + } +/* Reserve AG metadata blocks. */ error =xfs_fs_reserve_ag_blocks (mp);if (error && error != -ENOSPC )
Greg Kroah-Hartman
maintainerPATCH 203/206 xfs: fix crash and data corruption due to removal of busy COW extents
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
commit a1b7a4dea6166cf46be895bce4aac67ea5160fe8 upstream.
There is a race window between write_cache_pages calling clear_page_dirty_for_io and XFS calling set_page_writeback, in which the mapping for an inode is tagged neither as dirty, nor as writeback.
If the COW shrinker hits in exactly that window we'll remove the delayed COW extents and writepages trying to write it back, which in release kernels will manifest as corruption of the bmap btree, and in debug kernels will trip the ASSERT about now calling xfs_bmapi_write with the COWFORK flag for holes. A complex customer load manages to hit this window fairly reliably, probably by always having COW writeback in flight while the cow shrinker runs.
This patch adds another check for having the I_DIRTY_PAGES flag set, which is still set during this race window. While this fixes the problem I'm still not overly happy about the way the COW shrinker works as it still seems a bit fragile.
--- fs/xfs/xfs_icache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/xfs/xfs_icache.c +2 -1
@@ -1599,7 +1599,8 @@ xfs_inode_free_cowblocks(* If the mapping is dirty or under writeback we cannot touch the * CoW fork. Leave it alone if we're in the midst of a directio. */ -if (mapping_tagged (VFS_I (ip)->i_mapping,PAGECACHE_TAG_DIRTY ) || +if ((VFS_I (ip)->i_state &I_DIRTY_PAGES ) || +mapping_tagged (VFS_I (ip)->i_mapping,PAGECACHE_TAG_DIRTY ) ||mapping_tagged (VFS_I (ip)->i_mapping,PAGECACHE_TAG_WRITEBACK ) ||atomic_read (&VFS_I (ip)->i_dio_count))return 0 ;
Greg Kroah-Hartman
maintainerPATCH 204/206 xfs: fix max_retries _show and _store functions
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Maiolino <[email protected]>
commit ff97f2399edac1e0fb3fa7851d5fbcbdf04717cf upstream.
max_retries _show and _store functions should test against cfg->max_retries, not cfg->retry_timeout
--- fs/xfs/xfs_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/xfs/xfs_sysfs.c +2 -2
@@ -396,7 +396,7 @@ max_retries_show(int retries;struct xfs_error_cfg *cfg =to_error_cfg (kobject); -if (cfg->retry_timeout ==XFS_ERR_RETRY_FOREVER ) +if (cfg->max_retries ==XFS_ERR_RETRY_FOREVER ) retries =-1 ;else retries = cfg->max_retries;
@@ -422,7 +422,7 @@ max_retries_store(return -EINVAL ;if (val ==-1 ) - cfg->retry_timeout =XFS_ERR_RETRY_FOREVER ; + cfg->max_retries =XFS_ERR_RETRY_FOREVER ;else cfg->max_retries = val;return count;
Greg Kroah-Hartman
maintainerPATCH 205/206 clocksource/dummy_timer: Move hotplug callback after the real timers
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 9bf11ecce5a2758e5a097c2f3a13d08552d0d6f9 upstream.
When the dummy timer callback is invoked before the real timer callbacks, then it tries to install that timer for the starting CPU. If the platform does not have a broadcast timer installed the installation fails with a kernel crash. The crash happens due to a unconditional deference of the non available broadcast device. This needs to be fixed in the timer core code.
But even when this is fixed in the core code then installing the dummy timer before the real timers is a pointless exercise.
Move it to the end of the callback list.
--- include/linux/cpuhotplug.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/linux/cpuhotplug.h +2 -1
@@ -80,7 +80,6 @@ enum cpuhp_state {CPUHP_AP_ARM_L2X0_STARTING ,CPUHP_AP_ARM_ARCH_TIMER_STARTING ,CPUHP_AP_ARM_GLOBAL_TIMER_STARTING , -CPUHP_AP_DUMMY_TIMER_STARTING ,CPUHP_AP_JCORE_TIMER_STARTING ,CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING , CPUHP_AP_ARM_TWD_STARTING,
@@ -94,6 +93,8 @@ enum cpuhp_state {CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING ,CPUHP_AP_KVM_ARM_VGIC_STARTING ,CPUHP_AP_KVM_ARM_TIMER_STARTING , +/* Must be the last timer callback */ +CPUHP_AP_DUMMY_TIMER_STARTING ,CPUHP_AP_ARM_XEN_STARTING ,CPUHP_AP_ARM_CORESIGHT_STARTING , CPUHP_AP_ARM_CORESIGHT4_STARTING,
Greg Kroah-Hartman
maintainerPATCH 206/206 tick/broadcast: Prevent NULL pointer dereference
In reply to Greg Kroah-Hartman4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit c1a9eeb938b5433947e5ea22f89baff3182e7075 upstream.
When a disfunctional timer, e.g. dummy timer, is installed, the tick core tries to setup the broadcast timer.
If no broadcast device is installed, the kernel crashes with a NULL pointer dereference in tick_broadcast_setup_oneshot() because the function has no sanity check.
--- kernel/time/tick-broadcast.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/time/tick-broadcast.c +3 -0
@@ -871,6 +871,9 @@ void tick_broadcast_setup_oneshot(struct {int cpu =smp_processor_id (); +if (!bc) +return ; +/* Set it up only once ! */ if (bc->event_handler != tick_handle_oneshot_broadcast) {int was_periodic =clockevent_state_periodic (bc);
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.9.3 release. There are 206 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu Jan 12 13:14:24 UTC 2017. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.9.3-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-4.9.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Signature · 5 lines
Shuah Khan Sr. Linux Kernel Developer Open Source Innovation Group Samsung Research America(Silicon Valley) [email protected]
Greg Kroah-Hartman
maintainerQuoted 15 lines · Shuah Khan
Quoted 14 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.9.3 release. There are 206 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu Jan 12 13:14:24 UTC 2017. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.9.3-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-4.9.y
and the diffstat can be found below.
Quoted 6 lines
Quoted 4 lines
thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
Great, thanks for testing these and letting me know.
greg k-h
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.9.3 release. There are 206 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu Jan 12 13:14:24 UTC 2017. Anything received after that time might be too late.
Build results:
total: 150 pass: 149 fail: 1 Failed builds: avr32:merisc_defconfig Qemu test results: total: 122 pass: 122 fail: 0
Details are available at http://kerneltests.org/builders.
Guenter
Greg Kroah-Hartman
maintainerQuoted 10 lines · Guenter Roeck
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.9.3 release. There are 206 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu Jan 12 13:14:24 UTC 2017. Anything received after that time might be too late.
Quoted 8 lines
Build results:
total: 150 pass: 149 fail: 1 Failed builds: avr32:merisc_defconfig Qemu test results: total: 122 pass: 122 fail: 0Details are available at http://kerneltests.org/builders.
This is the "known to fail" failure, correct?
Thanks for testing these and letting me know.
greg k-h
Quoted 18 lines · Greg Kroah-Hartman
Quoted 17 lines · Guenter Roeck
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.9.3 release. There are 206 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu Jan 12 13:14:24 UTC 2017. Anything received after that time might be too late.
Build results:
total: 150 pass: 149 fail: 1 Failed builds: avr32:merisc_defconfig Qemu test results: total: 122 pass: 122 fail: 0
Quoted 4 lines
Quoted 1 line
Details are available at http://kerneltests.org/builders.
This is the "known to fail" failure, correct?
Yes, sorry, I didn't bother to spell it out.
Guenter