diff options
author | Dave Chinner <david@fromorbit.com> | 2016-11-23 19:41:59 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-11-23 19:41:59 -0500 |
commit | ed24bee6f26b268669702cf7521756d9031383af (patch) | |
tree | 127ee4098f6b751aac3443e6ccee88bbe139d3f4 | |
parent | 0fc204e2eb648ca31c80c8490178f70135807f05 (diff) | |
parent | 0e8d630ba039d9976d250eedb82c3a423ad15447 (diff) |
Merge branch 'xfs-4.10-extent-lookup' into for-next
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 234 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.h | 7 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 46 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.h | 6 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_types.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_aops.c | 16 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 23 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 108 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.h | 4 |
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 | */ | ||
1381 | STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ | ||
1382 | xfs_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 | */ | ||
1428 | xfs_bmbt_rec_host_t * /* pointer to found extent entry */ | ||
1429 | xfs_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 | */ |
1524 | int /* error */ | 1433 | int /* error */ |
1525 | xfs_bmap_last_before( | 1434 | xfs_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); |
239 | int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); | 239 | int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); |
240 | struct 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); | ||
244 | int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, | 240 | int 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 | ||
249 | enum xfs_bmap_intent_type { | 244 | enum 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 | */ | ||
2018 | bool | ||
2019 | xfs_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 | */ | ||
2041 | bool | ||
2042 | xfs_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 *); | |||
182 | void xfs_iext_irec_compact_full(struct xfs_ifork *); | 182 | void xfs_iext_irec_compact_full(struct xfs_ifork *); |
183 | void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); | 183 | void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); |
184 | 184 | ||
185 | bool 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); | ||
188 | bool xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx, | ||
189 | struct xfs_bmbt_irec *gotp); | ||
190 | |||
185 | extern struct kmem_zone *xfs_ifork_zone; | 191 | extern struct kmem_zone *xfs_ifork_zone; |
186 | 192 | ||
187 | extern void xfs_ifork_init_cow(struct xfs_inode *ip); | 193 | extern 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 | ||
623 | retry: | 621 | retry: |
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 | ||
294 | retry: | 296 | retry: |
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 | */ |
424 | bool | 425 | bool |
425 | xfs_reflink_find_cow_mapping( | 426 | xfs_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 | */ |
465 | int | 454 | void |
466 | xfs_reflink_trim_irec_to_next_cow( | 455 | xfs_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 | |||
726 | next_extent: | 699 | next_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, | |||
31 | extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, | 31 | extern 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); |
33 | extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, | 33 | extern 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); |
35 | extern int xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, | 35 | extern 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 | ||
38 | extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, | 38 | extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, |