aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2016-11-23 19:41:59 -0500
committerDave Chinner <david@fromorbit.com>2016-11-23 19:41:59 -0500
commited24bee6f26b268669702cf7521756d9031383af (patch)
tree127ee4098f6b751aac3443e6ccee88bbe139d3f4
parent0fc204e2eb648ca31c80c8490178f70135807f05 (diff)
parent0e8d630ba039d9976d250eedb82c3a423ad15447 (diff)
Merge branch 'xfs-4.10-extent-lookup' into for-next
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c234
-rw-r--r--fs/xfs/libxfs/xfs_bmap.h7
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c46
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.h6
-rw-r--r--fs/xfs/libxfs/xfs_types.h1
-rw-r--r--fs/xfs/xfs_aops.c16
-rw-r--r--fs/xfs/xfs_iomap.c23
-rw-r--r--fs/xfs/xfs_reflink.c108
-rw-r--r--fs/xfs/xfs_reflink.h4
9 files changed, 178 insertions, 267 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 5c3c4dd14735..4a5b335c7bb3 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -1370,97 +1370,6 @@ error0:
1370 return -EFSCORRUPTED; 1370 return -EFSCORRUPTED;
1371} 1371}
1372 1372
1373
1374/*
1375 * Search the extent records for the entry containing block bno.
1376 * If bno lies in a hole, point to the next entry. If bno lies
1377 * past eof, *eofp will be set, and *prevp will contain the last
1378 * entry (null if none). Else, *lastxp will be set to the index
1379 * of the found entry; *gotp will contain the entry.
1380 */
1381STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */
1382xfs_bmap_search_multi_extents(
1383 xfs_ifork_t *ifp, /* inode fork pointer */
1384 xfs_fileoff_t bno, /* block number searched for */
1385 int *eofp, /* out: end of file found */
1386 xfs_extnum_t *lastxp, /* out: last extent index */
1387 xfs_bmbt_irec_t *gotp, /* out: extent entry found */
1388 xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
1389{
1390 xfs_bmbt_rec_host_t *ep; /* extent record pointer */
1391 xfs_extnum_t lastx; /* last extent index */
1392
1393 /*
1394 * Initialize the extent entry structure to catch access to
1395 * uninitialized br_startblock field.
1396 */
1397 gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL;
1398 gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL;
1399 gotp->br_state = XFS_EXT_INVALID;
1400 gotp->br_startblock = 0xffffa5a5a5a5a5a5LL;
1401 prevp->br_startoff = NULLFILEOFF;
1402
1403 ep = xfs_iext_bno_to_ext(ifp, bno, &lastx);
1404 if (lastx > 0) {
1405 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp);
1406 }
1407 if (lastx < xfs_iext_count(ifp)) {
1408 xfs_bmbt_get_all(ep, gotp);
1409 *eofp = 0;
1410 } else {
1411 if (lastx > 0) {
1412 *gotp = *prevp;
1413 }
1414 *eofp = 1;
1415 ep = NULL;
1416 }
1417 *lastxp = lastx;
1418 return ep;
1419}
1420
1421/*
1422 * Search the extents list for the inode, for the extent containing bno.
1423 * If bno lies in a hole, point to the next entry. If bno lies past eof,
1424 * *eofp will be set, and *prevp will contain the last entry (null if none).
1425 * Else, *lastxp will be set to the index of the found
1426 * entry; *gotp will contain the entry.
1427 */
1428xfs_bmbt_rec_host_t * /* pointer to found extent entry */
1429xfs_bmap_search_extents(
1430 xfs_inode_t *ip, /* incore inode pointer */
1431 xfs_fileoff_t bno, /* block number searched for */
1432 int fork, /* data or attr fork */
1433 int *eofp, /* out: end of file found */
1434 xfs_extnum_t *lastxp, /* out: last extent index */
1435 xfs_bmbt_irec_t *gotp, /* out: extent entry found */
1436 xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
1437{
1438 xfs_ifork_t *ifp; /* inode fork pointer */
1439 xfs_bmbt_rec_host_t *ep; /* extent record pointer */
1440
1441 XFS_STATS_INC(ip->i_mount, xs_look_exlist);
1442 ifp = XFS_IFORK_PTR(ip, fork);
1443
1444 ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
1445
1446 if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
1447 !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
1448 xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
1449 "Access to block zero in inode %llu "
1450 "start_block: %llx start_off: %llx "
1451 "blkcnt: %llx extent-state: %x lastx: %x",
1452 (unsigned long long)ip->i_ino,
1453 (unsigned long long)gotp->br_startblock,
1454 (unsigned long long)gotp->br_startoff,
1455 (unsigned long long)gotp->br_blockcount,
1456 gotp->br_state, *lastxp);
1457 *lastxp = NULLEXTNUM;
1458 *eofp = 1;
1459 return NULL;
1460 }
1461 return ep;
1462}
1463
1464/* 1373/*
1465 * Returns the file-relative block number of the first unused block(s) 1374 * Returns the file-relative block number of the first unused block(s)
1466 * in the file with at least "len" logically contiguous blocks free. 1375 * in the file with at least "len" logically contiguous blocks free.
@@ -1523,44 +1432,44 @@ xfs_bmap_first_unused(
1523 */ 1432 */
1524int /* error */ 1433int /* error */
1525xfs_bmap_last_before( 1434xfs_bmap_last_before(
1526 xfs_trans_t *tp, /* transaction pointer */ 1435 struct xfs_trans *tp, /* transaction pointer */
1527 xfs_inode_t *ip, /* incore inode */ 1436 struct xfs_inode *ip, /* incore inode */
1528 xfs_fileoff_t *last_block, /* last block */ 1437 xfs_fileoff_t *last_block, /* last block */
1529 int whichfork) /* data or attr fork */ 1438 int whichfork) /* data or attr fork */
1530{ 1439{
1531 xfs_fileoff_t bno; /* input file offset */ 1440 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
1532 int eof; /* hit end of file */ 1441 struct xfs_bmbt_irec got;
1533 xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ 1442 xfs_extnum_t idx;
1534 int error; /* error return value */ 1443 int error;
1535 xfs_bmbt_irec_t got; /* current extent value */
1536 xfs_ifork_t *ifp; /* inode fork pointer */
1537 xfs_extnum_t lastx; /* last extent used */
1538 xfs_bmbt_irec_t prev; /* previous extent value */
1539 1444
1540 if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && 1445 switch (XFS_IFORK_FORMAT(ip, whichfork)) {
1541 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && 1446 case XFS_DINODE_FMT_LOCAL:
1542 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
1543 return -EIO;
1544 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
1545 *last_block = 0; 1447 *last_block = 0;
1546 return 0; 1448 return 0;
1449 case XFS_DINODE_FMT_BTREE:
1450 case XFS_DINODE_FMT_EXTENTS:
1451 break;
1452 default:
1453 return -EIO;
1547 } 1454 }
1548 ifp = XFS_IFORK_PTR(ip, whichfork); 1455
1549 if (!(ifp->if_flags & XFS_IFEXTENTS) && 1456 if (!(ifp->if_flags & XFS_IFEXTENTS)) {
1550 (error = xfs_iread_extents(tp, ip, whichfork))) 1457 error = xfs_iread_extents(tp, ip, whichfork);
1551 return error; 1458 if (error)
1552 bno = *last_block - 1; 1459 return error;
1553 ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
1554 &prev);
1555 if (eof || xfs_bmbt_get_startoff(ep) > bno) {
1556 if (prev.br_startoff == NULLFILEOFF)
1557 *last_block = 0;
1558 else
1559 *last_block = prev.br_startoff + prev.br_blockcount;
1560 } 1460 }
1561 /* 1461
1562 * Otherwise *last_block is already the right answer. 1462 if (xfs_iext_lookup_extent(ip, ifp, *last_block - 1, &idx, &got)) {
1563 */ 1463 if (got.br_startoff <= *last_block - 1)
1464 return 0;
1465 }
1466
1467 if (xfs_iext_get_extent(ifp, idx - 1, &got)) {
1468 *last_block = got.br_startoff + got.br_blockcount;
1469 return 0;
1470 }
1471
1472 *last_block = 0;
1564 return 0; 1473 return 0;
1565} 1474}
1566 1475
@@ -4145,12 +4054,11 @@ xfs_bmapi_read(
4145 struct xfs_mount *mp = ip->i_mount; 4054 struct xfs_mount *mp = ip->i_mount;
4146 struct xfs_ifork *ifp; 4055 struct xfs_ifork *ifp;
4147 struct xfs_bmbt_irec got; 4056 struct xfs_bmbt_irec got;
4148 struct xfs_bmbt_irec prev;
4149 xfs_fileoff_t obno; 4057 xfs_fileoff_t obno;
4150 xfs_fileoff_t end; 4058 xfs_fileoff_t end;
4151 xfs_extnum_t lastx; 4059 xfs_extnum_t idx;
4152 int error; 4060 int error;
4153 int eof; 4061 bool eof = false;
4154 int n = 0; 4062 int n = 0;
4155 int whichfork = xfs_bmapi_whichfork(flags); 4063 int whichfork = xfs_bmapi_whichfork(flags);
4156 4064
@@ -4190,7 +4098,8 @@ xfs_bmapi_read(
4190 return error; 4098 return error;
4191 } 4099 }
4192 4100
4193 xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); 4101 if (!xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got))
4102 eof = true;
4194 end = bno + len; 4103 end = bno + len;
4195 obno = bno; 4104 obno = bno;
4196 4105
@@ -4221,10 +4130,8 @@ xfs_bmapi_read(
4221 break; 4130 break;
4222 4131
4223 /* Else go on to the next record. */ 4132 /* Else go on to the next record. */
4224 if (++lastx < xfs_iext_count(ifp)) 4133 if (!xfs_iext_get_extent(ifp, ++idx, &got))
4225 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); 4134 eof = true;
4226 else
4227 eof = 1;
4228 } 4135 }
4229 *nmap = n; 4136 *nmap = n;
4230 return 0; 4137 return 0;
@@ -4237,7 +4144,6 @@ xfs_bmapi_reserve_delalloc(
4237 xfs_fileoff_t aoff, 4144 xfs_fileoff_t aoff,
4238 xfs_filblks_t len, 4145 xfs_filblks_t len,
4239 struct xfs_bmbt_irec *got, 4146 struct xfs_bmbt_irec *got,
4240 struct xfs_bmbt_irec *prev,
4241 xfs_extnum_t *lastx, 4147 xfs_extnum_t *lastx,
4242 int eof) 4148 int eof)
4243{ 4149{
@@ -4259,7 +4165,12 @@ xfs_bmapi_reserve_delalloc(
4259 else 4165 else
4260 extsz = xfs_get_extsz_hint(ip); 4166 extsz = xfs_get_extsz_hint(ip);
4261 if (extsz) { 4167 if (extsz) {
4262 error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, 4168 struct xfs_bmbt_irec prev;
4169
4170 if (!xfs_iext_get_extent(ifp, *lastx - 1, &prev))
4171 prev.br_startoff = NULLFILEOFF;
4172
4173 error = xfs_bmap_extsize_align(mp, got, &prev, extsz, rt, eof,
4263 1, 0, &aoff, &alen); 4174 1, 0, &aoff, &alen);
4264 ASSERT(!error); 4175 ASSERT(!error);
4265 } 4176 }
@@ -4349,7 +4260,7 @@ xfs_bmapi_allocate(
4349 if (bma->wasdel) { 4260 if (bma->wasdel) {
4350 bma->length = (xfs_extlen_t)bma->got.br_blockcount; 4261 bma->length = (xfs_extlen_t)bma->got.br_blockcount;
4351 bma->offset = bma->got.br_startoff; 4262 bma->offset = bma->got.br_startoff;
4352 if (bma->idx != NULLEXTNUM && bma->idx) { 4263 if (bma->idx) {
4353 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), 4264 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1),
4354 &bma->prev); 4265 &bma->prev);
4355 } 4266 }
@@ -4563,7 +4474,7 @@ xfs_bmapi_write(
4563 struct xfs_ifork *ifp; 4474 struct xfs_ifork *ifp;
4564 struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */ 4475 struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */
4565 xfs_fileoff_t end; /* end of mapped file region */ 4476 xfs_fileoff_t end; /* end of mapped file region */
4566 int eof; /* after the end of extents */ 4477 bool eof = false; /* after the end of extents */
4567 int error; /* error return */ 4478 int error; /* error return */
4568 int n; /* current extent index */ 4479 int n; /* current extent index */
4569 xfs_fileoff_t obno; /* old block number (offset) */ 4480 xfs_fileoff_t obno; /* old block number (offset) */
@@ -4641,12 +4552,14 @@ xfs_bmapi_write(
4641 goto error0; 4552 goto error0;
4642 } 4553 }
4643 4554
4644 xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got,
4645 &bma.prev);
4646 n = 0; 4555 n = 0;
4647 end = bno + len; 4556 end = bno + len;
4648 obno = bno; 4557 obno = bno;
4649 4558
4559 if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.idx, &bma.got))
4560 eof = true;
4561 if (!xfs_iext_get_extent(ifp, bma.idx - 1, &bma.prev))
4562 bma.prev.br_startoff = NULLFILEOFF;
4650 bma.tp = tp; 4563 bma.tp = tp;
4651 bma.ip = ip; 4564 bma.ip = ip;
4652 bma.total = total; 4565 bma.total = total;
@@ -4733,11 +4646,8 @@ xfs_bmapi_write(
4733 4646
4734 /* Else go on to the next record. */ 4647 /* Else go on to the next record. */
4735 bma.prev = bma.got; 4648 bma.prev = bma.got;
4736 if (++bma.idx < xfs_iext_count(ifp)) { 4649 if (!xfs_iext_get_extent(ifp, ++bma.idx, &bma.got))
4737 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx), 4650 eof = true;
4738 &bma.got);
4739 } else
4740 eof = 1;
4741 } 4651 }
4742 *nmap = n; 4652 *nmap = n;
4743 4653
@@ -5436,8 +5346,6 @@ __xfs_bunmapi(
5436{ 5346{
5437 xfs_btree_cur_t *cur; /* bmap btree cursor */ 5347 xfs_btree_cur_t *cur; /* bmap btree cursor */
5438 xfs_bmbt_irec_t del; /* extent being deleted */ 5348 xfs_bmbt_irec_t del; /* extent being deleted */
5439 int eof; /* is deleting at eof */
5440 xfs_bmbt_rec_host_t *ep; /* extent record pointer */
5441 int error; /* error return value */ 5349 int error; /* error return value */
5442 xfs_extnum_t extno; /* extent number in list */ 5350 xfs_extnum_t extno; /* extent number in list */
5443 xfs_bmbt_irec_t got; /* current extent record */ 5351 xfs_bmbt_irec_t got; /* current extent record */
@@ -5447,7 +5355,6 @@ __xfs_bunmapi(
5447 int logflags; /* transaction logging flags */ 5355 int logflags; /* transaction logging flags */
5448 xfs_extlen_t mod; /* rt extent offset */ 5356 xfs_extlen_t mod; /* rt extent offset */
5449 xfs_mount_t *mp; /* mount structure */ 5357 xfs_mount_t *mp; /* mount structure */
5450 xfs_bmbt_irec_t prev; /* previous extent record */
5451 xfs_fileoff_t start; /* first file offset deleted */ 5358 xfs_fileoff_t start; /* first file offset deleted */
5452 int tmp_logflags; /* partial logging flags */ 5359 int tmp_logflags; /* partial logging flags */
5453 int wasdel; /* was a delayed alloc extent */ 5360 int wasdel; /* was a delayed alloc extent */
@@ -5486,18 +5393,17 @@ __xfs_bunmapi(
5486 isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); 5393 isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
5487 start = bno; 5394 start = bno;
5488 bno = start + len - 1; 5395 bno = start + len - 1;
5489 ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
5490 &prev);
5491 5396
5492 /* 5397 /*
5493 * Check to see if the given block number is past the end of the 5398 * Check to see if the given block number is past the end of the
5494 * file, back up to the last block if so... 5399 * file, back up to the last block if so...
5495 */ 5400 */
5496 if (eof) { 5401 if (!xfs_iext_lookup_extent(ip, ifp, bno, &lastx, &got)) {
5497 ep = xfs_iext_get_ext(ifp, --lastx); 5402 ASSERT(lastx > 0);
5498 xfs_bmbt_get_all(ep, &got); 5403 xfs_iext_get_extent(ifp, --lastx, &got);
5499 bno = got.br_startoff + got.br_blockcount - 1; 5404 bno = got.br_startoff + got.br_blockcount - 1;
5500 } 5405 }
5406
5501 logflags = 0; 5407 logflags = 0;
5502 if (ifp->if_flags & XFS_IFBROOT) { 5408 if (ifp->if_flags & XFS_IFBROOT) {
5503 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); 5409 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
@@ -5528,8 +5434,7 @@ __xfs_bunmapi(
5528 if (got.br_startoff > bno) { 5434 if (got.br_startoff > bno) {
5529 if (--lastx < 0) 5435 if (--lastx < 0)
5530 break; 5436 break;
5531 ep = xfs_iext_get_ext(ifp, lastx); 5437 xfs_iext_get_extent(ifp, lastx, &got);
5532 xfs_bmbt_get_all(ep, &got);
5533 } 5438 }
5534 /* 5439 /*
5535 * Is the last block of this extent before the range 5440 * Is the last block of this extent before the range
@@ -5543,7 +5448,6 @@ __xfs_bunmapi(
5543 * Then deal with the (possibly delayed) allocated space 5448 * Then deal with the (possibly delayed) allocated space
5544 * we found. 5449 * we found.
5545 */ 5450 */
5546 ASSERT(ep != NULL);
5547 del = got; 5451 del = got;
5548 wasdel = isnullstartblock(del.br_startblock); 5452 wasdel = isnullstartblock(del.br_startblock);
5549 if (got.br_startoff < start) { 5453 if (got.br_startoff < start) {
@@ -5624,15 +5528,12 @@ __xfs_bunmapi(
5624 */ 5528 */
5625 ASSERT(bno >= del.br_blockcount); 5529 ASSERT(bno >= del.br_blockcount);
5626 bno -= del.br_blockcount; 5530 bno -= del.br_blockcount;
5627 if (got.br_startoff > bno) { 5531 if (got.br_startoff > bno && --lastx >= 0)
5628 if (--lastx >= 0) { 5532 xfs_iext_get_extent(ifp, lastx, &got);
5629 ep = xfs_iext_get_ext(ifp,
5630 lastx);
5631 xfs_bmbt_get_all(ep, &got);
5632 }
5633 }
5634 continue; 5533 continue;
5635 } else if (del.br_state == XFS_EXT_UNWRITTEN) { 5534 } else if (del.br_state == XFS_EXT_UNWRITTEN) {
5535 struct xfs_bmbt_irec prev;
5536
5636 /* 5537 /*
5637 * This one is already unwritten. 5538 * This one is already unwritten.
5638 * It must have a written left neighbor. 5539 * It must have a written left neighbor.
@@ -5640,8 +5541,7 @@ __xfs_bunmapi(
5640 * try again. 5541 * try again.
5641 */ 5542 */
5642 ASSERT(lastx > 0); 5543 ASSERT(lastx > 0);
5643 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, 5544 xfs_iext_get_extent(ifp, lastx - 1, &prev);
5644 lastx - 1), &prev);
5645 ASSERT(prev.br_state == XFS_EXT_NORM); 5545 ASSERT(prev.br_state == XFS_EXT_NORM);
5646 ASSERT(!isnullstartblock(prev.br_startblock)); 5546 ASSERT(!isnullstartblock(prev.br_startblock));
5647 ASSERT(del.br_startblock == 5547 ASSERT(del.br_startblock ==
@@ -5739,13 +5639,9 @@ nodelete:
5739 */ 5639 */
5740 if (bno != (xfs_fileoff_t)-1 && bno >= start) { 5640 if (bno != (xfs_fileoff_t)-1 && bno >= start) {
5741 if (lastx >= 0) { 5641 if (lastx >= 0) {
5742 ep = xfs_iext_get_ext(ifp, lastx); 5642 xfs_iext_get_extent(ifp, lastx, &got);
5743 if (xfs_bmbt_get_startoff(ep) > bno) { 5643 if (got.br_startoff > bno && --lastx >= 0)
5744 if (--lastx >= 0) 5644 xfs_iext_get_extent(ifp, lastx, &got);
5745 ep = xfs_iext_get_ext(ifp,
5746 lastx);
5747 }
5748 xfs_bmbt_get_all(ep, &got);
5749 } 5645 }
5750 extno++; 5646 extno++;
5751 } 5647 }
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index 7cae6ec27fa6..ffed1f9208ce 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -237,14 +237,9 @@ int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
237 struct xfs_defer_ops *dfops, enum shift_direction direction, 237 struct xfs_defer_ops *dfops, enum shift_direction direction,
238 int num_exts); 238 int num_exts);
239int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); 239int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
240struct xfs_bmbt_rec_host *
241 xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno,
242 int fork, int *eofp, xfs_extnum_t *lastxp,
243 struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp);
244int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, 240int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
245 xfs_fileoff_t aoff, xfs_filblks_t len, 241 xfs_fileoff_t aoff, xfs_filblks_t len,
246 struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev, 242 struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof);
247 xfs_extnum_t *lastx, int eof);
248 243
249enum xfs_bmap_intent_type { 244enum xfs_bmap_intent_type {
250 XFS_BMAP_MAP = 1, 245 XFS_BMAP_MAP = 1,
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 5fbe24c31679..222e103356c6 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -2003,3 +2003,49 @@ xfs_ifork_init_cow(
2003 ip->i_cformat = XFS_DINODE_FMT_EXTENTS; 2003 ip->i_cformat = XFS_DINODE_FMT_EXTENTS;
2004 ip->i_cnextents = 0; 2004 ip->i_cnextents = 0;
2005} 2005}
2006
2007/*
2008 * Lookup the extent covering bno.
2009 *
2010 * If there is an extent covering bno return the extent index, and store the
2011 * expanded extent structure in *gotp, and the extent index in *idx.
2012 * If there is no extent covering bno, but there is an extent after it (e.g.
2013 * it lies in a hole) return that extent in *gotp and its index in *idx
2014 * instead.
2015 * If bno is beyond the last extent return false, and return the index after
2016 * the last valid index in *idxp.
2017 */
2018bool
2019xfs_iext_lookup_extent(
2020 struct xfs_inode *ip,
2021 struct xfs_ifork *ifp,
2022 xfs_fileoff_t bno,
2023 xfs_extnum_t *idxp,
2024 struct xfs_bmbt_irec *gotp)
2025{
2026 struct xfs_bmbt_rec_host *ep;
2027
2028 XFS_STATS_INC(ip->i_mount, xs_look_exlist);
2029
2030 ep = xfs_iext_bno_to_ext(ifp, bno, idxp);
2031 if (!ep)
2032 return false;
2033 xfs_bmbt_get_all(ep, gotp);
2034 return true;
2035}
2036
2037/*
2038 * Return true if there is an extent at index idx, and return the expanded
2039 * extent structure at idx in that case. Else return false.
2040 */
2041bool
2042xfs_iext_get_extent(
2043 struct xfs_ifork *ifp,
2044 xfs_extnum_t idx,
2045 struct xfs_bmbt_irec *gotp)
2046{
2047 if (idx < 0 || idx >= xfs_iext_count(ifp))
2048 return false;
2049 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), gotp);
2050 return true;
2051}
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 8bf112e29aa1..7fb8365326d1 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -182,6 +182,12 @@ void xfs_iext_irec_compact_pages(struct xfs_ifork *);
182void xfs_iext_irec_compact_full(struct xfs_ifork *); 182void xfs_iext_irec_compact_full(struct xfs_ifork *);
183void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); 183void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int);
184 184
185bool xfs_iext_lookup_extent(struct xfs_inode *ip,
186 struct xfs_ifork *ifp, xfs_fileoff_t bno,
187 xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp);
188bool xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx,
189 struct xfs_bmbt_irec *gotp);
190
185extern struct kmem_zone *xfs_ifork_zone; 191extern struct kmem_zone *xfs_ifork_zone;
186 192
187extern void xfs_ifork_init_cow(struct xfs_inode *ip); 193extern void xfs_ifork_init_cow(struct xfs_inode *ip);
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index cf044c0f4d41..717909f2f7b7 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -57,7 +57,6 @@ typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */
57 57
58#define NULLAGBLOCK ((xfs_agblock_t)-1) 58#define NULLAGBLOCK ((xfs_agblock_t)-1)
59#define NULLAGNUMBER ((xfs_agnumber_t)-1) 59#define NULLAGNUMBER ((xfs_agnumber_t)-1)
60#define NULLEXTNUM ((xfs_extnum_t)-1)
61 60
62#define NULLCOMMITLSN ((xfs_lsn_t)-1) 61#define NULLCOMMITLSN ((xfs_lsn_t)-1)
63 62
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index dd6cacf59b5a..ab266d66124d 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -777,7 +777,7 @@ xfs_map_cow(
777{ 777{
778 struct xfs_inode *ip = XFS_I(inode); 778 struct xfs_inode *ip = XFS_I(inode);
779 struct xfs_bmbt_irec imap; 779 struct xfs_bmbt_irec imap;
780 bool is_cow = false, need_alloc = false; 780 bool is_cow = false;
781 int error; 781 int error;
782 782
783 /* 783 /*
@@ -795,7 +795,7 @@ xfs_map_cow(
795 * Else we need to check if there is a COW mapping at this offset. 795 * Else we need to check if there is a COW mapping at this offset.
796 */ 796 */
797 xfs_ilock(ip, XFS_ILOCK_SHARED); 797 xfs_ilock(ip, XFS_ILOCK_SHARED);
798 is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, &need_alloc); 798 is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap);
799 xfs_iunlock(ip, XFS_ILOCK_SHARED); 799 xfs_iunlock(ip, XFS_ILOCK_SHARED);
800 800
801 if (!is_cow) 801 if (!is_cow)
@@ -805,7 +805,7 @@ xfs_map_cow(
805 * And if the COW mapping has a delayed extent here we need to 805 * And if the COW mapping has a delayed extent here we need to
806 * allocate real space for it now. 806 * allocate real space for it now.
807 */ 807 */
808 if (need_alloc) { 808 if (isnullstartblock(imap.br_startblock)) {
809 error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset, 809 error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset,
810 &imap); 810 &imap);
811 if (error) 811 if (error)
@@ -1311,7 +1311,6 @@ __xfs_get_blocks(
1311 ssize_t size; 1311 ssize_t size;
1312 int new = 0; 1312 int new = 0;
1313 bool is_cow = false; 1313 bool is_cow = false;
1314 bool need_alloc = false;
1315 1314
1316 BUG_ON(create && !direct); 1315 BUG_ON(create && !direct);
1317 1316
@@ -1337,9 +1336,11 @@ __xfs_get_blocks(
1337 end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size); 1336 end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
1338 offset_fsb = XFS_B_TO_FSBT(mp, offset); 1337 offset_fsb = XFS_B_TO_FSBT(mp, offset);
1339 1338
1340 if (create && direct && xfs_is_reflink_inode(ip)) 1339 if (create && direct && xfs_is_reflink_inode(ip)) {
1341 is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, 1340 is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap);
1342 &need_alloc); 1341 ASSERT(!is_cow || !isnullstartblock(imap.br_startblock));
1342 }
1343
1343 if (!is_cow) { 1344 if (!is_cow) {
1344 error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, 1345 error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
1345 &imap, &nimaps, XFS_BMAPI_ENTIRE); 1346 &imap, &nimaps, XFS_BMAPI_ENTIRE);
@@ -1356,7 +1357,6 @@ __xfs_get_blocks(
1356 xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb, 1357 xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb,
1357 &imap); 1358 &imap);
1358 } 1359 }
1359 ASSERT(!need_alloc);
1360 if (error) 1360 if (error)
1361 goto out_unlock; 1361 goto out_unlock;
1362 1362
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 436e109bb01e..2272190b70ae 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -395,11 +395,12 @@ xfs_iomap_prealloc_size(
395 struct xfs_inode *ip, 395 struct xfs_inode *ip,
396 loff_t offset, 396 loff_t offset,
397 loff_t count, 397 loff_t count,
398 xfs_extnum_t idx, 398 xfs_extnum_t idx)
399 struct xfs_bmbt_irec *prev)
400{ 399{
401 struct xfs_mount *mp = ip->i_mount; 400 struct xfs_mount *mp = ip->i_mount;
401 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
402 xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); 402 xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
403 struct xfs_bmbt_irec prev;
403 int shift = 0; 404 int shift = 0;
404 int64_t freesp; 405 int64_t freesp;
405 xfs_fsblock_t qblocks; 406 xfs_fsblock_t qblocks;
@@ -419,8 +420,8 @@ xfs_iomap_prealloc_size(
419 */ 420 */
420 if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) || 421 if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ||
421 XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) || 422 XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
422 idx == 0 || 423 !xfs_iext_get_extent(ifp, idx - 1, &prev) ||
423 prev->br_startoff + prev->br_blockcount < offset_fsb) 424 prev.br_startoff + prev.br_blockcount < offset_fsb)
424 return mp->m_writeio_blocks; 425 return mp->m_writeio_blocks;
425 426
426 /* 427 /*
@@ -439,8 +440,8 @@ xfs_iomap_prealloc_size(
439 * always extends to MAXEXTLEN rather than falling short due to things 440 * always extends to MAXEXTLEN rather than falling short due to things
440 * like stripe unit/width alignment of real extents. 441 * like stripe unit/width alignment of real extents.
441 */ 442 */
442 if (prev->br_blockcount <= (MAXEXTLEN >> 1)) 443 if (prev.br_blockcount <= (MAXEXTLEN >> 1))
443 alloc_blocks = prev->br_blockcount << 1; 444 alloc_blocks = prev.br_blockcount << 1;
444 else 445 else
445 alloc_blocks = XFS_B_TO_FSB(mp, offset); 446 alloc_blocks = XFS_B_TO_FSB(mp, offset);
446 if (!alloc_blocks) 447 if (!alloc_blocks)
@@ -538,7 +539,6 @@ xfs_file_iomap_begin_delay(
538 xfs_fileoff_t end_fsb, orig_end_fsb; 539 xfs_fileoff_t end_fsb, orig_end_fsb;
539 int error = 0, eof = 0; 540 int error = 0, eof = 0;
540 struct xfs_bmbt_irec got; 541 struct xfs_bmbt_irec got;
541 struct xfs_bmbt_irec prev;
542 xfs_extnum_t idx; 542 xfs_extnum_t idx;
543 543
544 ASSERT(!XFS_IS_REALTIME_INODE(ip)); 544 ASSERT(!XFS_IS_REALTIME_INODE(ip));
@@ -563,8 +563,7 @@ xfs_file_iomap_begin_delay(
563 goto out_unlock; 563 goto out_unlock;
564 } 564 }
565 565
566 xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx, 566 eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got);
567 &got, &prev);
568 if (!eof && got.br_startoff <= offset_fsb) { 567 if (!eof && got.br_startoff <= offset_fsb) {
569 if (xfs_is_reflink_inode(ip)) { 568 if (xfs_is_reflink_inode(ip)) {
570 bool shared; 569 bool shared;
@@ -601,8 +600,7 @@ xfs_file_iomap_begin_delay(
601 if (eof) { 600 if (eof) {
602 xfs_fsblock_t prealloc_blocks; 601 xfs_fsblock_t prealloc_blocks;
603 602
604 prealloc_blocks = 603 prealloc_blocks = xfs_iomap_prealloc_size(ip, offset, count, idx);
605 xfs_iomap_prealloc_size(ip, offset, count, idx, &prev);
606 if (prealloc_blocks) { 604 if (prealloc_blocks) {
607 xfs_extlen_t align; 605 xfs_extlen_t align;
608 xfs_off_t end_offset; 606 xfs_off_t end_offset;
@@ -622,8 +620,7 @@ xfs_file_iomap_begin_delay(
622 620
623retry: 621retry:
624 error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb, 622 error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb,
625 end_fsb - offset_fsb, &got, 623 end_fsb - offset_fsb, &got, &idx, eof);
626 &prev, &idx, eof);
627 switch (error) { 624 switch (error) {
628 case 0: 625 case 0:
629 break; 626 break;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 0edf835af32d..56372bee08c5 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -243,10 +243,11 @@ xfs_reflink_reserve_cow(
243 struct xfs_bmbt_irec *imap, 243 struct xfs_bmbt_irec *imap,
244 bool *shared) 244 bool *shared)
245{ 245{
246 struct xfs_bmbt_irec got, prev; 246 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
247 struct xfs_bmbt_irec got;
247 xfs_fileoff_t end_fsb, orig_end_fsb; 248 xfs_fileoff_t end_fsb, orig_end_fsb;
248 int eof = 0, error = 0; 249 int error = 0;
249 bool trimmed; 250 bool eof = false, trimmed;
250 xfs_extnum_t idx; 251 xfs_extnum_t idx;
251 xfs_extlen_t align; 252 xfs_extlen_t align;
252 253
@@ -258,8 +259,9 @@ xfs_reflink_reserve_cow(
258 * extent list is generally faster than going out to the shared extent 259 * extent list is generally faster than going out to the shared extent
259 * tree. 260 * tree.
260 */ 261 */
261 xfs_bmap_search_extents(ip, imap->br_startoff, XFS_COW_FORK, &eof, &idx, 262
262 &got, &prev); 263 if (!xfs_iext_lookup_extent(ip, ifp, imap->br_startoff, &idx, &got))
264 eof = true;
263 if (!eof && got.br_startoff <= imap->br_startoff) { 265 if (!eof && got.br_startoff <= imap->br_startoff) {
264 trace_xfs_reflink_cow_found(ip, imap); 266 trace_xfs_reflink_cow_found(ip, imap);
265 xfs_trim_extent(imap, got.br_startoff, got.br_blockcount); 267 xfs_trim_extent(imap, got.br_startoff, got.br_blockcount);
@@ -293,7 +295,7 @@ xfs_reflink_reserve_cow(
293 295
294retry: 296retry:
295 error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff, 297 error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
296 end_fsb - imap->br_startoff, &got, &prev, &idx, eof); 298 end_fsb - imap->br_startoff, &got, &idx, eof);
297 switch (error) { 299 switch (error) {
298 case 0: 300 case 0:
299 break; 301 break;
@@ -418,87 +420,65 @@ xfs_reflink_allocate_cow_range(
418} 420}
419 421
420/* 422/*
421 * Find the CoW reservation (and whether or not it needs block allocation) 423 * Find the CoW reservation for a given byte offset of a file.
422 * for a given byte offset of a file.
423 */ 424 */
424bool 425bool
425xfs_reflink_find_cow_mapping( 426xfs_reflink_find_cow_mapping(
426 struct xfs_inode *ip, 427 struct xfs_inode *ip,
427 xfs_off_t offset, 428 xfs_off_t offset,
428 struct xfs_bmbt_irec *imap, 429 struct xfs_bmbt_irec *imap)
429 bool *need_alloc)
430{ 430{
431 struct xfs_bmbt_irec irec; 431 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
432 struct xfs_ifork *ifp; 432 xfs_fileoff_t offset_fsb;
433 struct xfs_bmbt_rec_host *gotp; 433 struct xfs_bmbt_irec got;
434 xfs_fileoff_t bno;
435 xfs_extnum_t idx; 434 xfs_extnum_t idx;
436 435
437 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); 436 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
438 ASSERT(xfs_is_reflink_inode(ip)); 437 ASSERT(xfs_is_reflink_inode(ip));
439 438
440 /* Find the extent in the CoW fork. */ 439 offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
441 ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); 440 if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
442 bno = XFS_B_TO_FSBT(ip->i_mount, offset);
443 gotp = xfs_iext_bno_to_ext(ifp, bno, &idx);
444 if (!gotp)
445 return false; 441 return false;
446 442 if (got.br_startoff > offset_fsb)
447 xfs_bmbt_get_all(gotp, &irec);
448 if (bno >= irec.br_startoff + irec.br_blockcount ||
449 bno < irec.br_startoff)
450 return false; 443 return false;
451 444
452 trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE, 445 trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE,
453 &irec); 446 &got);
454 447 *imap = got;
455 /* If it's still delalloc, we must allocate later. */
456 *imap = irec;
457 *need_alloc = !!(isnullstartblock(irec.br_startblock));
458
459 return true; 448 return true;
460} 449}
461 450
462/* 451/*
463 * Trim an extent to end at the next CoW reservation past offset_fsb. 452 * Trim an extent to end at the next CoW reservation past offset_fsb.
464 */ 453 */
465int 454void
466xfs_reflink_trim_irec_to_next_cow( 455xfs_reflink_trim_irec_to_next_cow(
467 struct xfs_inode *ip, 456 struct xfs_inode *ip,
468 xfs_fileoff_t offset_fsb, 457 xfs_fileoff_t offset_fsb,
469 struct xfs_bmbt_irec *imap) 458 struct xfs_bmbt_irec *imap)
470{ 459{
471 struct xfs_bmbt_irec irec; 460 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
472 struct xfs_ifork *ifp; 461 struct xfs_bmbt_irec got;
473 struct xfs_bmbt_rec_host *gotp;
474 xfs_extnum_t idx; 462 xfs_extnum_t idx;
475 463
476 if (!xfs_is_reflink_inode(ip)) 464 if (!xfs_is_reflink_inode(ip))
477 return 0; 465 return;
478 466
479 /* Find the extent in the CoW fork. */ 467 /* Find the extent in the CoW fork. */
480 ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); 468 if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
481 gotp = xfs_iext_bno_to_ext(ifp, offset_fsb, &idx); 469 return;
482 if (!gotp)
483 return 0;
484 xfs_bmbt_get_all(gotp, &irec);
485 470
486 /* This is the extent before; try sliding up one. */ 471 /* This is the extent before; try sliding up one. */
487 if (irec.br_startoff < offset_fsb) { 472 if (got.br_startoff < offset_fsb) {
488 idx++; 473 if (!xfs_iext_get_extent(ifp, idx + 1, &got))
489 if (idx >= xfs_iext_count(ifp)) 474 return;
490 return 0;
491 gotp = xfs_iext_get_ext(ifp, idx);
492 xfs_bmbt_get_all(gotp, &irec);
493 } 475 }
494 476
495 if (irec.br_startoff >= imap->br_startoff + imap->br_blockcount) 477 if (got.br_startoff >= imap->br_startoff + imap->br_blockcount)
496 return 0; 478 return;
497 479
498 imap->br_blockcount = irec.br_startoff - imap->br_startoff; 480 imap->br_blockcount = got.br_startoff - imap->br_startoff;
499 trace_xfs_reflink_trim_irec(ip, imap); 481 trace_xfs_reflink_trim_irec(ip, imap);
500
501 return 0;
502} 482}
503 483
504/* 484/*
@@ -512,18 +492,15 @@ xfs_reflink_cancel_cow_blocks(
512 xfs_fileoff_t end_fsb) 492 xfs_fileoff_t end_fsb)
513{ 493{
514 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); 494 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
515 struct xfs_bmbt_irec got, prev, del; 495 struct xfs_bmbt_irec got, del;
516 xfs_extnum_t idx; 496 xfs_extnum_t idx;
517 xfs_fsblock_t firstfsb; 497 xfs_fsblock_t firstfsb;
518 struct xfs_defer_ops dfops; 498 struct xfs_defer_ops dfops;
519 int error = 0, eof = 0; 499 int error = 0;
520 500
521 if (!xfs_is_reflink_inode(ip)) 501 if (!xfs_is_reflink_inode(ip))
522 return 0; 502 return 0;
523 503 if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
524 xfs_bmap_search_extents(ip, offset_fsb, XFS_COW_FORK, &eof, &idx,
525 &got, &prev);
526 if (eof)
527 return 0; 504 return 0;
528 505
529 while (got.br_startoff < end_fsb) { 506 while (got.br_startoff < end_fsb) {
@@ -566,9 +543,8 @@ xfs_reflink_cancel_cow_blocks(
566 xfs_bmap_del_extent_cow(ip, &idx, &got, &del); 543 xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
567 } 544 }
568 545
569 if (++idx >= xfs_iext_count(ifp)) 546 if (!xfs_iext_get_extent(ifp, ++idx, &got))
570 break; 547 break;
571 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
572 } 548 }
573 549
574 /* clear tag if cow fork is emptied */ 550 /* clear tag if cow fork is emptied */
@@ -638,13 +614,13 @@ xfs_reflink_end_cow(
638 xfs_off_t count) 614 xfs_off_t count)
639{ 615{
640 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); 616 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
641 struct xfs_bmbt_irec got, prev, del; 617 struct xfs_bmbt_irec got, del;
642 struct xfs_trans *tp; 618 struct xfs_trans *tp;
643 xfs_fileoff_t offset_fsb; 619 xfs_fileoff_t offset_fsb;
644 xfs_fileoff_t end_fsb; 620 xfs_fileoff_t end_fsb;
645 xfs_fsblock_t firstfsb; 621 xfs_fsblock_t firstfsb;
646 struct xfs_defer_ops dfops; 622 struct xfs_defer_ops dfops;
647 int error, eof = 0; 623 int error;
648 unsigned int resblks; 624 unsigned int resblks;
649 xfs_filblks_t rlen; 625 xfs_filblks_t rlen;
650 xfs_extnum_t idx; 626 xfs_extnum_t idx;
@@ -668,13 +644,11 @@ xfs_reflink_end_cow(
668 xfs_ilock(ip, XFS_ILOCK_EXCL); 644 xfs_ilock(ip, XFS_ILOCK_EXCL);
669 xfs_trans_ijoin(tp, ip, 0); 645 xfs_trans_ijoin(tp, ip, 0);
670 646
671 xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx,
672 &got, &prev);
673
674 /* If there is a hole at end_fsb - 1 go to the previous extent */ 647 /* If there is a hole at end_fsb - 1 go to the previous extent */
675 if (eof || got.br_startoff > end_fsb) { 648 if (!xfs_iext_lookup_extent(ip, ifp, end_fsb - 1, &idx, &got) ||
649 got.br_startoff > end_fsb) {
676 ASSERT(idx > 0); 650 ASSERT(idx > 0);
677 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got); 651 xfs_iext_get_extent(ifp, --idx, &got);
678 } 652 }
679 653
680 /* Walk backwards until we're out of the I/O range... */ 654 /* Walk backwards until we're out of the I/O range... */
@@ -722,11 +696,9 @@ xfs_reflink_end_cow(
722 error = xfs_defer_finish(&tp, &dfops, ip); 696 error = xfs_defer_finish(&tp, &dfops, ip);
723 if (error) 697 if (error)
724 goto out_defer; 698 goto out_defer;
725
726next_extent: 699next_extent:
727 if (idx < 0) 700 if (!xfs_iext_get_extent(ifp, idx, &got))
728 break; 701 break;
729 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
730 } 702 }
731 703
732 error = xfs_trans_commit(tp); 704 error = xfs_trans_commit(tp);
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h
index 97ea9b487884..aa6a4d64bd35 100644
--- a/fs/xfs/xfs_reflink.h
+++ b/fs/xfs/xfs_reflink.h
@@ -31,8 +31,8 @@ extern int xfs_reflink_reserve_cow(struct xfs_inode *ip,
31extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, 31extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip,
32 xfs_off_t offset, xfs_off_t count); 32 xfs_off_t offset, xfs_off_t count);
33extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, 33extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset,
34 struct xfs_bmbt_irec *imap, bool *need_alloc); 34 struct xfs_bmbt_irec *imap);
35extern int xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, 35extern void xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip,
36 xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap); 36 xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap);
37 37
38extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, 38extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip,