diff options
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r-- | fs/gfs2/ops_address.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 2c4ec5cf21ff..031270ad55e2 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "rgrp.h" | 33 | #include "rgrp.h" |
34 | #include "ops_file.h" | 34 | #include "ops_file.h" |
35 | #include "util.h" | 35 | #include "util.h" |
36 | #include "glops.h" | ||
36 | 37 | ||
37 | /** | 38 | /** |
38 | * gfs2_get_block - Fills in a buffer head with details about a block | 39 | * gfs2_get_block - Fills in a buffer head with details about a block |
@@ -659,6 +660,115 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
659 | return ret; | 660 | return ret; |
660 | } | 661 | } |
661 | 662 | ||
663 | /** | ||
664 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | ||
665 | * @bh: the buffer we're stuck on | ||
666 | * | ||
667 | */ | ||
668 | |||
669 | static void stuck_releasepage(struct buffer_head *bh) | ||
670 | { | ||
671 | struct inode *inode = bh->b_page->mapping->host; | ||
672 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
673 | struct gfs2_bufdata *bd = bh->b_private; | ||
674 | struct gfs2_glock *gl; | ||
675 | |||
676 | fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); | ||
677 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | ||
678 | (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); | ||
679 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | ||
680 | fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); | ||
681 | |||
682 | if (!bd) | ||
683 | return; | ||
684 | |||
685 | gl = bd->bd_gl; | ||
686 | |||
687 | fs_warn(sdp, "gl = (%u, %llu)\n", | ||
688 | gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); | ||
689 | |||
690 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | ||
691 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | ||
692 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | ||
693 | |||
694 | if (gl->gl_ops == &gfs2_inode_glops) { | ||
695 | struct gfs2_inode *ip = gl->gl_object; | ||
696 | unsigned int x; | ||
697 | |||
698 | if (!ip) | ||
699 | return; | ||
700 | |||
701 | fs_warn(sdp, "ip = %llu %llu\n", | ||
702 | (unsigned long long)ip->i_num.no_formal_ino, | ||
703 | (unsigned long long)ip->i_num.no_addr); | ||
704 | |||
705 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | ||
706 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | ||
707 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * gfs2_aspace_releasepage - free the metadata associated with a page | ||
713 | * @page: the page that's being released | ||
714 | * @gfp_mask: passed from Linux VFS, ignored by us | ||
715 | * | ||
716 | * Call try_to_free_buffers() if the buffers in this page can be | ||
717 | * released. | ||
718 | * | ||
719 | * Returns: 0 | ||
720 | */ | ||
721 | |||
722 | int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | ||
723 | { | ||
724 | struct inode *aspace = page->mapping->host; | ||
725 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; | ||
726 | struct buffer_head *bh, *head; | ||
727 | struct gfs2_bufdata *bd; | ||
728 | unsigned long t; | ||
729 | |||
730 | if (!page_has_buffers(page)) | ||
731 | goto out; | ||
732 | |||
733 | head = bh = page_buffers(page); | ||
734 | do { | ||
735 | t = jiffies; | ||
736 | |||
737 | while (atomic_read(&bh->b_count)) { | ||
738 | if (atomic_read(&aspace->i_writecount)) { | ||
739 | if (time_after_eq(jiffies, t + | ||
740 | gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { | ||
741 | stuck_releasepage(bh); | ||
742 | t = jiffies; | ||
743 | } | ||
744 | |||
745 | yield(); | ||
746 | continue; | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | ||
753 | |||
754 | bd = bh->b_private; | ||
755 | if (bd) { | ||
756 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | ||
757 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | ||
758 | gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); | ||
759 | gfs2_assert_warn(sdp, !bd->bd_ail); | ||
760 | kmem_cache_free(gfs2_bufdata_cachep, bd); | ||
761 | bh->b_private = NULL; | ||
762 | } | ||
763 | |||
764 | bh = bh->b_this_page; | ||
765 | } | ||
766 | while (bh != head); | ||
767 | |||
768 | out: | ||
769 | return try_to_free_buffers(page); | ||
770 | } | ||
771 | |||
662 | const struct address_space_operations gfs2_file_aops = { | 772 | const struct address_space_operations gfs2_file_aops = { |
663 | .writepage = gfs2_writepage, | 773 | .writepage = gfs2_writepage, |
664 | .readpage = gfs2_readpage, | 774 | .readpage = gfs2_readpage, |
@@ -668,6 +778,7 @@ const struct address_space_operations gfs2_file_aops = { | |||
668 | .commit_write = gfs2_commit_write, | 778 | .commit_write = gfs2_commit_write, |
669 | .bmap = gfs2_bmap, | 779 | .bmap = gfs2_bmap, |
670 | .invalidatepage = gfs2_invalidatepage, | 780 | .invalidatepage = gfs2_invalidatepage, |
781 | .releasepage = gfs2_releasepage, | ||
671 | .direct_IO = gfs2_direct_IO, | 782 | .direct_IO = gfs2_direct_IO, |
672 | }; | 783 | }; |
673 | 784 | ||