aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/log.c
diff options
context:
space:
mode:
authorRobert Peterson <rpeterso@redhat.com>2007-06-18 15:50:20 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-07-09 03:23:47 -0400
commit2332c4435bb733b5cd4f612ee57532bd8fde4c1c (patch)
treedfa006c482a6e9c1a5e693478b424db0f5492fbe /fs/gfs2/log.c
parent2840501ac822c5bf712f67b4b02640e16e145a29 (diff)
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to fail under one circumstance or another. Here is a complete summary of all changes from today's git tree, in order of appearance: 1. There are now separate variables for metadata buffer accounting. 2. Variable sd_log_num_hdrs is no longer needed, since the header accounting is taken care of by the reserve/refund sequence. 3. Fixed a tiny grammatical problem in a comment. 4. Added a new function "calc_reserved" to calculate the reserved log space. This isn't entirely necessary, but it has two benefits: First, it simplifies the gfs2_log_refund function greatly. Second, it allows for easier debugging because I could sprinkle the code with calls to this function to make sure the accounting is proper (by adding asserts and printks) at strategic point of the code. 5. In log_pull_tail there apparently was a kludge to fix up the accounting based on a "pull" parameter. The buffer accounting is now done properly, so the kludge was removed. 6. File sync operations were making a call to gfs2_log_flush that writes another journal header. Since that header was unplanned for (reserved) by the reserve/refund sequence, the free space had to be decremented so that when log_pull_tail gets called, the free space is be adjusted properly. (Did I hear you call that a kludge? well, maybe, but a lot more justifiable than the one I removed). 7. In the gfs2_log_shutdown code, it optionally syncs the log by specifying the PULL parameter to log_write_header. I'm not sure this is necessary anymore. It just seems to me there could be cases where shutdown is called while there are outstanding log buffers. 8. In the (data)buf_lo_before_commit functions, I changed some offset values from being calculated on the fly to being constants. That simplified some code and we might as well let the compiler do the calculation once rather than redoing those cycles at run time. 9. This version has my rewritten databuf_lo_add function. This version is much more like its predecessor, buf_lo_add, which makes it easier to understand. Again, this might not be necessary, but it seems as if this one works as well as the previous one, maybe even better, so I decided to leave it in. 10. In databuf_lo_before_commit, a previous data corruption problem was caused by going off the end of the buffer. The proper solution is to have the proper limit in place, rather than stopping earlier. (Thus my previous attempt to fix it is wrong). If you don't wrap the buffer, you're stopping too early and that causes more log buffer accounting problems. 11. In lops.h there are two new (previously mentioned) constants for figuring out the data offset for the journal buffers. 12. There are also two new functions, buf_limit and databuf_limit to calculate how many entries will fit in the buffer. 13. In function gfs2_meta_wipe, it needs to distinguish between pinned metadata buffers and journaled data buffers for proper journal buffer accounting. It can't use the JDATA gfs2_inode flag because it's sometimes passed the "real" inode and sometimes the "metadata inode" and the inode flags will be random bits in a metadata gfs2_inode. It needs to base its decision on which was passed in. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r--fs/gfs2/log.c100
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 */
399static 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
374static unsigned int current_tail(struct gfs2_sbd *sdp) 426static 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
464static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) 516static 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
617static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 675static 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);