diff options
Diffstat (limited to 'fs/gfs2/meta_io.c')
-rw-r--r-- | fs/gfs2/meta_io.c | 112 |
1 files changed, 2 insertions, 110 deletions
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index ddcd4dc1081d..cad44fd70d67 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "rgrp.h" | 31 | #include "rgrp.h" |
32 | #include "trans.h" | 32 | #include "trans.h" |
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "ops_address.h" | ||
34 | 35 | ||
35 | #define buffer_busy(bh) \ | 36 | #define buffer_busy(bh) \ |
36 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) | 37 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) |
@@ -50,118 +51,9 @@ static int gfs2_aspace_writepage(struct page *page, | |||
50 | return block_write_full_page(page, aspace_get_block, wbc); | 51 | return block_write_full_page(page, aspace_get_block, wbc); |
51 | } | 52 | } |
52 | 53 | ||
53 | /** | ||
54 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | ||
55 | * @bh: the buffer we're stuck on | ||
56 | * | ||
57 | */ | ||
58 | |||
59 | static void stuck_releasepage(struct buffer_head *bh) | ||
60 | { | ||
61 | struct inode *inode = bh->b_page->mapping->host; | ||
62 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
63 | struct gfs2_bufdata *bd = bh->b_private; | ||
64 | struct gfs2_glock *gl; | ||
65 | |||
66 | fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); | ||
67 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | ||
68 | (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); | ||
69 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | ||
70 | fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); | ||
71 | |||
72 | if (!bd) | ||
73 | return; | ||
74 | |||
75 | gl = bd->bd_gl; | ||
76 | |||
77 | fs_warn(sdp, "gl = (%u, %llu)\n", | ||
78 | gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); | ||
79 | |||
80 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | ||
81 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | ||
82 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | ||
83 | |||
84 | if (gl->gl_ops == &gfs2_inode_glops) { | ||
85 | struct gfs2_inode *ip = gl->gl_object; | ||
86 | unsigned int x; | ||
87 | |||
88 | if (!ip) | ||
89 | return; | ||
90 | |||
91 | fs_warn(sdp, "ip = %llu %llu\n", | ||
92 | (unsigned long long)ip->i_num.no_formal_ino, | ||
93 | (unsigned long long)ip->i_num.no_addr); | ||
94 | |||
95 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | ||
96 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | ||
97 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * gfs2_aspace_releasepage - free the metadata associated with a page | ||
103 | * @page: the page that's being released | ||
104 | * @gfp_mask: passed from Linux VFS, ignored by us | ||
105 | * | ||
106 | * Call try_to_free_buffers() if the buffers in this page can be | ||
107 | * released. | ||
108 | * | ||
109 | * Returns: 0 | ||
110 | */ | ||
111 | |||
112 | static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) | ||
113 | { | ||
114 | struct inode *aspace = page->mapping->host; | ||
115 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; | ||
116 | struct buffer_head *bh, *head; | ||
117 | struct gfs2_bufdata *bd; | ||
118 | unsigned long t; | ||
119 | |||
120 | if (!page_has_buffers(page)) | ||
121 | goto out; | ||
122 | |||
123 | head = bh = page_buffers(page); | ||
124 | do { | ||
125 | t = jiffies; | ||
126 | |||
127 | while (atomic_read(&bh->b_count)) { | ||
128 | if (atomic_read(&aspace->i_writecount)) { | ||
129 | if (time_after_eq(jiffies, t + | ||
130 | gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { | ||
131 | stuck_releasepage(bh); | ||
132 | t = jiffies; | ||
133 | } | ||
134 | |||
135 | yield(); | ||
136 | continue; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | ||
143 | |||
144 | bd = bh->b_private; | ||
145 | if (bd) { | ||
146 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | ||
147 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | ||
148 | gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); | ||
149 | gfs2_assert_warn(sdp, !bd->bd_ail); | ||
150 | kmem_cache_free(gfs2_bufdata_cachep, bd); | ||
151 | bh->b_private = NULL; | ||
152 | } | ||
153 | |||
154 | bh = bh->b_this_page; | ||
155 | } | ||
156 | while (bh != head); | ||
157 | |||
158 | out: | ||
159 | return try_to_free_buffers(page); | ||
160 | } | ||
161 | |||
162 | static const struct address_space_operations aspace_aops = { | 54 | static const struct address_space_operations aspace_aops = { |
163 | .writepage = gfs2_aspace_writepage, | 55 | .writepage = gfs2_aspace_writepage, |
164 | .releasepage = gfs2_aspace_releasepage, | 56 | .releasepage = gfs2_releasepage, |
165 | }; | 57 | }; |
166 | 58 | ||
167 | /** | 59 | /** |