aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorRobert Peterson <rpeterso@redhat.com>2007-06-12 12:24:36 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-07-09 03:23:40 -0400
commit8fb68595d508fd30ec90939572484b263600376c (patch)
tree218a457675c111e2224fb57998d38e45d5786bd1 /fs/gfs2
parentfad59c1390045b5adb7c7249ec4e77e0f868aca5 (diff)
[GFS2] Journaled file write/unstuff bug
This patch is for bugzilla bug 283162, which uncovered a number of bugs pertaining to writing to files that have the journaled bit on. These bugs happen most often when writing to the meta_fs because the files are always journaled. So operations like gfs2_grow were particularly vulnerable, although many of the problems could be recreated with normal files after setting the journaled bit on. The problems fixed are: -GFS2 wasn't ever writing unstuffed journaled data blocks to their in-place location on disk. Now it does. -If you unmounted too quickly after doing IO to a journaled file, GFS2 was crashing because you would discard a buffer whose bufdata was still on the active items list. GFS2 now deals with this gracefully. -GFS2 was losing track of the bufdata for journaled data blocks, and it wasn't getting freed, causing an error when you tried to unmount the module. GFS2 now frees all the bufdata structures. -There was a memory corruption occurring because GFS2 wrote twice as many log entries for journaled buffers. -It was occasionally trying to write journal headers in buffers that weren't currently mapped. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/log.c15
-rw-r--r--fs/gfs2/lops.c4
-rw-r--r--fs/gfs2/ops_address.c26
3 files changed, 42 insertions, 3 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 1fb846fc545e..fbdc0dc9923e 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -83,6 +83,11 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
83 83
84 gfs2_assert(sdp, bd->bd_ail == ai); 84 gfs2_assert(sdp, bd->bd_ail == ai);
85 85
86 if (!bh){
87 list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
88 continue;
89 }
90
86 if (!buffer_busy(bh)) { 91 if (!buffer_busy(bh)) {
87 if (!buffer_uptodate(bh)) { 92 if (!buffer_uptodate(bh)) {
88 gfs2_log_unlock(sdp); 93 gfs2_log_unlock(sdp);
@@ -125,6 +130,11 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl
125 bd_ail_st_list) { 130 bd_ail_st_list) {
126 bh = bd->bd_bh; 131 bh = bd->bd_bh;
127 132
133 if (!bh){
134 list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
135 continue;
136 }
137
128 gfs2_assert(sdp, bd->bd_ail == ai); 138 gfs2_assert(sdp, bd->bd_ail == ai);
129 139
130 if (buffer_busy(bh)) { 140 if (buffer_busy(bh)) {
@@ -227,7 +237,10 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
227 list_del(&bd->bd_ail_st_list); 237 list_del(&bd->bd_ail_st_list);
228 list_del(&bd->bd_ail_gl_list); 238 list_del(&bd->bd_ail_gl_list);
229 atomic_dec(&bd->bd_gl->gl_ail_count); 239 atomic_dec(&bd->bd_gl->gl_ail_count);
230 brelse(bd->bd_bh); 240 if (bd->bd_bh)
241 brelse(bd->bd_bh);
242 else
243 kmem_cache_free(gfs2_bufdata_cachep, bd);
231 } 244 }
232} 245}
233 246
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 3e971f25120d..df6bceea379a 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -607,7 +607,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
607 if (unlikely(magic != 0)) 607 if (unlikely(magic != 0))
608 set_buffer_escaped(bh1); 608 set_buffer_escaped(bh1);
609 gfs2_log_lock(sdp); 609 gfs2_log_lock(sdp);
610 if (n++ > num) 610 n += 2;
611 if (n >= num)
611 break; 612 break;
612 } else if (!bh1) { 613 } else if (!bh1) {
613 total_dbuf--; 614 total_dbuf--;
@@ -624,6 +625,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
624 } 625 }
625 gfs2_log_unlock(sdp); 626 gfs2_log_unlock(sdp);
626 if (bh) { 627 if (bh) {
628 set_buffer_mapped(bh);
627 set_buffer_dirty(bh); 629 set_buffer_dirty(bh);
628 ll_rw_block(WRITE, 1, &bh); 630 ll_rw_block(WRITE, 1, &bh);
629 bh = NULL; 631 bh = NULL;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index ac5659521386..9ab35a9ee75a 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -137,7 +137,9 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
137 return 0; /* don't care */ 137 return 0; /* don't care */
138 } 138 }
139 139
140 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) { 140 if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) &&
141 PageChecked(page)) {
142 ClearPageChecked(page);
141 error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); 143 error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
142 if (error) 144 if (error)
143 goto out_ignore; 145 goto out_ignore;
@@ -574,6 +576,23 @@ fail_nounlock:
574} 576}
575 577
576/** 578/**
579 * gfs2_set_page_dirty - Page dirtying function
580 * @page: The page to dirty
581 *
582 * Returns: 1 if it dirtyed the page, or 0 otherwise
583 */
584
585static int gfs2_set_page_dirty(struct page *page)
586{
587 struct gfs2_inode *ip = GFS2_I(page->mapping->host);
588 struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
589
590 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
591 SetPageChecked(page);
592 return __set_page_dirty_buffers(page);
593}
594
595/**
577 * gfs2_bmap - Block map function 596 * gfs2_bmap - Block map function
578 * @mapping: Address space info 597 * @mapping: Address space info
579 * @lblock: The block to map 598 * @lblock: The block to map
@@ -609,6 +628,8 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
609 if (bd) { 628 if (bd) {
610 bd->bd_bh = NULL; 629 bd->bd_bh = NULL;
611 bh->b_private = NULL; 630 bh->b_private = NULL;
631 if (!bd->bd_ail && list_empty(&bd->bd_le.le_list))
632 kmem_cache_free(gfs2_bufdata_cachep, bd);
612 } 633 }
613 gfs2_log_unlock(sdp); 634 gfs2_log_unlock(sdp);
614 635
@@ -629,6 +650,8 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset)
629 unsigned int curr_off = 0; 650 unsigned int curr_off = 0;
630 651
631 BUG_ON(!PageLocked(page)); 652 BUG_ON(!PageLocked(page));
653 if (offset == 0)
654 ClearPageChecked(page);
632 if (!page_has_buffers(page)) 655 if (!page_has_buffers(page))
633 return; 656 return;
634 657
@@ -841,6 +864,7 @@ const struct address_space_operations gfs2_file_aops = {
841 .sync_page = block_sync_page, 864 .sync_page = block_sync_page,
842 .prepare_write = gfs2_prepare_write, 865 .prepare_write = gfs2_prepare_write,
843 .commit_write = gfs2_commit_write, 866 .commit_write = gfs2_commit_write,
867 .set_page_dirty = gfs2_set_page_dirty,
844 .bmap = gfs2_bmap, 868 .bmap = gfs2_bmap,
845 .invalidatepage = gfs2_invalidatepage, 869 .invalidatepage = gfs2_invalidatepage,
846 .releasepage = gfs2_releasepage, 870 .releasepage = gfs2_releasepage,