diff options
author | Dave Chinner <dchinner@redhat.com> | 2015-02-23 05:24:11 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-02-23 05:24:11 -0500 |
commit | 0bd5ddedccca4451ac2390d1155b4ab74b990eff (patch) | |
tree | 2ce9d784ac9ccb57f99f03b2394f4b438a937830 /fs/xfs | |
parent | bab98bbe6e1e38bf2fa5018a195608553095f51b (diff) |
xfs: replace xfs_mod_incore_sb_batched
Introduce helper functions for modifying fields in the superblock
into xfs_trans.c, the only caller of xfs_mod_incore_sb_batch(). We
can then use these directly in xfs_trans_unreserve_and_mod_sb() and
so remove another user of the xfs_mode_incore_sb() API without
losing any functionality or scalability of the transaction commit
code..
Based on a patch from Christoph Hellwig.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_mount.c | 51 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 11 | ||||
-rw-r--r-- | fs/xfs/xfs_trans.c | 198 |
3 files changed, 126 insertions, 134 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index df4c32fdc706..d748aa73003b 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -1353,57 +1353,6 @@ xfs_mod_incore_sb( | |||
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | /* | 1355 | /* |
1356 | * Change more than one field in the in-core superblock structure at a time. | ||
1357 | * | ||
1358 | * The fields and changes to those fields are specified in the array of | ||
1359 | * xfs_mod_sb structures passed in. Either all of the specified deltas | ||
1360 | * will be applied or none of them will. If any modified field dips below 0, | ||
1361 | * then all modifications will be backed out and EINVAL will be returned. | ||
1362 | * | ||
1363 | * Note that this function may not be used for the superblock values that | ||
1364 | * are tracked with the in-memory per-cpu counters - a direct call to | ||
1365 | * xfs_mod_incore_sb is required for these. | ||
1366 | */ | ||
1367 | int | ||
1368 | xfs_mod_incore_sb_batch( | ||
1369 | struct xfs_mount *mp, | ||
1370 | xfs_mod_sb_t *msb, | ||
1371 | uint nmsb, | ||
1372 | int rsvd) | ||
1373 | { | ||
1374 | xfs_mod_sb_t *msbp; | ||
1375 | int error = 0; | ||
1376 | |||
1377 | /* | ||
1378 | * Loop through the array of mod structures and apply each individually. | ||
1379 | * If any fail, then back out all those which have already been applied. | ||
1380 | * Do all of this within the scope of the m_sb_lock so that all of the | ||
1381 | * changes will be atomic. | ||
1382 | */ | ||
1383 | spin_lock(&mp->m_sb_lock); | ||
1384 | for (msbp = msb; msbp < (msb + nmsb); msbp++) { | ||
1385 | ASSERT(msbp->msb_field < XFS_SBS_ICOUNT || | ||
1386 | msbp->msb_field > XFS_SBS_FDBLOCKS); | ||
1387 | |||
1388 | error = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, | ||
1389 | msbp->msb_delta, rsvd); | ||
1390 | if (error) | ||
1391 | goto unwind; | ||
1392 | } | ||
1393 | spin_unlock(&mp->m_sb_lock); | ||
1394 | return 0; | ||
1395 | |||
1396 | unwind: | ||
1397 | while (--msbp >= msb) { | ||
1398 | error = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, | ||
1399 | -msbp->msb_delta, rsvd); | ||
1400 | ASSERT(error == 0); | ||
1401 | } | ||
1402 | spin_unlock(&mp->m_sb_lock); | ||
1403 | return error; | ||
1404 | } | ||
1405 | |||
1406 | /* | ||
1407 | * xfs_getsb() is called to obtain the buffer for the superblock. | 1356 | * xfs_getsb() is called to obtain the buffer for the superblock. |
1408 | * The buffer is returned locked and read in from disk. | 1357 | * The buffer is returned locked and read in from disk. |
1409 | * The buffer should be released with a call to xfs_brelse(). | 1358 | * The buffer should be released with a call to xfs_brelse(). |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index d65e0f23b847..1c11512bab83 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -260,15 +260,6 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) | |||
260 | } | 260 | } |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * This structure is for use by the xfs_mod_incore_sb_batch() routine. | ||
264 | * xfs_growfs can specify a few fields which are more than int limit | ||
265 | */ | ||
266 | typedef struct xfs_mod_sb { | ||
267 | xfs_sb_field_t msb_field; /* Field to modify, see below */ | ||
268 | int64_t msb_delta; /* Change to make to specified field */ | ||
269 | } xfs_mod_sb_t; | ||
270 | |||
271 | /* | ||
272 | * Per-ag incore structure, copies of information in agf and agi, to improve the | 263 | * Per-ag incore structure, copies of information in agf and agi, to improve the |
273 | * performance of allocation group selection. | 264 | * performance of allocation group selection. |
274 | */ | 265 | */ |
@@ -325,8 +316,6 @@ extern int xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount, | |||
325 | 316 | ||
326 | extern void xfs_unmountfs(xfs_mount_t *); | 317 | extern void xfs_unmountfs(xfs_mount_t *); |
327 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); | 318 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); |
328 | extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, | ||
329 | uint, int); | ||
330 | extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); | 319 | extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); |
331 | extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta); | 320 | extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta); |
332 | extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, | 321 | extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, |
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 4e4bc5aed6b6..220ef2c906b2 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
@@ -485,6 +485,54 @@ xfs_trans_apply_sb_deltas( | |||
485 | sizeof(sbp->sb_frextents) - 1); | 485 | sizeof(sbp->sb_frextents) - 1); |
486 | } | 486 | } |
487 | 487 | ||
488 | STATIC int | ||
489 | xfs_sb_mod8( | ||
490 | uint8_t *field, | ||
491 | int8_t delta) | ||
492 | { | ||
493 | int8_t counter = *field; | ||
494 | |||
495 | counter += delta; | ||
496 | if (counter < 0) { | ||
497 | ASSERT(0); | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | *field = counter; | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | STATIC int | ||
505 | xfs_sb_mod32( | ||
506 | uint32_t *field, | ||
507 | int32_t delta) | ||
508 | { | ||
509 | int32_t counter = *field; | ||
510 | |||
511 | counter += delta; | ||
512 | if (counter < 0) { | ||
513 | ASSERT(0); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | *field = counter; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | STATIC int | ||
521 | xfs_sb_mod64( | ||
522 | uint64_t *field, | ||
523 | int64_t delta) | ||
524 | { | ||
525 | int64_t counter = *field; | ||
526 | |||
527 | counter += delta; | ||
528 | if (counter < 0) { | ||
529 | ASSERT(0); | ||
530 | return -EINVAL; | ||
531 | } | ||
532 | *field = counter; | ||
533 | return 0; | ||
534 | } | ||
535 | |||
488 | /* | 536 | /* |
489 | * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations | 537 | * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations |
490 | * and apply superblock counter changes to the in-core superblock. The | 538 | * and apply superblock counter changes to the in-core superblock. The |
@@ -492,13 +540,6 @@ xfs_trans_apply_sb_deltas( | |||
492 | * applied to the in-core superblock. The idea is that that has already been | 540 | * applied to the in-core superblock. The idea is that that has already been |
493 | * done. | 541 | * done. |
494 | * | 542 | * |
495 | * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). | ||
496 | * However, we have to ensure that we only modify each superblock field only | ||
497 | * once because the application of the delta values may not be atomic. That can | ||
498 | * lead to ENOSPC races occurring if we have two separate modifcations of the | ||
499 | * free space counter to put back the entire reservation and then take away | ||
500 | * what we used. | ||
501 | * | ||
502 | * If we are not logging superblock counters, then the inode allocated/free and | 543 | * If we are not logging superblock counters, then the inode allocated/free and |
503 | * used block counts are not updated in the on disk superblock. In this case, | 544 | * used block counts are not updated in the on disk superblock. In this case, |
504 | * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we | 545 | * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we |
@@ -506,20 +547,15 @@ xfs_trans_apply_sb_deltas( | |||
506 | */ | 547 | */ |
507 | void | 548 | void |
508 | xfs_trans_unreserve_and_mod_sb( | 549 | xfs_trans_unreserve_and_mod_sb( |
509 | xfs_trans_t *tp) | 550 | struct xfs_trans *tp) |
510 | { | 551 | { |
511 | xfs_mod_sb_t msb[9]; /* If you add cases, add entries */ | 552 | struct xfs_mount *mp = tp->t_mountp; |
512 | xfs_mod_sb_t *msbp; | 553 | bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; |
513 | xfs_mount_t *mp = tp->t_mountp; | 554 | int64_t blkdelta = 0; |
514 | /* REFERENCED */ | 555 | int64_t rtxdelta = 0; |
515 | int error; | 556 | int64_t idelta = 0; |
516 | bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; | 557 | int64_t ifreedelta = 0; |
517 | int64_t blkdelta = 0; | 558 | int error; |
518 | int64_t rtxdelta = 0; | ||
519 | int64_t idelta = 0; | ||
520 | int64_t ifreedelta = 0; | ||
521 | |||
522 | msbp = msb; | ||
523 | 559 | ||
524 | /* calculate deltas */ | 560 | /* calculate deltas */ |
525 | if (tp->t_blk_res > 0) | 561 | if (tp->t_blk_res > 0) |
@@ -560,72 +596,90 @@ xfs_trans_unreserve_and_mod_sb( | |||
560 | goto out_undo_icount; | 596 | goto out_undo_icount; |
561 | } | 597 | } |
562 | 598 | ||
599 | if (rtxdelta == 0 && !(tp->t_flags & XFS_TRANS_SB_DIRTY)) | ||
600 | return; | ||
601 | |||
563 | /* apply remaining deltas */ | 602 | /* apply remaining deltas */ |
603 | spin_lock(&mp->m_sb_lock); | ||
564 | if (rtxdelta) { | 604 | if (rtxdelta) { |
565 | error = xfs_mod_frextents(mp, rtxdelta); | 605 | error = xfs_sb_mod64(&mp->m_sb.sb_frextents, rtxdelta); |
566 | if (error) | 606 | if (error) |
567 | goto out_undo_ifree; | 607 | goto out_undo_ifree; |
568 | } | 608 | } |
569 | 609 | ||
570 | if (tp->t_flags & XFS_TRANS_SB_DIRTY) { | 610 | if (tp->t_dblocks_delta != 0) { |
571 | if (tp->t_dblocks_delta != 0) { | 611 | error = xfs_sb_mod64(&mp->m_sb.sb_dblocks, tp->t_dblocks_delta); |
572 | msbp->msb_field = XFS_SBS_DBLOCKS; | ||
573 | msbp->msb_delta = tp->t_dblocks_delta; | ||
574 | msbp++; | ||
575 | } | ||
576 | if (tp->t_agcount_delta != 0) { | ||
577 | msbp->msb_field = XFS_SBS_AGCOUNT; | ||
578 | msbp->msb_delta = tp->t_agcount_delta; | ||
579 | msbp++; | ||
580 | } | ||
581 | if (tp->t_imaxpct_delta != 0) { | ||
582 | msbp->msb_field = XFS_SBS_IMAX_PCT; | ||
583 | msbp->msb_delta = tp->t_imaxpct_delta; | ||
584 | msbp++; | ||
585 | } | ||
586 | if (tp->t_rextsize_delta != 0) { | ||
587 | msbp->msb_field = XFS_SBS_REXTSIZE; | ||
588 | msbp->msb_delta = tp->t_rextsize_delta; | ||
589 | msbp++; | ||
590 | } | ||
591 | if (tp->t_rbmblocks_delta != 0) { | ||
592 | msbp->msb_field = XFS_SBS_RBMBLOCKS; | ||
593 | msbp->msb_delta = tp->t_rbmblocks_delta; | ||
594 | msbp++; | ||
595 | } | ||
596 | if (tp->t_rblocks_delta != 0) { | ||
597 | msbp->msb_field = XFS_SBS_RBLOCKS; | ||
598 | msbp->msb_delta = tp->t_rblocks_delta; | ||
599 | msbp++; | ||
600 | } | ||
601 | if (tp->t_rextents_delta != 0) { | ||
602 | msbp->msb_field = XFS_SBS_REXTENTS; | ||
603 | msbp->msb_delta = tp->t_rextents_delta; | ||
604 | msbp++; | ||
605 | } | ||
606 | if (tp->t_rextslog_delta != 0) { | ||
607 | msbp->msb_field = XFS_SBS_REXTSLOG; | ||
608 | msbp->msb_delta = tp->t_rextslog_delta; | ||
609 | msbp++; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | /* | ||
614 | * If we need to change anything, do it. | ||
615 | */ | ||
616 | if (msbp > msb) { | ||
617 | error = xfs_mod_incore_sb_batch(tp->t_mountp, msb, | ||
618 | (uint)(msbp - msb), rsvd); | ||
619 | if (error) | 612 | if (error) |
620 | goto out_undo_frextents; | 613 | goto out_undo_frextents; |
621 | } | 614 | } |
622 | 615 | if (tp->t_agcount_delta != 0) { | |
616 | error = xfs_sb_mod32(&mp->m_sb.sb_agcount, tp->t_agcount_delta); | ||
617 | if (error) | ||
618 | goto out_undo_dblocks; | ||
619 | } | ||
620 | if (tp->t_imaxpct_delta != 0) { | ||
621 | error = xfs_sb_mod8(&mp->m_sb.sb_imax_pct, tp->t_imaxpct_delta); | ||
622 | if (error) | ||
623 | goto out_undo_agcount; | ||
624 | } | ||
625 | if (tp->t_rextsize_delta != 0) { | ||
626 | error = xfs_sb_mod32(&mp->m_sb.sb_rextsize, | ||
627 | tp->t_rextsize_delta); | ||
628 | if (error) | ||
629 | goto out_undo_imaxpct; | ||
630 | } | ||
631 | if (tp->t_rbmblocks_delta != 0) { | ||
632 | error = xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, | ||
633 | tp->t_rbmblocks_delta); | ||
634 | if (error) | ||
635 | goto out_undo_rextsize; | ||
636 | } | ||
637 | if (tp->t_rblocks_delta != 0) { | ||
638 | error = xfs_sb_mod64(&mp->m_sb.sb_rblocks, tp->t_rblocks_delta); | ||
639 | if (error) | ||
640 | goto out_undo_rbmblocks; | ||
641 | } | ||
642 | if (tp->t_rextents_delta != 0) { | ||
643 | error = xfs_sb_mod64(&mp->m_sb.sb_rextents, | ||
644 | tp->t_rextents_delta); | ||
645 | if (error) | ||
646 | goto out_undo_rblocks; | ||
647 | } | ||
648 | if (tp->t_rextslog_delta != 0) { | ||
649 | error = xfs_sb_mod8(&mp->m_sb.sb_rextslog, | ||
650 | tp->t_rextslog_delta); | ||
651 | if (error) | ||
652 | goto out_undo_rextents; | ||
653 | } | ||
654 | spin_unlock(&mp->m_sb_lock); | ||
623 | return; | 655 | return; |
624 | 656 | ||
657 | out_undo_rextents: | ||
658 | if (tp->t_rextents_delta) | ||
659 | xfs_sb_mod64(&mp->m_sb.sb_rextents, -tp->t_rextents_delta); | ||
660 | out_undo_rblocks: | ||
661 | if (tp->t_rblocks_delta) | ||
662 | xfs_sb_mod64(&mp->m_sb.sb_rblocks, -tp->t_rblocks_delta); | ||
663 | out_undo_rbmblocks: | ||
664 | if (tp->t_rbmblocks_delta) | ||
665 | xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, -tp->t_rbmblocks_delta); | ||
666 | out_undo_rextsize: | ||
667 | if (tp->t_rextsize_delta) | ||
668 | xfs_sb_mod32(&mp->m_sb.sb_rextsize, -tp->t_rextsize_delta); | ||
669 | out_undo_imaxpct: | ||
670 | if (tp->t_rextsize_delta) | ||
671 | xfs_sb_mod8(&mp->m_sb.sb_imax_pct, -tp->t_imaxpct_delta); | ||
672 | out_undo_agcount: | ||
673 | if (tp->t_agcount_delta) | ||
674 | xfs_sb_mod32(&mp->m_sb.sb_agcount, -tp->t_agcount_delta); | ||
675 | out_undo_dblocks: | ||
676 | if (tp->t_dblocks_delta) | ||
677 | xfs_sb_mod64(&mp->m_sb.sb_dblocks, -tp->t_dblocks_delta); | ||
625 | out_undo_frextents: | 678 | out_undo_frextents: |
626 | if (rtxdelta) | 679 | if (rtxdelta) |
627 | xfs_mod_frextents(mp, -rtxdelta); | 680 | xfs_sb_mod64(&mp->m_sb.sb_frextents, -rtxdelta); |
628 | out_undo_ifree: | 681 | out_undo_ifree: |
682 | spin_unlock(&mp->m_sb_lock); | ||
629 | if (ifreedelta) | 683 | if (ifreedelta) |
630 | xfs_mod_ifree(mp, -ifreedelta); | 684 | xfs_mod_ifree(mp, -ifreedelta); |
631 | out_undo_icount: | 685 | out_undo_icount: |