diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 119 |
1 files changed, 72 insertions, 47 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 7df702473252..161ab6f2058e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This copyrighted material is made available to anyone wishing to use, | 5 | * This copyrighted material is made available to anyone wishing to use, |
6 | * modify, copy, or redistribute it subject to the terms and conditions | 6 | * modify, copy, or redistribute it subject to the terms and conditions |
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/crc32.h> | 16 | #include <linux/crc32.h> |
17 | #include <linux/lm_interface.h> | 17 | #include <linux/lm_interface.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/kthread.h> | ||
20 | #include <linux/freezer.h> | ||
19 | 21 | ||
20 | #include "gfs2.h" | 22 | #include "gfs2.h" |
21 | #include "incore.h" | 23 | #include "incore.h" |
@@ -68,14 +70,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, | |||
68 | * | 70 | * |
69 | */ | 71 | */ |
70 | 72 | ||
71 | void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) | 73 | void gfs2_remove_from_ail(struct gfs2_bufdata *bd) |
72 | { | 74 | { |
73 | bd->bd_ail = NULL; | 75 | bd->bd_ail = NULL; |
74 | list_del_init(&bd->bd_ail_st_list); | 76 | list_del_init(&bd->bd_ail_st_list); |
75 | list_del_init(&bd->bd_ail_gl_list); | 77 | list_del_init(&bd->bd_ail_gl_list); |
76 | atomic_dec(&bd->bd_gl->gl_ail_count); | 78 | 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); | 79 | brelse(bd->bd_bh); |
80 | } | 80 | } |
81 | 81 | ||
@@ -92,8 +92,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
92 | struct buffer_head *bh; | 92 | struct buffer_head *bh; |
93 | int retry; | 93 | int retry; |
94 | 94 | ||
95 | BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); | ||
96 | |||
97 | do { | 95 | do { |
98 | retry = 0; | 96 | retry = 0; |
99 | 97 | ||
@@ -210,7 +208,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) | |||
210 | gfs2_log_unlock(sdp); | 208 | gfs2_log_unlock(sdp); |
211 | } | 209 | } |
212 | 210 | ||
213 | int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | 211 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) |
214 | { | 212 | { |
215 | struct gfs2_ail *ai, *s; | 213 | struct gfs2_ail *ai, *s; |
216 | int ret; | 214 | int ret; |
@@ -248,7 +246,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
248 | bd = list_entry(head->prev, struct gfs2_bufdata, | 246 | bd = list_entry(head->prev, struct gfs2_bufdata, |
249 | bd_ail_st_list); | 247 | bd_ail_st_list); |
250 | gfs2_assert(sdp, bd->bd_ail == ai); | 248 | gfs2_assert(sdp, bd->bd_ail == ai); |
251 | gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd); | 249 | gfs2_remove_from_ail(bd); |
252 | } | 250 | } |
253 | } | 251 | } |
254 | 252 | ||
@@ -303,7 +301,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) | |||
303 | 301 | ||
304 | mutex_lock(&sdp->sd_log_reserve_mutex); | 302 | mutex_lock(&sdp->sd_log_reserve_mutex); |
305 | gfs2_log_lock(sdp); | 303 | gfs2_log_lock(sdp); |
306 | while(sdp->sd_log_blks_free <= (blks + reserved_blks)) { | 304 | while(atomic_read(&sdp->sd_log_blks_free) <= (blks + reserved_blks)) { |
307 | gfs2_log_unlock(sdp); | 305 | gfs2_log_unlock(sdp); |
308 | gfs2_ail1_empty(sdp, 0); | 306 | gfs2_ail1_empty(sdp, 0); |
309 | gfs2_log_flush(sdp, NULL); | 307 | gfs2_log_flush(sdp, NULL); |
@@ -312,7 +310,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) | |||
312 | gfs2_ail1_start(sdp, 0); | 310 | gfs2_ail1_start(sdp, 0); |
313 | gfs2_log_lock(sdp); | 311 | gfs2_log_lock(sdp); |
314 | } | 312 | } |
315 | sdp->sd_log_blks_free -= blks; | 313 | atomic_sub(blks, &sdp->sd_log_blks_free); |
316 | gfs2_log_unlock(sdp); | 314 | gfs2_log_unlock(sdp); |
317 | mutex_unlock(&sdp->sd_log_reserve_mutex); | 315 | mutex_unlock(&sdp->sd_log_reserve_mutex); |
318 | 316 | ||
@@ -332,27 +330,23 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) | |||
332 | { | 330 | { |
333 | 331 | ||
334 | gfs2_log_lock(sdp); | 332 | gfs2_log_lock(sdp); |
335 | sdp->sd_log_blks_free += blks; | 333 | atomic_add(blks, &sdp->sd_log_blks_free); |
336 | gfs2_assert_withdraw(sdp, | 334 | gfs2_assert_withdraw(sdp, |
337 | sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); | 335 | atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); |
338 | gfs2_log_unlock(sdp); | 336 | gfs2_log_unlock(sdp); |
339 | up_read(&sdp->sd_log_flush_lock); | 337 | up_read(&sdp->sd_log_flush_lock); |
340 | } | 338 | } |
341 | 339 | ||
342 | static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) | 340 | static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) |
343 | { | 341 | { |
344 | struct inode *inode = sdp->sd_jdesc->jd_inode; | 342 | struct gfs2_journal_extent *je; |
345 | int error; | 343 | |
346 | struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; | 344 | list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) { |
347 | 345 | if (lbn >= je->lblock && lbn < je->lblock + je->blocks) | |
348 | bh_map.b_size = 1 << inode->i_blkbits; | 346 | return je->dblock + lbn - je->lblock; |
349 | error = gfs2_block_map(inode, lbn, 0, &bh_map); | 347 | } |
350 | if (error || !bh_map.b_blocknr) | 348 | |
351 | printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, | 349 | return -1; |
352 | (unsigned long long)bh_map.b_blocknr, lbn); | ||
353 | gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr); | ||
354 | |||
355 | return bh_map.b_blocknr; | ||
356 | } | 350 | } |
357 | 351 | ||
358 | /** | 352 | /** |
@@ -561,8 +555,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
561 | ail2_empty(sdp, new_tail); | 555 | ail2_empty(sdp, new_tail); |
562 | 556 | ||
563 | gfs2_log_lock(sdp); | 557 | gfs2_log_lock(sdp); |
564 | sdp->sd_log_blks_free += dist; | 558 | atomic_add(dist, &sdp->sd_log_blks_free); |
565 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); | 559 | gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); |
566 | gfs2_log_unlock(sdp); | 560 | gfs2_log_unlock(sdp); |
567 | 561 | ||
568 | sdp->sd_log_tail = new_tail; | 562 | sdp->sd_log_tail = new_tail; |
@@ -652,7 +646,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp) | |||
652 | get_bh(bh); | 646 | get_bh(bh); |
653 | gfs2_log_unlock(sdp); | 647 | gfs2_log_unlock(sdp); |
654 | lock_buffer(bh); | 648 | lock_buffer(bh); |
655 | if (test_clear_buffer_dirty(bh)) { | 649 | if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) { |
656 | bh->b_end_io = end_buffer_write_sync; | 650 | bh->b_end_io = end_buffer_write_sync; |
657 | submit_bh(WRITE, bh); | 651 | submit_bh(WRITE, bh); |
658 | } else { | 652 | } else { |
@@ -694,20 +688,16 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp) | |||
694 | * | 688 | * |
695 | */ | 689 | */ |
696 | 690 | ||
697 | void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | 691 | void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) |
698 | { | 692 | { |
699 | struct gfs2_ail *ai; | 693 | struct gfs2_ail *ai; |
700 | 694 | ||
701 | down_write(&sdp->sd_log_flush_lock); | 695 | down_write(&sdp->sd_log_flush_lock); |
702 | 696 | ||
703 | if (gl) { | 697 | /* Log might have been flushed while we waited for the flush lock */ |
704 | gfs2_log_lock(sdp); | 698 | if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) { |
705 | if (list_empty(&gl->gl_le.le_list)) { | 699 | up_write(&sdp->sd_log_flush_lock); |
706 | gfs2_log_unlock(sdp); | 700 | return; |
707 | up_write(&sdp->sd_log_flush_lock); | ||
708 | return; | ||
709 | } | ||
710 | gfs2_log_unlock(sdp); | ||
711 | } | 701 | } |
712 | 702 | ||
713 | ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); | 703 | ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); |
@@ -739,7 +729,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
739 | log_flush_commit(sdp); | 729 | log_flush_commit(sdp); |
740 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ | 730 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ |
741 | gfs2_log_lock(sdp); | 731 | gfs2_log_lock(sdp); |
742 | sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */ | 732 | atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ |
743 | gfs2_log_unlock(sdp); | 733 | gfs2_log_unlock(sdp); |
744 | log_write_header(sdp, 0, PULL); | 734 | log_write_header(sdp, 0, PULL); |
745 | } | 735 | } |
@@ -767,7 +757,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
767 | static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | 757 | static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) |
768 | { | 758 | { |
769 | unsigned int reserved; | 759 | unsigned int reserved; |
770 | unsigned int old; | 760 | unsigned int unused; |
771 | 761 | ||
772 | gfs2_log_lock(sdp); | 762 | gfs2_log_lock(sdp); |
773 | 763 | ||
@@ -779,14 +769,11 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | |||
779 | sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; | 769 | sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; |
780 | gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); | 770 | gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); |
781 | reserved = calc_reserved(sdp); | 771 | reserved = calc_reserved(sdp); |
782 | old = sdp->sd_log_blks_free; | 772 | unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved; |
783 | sdp->sd_log_blks_free += tr->tr_reserved - | 773 | gfs2_assert_withdraw(sdp, unused >= 0); |
784 | (reserved - sdp->sd_log_blks_reserved); | 774 | atomic_add(unused, &sdp->sd_log_blks_free); |
785 | 775 | gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= | |
786 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old); | ||
787 | gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= | ||
788 | sdp->sd_jdesc->jd_blocks); | 776 | sdp->sd_jdesc->jd_blocks); |
789 | |||
790 | sdp->sd_log_blks_reserved = reserved; | 777 | sdp->sd_log_blks_reserved = reserved; |
791 | 778 | ||
792 | gfs2_log_unlock(sdp); | 779 | gfs2_log_unlock(sdp); |
@@ -825,7 +812,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) | |||
825 | down_write(&sdp->sd_log_flush_lock); | 812 | down_write(&sdp->sd_log_flush_lock); |
826 | 813 | ||
827 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); | 814 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); |
828 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); | ||
829 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); | 815 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); |
830 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); | 816 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); |
831 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); | 817 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); |
@@ -838,7 +824,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) | |||
838 | log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, | 824 | log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, |
839 | (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL); | 825 | (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL); |
840 | 826 | ||
841 | gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); | 827 | gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks); |
842 | gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); | 828 | gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); |
843 | gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); | 829 | gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); |
844 | 830 | ||
@@ -866,3 +852,42 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) | |||
866 | } | 852 | } |
867 | } | 853 | } |
868 | 854 | ||
855 | |||
856 | /** | ||
857 | * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks | ||
858 | * @sdp: Pointer to GFS2 superblock | ||
859 | * | ||
860 | * Also, periodically check to make sure that we're using the most recent | ||
861 | * journal index. | ||
862 | */ | ||
863 | |||
864 | int gfs2_logd(void *data) | ||
865 | { | ||
866 | struct gfs2_sbd *sdp = data; | ||
867 | unsigned long t; | ||
868 | int need_flush; | ||
869 | |||
870 | while (!kthread_should_stop()) { | ||
871 | /* Advance the log tail */ | ||
872 | |||
873 | t = sdp->sd_log_flush_time + | ||
874 | gfs2_tune_get(sdp, gt_log_flush_secs) * HZ; | ||
875 | |||
876 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
877 | gfs2_log_lock(sdp); | ||
878 | need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks); | ||
879 | gfs2_log_unlock(sdp); | ||
880 | if (need_flush || time_after_eq(jiffies, t)) { | ||
881 | gfs2_log_flush(sdp, NULL); | ||
882 | sdp->sd_log_flush_time = jiffies; | ||
883 | } | ||
884 | |||
885 | t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; | ||
886 | if (freezing(current)) | ||
887 | refrigerator(); | ||
888 | schedule_timeout_interruptible(t); | ||
889 | } | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||