diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 230 |
1 files changed, 156 insertions, 74 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f49a12e24086..7df702473252 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -60,6 +60,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, | |||
60 | } | 60 | } |
61 | 61 | ||
62 | /** | 62 | /** |
63 | * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters | ||
64 | * @mapping: The associated mapping (maybe NULL) | ||
65 | * @bd: The gfs2_bufdata to remove | ||
66 | * | ||
67 | * The log lock _must_ be held when calling this function | ||
68 | * | ||
69 | */ | ||
70 | |||
71 | void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) | ||
72 | { | ||
73 | bd->bd_ail = NULL; | ||
74 | list_del_init(&bd->bd_ail_st_list); | ||
75 | list_del_init(&bd->bd_ail_gl_list); | ||
76 | atomic_dec(&bd->bd_gl->gl_ail_count); | ||
77 | if (mapping) | ||
78 | gfs2_meta_cache_flush(GFS2_I(mapping->host)); | ||
79 | brelse(bd->bd_bh); | ||
80 | } | ||
81 | |||
82 | /** | ||
63 | * gfs2_ail1_start_one - Start I/O on a part of the AIL | 83 | * gfs2_ail1_start_one - Start I/O on a part of the AIL |
64 | * @sdp: the filesystem | 84 | * @sdp: the filesystem |
65 | * @tr: the part of the AIL | 85 | * @tr: the part of the AIL |
@@ -83,17 +103,9 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
83 | 103 | ||
84 | gfs2_assert(sdp, bd->bd_ail == ai); | 104 | gfs2_assert(sdp, bd->bd_ail == ai); |
85 | 105 | ||
86 | if (!bh){ | ||
87 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | ||
88 | continue; | ||
89 | } | ||
90 | |||
91 | if (!buffer_busy(bh)) { | 106 | if (!buffer_busy(bh)) { |
92 | if (!buffer_uptodate(bh)) { | 107 | if (!buffer_uptodate(bh)) |
93 | gfs2_log_unlock(sdp); | ||
94 | gfs2_io_error_bh(sdp, bh); | 108 | gfs2_io_error_bh(sdp, bh); |
95 | gfs2_log_lock(sdp); | ||
96 | } | ||
97 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | 109 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); |
98 | continue; | 110 | continue; |
99 | } | 111 | } |
@@ -103,9 +115,16 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
103 | 115 | ||
104 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | 116 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); |
105 | 117 | ||
118 | get_bh(bh); | ||
106 | gfs2_log_unlock(sdp); | 119 | gfs2_log_unlock(sdp); |
107 | wait_on_buffer(bh); | 120 | lock_buffer(bh); |
108 | ll_rw_block(WRITE, 1, &bh); | 121 | if (test_clear_buffer_dirty(bh)) { |
122 | bh->b_end_io = end_buffer_write_sync; | ||
123 | submit_bh(WRITE, bh); | ||
124 | } else { | ||
125 | unlock_buffer(bh); | ||
126 | brelse(bh); | ||
127 | } | ||
109 | gfs2_log_lock(sdp); | 128 | gfs2_log_lock(sdp); |
110 | 129 | ||
111 | retry = 1; | 130 | retry = 1; |
@@ -130,11 +149,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl | |||
130 | bd_ail_st_list) { | 149 | bd_ail_st_list) { |
131 | bh = bd->bd_bh; | 150 | bh = bd->bd_bh; |
132 | 151 | ||
133 | if (!bh){ | ||
134 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | ||
135 | continue; | ||
136 | } | ||
137 | |||
138 | gfs2_assert(sdp, bd->bd_ail == ai); | 152 | gfs2_assert(sdp, bd->bd_ail == ai); |
139 | 153 | ||
140 | if (buffer_busy(bh)) { | 154 | if (buffer_busy(bh)) { |
@@ -155,13 +169,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl | |||
155 | 169 | ||
156 | static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) | 170 | static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) |
157 | { | 171 | { |
158 | struct list_head *head = &sdp->sd_ail1_list; | 172 | struct list_head *head; |
159 | u64 sync_gen; | 173 | u64 sync_gen; |
160 | struct list_head *first; | 174 | struct list_head *first; |
161 | struct gfs2_ail *first_ai, *ai, *tmp; | 175 | struct gfs2_ail *first_ai, *ai, *tmp; |
162 | int done = 0; | 176 | int done = 0; |
163 | 177 | ||
164 | gfs2_log_lock(sdp); | 178 | gfs2_log_lock(sdp); |
179 | head = &sdp->sd_ail1_list; | ||
165 | if (list_empty(head)) { | 180 | if (list_empty(head)) { |
166 | gfs2_log_unlock(sdp); | 181 | gfs2_log_unlock(sdp); |
167 | return; | 182 | return; |
@@ -233,11 +248,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
233 | bd = list_entry(head->prev, struct gfs2_bufdata, | 248 | bd = list_entry(head->prev, struct gfs2_bufdata, |
234 | bd_ail_st_list); | 249 | bd_ail_st_list); |
235 | gfs2_assert(sdp, bd->bd_ail == ai); | 250 | gfs2_assert(sdp, bd->bd_ail == ai); |
236 | bd->bd_ail = NULL; | 251 | gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd); |
237 | list_del(&bd->bd_ail_st_list); | ||
238 | list_del(&bd->bd_ail_gl_list); | ||
239 | atomic_dec(&bd->bd_gl->gl_ail_count); | ||
240 | brelse(bd->bd_bh); | ||
241 | } | 252 | } |
242 | } | 253 | } |
243 | 254 | ||
@@ -439,10 +450,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) | |||
439 | return tail; | 450 | return tail; |
440 | } | 451 | } |
441 | 452 | ||
442 | static inline void log_incr_head(struct gfs2_sbd *sdp) | 453 | void gfs2_log_incr_head(struct gfs2_sbd *sdp) |
443 | { | 454 | { |
444 | if (sdp->sd_log_flush_head == sdp->sd_log_tail) | 455 | if (sdp->sd_log_flush_head == sdp->sd_log_tail) |
445 | gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head); | 456 | BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); |
446 | 457 | ||
447 | if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { | 458 | if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { |
448 | sdp->sd_log_flush_head = 0; | 459 | sdp->sd_log_flush_head = 0; |
@@ -451,6 +462,23 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) | |||
451 | } | 462 | } |
452 | 463 | ||
453 | /** | 464 | /** |
465 | * gfs2_log_write_endio - End of I/O for a log buffer | ||
466 | * @bh: The buffer head | ||
467 | * @uptodate: I/O Status | ||
468 | * | ||
469 | */ | ||
470 | |||
471 | static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) | ||
472 | { | ||
473 | struct gfs2_sbd *sdp = bh->b_private; | ||
474 | bh->b_private = NULL; | ||
475 | |||
476 | end_buffer_write_sync(bh, uptodate); | ||
477 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | ||
478 | wake_up(&sdp->sd_log_flush_wait); | ||
479 | } | ||
480 | |||
481 | /** | ||
454 | * gfs2_log_get_buf - Get and initialize a buffer to use for log control data | 482 | * gfs2_log_get_buf - Get and initialize a buffer to use for log control data |
455 | * @sdp: The GFS2 superblock | 483 | * @sdp: The GFS2 superblock |
456 | * | 484 | * |
@@ -460,25 +488,43 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) | |||
460 | struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) | 488 | struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) |
461 | { | 489 | { |
462 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); | 490 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); |
463 | struct gfs2_log_buf *lb; | ||
464 | struct buffer_head *bh; | 491 | struct buffer_head *bh; |
465 | 492 | ||
466 | lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); | 493 | bh = sb_getblk(sdp->sd_vfs, blkno); |
467 | list_add(&lb->lb_list, &sdp->sd_log_flush_list); | ||
468 | |||
469 | bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); | ||
470 | lock_buffer(bh); | 494 | lock_buffer(bh); |
471 | memset(bh->b_data, 0, bh->b_size); | 495 | memset(bh->b_data, 0, bh->b_size); |
472 | set_buffer_uptodate(bh); | 496 | set_buffer_uptodate(bh); |
473 | clear_buffer_dirty(bh); | 497 | clear_buffer_dirty(bh); |
474 | unlock_buffer(bh); | 498 | gfs2_log_incr_head(sdp); |
475 | 499 | atomic_inc(&sdp->sd_log_in_flight); | |
476 | log_incr_head(sdp); | 500 | bh->b_private = sdp; |
501 | bh->b_end_io = gfs2_log_write_endio; | ||
477 | 502 | ||
478 | return bh; | 503 | return bh; |
479 | } | 504 | } |
480 | 505 | ||
481 | /** | 506 | /** |
507 | * gfs2_fake_write_endio - | ||
508 | * @bh: The buffer head | ||
509 | * @uptodate: The I/O Status | ||
510 | * | ||
511 | */ | ||
512 | |||
513 | static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) | ||
514 | { | ||
515 | struct buffer_head *real_bh = bh->b_private; | ||
516 | struct gfs2_bufdata *bd = real_bh->b_private; | ||
517 | struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; | ||
518 | |||
519 | end_buffer_write_sync(bh, uptodate); | ||
520 | free_buffer_head(bh); | ||
521 | unlock_buffer(real_bh); | ||
522 | brelse(real_bh); | ||
523 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | ||
524 | wake_up(&sdp->sd_log_flush_wait); | ||
525 | } | ||
526 | |||
527 | /** | ||
482 | * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log | 528 | * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log |
483 | * @sdp: the filesystem | 529 | * @sdp: the filesystem |
484 | * @data: the data the buffer_head should point to | 530 | * @data: the data the buffer_head should point to |
@@ -490,22 +536,20 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, | |||
490 | struct buffer_head *real) | 536 | struct buffer_head *real) |
491 | { | 537 | { |
492 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); | 538 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); |
493 | struct gfs2_log_buf *lb; | ||
494 | struct buffer_head *bh; | 539 | struct buffer_head *bh; |
495 | 540 | ||
496 | lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); | 541 | bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); |
497 | list_add(&lb->lb_list, &sdp->sd_log_flush_list); | ||
498 | lb->lb_real = real; | ||
499 | |||
500 | bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); | ||
501 | atomic_set(&bh->b_count, 1); | 542 | atomic_set(&bh->b_count, 1); |
502 | bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); | 543 | bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); |
503 | set_bh_page(bh, real->b_page, bh_offset(real)); | 544 | set_bh_page(bh, real->b_page, bh_offset(real)); |
504 | bh->b_blocknr = blkno; | 545 | bh->b_blocknr = blkno; |
505 | bh->b_size = sdp->sd_sb.sb_bsize; | 546 | bh->b_size = sdp->sd_sb.sb_bsize; |
506 | bh->b_bdev = sdp->sd_vfs->s_bdev; | 547 | bh->b_bdev = sdp->sd_vfs->s_bdev; |
548 | bh->b_private = real; | ||
549 | bh->b_end_io = gfs2_fake_write_endio; | ||
507 | 550 | ||
508 | log_incr_head(sdp); | 551 | gfs2_log_incr_head(sdp); |
552 | atomic_inc(&sdp->sd_log_in_flight); | ||
509 | 553 | ||
510 | return bh; | 554 | return bh; |
511 | } | 555 | } |
@@ -572,45 +616,75 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
572 | gfs2_assert_withdraw(sdp, !pull); | 616 | gfs2_assert_withdraw(sdp, !pull); |
573 | 617 | ||
574 | sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); | 618 | sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); |
575 | log_incr_head(sdp); | 619 | gfs2_log_incr_head(sdp); |
576 | } | 620 | } |
577 | 621 | ||
578 | static void log_flush_commit(struct gfs2_sbd *sdp) | 622 | static void log_flush_commit(struct gfs2_sbd *sdp) |
579 | { | 623 | { |
580 | struct list_head *head = &sdp->sd_log_flush_list; | 624 | DEFINE_WAIT(wait); |
581 | struct gfs2_log_buf *lb; | 625 | |
582 | struct buffer_head *bh; | 626 | if (atomic_read(&sdp->sd_log_in_flight)) { |
583 | int flushcount = 0; | 627 | do { |
628 | prepare_to_wait(&sdp->sd_log_flush_wait, &wait, | ||
629 | TASK_UNINTERRUPTIBLE); | ||
630 | if (atomic_read(&sdp->sd_log_in_flight)) | ||
631 | io_schedule(); | ||
632 | } while(atomic_read(&sdp->sd_log_in_flight)); | ||
633 | finish_wait(&sdp->sd_log_flush_wait, &wait); | ||
634 | } | ||
584 | 635 | ||
585 | while (!list_empty(head)) { | 636 | log_write_header(sdp, 0, 0); |
586 | lb = list_entry(head->next, struct gfs2_log_buf, lb_list); | 637 | } |
587 | list_del(&lb->lb_list); | ||
588 | bh = lb->lb_bh; | ||
589 | 638 | ||
590 | wait_on_buffer(bh); | 639 | static void gfs2_ordered_write(struct gfs2_sbd *sdp) |
591 | if (!buffer_uptodate(bh)) | 640 | { |
592 | gfs2_io_error_bh(sdp, bh); | 641 | struct gfs2_bufdata *bd; |
593 | if (lb->lb_real) { | 642 | struct buffer_head *bh; |
594 | while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ | 643 | LIST_HEAD(written); |
595 | schedule(); | 644 | |
596 | free_buffer_head(bh); | 645 | gfs2_log_lock(sdp); |
597 | } else | 646 | while (!list_empty(&sdp->sd_log_le_ordered)) { |
647 | bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); | ||
648 | list_move(&bd->bd_le.le_list, &written); | ||
649 | bh = bd->bd_bh; | ||
650 | if (!buffer_dirty(bh)) | ||
651 | continue; | ||
652 | get_bh(bh); | ||
653 | gfs2_log_unlock(sdp); | ||
654 | lock_buffer(bh); | ||
655 | if (test_clear_buffer_dirty(bh)) { | ||
656 | bh->b_end_io = end_buffer_write_sync; | ||
657 | submit_bh(WRITE, bh); | ||
658 | } else { | ||
659 | unlock_buffer(bh); | ||
598 | brelse(bh); | 660 | brelse(bh); |
599 | kfree(lb); | 661 | } |
600 | flushcount++; | 662 | gfs2_log_lock(sdp); |
601 | } | 663 | } |
664 | list_splice(&written, &sdp->sd_log_le_ordered); | ||
665 | gfs2_log_unlock(sdp); | ||
666 | } | ||
602 | 667 | ||
603 | /* If nothing was journaled, the header is unplanned and unwanted. */ | 668 | static void gfs2_ordered_wait(struct gfs2_sbd *sdp) |
604 | if (flushcount) { | 669 | { |
605 | log_write_header(sdp, 0, 0); | 670 | struct gfs2_bufdata *bd; |
606 | } else { | 671 | struct buffer_head *bh; |
607 | unsigned int tail; | ||
608 | tail = current_tail(sdp); | ||
609 | 672 | ||
610 | gfs2_ail1_empty(sdp, 0); | 673 | gfs2_log_lock(sdp); |
611 | if (sdp->sd_log_tail != tail) | 674 | while (!list_empty(&sdp->sd_log_le_ordered)) { |
612 | log_pull_tail(sdp, tail); | 675 | bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list); |
676 | bh = bd->bd_bh; | ||
677 | if (buffer_locked(bh)) { | ||
678 | get_bh(bh); | ||
679 | gfs2_log_unlock(sdp); | ||
680 | wait_on_buffer(bh); | ||
681 | brelse(bh); | ||
682 | gfs2_log_lock(sdp); | ||
683 | continue; | ||
684 | } | ||
685 | list_del_init(&bd->bd_le.le_list); | ||
613 | } | 686 | } |
687 | gfs2_log_unlock(sdp); | ||
614 | } | 688 | } |
615 | 689 | ||
616 | /** | 690 | /** |
@@ -640,10 +714,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
640 | INIT_LIST_HEAD(&ai->ai_ail1_list); | 714 | INIT_LIST_HEAD(&ai->ai_ail1_list); |
641 | INIT_LIST_HEAD(&ai->ai_ail2_list); | 715 | INIT_LIST_HEAD(&ai->ai_ail2_list); |
642 | 716 | ||
643 | gfs2_assert_withdraw(sdp, | 717 | if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) { |
644 | sdp->sd_log_num_buf + sdp->sd_log_num_jdata == | 718 | printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf, |
645 | sdp->sd_log_commited_buf + | 719 | sdp->sd_log_commited_buf); |
646 | sdp->sd_log_commited_databuf); | 720 | gfs2_assert_withdraw(sdp, 0); |
721 | } | ||
722 | if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) { | ||
723 | printk(KERN_INFO "GFS2: log databuf %u %u\n", | ||
724 | sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf); | ||
725 | gfs2_assert_withdraw(sdp, 0); | ||
726 | } | ||
647 | gfs2_assert_withdraw(sdp, | 727 | gfs2_assert_withdraw(sdp, |
648 | sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); | 728 | sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); |
649 | 729 | ||
@@ -651,8 +731,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
651 | sdp->sd_log_flush_wrapped = 0; | 731 | sdp->sd_log_flush_wrapped = 0; |
652 | ai->ai_first = sdp->sd_log_flush_head; | 732 | ai->ai_first = sdp->sd_log_flush_head; |
653 | 733 | ||
734 | gfs2_ordered_write(sdp); | ||
654 | lops_before_commit(sdp); | 735 | lops_before_commit(sdp); |
655 | if (!list_empty(&sdp->sd_log_flush_list)) | 736 | gfs2_ordered_wait(sdp); |
737 | |||
738 | if (sdp->sd_log_head != sdp->sd_log_flush_head) | ||
656 | log_flush_commit(sdp); | 739 | log_flush_commit(sdp); |
657 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ | 740 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ |
658 | gfs2_log_lock(sdp); | 741 | gfs2_log_lock(sdp); |
@@ -744,7 +827,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) | |||
744 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); | 827 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); |
745 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); | 828 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); |
746 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); | 829 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); |
747 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata); | ||
748 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); | 830 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); |
749 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); | 831 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); |
750 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); | 832 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); |