diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 165 |
1 files changed, 85 insertions, 80 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 3ebafa1efad0..03e00417061b 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,50 +84,90 @@ 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 void 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 | { |
94 | struct gfs2_glock *gl = NULL; | 98 | struct gfs2_glock *gl = NULL; |
99 | struct address_space *mapping; | ||
95 | struct gfs2_bufdata *bd, *s; | 100 | struct gfs2_bufdata *bd, *s; |
96 | struct buffer_head *bh; | 101 | struct buffer_head *bh; |
97 | int retry; | ||
98 | 102 | ||
99 | do { | 103 | restart: |
100 | retry = 0; | 104 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) { |
105 | bh = bd->bd_bh; | ||
101 | 106 | ||
102 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | 107 | gfs2_assert(sdp, bd->bd_ail == ai); |
103 | bd_ail_st_list) { | ||
104 | bh = bd->bd_bh; | ||
105 | 108 | ||
106 | gfs2_assert(sdp, bd->bd_ail == ai); | 109 | if (!buffer_busy(bh)) { |
110 | if (!buffer_uptodate(bh)) | ||
111 | gfs2_io_error_bh(sdp, bh); | ||
112 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | ||
113 | continue; | ||
114 | } | ||
115 | |||
116 | if (!buffer_dirty(bh)) | ||
117 | continue; | ||
118 | if (gl == bd->bd_gl) | ||
119 | continue; | ||
120 | gl = bd->bd_gl; | ||
121 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | ||
122 | mapping = bh->b_page->mapping; | ||
123 | spin_unlock(&sdp->sd_ail_lock); | ||
124 | generic_writepages(mapping, wbc); | ||
125 | spin_lock(&sdp->sd_ail_lock); | ||
126 | if (wbc->nr_to_write <= 0) | ||
127 | break; | ||
128 | goto restart; | ||
129 | } | ||
130 | } | ||
107 | 131 | ||
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 | } | ||
114 | 132 | ||
115 | if (!buffer_dirty(bh)) | 133 | /** |
116 | continue; | 134 | * gfs2_ail1_flush - start writeback of some ail1 entries |
117 | if (gl == bd->bd_gl) | 135 | * @sdp: The super block |
118 | continue; | 136 | * @wbc: The writeback control structure |
119 | gl = bd->bd_gl; | 137 | * |
120 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | 138 | * Writes back some ail1 entries, according to the limits in the |
139 | * writeback control structure | ||
140 | */ | ||
121 | 141 | ||
122 | spin_unlock(&sdp->sd_ail_lock); | 142 | void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) |
123 | filemap_fdatawrite(gfs2_glock2aspace(gl)); | 143 | { |
124 | spin_lock(&sdp->sd_ail_lock); | 144 | struct list_head *head = &sdp->sd_ail1_list; |
145 | struct gfs2_ail *ai; | ||
125 | 146 | ||
126 | retry = 1; | 147 | spin_lock(&sdp->sd_ail_lock); |
148 | list_for_each_entry_reverse(ai, head, ai_list) { | ||
149 | if (wbc->nr_to_write <= 0) | ||
127 | break; | 150 | break; |
128 | } | 151 | gfs2_ail1_start_one(sdp, wbc, ai); /* This may drop ail lock */ |
129 | } while (retry); | 152 | } |
153 | spin_unlock(&sdp->sd_ail_lock); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * gfs2_ail1_start - start writeback of all ail1 entries | ||
158 | * @sdp: The superblock | ||
159 | */ | ||
160 | |||
161 | static void gfs2_ail1_start(struct gfs2_sbd *sdp) | ||
162 | { | ||
163 | struct writeback_control wbc = { | ||
164 | .sync_mode = WB_SYNC_NONE, | ||
165 | .nr_to_write = LONG_MAX, | ||
166 | .range_start = 0, | ||
167 | .range_end = LLONG_MAX, | ||
168 | }; | ||
169 | |||
170 | return gfs2_ail1_flush(sdp, &wbc); | ||
130 | } | 171 | } |
131 | 172 | ||
132 | /** | 173 | /** |
@@ -136,7 +177,7 @@ __acquires(&sdp->sd_ail_lock) | |||
136 | * | 177 | * |
137 | */ | 178 | */ |
138 | 179 | ||
139 | static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) | 180 | static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) |
140 | { | 181 | { |
141 | struct gfs2_bufdata *bd, *s; | 182 | struct gfs2_bufdata *bd, *s; |
142 | struct buffer_head *bh; | 183 | struct buffer_head *bh; |
@@ -144,71 +185,37 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl | |||
144 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | 185 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, |
145 | bd_ail_st_list) { | 186 | bd_ail_st_list) { |
146 | bh = bd->bd_bh; | 187 | bh = bd->bd_bh; |
147 | |||
148 | gfs2_assert(sdp, bd->bd_ail == ai); | 188 | gfs2_assert(sdp, bd->bd_ail == ai); |
149 | 189 | if (buffer_busy(bh)) | |
150 | if (buffer_busy(bh)) { | 190 | continue; |
151 | if (flags & DIO_ALL) | ||
152 | continue; | ||
153 | else | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | if (!buffer_uptodate(bh)) | 191 | if (!buffer_uptodate(bh)) |
158 | gfs2_io_error_bh(sdp, bh); | 192 | gfs2_io_error_bh(sdp, bh); |
159 | |||
160 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | 193 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); |
161 | } | 194 | } |
162 | 195 | ||
163 | return list_empty(&ai->ai_ail1_list); | ||
164 | } | 196 | } |
165 | 197 | ||
166 | static void gfs2_ail1_start(struct gfs2_sbd *sdp) | 198 | /** |
167 | { | 199 | * gfs2_ail1_empty - Try to empty the ail1 lists |
168 | struct list_head *head; | 200 | * @sdp: The superblock |
169 | u64 sync_gen; | 201 | * |
170 | struct gfs2_ail *ai; | 202 | * Tries to empty the ail1 lists, starting with the oldest first |
171 | int done = 0; | 203 | */ |
172 | |||
173 | spin_lock(&sdp->sd_ail_lock); | ||
174 | head = &sdp->sd_ail1_list; | ||
175 | if (list_empty(head)) { | ||
176 | spin_unlock(&sdp->sd_ail_lock); | ||
177 | return; | ||
178 | } | ||
179 | sync_gen = sdp->sd_ail_sync_gen++; | ||
180 | |||
181 | while(!done) { | ||
182 | done = 1; | ||
183 | list_for_each_entry_reverse(ai, head, ai_list) { | ||
184 | if (ai->ai_sync_gen >= sync_gen) | ||
185 | continue; | ||
186 | ai->ai_sync_gen = sync_gen; | ||
187 | gfs2_ail1_start_one(sdp, ai); /* This may drop ail lock */ | ||
188 | done = 0; | ||
189 | break; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | spin_unlock(&sdp->sd_ail_lock); | ||
194 | } | ||
195 | 204 | ||
196 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | 205 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp) |
197 | { | 206 | { |
198 | struct gfs2_ail *ai, *s; | 207 | struct gfs2_ail *ai, *s; |
199 | int ret; | 208 | int ret; |
200 | 209 | ||
201 | spin_lock(&sdp->sd_ail_lock); | 210 | spin_lock(&sdp->sd_ail_lock); |
202 | |||
203 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { | 211 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { |
204 | if (gfs2_ail1_empty_one(sdp, ai, flags)) | 212 | gfs2_ail1_empty_one(sdp, ai); |
213 | if (list_empty(&ai->ai_ail1_list)) | ||
205 | list_move(&ai->ai_list, &sdp->sd_ail2_list); | 214 | list_move(&ai->ai_list, &sdp->sd_ail2_list); |
206 | else if (!(flags & DIO_ALL)) | 215 | else |
207 | break; | 216 | break; |
208 | } | 217 | } |
209 | |||
210 | ret = list_empty(&sdp->sd_ail1_list); | 218 | ret = list_empty(&sdp->sd_ail1_list); |
211 | |||
212 | spin_unlock(&sdp->sd_ail_lock); | 219 | spin_unlock(&sdp->sd_ail_lock); |
213 | 220 | ||
214 | return ret; | 221 | return ret; |
@@ -569,7 +576,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
569 | set_buffer_uptodate(bh); | 576 | set_buffer_uptodate(bh); |
570 | clear_buffer_dirty(bh); | 577 | clear_buffer_dirty(bh); |
571 | 578 | ||
572 | gfs2_ail1_empty(sdp, 0); | 579 | gfs2_ail1_empty(sdp); |
573 | tail = current_tail(sdp); | 580 | tail = current_tail(sdp); |
574 | 581 | ||
575 | lh = (struct gfs2_log_header *)bh->b_data; | 582 | lh = (struct gfs2_log_header *)bh->b_data; |
@@ -864,7 +871,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) | |||
864 | gfs2_log_flush(sdp, NULL); | 871 | gfs2_log_flush(sdp, NULL); |
865 | for (;;) { | 872 | for (;;) { |
866 | gfs2_ail1_start(sdp); | 873 | gfs2_ail1_start(sdp); |
867 | if (gfs2_ail1_empty(sdp, DIO_ALL)) | 874 | if (gfs2_ail1_empty(sdp)) |
868 | break; | 875 | break; |
869 | msleep(10); | 876 | msleep(10); |
870 | } | 877 | } |
@@ -900,17 +907,15 @@ int gfs2_logd(void *data) | |||
900 | 907 | ||
901 | preflush = atomic_read(&sdp->sd_log_pinned); | 908 | preflush = atomic_read(&sdp->sd_log_pinned); |
902 | if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { | 909 | if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { |
903 | gfs2_ail1_empty(sdp, DIO_ALL); | 910 | gfs2_ail1_empty(sdp); |
904 | gfs2_log_flush(sdp, NULL); | 911 | gfs2_log_flush(sdp, NULL); |
905 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
906 | } | 912 | } |
907 | 913 | ||
908 | if (gfs2_ail_flush_reqd(sdp)) { | 914 | if (gfs2_ail_flush_reqd(sdp)) { |
909 | gfs2_ail1_start(sdp); | 915 | gfs2_ail1_start(sdp); |
910 | io_schedule(); | 916 | io_schedule(); |
911 | gfs2_ail1_empty(sdp, 0); | 917 | gfs2_ail1_empty(sdp); |
912 | gfs2_log_flush(sdp, NULL); | 918 | gfs2_log_flush(sdp, NULL); |
913 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
914 | } | 919 | } |
915 | 920 | ||
916 | wake_up(&sdp->sd_log_waitq); | 921 | wake_up(&sdp->sd_log_waitq); |