diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 179 |
1 files changed, 93 insertions, 86 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 5b102c1887fd..cec26c00b50d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
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 | 22 | ||
22 | #include "gfs2.h" | 23 | #include "gfs2.h" |
23 | #include "incore.h" | 24 | #include "incore.h" |
@@ -83,55 +84,97 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd) | |||
83 | /** | 84 | /** |
84 | * gfs2_ail1_start_one - Start I/O on a part of the AIL | 85 | * gfs2_ail1_start_one - Start I/O on a part of the AIL |
85 | * @sdp: the filesystem | 86 | * @sdp: the filesystem |
86 | * @tr: the part of the AIL | 87 | * @wbc: The writeback control structure |
88 | * @ai: The ail structure | ||
87 | * | 89 | * |
88 | */ | 90 | */ |
89 | 91 | ||
90 | static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | 92 | static int gfs2_ail1_start_one(struct gfs2_sbd *sdp, |
93 | struct writeback_control *wbc, | ||
94 | struct gfs2_ail *ai) | ||
91 | __releases(&sdp->sd_ail_lock) | 95 | __releases(&sdp->sd_ail_lock) |
92 | __acquires(&sdp->sd_ail_lock) | 96 | __acquires(&sdp->sd_ail_lock) |
93 | { | 97 | { |
98 | struct gfs2_glock *gl = NULL; | ||
99 | struct address_space *mapping; | ||
94 | struct gfs2_bufdata *bd, *s; | 100 | struct gfs2_bufdata *bd, *s; |
95 | struct buffer_head *bh; | 101 | struct buffer_head *bh; |
96 | int retry; | ||
97 | 102 | ||
98 | do { | 103 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) { |
99 | retry = 0; | 104 | bh = bd->bd_bh; |
100 | 105 | ||
101 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | 106 | gfs2_assert(sdp, bd->bd_ail == ai); |
102 | bd_ail_st_list) { | ||
103 | bh = bd->bd_bh; | ||
104 | 107 | ||
105 | gfs2_assert(sdp, bd->bd_ail == ai); | 108 | if (!buffer_busy(bh)) { |
109 | if (!buffer_uptodate(bh)) | ||
110 | gfs2_io_error_bh(sdp, bh); | ||
111 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | ||
112 | continue; | ||
113 | } | ||
106 | 114 | ||
107 | if (!buffer_busy(bh)) { | 115 | if (!buffer_dirty(bh)) |
108 | if (!buffer_uptodate(bh)) | 116 | continue; |
109 | gfs2_io_error_bh(sdp, bh); | 117 | if (gl == bd->bd_gl) |
110 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | 118 | continue; |
111 | continue; | 119 | gl = bd->bd_gl; |
112 | } | 120 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); |
121 | mapping = bh->b_page->mapping; | ||
122 | if (!mapping) | ||
123 | continue; | ||
124 | spin_unlock(&sdp->sd_ail_lock); | ||
125 | generic_writepages(mapping, wbc); | ||
126 | spin_lock(&sdp->sd_ail_lock); | ||
127 | if (wbc->nr_to_write <= 0) | ||
128 | break; | ||
129 | return 1; | ||
130 | } | ||
113 | 131 | ||
114 | if (!buffer_dirty(bh)) | 132 | return 0; |
115 | continue; | 133 | } |
116 | 134 | ||
117 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | ||
118 | 135 | ||
119 | get_bh(bh); | 136 | /** |
120 | spin_unlock(&sdp->sd_ail_lock); | 137 | * gfs2_ail1_flush - start writeback of some ail1 entries |
121 | lock_buffer(bh); | 138 | * @sdp: The super block |
122 | if (test_clear_buffer_dirty(bh)) { | 139 | * @wbc: The writeback control structure |
123 | bh->b_end_io = end_buffer_write_sync; | 140 | * |
124 | submit_bh(WRITE_SYNC, bh); | 141 | * Writes back some ail1 entries, according to the limits in the |
125 | } else { | 142 | * writeback control structure |
126 | unlock_buffer(bh); | 143 | */ |
127 | brelse(bh); | 144 | |
128 | } | 145 | void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) |
129 | spin_lock(&sdp->sd_ail_lock); | 146 | { |
130 | 147 | struct list_head *head = &sdp->sd_ail1_list; | |
131 | retry = 1; | 148 | struct gfs2_ail *ai; |
149 | |||
150 | trace_gfs2_ail_flush(sdp, wbc, 1); | ||
151 | spin_lock(&sdp->sd_ail_lock); | ||
152 | restart: | ||
153 | list_for_each_entry_reverse(ai, head, ai_list) { | ||
154 | if (wbc->nr_to_write <= 0) | ||
132 | break; | 155 | break; |
133 | } | 156 | if (gfs2_ail1_start_one(sdp, wbc, ai)) |
134 | } while (retry); | 157 | goto restart; |
158 | } | ||
159 | spin_unlock(&sdp->sd_ail_lock); | ||
160 | trace_gfs2_ail_flush(sdp, wbc, 0); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * gfs2_ail1_start - start writeback of all ail1 entries | ||
165 | * @sdp: The superblock | ||
166 | */ | ||
167 | |||
168 | static void gfs2_ail1_start(struct gfs2_sbd *sdp) | ||
169 | { | ||
170 | struct writeback_control wbc = { | ||
171 | .sync_mode = WB_SYNC_NONE, | ||
172 | .nr_to_write = LONG_MAX, | ||
173 | .range_start = 0, | ||
174 | .range_end = LLONG_MAX, | ||
175 | }; | ||
176 | |||
177 | return gfs2_ail1_flush(sdp, &wbc); | ||
135 | } | 178 | } |
136 | 179 | ||
137 | /** | 180 | /** |
@@ -141,7 +184,7 @@ __acquires(&sdp->sd_ail_lock) | |||
141 | * | 184 | * |
142 | */ | 185 | */ |
143 | 186 | ||
144 | static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) | 187 | static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) |
145 | { | 188 | { |
146 | struct gfs2_bufdata *bd, *s; | 189 | struct gfs2_bufdata *bd, *s; |
147 | struct buffer_head *bh; | 190 | struct buffer_head *bh; |
@@ -149,71 +192,37 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl | |||
149 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | 192 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, |
150 | bd_ail_st_list) { | 193 | bd_ail_st_list) { |
151 | bh = bd->bd_bh; | 194 | bh = bd->bd_bh; |
152 | |||
153 | gfs2_assert(sdp, bd->bd_ail == ai); | 195 | gfs2_assert(sdp, bd->bd_ail == ai); |
154 | 196 | if (buffer_busy(bh)) | |
155 | if (buffer_busy(bh)) { | 197 | continue; |
156 | if (flags & DIO_ALL) | ||
157 | continue; | ||
158 | else | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | if (!buffer_uptodate(bh)) | 198 | if (!buffer_uptodate(bh)) |
163 | gfs2_io_error_bh(sdp, bh); | 199 | gfs2_io_error_bh(sdp, bh); |
164 | |||
165 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | 200 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); |
166 | } | 201 | } |
167 | 202 | ||
168 | return list_empty(&ai->ai_ail1_list); | ||
169 | } | 203 | } |
170 | 204 | ||
171 | static void gfs2_ail1_start(struct gfs2_sbd *sdp) | 205 | /** |
172 | { | 206 | * gfs2_ail1_empty - Try to empty the ail1 lists |
173 | struct list_head *head; | 207 | * @sdp: The superblock |
174 | u64 sync_gen; | 208 | * |
175 | struct gfs2_ail *ai; | 209 | * Tries to empty the ail1 lists, starting with the oldest first |
176 | int done = 0; | 210 | */ |
177 | |||
178 | spin_lock(&sdp->sd_ail_lock); | ||
179 | head = &sdp->sd_ail1_list; | ||
180 | if (list_empty(head)) { | ||
181 | spin_unlock(&sdp->sd_ail_lock); | ||
182 | return; | ||
183 | } | ||
184 | sync_gen = sdp->sd_ail_sync_gen++; | ||
185 | |||
186 | while(!done) { | ||
187 | done = 1; | ||
188 | list_for_each_entry_reverse(ai, head, ai_list) { | ||
189 | if (ai->ai_sync_gen >= sync_gen) | ||
190 | continue; | ||
191 | ai->ai_sync_gen = sync_gen; | ||
192 | gfs2_ail1_start_one(sdp, ai); /* This may drop ail lock */ | ||
193 | done = 0; | ||
194 | break; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | spin_unlock(&sdp->sd_ail_lock); | ||
199 | } | ||
200 | 211 | ||
201 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | 212 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp) |
202 | { | 213 | { |
203 | struct gfs2_ail *ai, *s; | 214 | struct gfs2_ail *ai, *s; |
204 | int ret; | 215 | int ret; |
205 | 216 | ||
206 | spin_lock(&sdp->sd_ail_lock); | 217 | spin_lock(&sdp->sd_ail_lock); |
207 | |||
208 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { | 218 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { |
209 | if (gfs2_ail1_empty_one(sdp, ai, flags)) | 219 | gfs2_ail1_empty_one(sdp, ai); |
220 | if (list_empty(&ai->ai_ail1_list)) | ||
210 | list_move(&ai->ai_list, &sdp->sd_ail2_list); | 221 | list_move(&ai->ai_list, &sdp->sd_ail2_list); |
211 | else if (!(flags & DIO_ALL)) | 222 | else |
212 | break; | 223 | break; |
213 | } | 224 | } |
214 | |||
215 | ret = list_empty(&sdp->sd_ail1_list); | 225 | ret = list_empty(&sdp->sd_ail1_list); |
216 | |||
217 | spin_unlock(&sdp->sd_ail_lock); | 226 | spin_unlock(&sdp->sd_ail_lock); |
218 | 227 | ||
219 | return ret; | 228 | return ret; |
@@ -574,7 +583,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
574 | set_buffer_uptodate(bh); | 583 | set_buffer_uptodate(bh); |
575 | clear_buffer_dirty(bh); | 584 | clear_buffer_dirty(bh); |
576 | 585 | ||
577 | gfs2_ail1_empty(sdp, 0); | 586 | gfs2_ail1_empty(sdp); |
578 | tail = current_tail(sdp); | 587 | tail = current_tail(sdp); |
579 | 588 | ||
580 | lh = (struct gfs2_log_header *)bh->b_data; | 589 | lh = (struct gfs2_log_header *)bh->b_data; |
@@ -869,7 +878,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) | |||
869 | gfs2_log_flush(sdp, NULL); | 878 | gfs2_log_flush(sdp, NULL); |
870 | for (;;) { | 879 | for (;;) { |
871 | gfs2_ail1_start(sdp); | 880 | gfs2_ail1_start(sdp); |
872 | if (gfs2_ail1_empty(sdp, DIO_ALL)) | 881 | if (gfs2_ail1_empty(sdp)) |
873 | break; | 882 | break; |
874 | msleep(10); | 883 | msleep(10); |
875 | } | 884 | } |
@@ -905,17 +914,15 @@ int gfs2_logd(void *data) | |||
905 | 914 | ||
906 | preflush = atomic_read(&sdp->sd_log_pinned); | 915 | preflush = atomic_read(&sdp->sd_log_pinned); |
907 | if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { | 916 | if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { |
908 | gfs2_ail1_empty(sdp, DIO_ALL); | 917 | gfs2_ail1_empty(sdp); |
909 | gfs2_log_flush(sdp, NULL); | 918 | gfs2_log_flush(sdp, NULL); |
910 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
911 | } | 919 | } |
912 | 920 | ||
913 | if (gfs2_ail_flush_reqd(sdp)) { | 921 | if (gfs2_ail_flush_reqd(sdp)) { |
914 | gfs2_ail1_start(sdp); | 922 | gfs2_ail1_start(sdp); |
915 | io_schedule(); | 923 | io_schedule(); |
916 | gfs2_ail1_empty(sdp, 0); | 924 | gfs2_ail1_empty(sdp); |
917 | gfs2_log_flush(sdp, NULL); | 925 | gfs2_log_flush(sdp, NULL); |
918 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
919 | } | 926 | } |
920 | 927 | ||
921 | wake_up(&sdp->sd_log_waitq); | 928 | wake_up(&sdp->sd_log_waitq); |