diff options
Diffstat (limited to 'fs/jbd2')
-rw-r--r-- | fs/jbd2/checkpoint.c | 195 |
1 files changed, 84 insertions, 111 deletions
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 7f34f4716165..f1507e5b7c9a 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -255,81 +255,6 @@ __flush_batch(journal_t *journal, int *batch_count) | |||
255 | } | 255 | } |
256 | 256 | ||
257 | /* | 257 | /* |
258 | * Try to flush one buffer from the checkpoint list to disk. | ||
259 | * | ||
260 | * Return 1 if something happened which requires us to abort the current | ||
261 | * scan of the checkpoint list. Return <0 if the buffer has failed to | ||
262 | * be written out. | ||
263 | * | ||
264 | * Called with j_list_lock held and drops it if 1 is returned | ||
265 | */ | ||
266 | static int __process_buffer(journal_t *journal, struct journal_head *jh, | ||
267 | int *batch_count, transaction_t *transaction) | ||
268 | { | ||
269 | struct buffer_head *bh = jh2bh(jh); | ||
270 | int ret = 0; | ||
271 | |||
272 | if (buffer_locked(bh)) { | ||
273 | get_bh(bh); | ||
274 | spin_unlock(&journal->j_list_lock); | ||
275 | wait_on_buffer(bh); | ||
276 | /* the journal_head may have gone by now */ | ||
277 | BUFFER_TRACE(bh, "brelse"); | ||
278 | __brelse(bh); | ||
279 | ret = 1; | ||
280 | } else if (jh->b_transaction != NULL) { | ||
281 | transaction_t *t = jh->b_transaction; | ||
282 | tid_t tid = t->t_tid; | ||
283 | |||
284 | transaction->t_chp_stats.cs_forced_to_close++; | ||
285 | spin_unlock(&journal->j_list_lock); | ||
286 | if (unlikely(journal->j_flags & JBD2_UNMOUNT)) | ||
287 | /* | ||
288 | * The journal thread is dead; so starting and | ||
289 | * waiting for a commit to finish will cause | ||
290 | * us to wait for a _very_ long time. | ||
291 | */ | ||
292 | printk(KERN_ERR "JBD2: %s: " | ||
293 | "Waiting for Godot: block %llu\n", | ||
294 | journal->j_devname, | ||
295 | (unsigned long long) bh->b_blocknr); | ||
296 | jbd2_log_start_commit(journal, tid); | ||
297 | jbd2_log_wait_commit(journal, tid); | ||
298 | ret = 1; | ||
299 | } else if (!buffer_dirty(bh)) { | ||
300 | ret = 1; | ||
301 | if (unlikely(buffer_write_io_error(bh))) | ||
302 | ret = -EIO; | ||
303 | get_bh(bh); | ||
304 | BUFFER_TRACE(bh, "remove from checkpoint"); | ||
305 | __jbd2_journal_remove_checkpoint(jh); | ||
306 | spin_unlock(&journal->j_list_lock); | ||
307 | __brelse(bh); | ||
308 | } else { | ||
309 | /* | ||
310 | * Important: we are about to write the buffer, and | ||
311 | * possibly block, while still holding the journal lock. | ||
312 | * We cannot afford to let the transaction logic start | ||
313 | * messing around with this buffer before we write it to | ||
314 | * disk, as that would break recoverability. | ||
315 | */ | ||
316 | BUFFER_TRACE(bh, "queue"); | ||
317 | get_bh(bh); | ||
318 | J_ASSERT_BH(bh, !buffer_jwrite(bh)); | ||
319 | journal->j_chkpt_bhs[*batch_count] = bh; | ||
320 | __buffer_relink_io(jh); | ||
321 | transaction->t_chp_stats.cs_written++; | ||
322 | (*batch_count)++; | ||
323 | if (*batch_count == JBD2_NR_BATCH) { | ||
324 | spin_unlock(&journal->j_list_lock); | ||
325 | __flush_batch(journal, batch_count); | ||
326 | ret = 1; | ||
327 | } | ||
328 | } | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Perform an actual checkpoint. We take the first transaction on the | 258 | * Perform an actual checkpoint. We take the first transaction on the |
334 | * list of transactions to be checkpointed and send all its buffers | 259 | * list of transactions to be checkpointed and send all its buffers |
335 | * to disk. We submit larger chunks of data at once. | 260 | * to disk. We submit larger chunks of data at once. |
@@ -339,9 +264,11 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, | |||
339 | */ | 264 | */ |
340 | int jbd2_log_do_checkpoint(journal_t *journal) | 265 | int jbd2_log_do_checkpoint(journal_t *journal) |
341 | { | 266 | { |
342 | transaction_t *transaction; | 267 | struct journal_head *jh; |
343 | tid_t this_tid; | 268 | struct buffer_head *bh; |
344 | int result; | 269 | transaction_t *transaction; |
270 | tid_t this_tid; | ||
271 | int err, result, batch_count = 0; | ||
345 | 272 | ||
346 | jbd_debug(1, "Start checkpoint\n"); | 273 | jbd_debug(1, "Start checkpoint\n"); |
347 | 274 | ||
@@ -374,46 +301,92 @@ restart: | |||
374 | * done (maybe it's a new transaction, but it fell at the same | 301 | * done (maybe it's a new transaction, but it fell at the same |
375 | * address). | 302 | * address). |
376 | */ | 303 | */ |
377 | if (journal->j_checkpoint_transactions == transaction && | 304 | if (journal->j_checkpoint_transactions != transaction || |
378 | transaction->t_tid == this_tid) { | 305 | transaction->t_tid != this_tid) |
379 | int batch_count = 0; | 306 | goto out; |
380 | struct journal_head *jh; | ||
381 | int retry = 0, err; | ||
382 | |||
383 | while (!retry && transaction->t_checkpoint_list) { | ||
384 | jh = transaction->t_checkpoint_list; | ||
385 | retry = __process_buffer(journal, jh, &batch_count, | ||
386 | transaction); | ||
387 | if (retry < 0 && !result) | ||
388 | result = retry; | ||
389 | if (!retry && (need_resched() || | ||
390 | spin_needbreak(&journal->j_list_lock))) { | ||
391 | spin_unlock(&journal->j_list_lock); | ||
392 | retry = 1; | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | 307 | ||
397 | if (batch_count) { | 308 | /* checkpoint all of the transaction's buffers */ |
398 | if (!retry) { | 309 | while (transaction->t_checkpoint_list) { |
399 | spin_unlock(&journal->j_list_lock); | 310 | jh = transaction->t_checkpoint_list; |
400 | retry = 1; | 311 | bh = jh2bh(jh); |
401 | } | 312 | |
402 | __flush_batch(journal, &batch_count); | 313 | if (buffer_locked(bh)) { |
314 | spin_unlock(&journal->j_list_lock); | ||
315 | get_bh(bh); | ||
316 | wait_on_buffer(bh); | ||
317 | /* the journal_head may have gone by now */ | ||
318 | BUFFER_TRACE(bh, "brelse"); | ||
319 | __brelse(bh); | ||
320 | goto retry; | ||
403 | } | 321 | } |
322 | if (jh->b_transaction != NULL) { | ||
323 | transaction_t *t = jh->b_transaction; | ||
324 | tid_t tid = t->t_tid; | ||
404 | 325 | ||
405 | if (retry) { | 326 | transaction->t_chp_stats.cs_forced_to_close++; |
406 | spin_lock(&journal->j_list_lock); | 327 | spin_unlock(&journal->j_list_lock); |
407 | goto restart; | 328 | if (unlikely(journal->j_flags & JBD2_UNMOUNT)) |
329 | /* | ||
330 | * The journal thread is dead; so | ||
331 | * starting and waiting for a commit | ||
332 | * to finish will cause us to wait for | ||
333 | * a _very_ long time. | ||
334 | */ | ||
335 | printk(KERN_ERR | ||
336 | "JBD2: %s: Waiting for Godot: block %llu\n", | ||
337 | journal->j_devname, (unsigned long long) bh->b_blocknr); | ||
338 | |||
339 | jbd2_log_start_commit(journal, tid); | ||
340 | jbd2_log_wait_commit(journal, tid); | ||
341 | goto retry; | ||
342 | } | ||
343 | if (!buffer_dirty(bh)) { | ||
344 | if (unlikely(buffer_write_io_error(bh)) && !result) | ||
345 | result = -EIO; | ||
346 | get_bh(bh); | ||
347 | BUFFER_TRACE(bh, "remove from checkpoint"); | ||
348 | __jbd2_journal_remove_checkpoint(jh); | ||
349 | spin_unlock(&journal->j_list_lock); | ||
350 | __brelse(bh); | ||
351 | goto retry; | ||
408 | } | 352 | } |
409 | /* | 353 | /* |
410 | * Now we have cleaned up the first transaction's checkpoint | 354 | * Important: we are about to write the buffer, and |
411 | * list. Let's clean up the second one | 355 | * possibly block, while still holding the journal |
356 | * lock. We cannot afford to let the transaction | ||
357 | * logic start messing around with this buffer before | ||
358 | * we write it to disk, as that would break | ||
359 | * recoverability. | ||
412 | */ | 360 | */ |
413 | err = __wait_cp_io(journal, transaction); | 361 | BUFFER_TRACE(bh, "queue"); |
414 | if (!result) | 362 | get_bh(bh); |
415 | result = err; | 363 | J_ASSERT_BH(bh, !buffer_jwrite(bh)); |
364 | journal->j_chkpt_bhs[batch_count++] = bh; | ||
365 | __buffer_relink_io(jh); | ||
366 | transaction->t_chp_stats.cs_written++; | ||
367 | if ((batch_count == JBD2_NR_BATCH) || | ||
368 | need_resched() || | ||
369 | spin_needbreak(&journal->j_list_lock)) | ||
370 | goto unlock_and_flush; | ||
416 | } | 371 | } |
372 | |||
373 | if (batch_count) { | ||
374 | unlock_and_flush: | ||
375 | spin_unlock(&journal->j_list_lock); | ||
376 | retry: | ||
377 | if (batch_count) | ||
378 | __flush_batch(journal, &batch_count); | ||
379 | spin_lock(&journal->j_list_lock); | ||
380 | goto restart; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Now we issued all of the transaction's buffers, let's deal | ||
385 | * with the buffers that are out for I/O. | ||
386 | */ | ||
387 | err = __wait_cp_io(journal, transaction); | ||
388 | if (!result) | ||
389 | result = err; | ||
417 | out: | 390 | out: |
418 | spin_unlock(&journal->j_list_lock); | 391 | spin_unlock(&journal->j_list_lock); |
419 | if (result < 0) | 392 | if (result < 0) |