diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b404f4853034..610613fb65b5 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -211,15 +211,16 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | |||
211 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp) | 211 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp) |
212 | { | 212 | { |
213 | struct gfs2_trans *tr, *s; | 213 | struct gfs2_trans *tr, *s; |
214 | int oldest_tr = 1; | ||
214 | int ret; | 215 | int ret; |
215 | 216 | ||
216 | spin_lock(&sdp->sd_ail_lock); | 217 | spin_lock(&sdp->sd_ail_lock); |
217 | list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) { | 218 | list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) { |
218 | gfs2_ail1_empty_one(sdp, tr); | 219 | gfs2_ail1_empty_one(sdp, tr); |
219 | if (list_empty(&tr->tr_ail1_list)) | 220 | if (list_empty(&tr->tr_ail1_list) && oldest_tr) |
220 | list_move(&tr->tr_list, &sdp->sd_ail2_list); | 221 | list_move(&tr->tr_list, &sdp->sd_ail2_list); |
221 | else | 222 | else |
222 | break; | 223 | oldest_tr = 0; |
223 | } | 224 | } |
224 | ret = list_empty(&sdp->sd_ail1_list); | 225 | ret = list_empty(&sdp->sd_ail1_list); |
225 | spin_unlock(&sdp->sd_ail_lock); | 226 | spin_unlock(&sdp->sd_ail_lock); |
@@ -317,7 +318,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
317 | 318 | ||
318 | int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) | 319 | int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) |
319 | { | 320 | { |
320 | unsigned reserved_blks = 6 * (4096 / sdp->sd_vfs->s_blocksize); | 321 | unsigned reserved_blks = 7 * (4096 / sdp->sd_vfs->s_blocksize); |
321 | unsigned wanted = blks + reserved_blks; | 322 | unsigned wanted = blks + reserved_blks; |
322 | DEFINE_WAIT(wait); | 323 | DEFINE_WAIT(wait); |
323 | int did_wait = 0; | 324 | int did_wait = 0; |
@@ -545,6 +546,76 @@ void gfs2_ordered_del_inode(struct gfs2_inode *ip) | |||
545 | spin_unlock(&sdp->sd_ordered_lock); | 546 | spin_unlock(&sdp->sd_ordered_lock); |
546 | } | 547 | } |
547 | 548 | ||
549 | void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | ||
550 | { | ||
551 | struct buffer_head *bh = bd->bd_bh; | ||
552 | struct gfs2_glock *gl = bd->bd_gl; | ||
553 | |||
554 | gfs2_remove_from_ail(bd); | ||
555 | bd->bd_bh = NULL; | ||
556 | bh->b_private = NULL; | ||
557 | bd->bd_blkno = bh->b_blocknr; | ||
558 | bd->bd_ops = &gfs2_revoke_lops; | ||
559 | sdp->sd_log_num_revoke++; | ||
560 | atomic_inc(&gl->gl_revokes); | ||
561 | set_bit(GLF_LFLUSH, &gl->gl_flags); | ||
562 | list_add(&bd->bd_list, &sdp->sd_log_le_revoke); | ||
563 | } | ||
564 | |||
565 | void gfs2_write_revokes(struct gfs2_sbd *sdp) | ||
566 | { | ||
567 | struct gfs2_trans *tr; | ||
568 | struct gfs2_bufdata *bd, *tmp; | ||
569 | int have_revokes = 0; | ||
570 | int max_revokes = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / sizeof(u64); | ||
571 | |||
572 | gfs2_ail1_empty(sdp); | ||
573 | spin_lock(&sdp->sd_ail_lock); | ||
574 | list_for_each_entry(tr, &sdp->sd_ail1_list, tr_list) { | ||
575 | list_for_each_entry(bd, &tr->tr_ail2_list, bd_ail_st_list) { | ||
576 | if (list_empty(&bd->bd_list)) { | ||
577 | have_revokes = 1; | ||
578 | goto done; | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | done: | ||
583 | spin_unlock(&sdp->sd_ail_lock); | ||
584 | if (have_revokes == 0) | ||
585 | return; | ||
586 | while (sdp->sd_log_num_revoke > max_revokes) | ||
587 | max_revokes += (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / sizeof(u64); | ||
588 | max_revokes -= sdp->sd_log_num_revoke; | ||
589 | if (!sdp->sd_log_num_revoke) { | ||
590 | atomic_dec(&sdp->sd_log_blks_free); | ||
591 | /* If no blocks have been reserved, we need to also | ||
592 | * reserve a block for the header */ | ||
593 | if (!sdp->sd_log_blks_reserved) | ||
594 | atomic_dec(&sdp->sd_log_blks_free); | ||
595 | } | ||
596 | gfs2_log_lock(sdp); | ||
597 | spin_lock(&sdp->sd_ail_lock); | ||
598 | list_for_each_entry(tr, &sdp->sd_ail1_list, tr_list) { | ||
599 | list_for_each_entry_safe(bd, tmp, &tr->tr_ail2_list, bd_ail_st_list) { | ||
600 | if (max_revokes == 0) | ||
601 | goto out_of_blocks; | ||
602 | if (!list_empty(&bd->bd_list)) | ||
603 | continue; | ||
604 | gfs2_add_revoke(sdp, bd); | ||
605 | max_revokes--; | ||
606 | } | ||
607 | } | ||
608 | out_of_blocks: | ||
609 | spin_unlock(&sdp->sd_ail_lock); | ||
610 | gfs2_log_unlock(sdp); | ||
611 | |||
612 | if (!sdp->sd_log_num_revoke) { | ||
613 | atomic_inc(&sdp->sd_log_blks_free); | ||
614 | if (!sdp->sd_log_blks_reserved) | ||
615 | atomic_inc(&sdp->sd_log_blks_free); | ||
616 | } | ||
617 | } | ||
618 | |||
548 | /** | 619 | /** |
549 | * log_write_header - Get and initialize a journal header buffer | 620 | * log_write_header - Get and initialize a journal header buffer |
550 | * @sdp: The GFS2 superblock | 621 | * @sdp: The GFS2 superblock |
@@ -562,7 +633,6 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) | |||
562 | lh = page_address(page); | 633 | lh = page_address(page); |
563 | clear_page(lh); | 634 | clear_page(lh); |
564 | 635 | ||
565 | gfs2_ail1_empty(sdp); | ||
566 | tail = current_tail(sdp); | 636 | tail = current_tail(sdp); |
567 | 637 | ||
568 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | 638 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); |