diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 244 |
1 files changed, 84 insertions, 160 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 756fae9eaf8f..4752eadc7f6e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/freezer.h> | 19 | #include <linux/freezer.h> |
20 | #include <linux/bio.h> | 20 | #include <linux/bio.h> |
21 | #include <linux/writeback.h> | 21 | #include <linux/writeback.h> |
22 | #include <linux/list_sort.h> | ||
22 | 23 | ||
23 | #include "gfs2.h" | 24 | #include "gfs2.h" |
24 | #include "incore.h" | 25 | #include "incore.h" |
@@ -358,7 +359,7 @@ retry: | |||
358 | return 0; | 359 | return 0; |
359 | } | 360 | } |
360 | 361 | ||
361 | static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) | 362 | u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) |
362 | { | 363 | { |
363 | struct gfs2_journal_extent *je; | 364 | struct gfs2_journal_extent *je; |
364 | 365 | ||
@@ -467,8 +468,8 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) | |||
467 | 468 | ||
468 | void gfs2_log_incr_head(struct gfs2_sbd *sdp) | 469 | void gfs2_log_incr_head(struct gfs2_sbd *sdp) |
469 | { | 470 | { |
470 | if (sdp->sd_log_flush_head == sdp->sd_log_tail) | 471 | BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) && |
471 | BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); | 472 | (sdp->sd_log_flush_head != sdp->sd_log_head)); |
472 | 473 | ||
473 | if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { | 474 | if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { |
474 | sdp->sd_log_flush_head = 0; | 475 | sdp->sd_log_flush_head = 0; |
@@ -476,99 +477,6 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp) | |||
476 | } | 477 | } |
477 | } | 478 | } |
478 | 479 | ||
479 | /** | ||
480 | * gfs2_log_write_endio - End of I/O for a log buffer | ||
481 | * @bh: The buffer head | ||
482 | * @uptodate: I/O Status | ||
483 | * | ||
484 | */ | ||
485 | |||
486 | static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) | ||
487 | { | ||
488 | struct gfs2_sbd *sdp = bh->b_private; | ||
489 | bh->b_private = NULL; | ||
490 | |||
491 | end_buffer_write_sync(bh, uptodate); | ||
492 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | ||
493 | wake_up(&sdp->sd_log_flush_wait); | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * gfs2_log_get_buf - Get and initialize a buffer to use for log control data | ||
498 | * @sdp: The GFS2 superblock | ||
499 | * | ||
500 | * Returns: the buffer_head | ||
501 | */ | ||
502 | |||
503 | struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) | ||
504 | { | ||
505 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); | ||
506 | struct buffer_head *bh; | ||
507 | |||
508 | bh = sb_getblk(sdp->sd_vfs, blkno); | ||
509 | lock_buffer(bh); | ||
510 | memset(bh->b_data, 0, bh->b_size); | ||
511 | set_buffer_uptodate(bh); | ||
512 | clear_buffer_dirty(bh); | ||
513 | gfs2_log_incr_head(sdp); | ||
514 | atomic_inc(&sdp->sd_log_in_flight); | ||
515 | bh->b_private = sdp; | ||
516 | bh->b_end_io = gfs2_log_write_endio; | ||
517 | |||
518 | return bh; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * gfs2_fake_write_endio - | ||
523 | * @bh: The buffer head | ||
524 | * @uptodate: The I/O Status | ||
525 | * | ||
526 | */ | ||
527 | |||
528 | static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) | ||
529 | { | ||
530 | struct buffer_head *real_bh = bh->b_private; | ||
531 | struct gfs2_bufdata *bd = real_bh->b_private; | ||
532 | struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; | ||
533 | |||
534 | end_buffer_write_sync(bh, uptodate); | ||
535 | free_buffer_head(bh); | ||
536 | unlock_buffer(real_bh); | ||
537 | brelse(real_bh); | ||
538 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | ||
539 | wake_up(&sdp->sd_log_flush_wait); | ||
540 | } | ||
541 | |||
542 | /** | ||
543 | * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log | ||
544 | * @sdp: the filesystem | ||
545 | * @data: the data the buffer_head should point to | ||
546 | * | ||
547 | * Returns: the log buffer descriptor | ||
548 | */ | ||
549 | |||
550 | struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, | ||
551 | struct buffer_head *real) | ||
552 | { | ||
553 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); | ||
554 | struct buffer_head *bh; | ||
555 | |||
556 | bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); | ||
557 | atomic_set(&bh->b_count, 1); | ||
558 | bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); | ||
559 | set_bh_page(bh, real->b_page, bh_offset(real)); | ||
560 | bh->b_blocknr = blkno; | ||
561 | bh->b_size = sdp->sd_sb.sb_bsize; | ||
562 | bh->b_bdev = sdp->sd_vfs->s_bdev; | ||
563 | bh->b_private = real; | ||
564 | bh->b_end_io = gfs2_fake_write_endio; | ||
565 | |||
566 | gfs2_log_incr_head(sdp); | ||
567 | atomic_inc(&sdp->sd_log_in_flight); | ||
568 | |||
569 | return bh; | ||
570 | } | ||
571 | |||
572 | static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) | 480 | static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) |
573 | { | 481 | { |
574 | unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); | 482 | unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); |
@@ -583,66 +491,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
583 | sdp->sd_log_tail = new_tail; | 491 | sdp->sd_log_tail = new_tail; |
584 | } | 492 | } |
585 | 493 | ||
586 | /** | ||
587 | * log_write_header - Get and initialize a journal header buffer | ||
588 | * @sdp: The GFS2 superblock | ||
589 | * | ||
590 | * Returns: the initialized log buffer descriptor | ||
591 | */ | ||
592 | 494 | ||
593 | static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | 495 | static void log_flush_wait(struct gfs2_sbd *sdp) |
594 | { | ||
595 | u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); | ||
596 | struct buffer_head *bh; | ||
597 | struct gfs2_log_header *lh; | ||
598 | unsigned int tail; | ||
599 | u32 hash; | ||
600 | |||
601 | bh = sb_getblk(sdp->sd_vfs, blkno); | ||
602 | lock_buffer(bh); | ||
603 | memset(bh->b_data, 0, bh->b_size); | ||
604 | set_buffer_uptodate(bh); | ||
605 | clear_buffer_dirty(bh); | ||
606 | |||
607 | gfs2_ail1_empty(sdp); | ||
608 | tail = current_tail(sdp); | ||
609 | |||
610 | lh = (struct gfs2_log_header *)bh->b_data; | ||
611 | memset(lh, 0, sizeof(struct gfs2_log_header)); | ||
612 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | ||
613 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); | ||
614 | lh->lh_header.__pad0 = cpu_to_be64(0); | ||
615 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); | ||
616 | lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | ||
617 | lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); | ||
618 | lh->lh_flags = cpu_to_be32(flags); | ||
619 | lh->lh_tail = cpu_to_be32(tail); | ||
620 | lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); | ||
621 | hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); | ||
622 | lh->lh_hash = cpu_to_be32(hash); | ||
623 | |||
624 | bh->b_end_io = end_buffer_write_sync; | ||
625 | get_bh(bh); | ||
626 | if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) | ||
627 | submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); | ||
628 | else | ||
629 | submit_bh(WRITE_FLUSH_FUA | REQ_META, bh); | ||
630 | wait_on_buffer(bh); | ||
631 | |||
632 | if (!buffer_uptodate(bh)) | ||
633 | gfs2_io_error_bh(sdp, bh); | ||
634 | brelse(bh); | ||
635 | |||
636 | if (sdp->sd_log_tail != tail) | ||
637 | log_pull_tail(sdp, tail); | ||
638 | else | ||
639 | gfs2_assert_withdraw(sdp, !pull); | ||
640 | |||
641 | sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); | ||
642 | gfs2_log_incr_head(sdp); | ||
643 | } | ||
644 | |||
645 | static void log_flush_commit(struct gfs2_sbd *sdp) | ||
646 | { | 496 | { |
647 | DEFINE_WAIT(wait); | 497 | DEFINE_WAIT(wait); |
648 | 498 | ||
@@ -655,8 +505,20 @@ static void log_flush_commit(struct gfs2_sbd *sdp) | |||
655 | } while(atomic_read(&sdp->sd_log_in_flight)); | 505 | } while(atomic_read(&sdp->sd_log_in_flight)); |
656 | finish_wait(&sdp->sd_log_flush_wait, &wait); | 506 | finish_wait(&sdp->sd_log_flush_wait, &wait); |
657 | } | 507 | } |
508 | } | ||
509 | |||
510 | static int bd_cmp(void *priv, struct list_head *a, struct list_head *b) | ||
511 | { | ||
512 | struct gfs2_bufdata *bda, *bdb; | ||
658 | 513 | ||
659 | log_write_header(sdp, 0, 0); | 514 | bda = list_entry(a, struct gfs2_bufdata, bd_le.le_list); |
515 | bdb = list_entry(b, struct gfs2_bufdata, bd_le.le_list); | ||
516 | |||
517 | if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr) | ||
518 | return -1; | ||
519 | if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr) | ||
520 | return 1; | ||
521 | return 0; | ||
660 | } | 522 | } |
661 | 523 | ||
662 | static void gfs2_ordered_write(struct gfs2_sbd *sdp) | 524 | static void gfs2_ordered_write(struct gfs2_sbd *sdp) |
@@ -666,6 +528,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp) | |||
666 | LIST_HEAD(written); | 528 | LIST_HEAD(written); |
667 | 529 | ||
668 | gfs2_log_lock(sdp); | 530 | gfs2_log_lock(sdp); |
531 | list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp); | ||
669 | while (!list_empty(&sdp->sd_log_le_ordered)) { | 532 | while (!list_empty(&sdp->sd_log_le_ordered)) { |
670 | bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); | 533 | bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); |
671 | list_move(&bd->bd_le.le_list, &written); | 534 | list_move(&bd->bd_le.le_list, &written); |
@@ -711,6 +574,68 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp) | |||
711 | } | 574 | } |
712 | 575 | ||
713 | /** | 576 | /** |
577 | * log_write_header - Get and initialize a journal header buffer | ||
578 | * @sdp: The GFS2 superblock | ||
579 | * | ||
580 | * Returns: the initialized log buffer descriptor | ||
581 | */ | ||
582 | |||
583 | static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | ||
584 | { | ||
585 | u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); | ||
586 | struct buffer_head *bh; | ||
587 | struct gfs2_log_header *lh; | ||
588 | unsigned int tail; | ||
589 | u32 hash; | ||
590 | |||
591 | bh = sb_getblk(sdp->sd_vfs, blkno); | ||
592 | lock_buffer(bh); | ||
593 | memset(bh->b_data, 0, bh->b_size); | ||
594 | set_buffer_uptodate(bh); | ||
595 | clear_buffer_dirty(bh); | ||
596 | |||
597 | gfs2_ail1_empty(sdp); | ||
598 | tail = current_tail(sdp); | ||
599 | |||
600 | lh = (struct gfs2_log_header *)bh->b_data; | ||
601 | memset(lh, 0, sizeof(struct gfs2_log_header)); | ||
602 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | ||
603 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); | ||
604 | lh->lh_header.__pad0 = cpu_to_be64(0); | ||
605 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); | ||
606 | lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | ||
607 | lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); | ||
608 | lh->lh_flags = cpu_to_be32(flags); | ||
609 | lh->lh_tail = cpu_to_be32(tail); | ||
610 | lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); | ||
611 | hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); | ||
612 | lh->lh_hash = cpu_to_be32(hash); | ||
613 | |||
614 | bh->b_end_io = end_buffer_write_sync; | ||
615 | get_bh(bh); | ||
616 | if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) { | ||
617 | gfs2_ordered_wait(sdp); | ||
618 | log_flush_wait(sdp); | ||
619 | submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); | ||
620 | } else { | ||
621 | submit_bh(WRITE_FLUSH_FUA | REQ_META, bh); | ||
622 | } | ||
623 | wait_on_buffer(bh); | ||
624 | |||
625 | if (!buffer_uptodate(bh)) | ||
626 | gfs2_io_error_bh(sdp, bh); | ||
627 | brelse(bh); | ||
628 | |||
629 | if (sdp->sd_log_tail != tail) | ||
630 | log_pull_tail(sdp, tail); | ||
631 | else | ||
632 | gfs2_assert_withdraw(sdp, !pull); | ||
633 | |||
634 | sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); | ||
635 | gfs2_log_incr_head(sdp); | ||
636 | } | ||
637 | |||
638 | /** | ||
714 | * gfs2_log_flush - flush incore transaction(s) | 639 | * gfs2_log_flush - flush incore transaction(s) |
715 | * @sdp: the filesystem | 640 | * @sdp: the filesystem |
716 | * @gl: The glock structure to flush. If NULL, flush the whole incore log | 641 | * @gl: The glock structure to flush. If NULL, flush the whole incore log |
@@ -753,11 +678,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
753 | 678 | ||
754 | gfs2_ordered_write(sdp); | 679 | gfs2_ordered_write(sdp); |
755 | lops_before_commit(sdp); | 680 | lops_before_commit(sdp); |
756 | gfs2_ordered_wait(sdp); | ||
757 | 681 | ||
758 | if (sdp->sd_log_head != sdp->sd_log_flush_head) | 682 | if (sdp->sd_log_head != sdp->sd_log_flush_head) { |
759 | log_flush_commit(sdp); | 683 | log_write_header(sdp, 0, 0); |
760 | else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ | 684 | } else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ |
761 | gfs2_log_lock(sdp); | 685 | gfs2_log_lock(sdp); |
762 | atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ | 686 | atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ |
763 | trace_gfs2_log_blocks(sdp, -1); | 687 | trace_gfs2_log_blocks(sdp, -1); |