|
22 | 22 | #include "xfs_rtbitmap.h" |
23 | 23 | #include "xfs_attr_item.h" |
24 | 24 | #include "xfs_log.h" |
| 25 | +#include "xfs_defer.h" |
| 26 | +#include "xfs_bmap_item.h" |
| 27 | +#include "xfs_extfree_item.h" |
| 28 | +#include "xfs_rmap_item.h" |
| 29 | +#include "xfs_refcount_item.h" |
| 30 | +#include "xfs_trace.h" |
25 | 31 |
|
26 | 32 | #define _ALLOC true |
27 | 33 | #define _FREE false |
@@ -1394,3 +1400,91 @@ xfs_trans_resv_calc( |
1394 | 1400 | */ |
1395 | 1401 | xfs_calc_default_atomic_ioend_reservation(mp, resp); |
1396 | 1402 | } |
| 1403 | + |
| 1404 | +/* |
| 1405 | + * Return the per-extent and fixed transaction reservation sizes needed to |
| 1406 | + * complete an atomic write. |
| 1407 | + */ |
| 1408 | +STATIC unsigned int |
| 1409 | +xfs_calc_atomic_write_ioend_geometry( |
| 1410 | + struct xfs_mount *mp, |
| 1411 | + unsigned int *step_size) |
| 1412 | +{ |
| 1413 | + const unsigned int efi = xfs_efi_log_space(1); |
| 1414 | + const unsigned int efd = xfs_efd_log_space(1); |
| 1415 | + const unsigned int rui = xfs_rui_log_space(1); |
| 1416 | + const unsigned int rud = xfs_rud_log_space(); |
| 1417 | + const unsigned int cui = xfs_cui_log_space(1); |
| 1418 | + const unsigned int cud = xfs_cud_log_space(); |
| 1419 | + const unsigned int bui = xfs_bui_log_space(1); |
| 1420 | + const unsigned int bud = xfs_bud_log_space(); |
| 1421 | + |
| 1422 | + /* |
| 1423 | + * Maximum overhead to complete an atomic write ioend in software: |
| 1424 | + * remove data fork extent + remove cow fork extent + map extent into |
| 1425 | + * data fork. |
| 1426 | + * |
| 1427 | + * tx0: Creates a BUI and a CUI and that's all it needs. |
| 1428 | + * |
| 1429 | + * tx1: Roll to finish the BUI. Need space for the BUD, an RUI, and |
| 1430 | + * enough space to relog the CUI (== CUI + CUD). |
| 1431 | + * |
| 1432 | + * tx2: Roll again to finish the RUI. Need space for the RUD and space |
| 1433 | + * to relog the CUI. |
| 1434 | + * |
| 1435 | + * tx3: Roll again, need space for the CUD and possibly a new EFI. |
| 1436 | + * |
| 1437 | + * tx4: Roll again, need space for an EFD. |
| 1438 | + * |
| 1439 | + * If the extent referenced by the pair of BUI/CUI items is not the one |
| 1440 | + * being currently processed, then we need to reserve space to relog |
| 1441 | + * both items. |
| 1442 | + */ |
| 1443 | + const unsigned int tx0 = bui + cui; |
| 1444 | + const unsigned int tx1 = bud + rui + cui + cud; |
| 1445 | + const unsigned int tx2 = rud + cui + cud; |
| 1446 | + const unsigned int tx3 = cud + efi; |
| 1447 | + const unsigned int tx4 = efd; |
| 1448 | + const unsigned int relog = bui + bud + cui + cud; |
| 1449 | + |
| 1450 | + const unsigned int per_intent = max(max3(tx0, tx1, tx2), |
| 1451 | + max3(tx3, tx4, relog)); |
| 1452 | + |
| 1453 | + /* Overhead to finish one step of each intent item type */ |
| 1454 | + const unsigned int f1 = xfs_calc_finish_efi_reservation(mp, 1); |
| 1455 | + const unsigned int f2 = xfs_calc_finish_rui_reservation(mp, 1); |
| 1456 | + const unsigned int f3 = xfs_calc_finish_cui_reservation(mp, 1); |
| 1457 | + const unsigned int f4 = xfs_calc_finish_bui_reservation(mp, 1); |
| 1458 | + |
| 1459 | + /* We only finish one item per transaction in a chain */ |
| 1460 | + *step_size = max(f4, max3(f1, f2, f3)); |
| 1461 | + |
| 1462 | + return per_intent; |
| 1463 | +} |
| 1464 | + |
| 1465 | +/* |
| 1466 | + * Compute the maximum size (in fsblocks) of atomic writes that we can complete |
| 1467 | + * given the existing log reservations. |
| 1468 | + */ |
| 1469 | +xfs_extlen_t |
| 1470 | +xfs_calc_max_atomic_write_fsblocks( |
| 1471 | + struct xfs_mount *mp) |
| 1472 | +{ |
| 1473 | + const struct xfs_trans_res *resv = &M_RES(mp)->tr_atomic_ioend; |
| 1474 | + unsigned int per_intent = 0; |
| 1475 | + unsigned int step_size = 0; |
| 1476 | + unsigned int ret = 0; |
| 1477 | + |
| 1478 | + if (resv->tr_logres > 0) { |
| 1479 | + per_intent = xfs_calc_atomic_write_ioend_geometry(mp, |
| 1480 | + &step_size); |
| 1481 | + |
| 1482 | + if (resv->tr_logres >= step_size) |
| 1483 | + ret = (resv->tr_logres - step_size) / per_intent; |
| 1484 | + } |
| 1485 | + |
| 1486 | + trace_xfs_calc_max_atomic_write_fsblocks(mp, per_intent, step_size, |
| 1487 | + resv->tr_logres, ret); |
| 1488 | + |
| 1489 | + return ret; |
| 1490 | +} |
0 commit comments