diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 100 |
1 files changed, 76 insertions, 24 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index fbdc0dc9923e..8fcfb784f906 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -276,7 +276,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
276 | * @blks: The number of blocks to reserve | 276 | * @blks: The number of blocks to reserve |
277 | * | 277 | * |
278 | * Note that we never give out the last few blocks of the journal. Thats | 278 | * Note that we never give out the last few blocks of the journal. Thats |
279 | * due to the fact that there is are a small number of header blocks | 279 | * due to the fact that there is a small number of header blocks |
280 | * associated with each log flush. The exact number can't be known until | 280 | * associated with each log flush. The exact number can't be known until |
281 | * flush time, so we ensure that we have just enough free blocks at all | 281 | * flush time, so we ensure that we have just enough free blocks at all |
282 | * times to avoid running out during a log flush. | 282 | * times to avoid running out during a log flush. |
@@ -371,6 +371,58 @@ static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer | |||
371 | return dist; | 371 | return dist; |
372 | } | 372 | } |
373 | 373 | ||
374 | /** | ||
375 | * calc_reserved - Calculate the number of blocks to reserve when | ||
376 | * refunding a transaction's unused buffers. | ||
377 | * @sdp: The GFS2 superblock | ||
378 | * | ||
379 | * This is complex. We need to reserve room for all our currently used | ||
380 | * metadata buffers (e.g. normal file I/O rewriting file time stamps) and | ||
381 | * all our journaled data buffers for journaled files (e.g. files in the | ||
382 | * meta_fs like rindex, or files for which chattr +j was done.) | ||
383 | * If we don't reserve enough space, gfs2_log_refund and gfs2_log_flush | ||
384 | * will count it as free space (sd_log_blks_free) and corruption will follow. | ||
385 | * | ||
386 | * We can have metadata bufs and jdata bufs in the same journal. So each | ||
387 | * type gets its own log header, for which we need to reserve a block. | ||
388 | * In fact, each type has the potential for needing more than one header | ||
389 | * in cases where we have more buffers than will fit on a journal page. | ||
390 | * Metadata journal entries take up half the space of journaled buffer entries. | ||
391 | * Thus, metadata entries have buf_limit (502) and journaled buffers have | ||
392 | * databuf_limit (251) before they cause a wrap around. | ||
393 | * | ||
394 | * Also, we need to reserve blocks for revoke journal entries and one for an | ||
395 | * overall header for the lot. | ||
396 | * | ||
397 | * Returns: the number of blocks reserved | ||
398 | */ | ||
399 | static unsigned int calc_reserved(struct gfs2_sbd *sdp) | ||
400 | { | ||
401 | unsigned int reserved = 0; | ||
402 | unsigned int mbuf_limit, metabufhdrs_needed; | ||
403 | unsigned int dbuf_limit, databufhdrs_needed; | ||
404 | unsigned int revokes = 0; | ||
405 | |||
406 | mbuf_limit = buf_limit(sdp); | ||
407 | metabufhdrs_needed = (sdp->sd_log_commited_buf + | ||
408 | (mbuf_limit - 1)) / mbuf_limit; | ||
409 | dbuf_limit = databuf_limit(sdp); | ||
410 | databufhdrs_needed = (sdp->sd_log_commited_databuf + | ||
411 | (dbuf_limit - 1)) / dbuf_limit; | ||
412 | |||
413 | if (sdp->sd_log_commited_revoke) | ||
414 | revokes = gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, | ||
415 | sizeof(u64)); | ||
416 | |||
417 | reserved = sdp->sd_log_commited_buf + metabufhdrs_needed + | ||
418 | sdp->sd_log_commited_databuf + databufhdrs_needed + | ||
419 | revokes; | ||
420 | /* One for the overall header */ | ||
421 | if (reserved) | ||
422 | reserved++; | ||
423 | return reserved; | ||
424 | } | ||
425 | |||
374 | static unsigned int current_tail(struct gfs2_sbd *sdp) | 426 | static unsigned int current_tail(struct gfs2_sbd *sdp) |
375 | { | 427 | { |
376 | struct gfs2_ail *ai; | 428 | struct gfs2_ail *ai; |
@@ -461,14 +513,14 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, | |||
461 | return bh; | 513 | return bh; |
462 | } | 514 | } |
463 | 515 | ||
464 | static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) | 516 | static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) |
465 | { | 517 | { |
466 | unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); | 518 | unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); |
467 | 519 | ||
468 | ail2_empty(sdp, new_tail); | 520 | ail2_empty(sdp, new_tail); |
469 | 521 | ||
470 | gfs2_log_lock(sdp); | 522 | gfs2_log_lock(sdp); |
471 | sdp->sd_log_blks_free += dist - (pull ? 1 : 0); | 523 | sdp->sd_log_blks_free += dist; |
472 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); | 524 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); |
473 | gfs2_log_unlock(sdp); | 525 | gfs2_log_unlock(sdp); |
474 | 526 | ||
@@ -518,7 +570,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
518 | brelse(bh); | 570 | brelse(bh); |
519 | 571 | ||
520 | if (sdp->sd_log_tail != tail) | 572 | if (sdp->sd_log_tail != tail) |
521 | log_pull_tail(sdp, tail, pull); | 573 | log_pull_tail(sdp, tail); |
522 | else | 574 | else |
523 | gfs2_assert_withdraw(sdp, !pull); | 575 | gfs2_assert_withdraw(sdp, !pull); |
524 | 576 | ||
@@ -579,7 +631,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
579 | INIT_LIST_HEAD(&ai->ai_ail1_list); | 631 | INIT_LIST_HEAD(&ai->ai_ail1_list); |
580 | INIT_LIST_HEAD(&ai->ai_ail2_list); | 632 | INIT_LIST_HEAD(&ai->ai_ail2_list); |
581 | 633 | ||
582 | gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf + sdp->sd_log_num_jdata == sdp->sd_log_commited_buf); | 634 | gfs2_assert_withdraw(sdp, |
635 | sdp->sd_log_num_buf + sdp->sd_log_num_jdata == | ||
636 | sdp->sd_log_commited_buf + | ||
637 | sdp->sd_log_commited_databuf); | ||
583 | gfs2_assert_withdraw(sdp, | 638 | gfs2_assert_withdraw(sdp, |
584 | sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); | 639 | sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); |
585 | 640 | ||
@@ -590,16 +645,19 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
590 | lops_before_commit(sdp); | 645 | lops_before_commit(sdp); |
591 | if (!list_empty(&sdp->sd_log_flush_list)) | 646 | if (!list_empty(&sdp->sd_log_flush_list)) |
592 | log_flush_commit(sdp); | 647 | log_flush_commit(sdp); |
593 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle) | 648 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ |
649 | gfs2_log_lock(sdp); | ||
650 | sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */ | ||
651 | gfs2_log_unlock(sdp); | ||
594 | log_write_header(sdp, 0, PULL); | 652 | log_write_header(sdp, 0, PULL); |
653 | } | ||
595 | lops_after_commit(sdp, ai); | 654 | lops_after_commit(sdp, ai); |
596 | 655 | ||
597 | gfs2_log_lock(sdp); | 656 | gfs2_log_lock(sdp); |
598 | sdp->sd_log_head = sdp->sd_log_flush_head; | 657 | sdp->sd_log_head = sdp->sd_log_flush_head; |
599 | sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs; | ||
600 | sdp->sd_log_blks_reserved = 0; | 658 | sdp->sd_log_blks_reserved = 0; |
601 | sdp->sd_log_commited_buf = 0; | 659 | sdp->sd_log_commited_buf = 0; |
602 | sdp->sd_log_num_hdrs = 0; | 660 | sdp->sd_log_commited_databuf = 0; |
603 | sdp->sd_log_commited_revoke = 0; | 661 | sdp->sd_log_commited_revoke = 0; |
604 | 662 | ||
605 | if (!list_empty(&ai->ai_ail1_list)) { | 663 | if (!list_empty(&ai->ai_ail1_list)) { |
@@ -616,32 +674,26 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
616 | 674 | ||
617 | static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | 675 | static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) |
618 | { | 676 | { |
619 | unsigned int reserved = 0; | 677 | unsigned int reserved; |
620 | unsigned int old; | 678 | unsigned int old; |
621 | 679 | ||
622 | gfs2_log_lock(sdp); | 680 | gfs2_log_lock(sdp); |
623 | 681 | ||
624 | sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm; | 682 | sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm; |
625 | gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0); | 683 | sdp->sd_log_commited_databuf += tr->tr_num_databuf_new - |
684 | tr->tr_num_databuf_rm; | ||
685 | gfs2_assert_withdraw(sdp, (((int)sdp->sd_log_commited_buf) >= 0) || | ||
686 | (((int)sdp->sd_log_commited_databuf) >= 0)); | ||
626 | sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; | 687 | sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; |
627 | gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); | 688 | gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); |
628 | 689 | reserved = calc_reserved(sdp); | |
629 | if (sdp->sd_log_commited_buf) | ||
630 | reserved += sdp->sd_log_commited_buf; | ||
631 | if (sdp->sd_log_commited_revoke) | ||
632 | reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, | ||
633 | sizeof(u64)); | ||
634 | if (reserved) | ||
635 | reserved++; | ||
636 | |||
637 | old = sdp->sd_log_blks_free; | 690 | old = sdp->sd_log_blks_free; |
638 | sdp->sd_log_blks_free += tr->tr_reserved - | 691 | sdp->sd_log_blks_free += tr->tr_reserved - |
639 | (reserved - sdp->sd_log_blks_reserved); | 692 | (reserved - sdp->sd_log_blks_reserved); |
640 | 693 | ||
641 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old); | 694 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old); |
642 | gfs2_assert_withdraw(sdp, | 695 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= |
643 | sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks + | 696 | sdp->sd_jdesc->jd_blocks); |
644 | sdp->sd_log_num_hdrs); | ||
645 | 697 | ||
646 | sdp->sd_log_blks_reserved = reserved; | 698 | sdp->sd_log_blks_reserved = reserved; |
647 | 699 | ||
@@ -687,13 +739,13 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) | |||
687 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); | 739 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); |
688 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); | 740 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); |
689 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); | 741 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); |
690 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs); | ||
691 | gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); | 742 | gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); |
692 | 743 | ||
693 | sdp->sd_log_flush_head = sdp->sd_log_head; | 744 | sdp->sd_log_flush_head = sdp->sd_log_head; |
694 | sdp->sd_log_flush_wrapped = 0; | 745 | sdp->sd_log_flush_wrapped = 0; |
695 | 746 | ||
696 | log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); | 747 | log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, |
748 | (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL); | ||
697 | 749 | ||
698 | gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); | 750 | gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); |
699 | gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); | 751 | gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); |