aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2015-02-23 05:24:11 -0500
committerDave Chinner <david@fromorbit.com>2015-02-23 05:24:11 -0500
commit0bd5ddedccca4451ac2390d1155b4ab74b990eff (patch)
tree2ce9d784ac9ccb57f99f03b2394f4b438a937830 /fs/xfs
parentbab98bbe6e1e38bf2fa5018a195608553095f51b (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.c51
-rw-r--r--fs/xfs/xfs_mount.h11
-rw-r--r--fs/xfs/xfs_trans.c198
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 */
1367int
1368xfs_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
1396unwind:
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 */
266typedef 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
326extern void xfs_unmountfs(xfs_mount_t *); 317extern void xfs_unmountfs(xfs_mount_t *);
327extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); 318extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
328extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
329 uint, int);
330extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); 319extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta);
331extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta); 320extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta);
332extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, 321extern 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
488STATIC int
489xfs_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
504STATIC int
505xfs_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
520STATIC int
521xfs_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 */
507void 548void
508xfs_trans_unreserve_and_mod_sb( 549xfs_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
657out_undo_rextents:
658 if (tp->t_rextents_delta)
659 xfs_sb_mod64(&mp->m_sb.sb_rextents, -tp->t_rextents_delta);
660out_undo_rblocks:
661 if (tp->t_rblocks_delta)
662 xfs_sb_mod64(&mp->m_sb.sb_rblocks, -tp->t_rblocks_delta);
663out_undo_rbmblocks:
664 if (tp->t_rbmblocks_delta)
665 xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, -tp->t_rbmblocks_delta);
666out_undo_rextsize:
667 if (tp->t_rextsize_delta)
668 xfs_sb_mod32(&mp->m_sb.sb_rextsize, -tp->t_rextsize_delta);
669out_undo_imaxpct:
670 if (tp->t_rextsize_delta)
671 xfs_sb_mod8(&mp->m_sb.sb_imax_pct, -tp->t_imaxpct_delta);
672out_undo_agcount:
673 if (tp->t_agcount_delta)
674 xfs_sb_mod32(&mp->m_sb.sb_agcount, -tp->t_agcount_delta);
675out_undo_dblocks:
676 if (tp->t_dblocks_delta)
677 xfs_sb_mod64(&mp->m_sb.sb_dblocks, -tp->t_dblocks_delta);
625out_undo_frextents: 678out_undo_frextents:
626 if (rtxdelta) 679 if (rtxdelta)
627 xfs_mod_frextents(mp, -rtxdelta); 680 xfs_sb_mod64(&mp->m_sb.sb_frextents, -rtxdelta);
628out_undo_ifree: 681out_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);
631out_undo_icount: 685out_undo_icount: