aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:48 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2016-10-05 19:26:29 -0400
commit3f165b334e51477d2b33ac1c81b39927514daab7 (patch)
treed41f7847f6a185673853d50fd0ceeaecca0fc7ea
parentceeb9c832eeca5c1c2efc54a38f67283ccb60288 (diff)
xfs: convert unwritten status of reverse mappings for shared files
Provide a function to convert an unwritten extent to a real one and vice versa when shared extents are possible. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_rmap.c385
-rw-r--r--fs/xfs/xfs_rmap_item.c3
2 files changed, 387 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index bb5e2f840370..3a8cc7139912 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -1278,6 +1278,384 @@ done:
1278 return error; 1278 return error;
1279} 1279}
1280 1280
1281/*
1282 * Convert an unwritten extent to a real extent or vice versa. If there is no
1283 * possibility of overlapping extents, delegate to the simpler convert
1284 * function.
1285 */
1286STATIC int
1287xfs_rmap_convert_shared(
1288 struct xfs_btree_cur *cur,
1289 xfs_agblock_t bno,
1290 xfs_extlen_t len,
1291 bool unwritten,
1292 struct xfs_owner_info *oinfo)
1293{
1294 struct xfs_mount *mp = cur->bc_mp;
1295 struct xfs_rmap_irec r[4]; /* neighbor extent entries */
1296 /* left is 0, right is 1, prev is 2 */
1297 /* new is 3 */
1298 uint64_t owner;
1299 uint64_t offset;
1300 uint64_t new_endoff;
1301 unsigned int oldext;
1302 unsigned int newext;
1303 unsigned int flags = 0;
1304 int i;
1305 int state = 0;
1306 int error;
1307
1308 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1309 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1310 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1311 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1312 new_endoff = offset + len;
1313 trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
1314 unwritten, oinfo);
1315
1316 /*
1317 * For the initial lookup, look for and exact match or the left-adjacent
1318 * record for our insertion point. This will also give us the record for
1319 * start block contiguity tests.
1320 */
1321 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
1322 &PREV, &i);
1323 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1324
1325 ASSERT(PREV.rm_offset <= offset);
1326 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1327 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1328 newext = ~oldext & XFS_RMAP_UNWRITTEN;
1329
1330 /*
1331 * Set flags determining what part of the previous oldext allocation
1332 * extent is being replaced by a newext allocation.
1333 */
1334 if (PREV.rm_offset == offset)
1335 state |= RMAP_LEFT_FILLING;
1336 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1337 state |= RMAP_RIGHT_FILLING;
1338
1339 /* Is there a left record that abuts our range? */
1340 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
1341 &LEFT, &i);
1342 if (error)
1343 goto done;
1344 if (i) {
1345 state |= RMAP_LEFT_VALID;
1346 XFS_WANT_CORRUPTED_GOTO(mp,
1347 LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
1348 done);
1349 if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
1350 state |= RMAP_LEFT_CONTIG;
1351 }
1352
1353 /* Is there a right record that abuts our range? */
1354 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
1355 newext, &i);
1356 if (error)
1357 goto done;
1358 if (i) {
1359 state |= RMAP_RIGHT_VALID;
1360 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1361 if (error)
1362 goto done;
1363 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1364 XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
1365 done);
1366 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
1367 cur->bc_private.a.agno, RIGHT.rm_startblock,
1368 RIGHT.rm_blockcount, RIGHT.rm_owner,
1369 RIGHT.rm_offset, RIGHT.rm_flags);
1370 if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1371 state |= RMAP_RIGHT_CONTIG;
1372 }
1373
1374 /* check that left + prev + right is not too long */
1375 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1376 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1377 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1378 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1379 (unsigned long)LEFT.rm_blockcount + len +
1380 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1381 state &= ~RMAP_RIGHT_CONTIG;
1382
1383 trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
1384 _RET_IP_);
1385 /*
1386 * Switch out based on the FILLING and CONTIG state bits.
1387 */
1388 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1389 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1390 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1391 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1392 /*
1393 * Setting all of a previous oldext extent to newext.
1394 * The left and right neighbors are both contiguous with new.
1395 */
1396 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1397 RIGHT.rm_blockcount, RIGHT.rm_owner,
1398 RIGHT.rm_offset, RIGHT.rm_flags);
1399 if (error)
1400 goto done;
1401 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1402 PREV.rm_blockcount, PREV.rm_owner,
1403 PREV.rm_offset, PREV.rm_flags);
1404 if (error)
1405 goto done;
1406 NEW = LEFT;
1407 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1408 NEW.rm_blockcount, NEW.rm_owner,
1409 NEW.rm_offset, NEW.rm_flags, &i);
1410 if (error)
1411 goto done;
1412 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1413 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1414 error = xfs_rmap_update(cur, &NEW);
1415 if (error)
1416 goto done;
1417 break;
1418
1419 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1420 /*
1421 * Setting all of a previous oldext extent to newext.
1422 * The left neighbor is contiguous, the right is not.
1423 */
1424 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1425 PREV.rm_blockcount, PREV.rm_owner,
1426 PREV.rm_offset, PREV.rm_flags);
1427 if (error)
1428 goto done;
1429 NEW = LEFT;
1430 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1431 NEW.rm_blockcount, NEW.rm_owner,
1432 NEW.rm_offset, NEW.rm_flags, &i);
1433 if (error)
1434 goto done;
1435 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1436 NEW.rm_blockcount += PREV.rm_blockcount;
1437 error = xfs_rmap_update(cur, &NEW);
1438 if (error)
1439 goto done;
1440 break;
1441
1442 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1443 /*
1444 * Setting all of a previous oldext extent to newext.
1445 * The right neighbor is contiguous, the left is not.
1446 */
1447 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1448 RIGHT.rm_blockcount, RIGHT.rm_owner,
1449 RIGHT.rm_offset, RIGHT.rm_flags);
1450 if (error)
1451 goto done;
1452 NEW = PREV;
1453 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1454 NEW.rm_blockcount, NEW.rm_owner,
1455 NEW.rm_offset, NEW.rm_flags, &i);
1456 if (error)
1457 goto done;
1458 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1459 NEW.rm_blockcount += RIGHT.rm_blockcount;
1460 NEW.rm_flags = RIGHT.rm_flags;
1461 error = xfs_rmap_update(cur, &NEW);
1462 if (error)
1463 goto done;
1464 break;
1465
1466 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1467 /*
1468 * Setting all of a previous oldext extent to newext.
1469 * Neither the left nor right neighbors are contiguous with
1470 * the new one.
1471 */
1472 NEW = PREV;
1473 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1474 NEW.rm_blockcount, NEW.rm_owner,
1475 NEW.rm_offset, NEW.rm_flags, &i);
1476 if (error)
1477 goto done;
1478 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1479 NEW.rm_flags = newext;
1480 error = xfs_rmap_update(cur, &NEW);
1481 if (error)
1482 goto done;
1483 break;
1484
1485 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1486 /*
1487 * Setting the first part of a previous oldext extent to newext.
1488 * The left neighbor is contiguous.
1489 */
1490 NEW = PREV;
1491 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1492 NEW.rm_blockcount, NEW.rm_owner,
1493 NEW.rm_offset, NEW.rm_flags);
1494 if (error)
1495 goto done;
1496 NEW.rm_offset += len;
1497 NEW.rm_startblock += len;
1498 NEW.rm_blockcount -= len;
1499 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1500 NEW.rm_blockcount, NEW.rm_owner,
1501 NEW.rm_offset, NEW.rm_flags);
1502 if (error)
1503 goto done;
1504 NEW = LEFT;
1505 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1506 NEW.rm_blockcount, NEW.rm_owner,
1507 NEW.rm_offset, NEW.rm_flags, &i);
1508 if (error)
1509 goto done;
1510 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1511 NEW.rm_blockcount += len;
1512 error = xfs_rmap_update(cur, &NEW);
1513 if (error)
1514 goto done;
1515 break;
1516
1517 case RMAP_LEFT_FILLING:
1518 /*
1519 * Setting the first part of a previous oldext extent to newext.
1520 * The left neighbor is not contiguous.
1521 */
1522 NEW = PREV;
1523 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1524 NEW.rm_blockcount, NEW.rm_owner,
1525 NEW.rm_offset, NEW.rm_flags);
1526 if (error)
1527 goto done;
1528 NEW.rm_offset += len;
1529 NEW.rm_startblock += len;
1530 NEW.rm_blockcount -= len;
1531 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1532 NEW.rm_blockcount, NEW.rm_owner,
1533 NEW.rm_offset, NEW.rm_flags);
1534 if (error)
1535 goto done;
1536 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1537 if (error)
1538 goto done;
1539 break;
1540
1541 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1542 /*
1543 * Setting the last part of a previous oldext extent to newext.
1544 * The right neighbor is contiguous with the new allocation.
1545 */
1546 NEW = PREV;
1547 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1548 NEW.rm_blockcount, NEW.rm_owner,
1549 NEW.rm_offset, NEW.rm_flags, &i);
1550 if (error)
1551 goto done;
1552 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1553 NEW.rm_blockcount = offset - NEW.rm_offset;
1554 error = xfs_rmap_update(cur, &NEW);
1555 if (error)
1556 goto done;
1557 NEW = RIGHT;
1558 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1559 NEW.rm_blockcount, NEW.rm_owner,
1560 NEW.rm_offset, NEW.rm_flags);
1561 if (error)
1562 goto done;
1563 NEW.rm_offset = offset;
1564 NEW.rm_startblock = bno;
1565 NEW.rm_blockcount += len;
1566 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1567 NEW.rm_blockcount, NEW.rm_owner,
1568 NEW.rm_offset, NEW.rm_flags);
1569 if (error)
1570 goto done;
1571 break;
1572
1573 case RMAP_RIGHT_FILLING:
1574 /*
1575 * Setting the last part of a previous oldext extent to newext.
1576 * The right neighbor is not contiguous.
1577 */
1578 NEW = PREV;
1579 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1580 NEW.rm_blockcount, NEW.rm_owner,
1581 NEW.rm_offset, NEW.rm_flags, &i);
1582 if (error)
1583 goto done;
1584 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1585 NEW.rm_blockcount -= len;
1586 error = xfs_rmap_update(cur, &NEW);
1587 if (error)
1588 goto done;
1589 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1590 if (error)
1591 goto done;
1592 break;
1593
1594 case 0:
1595 /*
1596 * Setting the middle part of a previous oldext extent to
1597 * newext. Contiguity is impossible here.
1598 * One extent becomes three extents.
1599 */
1600 /* new right extent - oldext */
1601 NEW.rm_startblock = bno + len;
1602 NEW.rm_owner = owner;
1603 NEW.rm_offset = new_endoff;
1604 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1605 new_endoff;
1606 NEW.rm_flags = PREV.rm_flags;
1607 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1608 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1609 NEW.rm_flags);
1610 if (error)
1611 goto done;
1612 /* new left extent - oldext */
1613 NEW = PREV;
1614 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1615 NEW.rm_blockcount, NEW.rm_owner,
1616 NEW.rm_offset, NEW.rm_flags, &i);
1617 if (error)
1618 goto done;
1619 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1620 NEW.rm_blockcount = offset - NEW.rm_offset;
1621 error = xfs_rmap_update(cur, &NEW);
1622 if (error)
1623 goto done;
1624 /* new middle extent - newext */
1625 NEW.rm_startblock = bno;
1626 NEW.rm_blockcount = len;
1627 NEW.rm_owner = owner;
1628 NEW.rm_offset = offset;
1629 NEW.rm_flags = newext;
1630 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1631 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1632 NEW.rm_flags);
1633 if (error)
1634 goto done;
1635 break;
1636
1637 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1638 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1639 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1640 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1641 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1642 case RMAP_LEFT_CONTIG:
1643 case RMAP_RIGHT_CONTIG:
1644 /*
1645 * These cases are all impossible.
1646 */
1647 ASSERT(0);
1648 }
1649
1650 trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
1651 unwritten, oinfo);
1652done:
1653 if (error)
1654 trace_xfs_rmap_convert_error(cur->bc_mp,
1655 cur->bc_private.a.agno, error, _RET_IP_);
1656 return error;
1657}
1658
1281#undef NEW 1659#undef NEW
1282#undef LEFT 1660#undef LEFT
1283#undef RIGHT 1661#undef RIGHT
@@ -1754,6 +2132,10 @@ xfs_rmap_finish_one(
1754 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten, 2132 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
1755 &oinfo); 2133 &oinfo);
1756 break; 2134 break;
2135 case XFS_RMAP_CONVERT_SHARED:
2136 error = xfs_rmap_convert_shared(rcur, bno, blockcount,
2137 !unwritten, &oinfo);
2138 break;
1757 default: 2139 default:
1758 ASSERT(0); 2140 ASSERT(0);
1759 error = -EFSCORRUPTED; 2141 error = -EFSCORRUPTED;
@@ -1857,7 +2239,8 @@ xfs_rmap_convert_extent(
1857 if (!xfs_rmap_update_is_needed(mp, whichfork)) 2239 if (!xfs_rmap_update_is_needed(mp, whichfork))
1858 return 0; 2240 return 0;
1859 2241
1860 return __xfs_rmap_add(mp, dfops, XFS_RMAP_CONVERT, ip->i_ino, 2242 return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ?
2243 XFS_RMAP_CONVERT_SHARED : XFS_RMAP_CONVERT, ip->i_ino,
1861 whichfork, PREV); 2244 whichfork, PREV);
1862} 2245}
1863 2246
diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c
index 3b8742e48815..73c827831551 100644
--- a/fs/xfs/xfs_rmap_item.c
+++ b/fs/xfs/xfs_rmap_item.c
@@ -496,6 +496,9 @@ xfs_rui_recover(
496 case XFS_RMAP_EXTENT_CONVERT: 496 case XFS_RMAP_EXTENT_CONVERT:
497 type = XFS_RMAP_CONVERT; 497 type = XFS_RMAP_CONVERT;
498 break; 498 break;
499 case XFS_RMAP_EXTENT_CONVERT_SHARED:
500 type = XFS_RMAP_CONVERT_SHARED;
501 break;
499 case XFS_RMAP_EXTENT_ALLOC: 502 case XFS_RMAP_EXTENT_ALLOC:
500 type = XFS_RMAP_ALLOC; 503 type = XFS_RMAP_ALLOC;
501 break; 504 break;