Changed since last update:
- Fix indlen block reservation accounting bug when splitting delalloc extent - Fix warnings about unused variables that appeared in -rc1. - Don't spew errors when bmapping a local format directory - Fix an off-by-one error in a delalloc eof assertion - Make fsmap only return inode information for CAP_SYS_ADMIN - Fix a potential mount time deadlock recovering cow extents - Fix unaligned memory access in _btree_visit_blocks - Fix various SEEK_HOLE/SEEK_DATA bugs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJZJwnxAAoJEPh/dxk0SrTr/TMQAKP6OMsjYxpro+1Uif+oPTQ6 vvUfXJMWLKc07QI/czwLDY4A36h2TZjNxpBJypSfVumlD82ZPa8gp6XFWngwIUb4 3G+A9zq4Fviq8Vzz3G75C8Q49h8IpmU3SimTlhS1BIcxe+upu2qplzM3yc6/T4MB WTTqtjL3SaW5D2v0ZdPL9ulQKKAlL1WfbZV9dDJ4UiRw5Jlwj2Udg6HnbRvfrcZF IziYlidrTIt64ecA9GqR32soXqFBGPKo6Wp9Pk+iWLlsfM6qcCt1m+yfM1JonRGA wycygcrrjfR/lFHMQCGonLs1ajC6isLeMZ804P6OP2q6kfdtersedvY7XSoYsEJ4 ok4J3fiyqYgMGhPz7x0Y8IH9+gdudn7+fHiC5/RNkolEy8AbPPe21XhFDVxeTkCs 4GAHNGQfOEK2PT69Ya81taVzT/TpuIGIkUAaDH8vsfxwcVunM08/OffsCiinLMJx bt3G7fH3wJ+VuYJS92amj3k6n6EAeHYc0dAVGd5e8dtN25079nBm+EP0Wp+j8uVl PwaJjde68wxWUvuYXVK1a8vietRS7xChyta34cYcStd4wWu1knccpN/mjQnK/ucB 4etZspB1rQQx08KBqHVq8t508PA7nWtFxjE91JYkpvbyYym1WEH8Mz7rbVBI6NjS Y/8+uPhFq2BU1b9skj0U =pDjl -----END PGP SIGNATURE----- Merge tag 'xfs-4.12-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull XFS fixes from Darrick Wong: "A few miscellaneous bug fixes & cleanups: - Fix indlen block reservation accounting bug when splitting delalloc extent - Fix warnings about unused variables that appeared in -rc1. - Don't spew errors when bmapping a local format directory - Fix an off-by-one error in a delalloc eof assertion - Make fsmap only return inode information for CAP_SYS_ADMIN - Fix a potential mount time deadlock recovering cow extents - Fix unaligned memory access in _btree_visit_blocks - Fix various SEEK_HOLE/SEEK_DATA bugs" * tag 'xfs-4.12-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: Move handling of missing page into one place in xfs_find_get_desired_pgoff() xfs: Fix off-by-in in loop termination in xfs_find_get_desired_pgoff() xfs: Fix missed holes in SEEK_HOLE implementation xfs: fix off-by-one on max nr_pages in xfs_find_get_desired_pgoff() xfs: fix unaligned access in xfs_btree_visit_blocks xfs: avoid mount-time deadlock in CoW extent recovery xfs: only return detailed fsmap info if the caller has CAP_SYS_ADMIN xfs: bad assertion for delalloc an extent that start at i_size xfs: fix warnings about unused stack variables xfs: BMAPX shouldn't barf on inline-format directories xfs: fix indlen accounting error on partial delalloc conversion
This commit is contained in:
commit
cdbe020678
@ -1280,7 +1280,6 @@ xfs_bmap_read_extents(
|
||||
xfs_bmbt_rec_t *frp;
|
||||
xfs_fsblock_t nextbno;
|
||||
xfs_extnum_t num_recs;
|
||||
xfs_extnum_t start;
|
||||
|
||||
num_recs = xfs_btree_get_numrecs(block);
|
||||
if (unlikely(i + num_recs > room)) {
|
||||
@ -1303,7 +1302,6 @@ xfs_bmap_read_extents(
|
||||
* Copy records into the extent records.
|
||||
*/
|
||||
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
|
||||
start = i;
|
||||
for (j = 0; j < num_recs; j++, i++, frp++) {
|
||||
xfs_bmbt_rec_host_t *trp = xfs_iext_get_ext(ifp, i);
|
||||
trp->l0 = be64_to_cpu(frp->l0);
|
||||
@ -2065,8 +2063,10 @@ xfs_bmap_add_extent_delay_real(
|
||||
}
|
||||
temp = xfs_bmap_worst_indlen(bma->ip, temp);
|
||||
temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
|
||||
diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
|
||||
(bma->cur ? bma->cur->bc_private.b.allocated : 0));
|
||||
diff = (int)(temp + temp2 -
|
||||
(startblockval(PREV.br_startblock) -
|
||||
(bma->cur ?
|
||||
bma->cur->bc_private.b.allocated : 0)));
|
||||
if (diff > 0) {
|
||||
error = xfs_mod_fdblocks(bma->ip->i_mount,
|
||||
-((int64_t)diff), false);
|
||||
@ -2123,7 +2123,6 @@ xfs_bmap_add_extent_delay_real(
|
||||
temp = da_new;
|
||||
if (bma->cur)
|
||||
temp += bma->cur->bc_private.b.allocated;
|
||||
ASSERT(temp <= da_old);
|
||||
if (temp < da_old)
|
||||
xfs_mod_fdblocks(bma->ip->i_mount,
|
||||
(int64_t)(da_old - temp), false);
|
||||
|
@ -4395,7 +4395,7 @@ xfs_btree_visit_blocks(
|
||||
xfs_btree_readahead_ptr(cur, ptr, 1);
|
||||
|
||||
/* save for the next iteration of the loop */
|
||||
lptr = *ptr;
|
||||
xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
|
||||
}
|
||||
|
||||
/* for each buffer in the level */
|
||||
|
@ -1629,13 +1629,28 @@ xfs_refcount_recover_cow_leftovers(
|
||||
if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
|
||||
INIT_LIST_HEAD(&debris);
|
||||
|
||||
/*
|
||||
* In this first part, we use an empty transaction to gather up
|
||||
* all the leftover CoW extents so that we can subsequently
|
||||
* delete them. The empty transaction is used to avoid
|
||||
* a buffer lock deadlock if there happens to be a loop in the
|
||||
* refcountbt because we're allowed to re-grab a buffer that is
|
||||
* already attached to our transaction. When we're done
|
||||
* recording the CoW debris we cancel the (empty) transaction
|
||||
* and everything goes away cleanly.
|
||||
*/
|
||||
error = xfs_trans_alloc_empty(mp, &tp);
|
||||
if (error)
|
||||
return error;
|
||||
cur = xfs_refcountbt_init_cursor(mp, NULL, agbp, agno, NULL);
|
||||
|
||||
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
|
||||
if (error)
|
||||
goto out_trans;
|
||||
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
|
||||
|
||||
/* Find all the leftover CoW staging extents. */
|
||||
INIT_LIST_HEAD(&debris);
|
||||
memset(&low, 0, sizeof(low));
|
||||
memset(&high, 0, sizeof(high));
|
||||
low.rc.rc_startblock = XFS_REFC_COW_START;
|
||||
@ -1645,10 +1660,11 @@ xfs_refcount_recover_cow_leftovers(
|
||||
if (error)
|
||||
goto out_cursor;
|
||||
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
|
||||
xfs_buf_relse(agbp);
|
||||
xfs_trans_brelse(tp, agbp);
|
||||
xfs_trans_cancel(tp);
|
||||
|
||||
/* Now iterate the list to free the leftovers */
|
||||
list_for_each_entry(rr, &debris, rr_list) {
|
||||
list_for_each_entry_safe(rr, n, &debris, rr_list) {
|
||||
/* Set up transaction. */
|
||||
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp);
|
||||
if (error)
|
||||
@ -1676,8 +1692,16 @@ xfs_refcount_recover_cow_leftovers(
|
||||
error = xfs_trans_commit(tp);
|
||||
if (error)
|
||||
goto out_free;
|
||||
|
||||
list_del(&rr->rr_list);
|
||||
kmem_free(rr);
|
||||
}
|
||||
|
||||
return error;
|
||||
out_defer:
|
||||
xfs_defer_cancel(&dfops);
|
||||
out_trans:
|
||||
xfs_trans_cancel(tp);
|
||||
out_free:
|
||||
/* Free the leftover list */
|
||||
list_for_each_entry_safe(rr, n, &debris, rr_list) {
|
||||
@ -1688,11 +1712,6 @@ out_free:
|
||||
|
||||
out_cursor:
|
||||
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
|
||||
xfs_buf_relse(agbp);
|
||||
goto out_free;
|
||||
|
||||
out_defer:
|
||||
xfs_defer_cancel(&dfops);
|
||||
xfs_trans_cancel(tp);
|
||||
goto out_free;
|
||||
xfs_trans_brelse(tp, agbp);
|
||||
goto out_trans;
|
||||
}
|
||||
|
@ -582,9 +582,13 @@ xfs_getbmap(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Local format data forks report no extents. */
|
||||
if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
|
||||
bmv->bmv_entries = 0;
|
||||
return 0;
|
||||
}
|
||||
if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
|
||||
ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
|
||||
ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
|
||||
ip->i_d.di_format != XFS_DINODE_FMT_BTREE)
|
||||
return -EINVAL;
|
||||
|
||||
if (xfs_get_extsz_hint(ip) ||
|
||||
@ -712,7 +716,7 @@ xfs_getbmap(
|
||||
* extents.
|
||||
*/
|
||||
if (map[i].br_startblock == DELAYSTARTBLOCK &&
|
||||
map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
|
||||
map[i].br_startoff < XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
|
||||
ASSERT((iflags & BMV_IF_DELALLOC) != 0);
|
||||
|
||||
if (map[i].br_startblock == HOLESTARTBLOCK &&
|
||||
|
@ -1043,49 +1043,17 @@ xfs_find_get_desired_pgoff(
|
||||
|
||||
index = startoff >> PAGE_SHIFT;
|
||||
endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount);
|
||||
end = endoff >> PAGE_SHIFT;
|
||||
end = (endoff - 1) >> PAGE_SHIFT;
|
||||
do {
|
||||
int want;
|
||||
unsigned nr_pages;
|
||||
unsigned int i;
|
||||
|
||||
want = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
|
||||
want = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
|
||||
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
|
||||
want);
|
||||
/*
|
||||
* No page mapped into given range. If we are searching holes
|
||||
* and if this is the first time we got into the loop, it means
|
||||
* that the given offset is landed in a hole, return it.
|
||||
*
|
||||
* If we have already stepped through some block buffers to find
|
||||
* holes but they all contains data. In this case, the last
|
||||
* offset is already updated and pointed to the end of the last
|
||||
* mapped page, if it does not reach the endpoint to search,
|
||||
* that means there should be a hole between them.
|
||||
*/
|
||||
if (nr_pages == 0) {
|
||||
/* Data search found nothing */
|
||||
if (type == DATA_OFF)
|
||||
break;
|
||||
|
||||
ASSERT(type == HOLE_OFF);
|
||||
if (lastoff == startoff || lastoff < endoff) {
|
||||
found = true;
|
||||
*offset = lastoff;
|
||||
}
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* At lease we found one page. If this is the first time we
|
||||
* step into the loop, and if the first page index offset is
|
||||
* greater than the given search offset, a hole was found.
|
||||
*/
|
||||
if (type == HOLE_OFF && lastoff == startoff &&
|
||||
lastoff < page_offset(pvec.pages[0])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
@ -1098,18 +1066,18 @@ xfs_find_get_desired_pgoff(
|
||||
* file mapping. However, page->index will not change
|
||||
* because we have a reference on the page.
|
||||
*
|
||||
* Searching done if the page index is out of range.
|
||||
* If the current offset is not reaches the end of
|
||||
* the specified search range, there should be a hole
|
||||
* between them.
|
||||
* If current page offset is beyond where we've ended,
|
||||
* we've found a hole.
|
||||
*/
|
||||
if (page->index > end) {
|
||||
if (type == HOLE_OFF && lastoff < endoff) {
|
||||
*offset = lastoff;
|
||||
found = true;
|
||||
}
|
||||
if (type == HOLE_OFF && lastoff < endoff &&
|
||||
lastoff < page_offset(pvec.pages[i])) {
|
||||
found = true;
|
||||
*offset = lastoff;
|
||||
goto out;
|
||||
}
|
||||
/* Searching done if the page index is out of range. */
|
||||
if (page->index > end)
|
||||
goto out;
|
||||
|
||||
lock_page(page);
|
||||
/*
|
||||
@ -1151,21 +1119,20 @@ xfs_find_get_desired_pgoff(
|
||||
|
||||
/*
|
||||
* The number of returned pages less than our desired, search
|
||||
* done. In this case, nothing was found for searching data,
|
||||
* but we found a hole behind the last offset.
|
||||
* done.
|
||||
*/
|
||||
if (nr_pages < want) {
|
||||
if (type == HOLE_OFF) {
|
||||
*offset = lastoff;
|
||||
found = true;
|
||||
}
|
||||
if (nr_pages < want)
|
||||
break;
|
||||
}
|
||||
|
||||
index = pvec.pages[i - 1]->index + 1;
|
||||
pagevec_release(&pvec);
|
||||
} while (index <= end);
|
||||
|
||||
/* No page at lastoff and we are not done - we found a hole. */
|
||||
if (type == HOLE_OFF && lastoff < endoff) {
|
||||
*offset = lastoff;
|
||||
found = true;
|
||||
}
|
||||
out:
|
||||
pagevec_release(&pvec);
|
||||
return found;
|
||||
|
@ -828,6 +828,7 @@ xfs_getfsmap(
|
||||
struct xfs_fsmap dkeys[2]; /* per-dev keys */
|
||||
struct xfs_getfsmap_dev handlers[XFS_GETFSMAP_DEVS];
|
||||
struct xfs_getfsmap_info info = { NULL };
|
||||
bool use_rmap;
|
||||
int i;
|
||||
int error = 0;
|
||||
|
||||
@ -837,12 +838,14 @@ xfs_getfsmap(
|
||||
!xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[1]))
|
||||
return -EINVAL;
|
||||
|
||||
use_rmap = capable(CAP_SYS_ADMIN) &&
|
||||
xfs_sb_version_hasrmapbt(&mp->m_sb);
|
||||
head->fmh_entries = 0;
|
||||
|
||||
/* Set up our device handlers. */
|
||||
memset(handlers, 0, sizeof(handlers));
|
||||
handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
|
||||
if (xfs_sb_version_hasrmapbt(&mp->m_sb))
|
||||
if (use_rmap)
|
||||
handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
|
||||
else
|
||||
handlers[0].fn = xfs_getfsmap_datadev_bnobt;
|
||||
|
Loading…
Reference in New Issue
Block a user