aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/recovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/recovery.c')
-rw-r--r--fs/gfs2/recovery.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 7389e445a7a7..2dac43065382 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -182,6 +182,129 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
182} 182}
183 183
184/** 184/**
185 * find_good_lh - find a good log header
186 * @jd: the journal
187 * @blk: the segment to start searching from
188 * @lh: the log header to fill in
189 * @forward: if true search forward in the log, else search backward
190 *
191 * Call get_log_header() to get a log header for a segment, but if the
192 * segment is bad, either scan forward or backward until we find a good one.
193 *
194 * Returns: errno
195 */
196
197static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
198 struct gfs2_log_header_host *head)
199{
200 unsigned int orig_blk = *blk;
201 int error;
202
203 for (;;) {
204 error = get_log_header(jd, *blk, head);
205 if (error <= 0)
206 return error;
207
208 if (++*blk == jd->jd_blocks)
209 *blk = 0;
210
211 if (*blk == orig_blk) {
212 gfs2_consist_inode(GFS2_I(jd->jd_inode));
213 return -EIO;
214 }
215 }
216}
217
218/**
219 * jhead_scan - make sure we've found the head of the log
220 * @jd: the journal
221 * @head: this is filled in with the log descriptor of the head
222 *
223 * At this point, seg and lh should be either the head of the log or just
224 * before. Scan forward until we find the head.
225 *
226 * Returns: errno
227 */
228
229static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
230{
231 unsigned int blk = head->lh_blkno;
232 struct gfs2_log_header_host lh;
233 int error;
234
235 for (;;) {
236 if (++blk == jd->jd_blocks)
237 blk = 0;
238
239 error = get_log_header(jd, blk, &lh);
240 if (error < 0)
241 return error;
242 if (error == 1)
243 continue;
244
245 if (lh.lh_sequence == head->lh_sequence) {
246 gfs2_consist_inode(GFS2_I(jd->jd_inode));
247 return -EIO;
248 }
249 if (lh.lh_sequence < head->lh_sequence)
250 break;
251
252 *head = lh;
253 }
254
255 return 0;
256}
257
258/**
259 * gfs2_find_jhead - find the head of a log
260 * @jd: the journal
261 * @head: the log descriptor for the head of the log is returned here
262 *
263 * Do a binary search of a journal and find the valid log entry with the
264 * highest sequence number. (i.e. the log head)
265 *
266 * Returns: errno
267 */
268
269int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
270{
271 struct gfs2_log_header_host lh_1, lh_m;
272 u32 blk_1, blk_2, blk_m;
273 int error;
274
275 blk_1 = 0;
276 blk_2 = jd->jd_blocks - 1;
277
278 for (;;) {
279 blk_m = (blk_1 + blk_2) / 2;
280
281 error = find_good_lh(jd, &blk_1, &lh_1);
282 if (error)
283 return error;
284
285 error = find_good_lh(jd, &blk_m, &lh_m);
286 if (error)
287 return error;
288
289 if (blk_1 == blk_m || blk_m == blk_2)
290 break;
291
292 if (lh_1.lh_sequence <= lh_m.lh_sequence)
293 blk_1 = blk_m;
294 else
295 blk_2 = blk_m;
296 }
297
298 error = jhead_scan(jd, &lh_1);
299 if (error)
300 return error;
301
302 *head = lh_1;
303
304 return error;
305}
306
307/**
185 * foreach_descriptor - go through the active part of the log 308 * foreach_descriptor - go through the active part of the log
186 * @jd: the journal 309 * @jd: the journal
187 * @start: the first log header in the active region 310 * @start: the first log header in the active region