diff options
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r-- | fs/gfs2/ops_address.c | 146 |
1 files changed, 43 insertions, 103 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 42a5f58f6fca..873a511ef2be 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -90,7 +90,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, | |||
90 | error = gfs2_block_map(inode, lblock, 0, bh_result); | 90 | error = gfs2_block_map(inode, lblock, 0, bh_result); |
91 | if (error) | 91 | if (error) |
92 | return error; | 92 | return error; |
93 | if (bh_result->b_blocknr == 0) | 93 | if (!buffer_mapped(bh_result)) |
94 | return -EIO; | 94 | return -EIO; |
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
@@ -414,7 +414,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page, | |||
414 | if (ind_blocks || data_blocks) | 414 | if (ind_blocks || data_blocks) |
415 | rblocks += RES_STATFS + RES_QUOTA; | 415 | rblocks += RES_STATFS + RES_QUOTA; |
416 | 416 | ||
417 | error = gfs2_trans_begin(sdp, rblocks, 0); | 417 | error = gfs2_trans_begin(sdp, rblocks, |
418 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); | ||
418 | if (error) | 419 | if (error) |
419 | goto out_trans_fail; | 420 | goto out_trans_fail; |
420 | 421 | ||
@@ -616,58 +617,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) | |||
616 | return dblock; | 617 | return dblock; |
617 | } | 618 | } |
618 | 619 | ||
619 | static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) | 620 | static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) |
620 | { | 621 | { |
621 | struct gfs2_bufdata *bd; | 622 | struct gfs2_bufdata *bd; |
622 | 623 | ||
624 | lock_buffer(bh); | ||
623 | gfs2_log_lock(sdp); | 625 | gfs2_log_lock(sdp); |
626 | clear_buffer_dirty(bh); | ||
624 | bd = bh->b_private; | 627 | bd = bh->b_private; |
625 | if (bd) { | 628 | if (bd) { |
626 | bd->bd_bh = NULL; | 629 | if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh)) |
627 | bh->b_private = NULL; | 630 | list_del_init(&bd->bd_le.le_list); |
628 | if (!bd->bd_ail && list_empty(&bd->bd_le.le_list)) | 631 | else |
629 | kmem_cache_free(gfs2_bufdata_cachep, bd); | 632 | gfs2_remove_from_journal(bh, current->journal_info, 0); |
630 | } | 633 | } |
631 | gfs2_log_unlock(sdp); | ||
632 | |||
633 | lock_buffer(bh); | ||
634 | clear_buffer_dirty(bh); | ||
635 | bh->b_bdev = NULL; | 634 | bh->b_bdev = NULL; |
636 | clear_buffer_mapped(bh); | 635 | clear_buffer_mapped(bh); |
637 | clear_buffer_req(bh); | 636 | clear_buffer_req(bh); |
638 | clear_buffer_new(bh); | 637 | clear_buffer_new(bh); |
639 | clear_buffer_delay(bh); | 638 | gfs2_log_unlock(sdp); |
640 | unlock_buffer(bh); | 639 | unlock_buffer(bh); |
641 | } | 640 | } |
642 | 641 | ||
643 | static void gfs2_invalidatepage(struct page *page, unsigned long offset) | 642 | static void gfs2_invalidatepage(struct page *page, unsigned long offset) |
644 | { | 643 | { |
645 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); | 644 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); |
646 | struct buffer_head *head, *bh, *next; | 645 | struct buffer_head *bh, *head; |
647 | unsigned int curr_off = 0; | 646 | unsigned long pos = 0; |
648 | 647 | ||
649 | BUG_ON(!PageLocked(page)); | 648 | BUG_ON(!PageLocked(page)); |
650 | if (offset == 0) | 649 | if (offset == 0) |
651 | ClearPageChecked(page); | 650 | ClearPageChecked(page); |
652 | if (!page_has_buffers(page)) | 651 | if (!page_has_buffers(page)) |
653 | return; | 652 | goto out; |
654 | 653 | ||
655 | bh = head = page_buffers(page); | 654 | bh = head = page_buffers(page); |
656 | do { | 655 | do { |
657 | unsigned int next_off = curr_off + bh->b_size; | 656 | if (offset <= pos) |
658 | next = bh->b_this_page; | 657 | gfs2_discard(sdp, bh); |
659 | 658 | pos += bh->b_size; | |
660 | if (offset <= curr_off) | 659 | bh = bh->b_this_page; |
661 | discard_buffer(sdp, bh); | ||
662 | |||
663 | curr_off = next_off; | ||
664 | bh = next; | ||
665 | } while (bh != head); | 660 | } while (bh != head); |
666 | 661 | out: | |
667 | if (!offset) | 662 | if (offset == 0) |
668 | try_to_release_page(page, 0); | 663 | try_to_release_page(page, 0); |
669 | |||
670 | return; | ||
671 | } | 664 | } |
672 | 665 | ||
673 | /** | 666 | /** |
@@ -736,59 +729,6 @@ out: | |||
736 | } | 729 | } |
737 | 730 | ||
738 | /** | 731 | /** |
739 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | ||
740 | * @bh: the buffer we're stuck on | ||
741 | * | ||
742 | */ | ||
743 | |||
744 | static void stuck_releasepage(struct buffer_head *bh) | ||
745 | { | ||
746 | struct inode *inode = bh->b_page->mapping->host; | ||
747 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
748 | struct gfs2_bufdata *bd = bh->b_private; | ||
749 | struct gfs2_glock *gl; | ||
750 | static unsigned limit = 0; | ||
751 | |||
752 | if (limit > 3) | ||
753 | return; | ||
754 | limit++; | ||
755 | |||
756 | fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); | ||
757 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | ||
758 | (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); | ||
759 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | ||
760 | fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); | ||
761 | |||
762 | if (!bd) | ||
763 | return; | ||
764 | |||
765 | gl = bd->bd_gl; | ||
766 | |||
767 | fs_warn(sdp, "gl = (%u, %llu)\n", | ||
768 | gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); | ||
769 | |||
770 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | ||
771 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | ||
772 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | ||
773 | |||
774 | if (gl->gl_ops == &gfs2_inode_glops) { | ||
775 | struct gfs2_inode *ip = gl->gl_object; | ||
776 | unsigned int x; | ||
777 | |||
778 | if (!ip) | ||
779 | return; | ||
780 | |||
781 | fs_warn(sdp, "ip = %llu %llu\n", | ||
782 | (unsigned long long)ip->i_no_formal_ino, | ||
783 | (unsigned long long)ip->i_no_addr); | ||
784 | |||
785 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | ||
786 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | ||
787 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /** | ||
792 | * gfs2_releasepage - free the metadata associated with a page | 732 | * gfs2_releasepage - free the metadata associated with a page |
793 | * @page: the page that's being released | 733 | * @page: the page that's being released |
794 | * @gfp_mask: passed from Linux VFS, ignored by us | 734 | * @gfp_mask: passed from Linux VFS, ignored by us |
@@ -805,41 +745,39 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | |||
805 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; | 745 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; |
806 | struct buffer_head *bh, *head; | 746 | struct buffer_head *bh, *head; |
807 | struct gfs2_bufdata *bd; | 747 | struct gfs2_bufdata *bd; |
808 | unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ; | ||
809 | 748 | ||
810 | if (!page_has_buffers(page)) | 749 | if (!page_has_buffers(page)) |
811 | goto out; | 750 | return 0; |
812 | 751 | ||
752 | gfs2_log_lock(sdp); | ||
813 | head = bh = page_buffers(page); | 753 | head = bh = page_buffers(page); |
814 | do { | 754 | do { |
815 | while (atomic_read(&bh->b_count)) { | 755 | if (atomic_read(&bh->b_count)) |
816 | if (!atomic_read(&aspace->i_writecount)) | 756 | goto cannot_release; |
817 | return 0; | 757 | bd = bh->b_private; |
818 | 758 | if (bd && bd->bd_ail) | |
819 | if (!(gfp_mask & __GFP_WAIT)) | 759 | goto cannot_release; |
820 | return 0; | ||
821 | |||
822 | if (time_after_eq(jiffies, t)) { | ||
823 | stuck_releasepage(bh); | ||
824 | /* should we withdraw here? */ | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | yield(); | ||
829 | } | ||
830 | |||
831 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | 760 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); |
832 | gfs2_assert_warn(sdp, !buffer_dirty(bh)); | 761 | gfs2_assert_warn(sdp, !buffer_dirty(bh)); |
762 | bh = bh->b_this_page; | ||
763 | } while(bh != head); | ||
764 | gfs2_log_unlock(sdp); | ||
833 | 765 | ||
766 | head = bh = page_buffers(page); | ||
767 | do { | ||
834 | gfs2_log_lock(sdp); | 768 | gfs2_log_lock(sdp); |
835 | bd = bh->b_private; | 769 | bd = bh->b_private; |
836 | if (bd) { | 770 | if (bd) { |
837 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | 771 | gfs2_assert_warn(sdp, bd->bd_bh == bh); |
838 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | 772 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); |
839 | gfs2_assert_warn(sdp, !bd->bd_ail); | 773 | if (!list_empty(&bd->bd_le.le_list)) { |
840 | bd->bd_bh = NULL; | 774 | if (!buffer_pinned(bh)) |
841 | if (!list_empty(&bd->bd_le.le_list)) | 775 | list_del_init(&bd->bd_le.le_list); |
842 | bd = NULL; | 776 | else |
777 | bd = NULL; | ||
778 | } | ||
779 | if (bd) | ||
780 | bd->bd_bh = NULL; | ||
843 | bh->b_private = NULL; | 781 | bh->b_private = NULL; |
844 | } | 782 | } |
845 | gfs2_log_unlock(sdp); | 783 | gfs2_log_unlock(sdp); |
@@ -849,8 +787,10 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | |||
849 | bh = bh->b_this_page; | 787 | bh = bh->b_this_page; |
850 | } while (bh != head); | 788 | } while (bh != head); |
851 | 789 | ||
852 | out: | ||
853 | return try_to_free_buffers(page); | 790 | return try_to_free_buffers(page); |
791 | cannot_release: | ||
792 | gfs2_log_unlock(sdp); | ||
793 | return 0; | ||
854 | } | 794 | } |
855 | 795 | ||
856 | const struct address_space_operations gfs2_file_aops = { | 796 | const struct address_space_operations gfs2_file_aops = { |