|
17 | 17 | #include <linux/bio.h>
|
18 | 18 | #include <linux/fs.h>
|
19 | 19 | #include <linux/list_sort.h>
|
| 20 | +#include <linux/blkdev.h> |
20 | 21 |
|
| 22 | +#include "bmap.h" |
21 | 23 | #include "dir.h"
|
22 | 24 | #include "gfs2.h"
|
23 | 25 | #include "incore.h"
|
@@ -193,7 +195,6 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec,
|
193 | 195 | /**
|
194 | 196 | * gfs2_end_log_write - end of i/o to the log
|
195 | 197 | * @bio: The bio
|
196 |
| - * @error: Status of i/o request |
197 | 198 | *
|
198 | 199 | * Each bio_vec contains either data from the pagecache or data
|
199 | 200 | * relating to the log itself. Here we iterate over the bio_vec
|
@@ -230,20 +231,19 @@ static void gfs2_end_log_write(struct bio *bio)
|
230 | 231 | /**
|
231 | 232 | * gfs2_log_submit_bio - Submit any pending log bio
|
232 | 233 | * @biop: Address of the bio pointer
|
233 |
| - * @op: REQ_OP |
234 |
| - * @op_flags: req_flag_bits |
| 234 | + * @opf: REQ_OP | op_flags |
235 | 235 | *
|
236 | 236 | * Submit any pending part-built or full bio to the block device. If
|
237 | 237 | * there is no pending bio, then this is a no-op.
|
238 | 238 | */
|
239 | 239 |
|
240 |
| -void gfs2_log_submit_bio(struct bio **biop, int op, int op_flags) |
| 240 | +void gfs2_log_submit_bio(struct bio **biop, int opf) |
241 | 241 | {
|
242 | 242 | struct bio *bio = *biop;
|
243 | 243 | if (bio) {
|
244 | 244 | struct gfs2_sbd *sdp = bio->bi_private;
|
245 | 245 | atomic_inc(&sdp->sd_log_in_flight);
|
246 |
| - bio_set_op_attrs(bio, op, op_flags); |
| 246 | + bio->bi_opf = opf; |
247 | 247 | submit_bio(bio);
|
248 | 248 | *biop = NULL;
|
249 | 249 | }
|
@@ -304,7 +304,7 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno,
|
304 | 304 | nblk >>= sdp->sd_fsb2bb_shift;
|
305 | 305 | if (blkno == nblk && !flush)
|
306 | 306 | return bio;
|
307 |
| - gfs2_log_submit_bio(biop, op, 0); |
| 307 | + gfs2_log_submit_bio(biop, op); |
308 | 308 | }
|
309 | 309 |
|
310 | 310 | *biop = gfs2_log_alloc_bio(sdp, blkno, end_io);
|
@@ -375,6 +375,184 @@ void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
|
375 | 375 | gfs2_log_bmap(sdp));
|
376 | 376 | }
|
377 | 377 |
|
| 378 | +/** |
| 379 | + * gfs2_end_log_read - end I/O callback for reads from the log |
| 380 | + * @bio: The bio |
| 381 | + * |
| 382 | + * Simply unlock the pages in the bio. The main thread will wait on them and |
| 383 | + * process them in order as necessary. |
| 384 | + */ |
| 385 | + |
| 386 | +static void gfs2_end_log_read(struct bio *bio) |
| 387 | +{ |
| 388 | + struct page *page; |
| 389 | + struct bio_vec *bvec; |
| 390 | + int i; |
| 391 | + |
| 392 | + bio_for_each_segment_all(bvec, bio, i) { |
| 393 | + page = bvec->bv_page; |
| 394 | + if (bio->bi_status) { |
| 395 | + int err = blk_status_to_errno(bio->bi_status); |
| 396 | + |
| 397 | + SetPageError(page); |
| 398 | + mapping_set_error(page->mapping, err); |
| 399 | + } |
| 400 | + unlock_page(page); |
| 401 | + } |
| 402 | + |
| 403 | + bio_put(bio); |
| 404 | +} |
| 405 | + |
| 406 | +/** |
| 407 | + * gfs2_jhead_pg_srch - Look for the journal head in a given page. |
| 408 | + * @jd: The journal descriptor |
| 409 | + * @page: The page to look in |
| 410 | + * |
| 411 | + * Returns: 1 if found, 0 otherwise. |
| 412 | + */ |
| 413 | + |
| 414 | +static bool gfs2_jhead_pg_srch(struct gfs2_jdesc *jd, |
| 415 | + struct gfs2_log_header_host *head, |
| 416 | + struct page *page) |
| 417 | +{ |
| 418 | + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
| 419 | + struct gfs2_log_header_host uninitialized_var(lh); |
| 420 | + void *kaddr = kmap_atomic(page); |
| 421 | + unsigned int offset; |
| 422 | + bool ret = false; |
| 423 | + |
| 424 | + for (offset = 0; offset < PAGE_SIZE; offset += sdp->sd_sb.sb_bsize) { |
| 425 | + if (!__get_log_header(sdp, kaddr + offset, 0, &lh)) { |
| 426 | + if (lh.lh_sequence > head->lh_sequence) |
| 427 | + *head = lh; |
| 428 | + else { |
| 429 | + ret = true; |
| 430 | + break; |
| 431 | + } |
| 432 | + } |
| 433 | + } |
| 434 | + kunmap_atomic(kaddr); |
| 435 | + return ret; |
| 436 | +} |
| 437 | + |
| 438 | +/** |
| 439 | + * gfs2_jhead_process_page - Search/cleanup a page |
| 440 | + * @jd: The journal descriptor |
| 441 | + * @index: Index of the page to look into |
| 442 | + * @done: If set, perform only cleanup, else search and set if found. |
| 443 | + * |
| 444 | + * Find the page with 'index' in the journal's mapping. Search the page for |
| 445 | + * the journal head if requested (cleanup == false). Release refs on the |
| 446 | + * page so the page cache can reclaim it (put_page() twice). We grabbed a |
| 447 | + * reference on this page two times, first when we did a find_or_create_page() |
| 448 | + * to obtain the page to add it to the bio and second when we do a |
| 449 | + * find_get_page() here to get the page to wait on while I/O on it is being |
| 450 | + * completed. |
| 451 | + * This function is also used to free up a page we might've grabbed but not |
| 452 | + * used. Maybe we added it to a bio, but not submitted it for I/O. Or we |
| 453 | + * submitted the I/O, but we already found the jhead so we only need to drop |
| 454 | + * our references to the page. |
| 455 | + */ |
| 456 | + |
| 457 | +static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index, |
| 458 | + struct gfs2_log_header_host *head, |
| 459 | + bool *done) |
| 460 | +{ |
| 461 | + struct page *page; |
| 462 | + |
| 463 | + page = find_get_page(jd->jd_inode->i_mapping, index); |
| 464 | + wait_on_page_locked(page); |
| 465 | + |
| 466 | + if (PageError(page)) |
| 467 | + *done = true; |
| 468 | + |
| 469 | + if (!*done) |
| 470 | + *done = gfs2_jhead_pg_srch(jd, head, page); |
| 471 | + |
| 472 | + put_page(page); /* Once for find_get_page */ |
| 473 | + put_page(page); /* Once more for find_or_create_page */ |
| 474 | +} |
| 475 | + |
| 476 | +/** |
| 477 | + * gfs2_find_jhead - find the head of a log |
| 478 | + * @jd: The journal descriptor |
| 479 | + * @head: The log descriptor for the head of the log is returned here |
| 480 | + * |
| 481 | + * Do a search of a journal by reading it in large chunks using bios and find |
| 482 | + * the valid log entry with the highest sequence number. (i.e. the log head) |
| 483 | + * |
| 484 | + * Returns: 0 on success, errno otherwise |
| 485 | + */ |
| 486 | + |
| 487 | +int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) |
| 488 | +{ |
| 489 | + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
| 490 | + struct address_space *mapping = jd->jd_inode->i_mapping; |
| 491 | + struct gfs2_journal_extent *je; |
| 492 | + u32 block, read_idx = 0, submit_idx = 0, index = 0; |
| 493 | + int shift = PAGE_SHIFT - sdp->sd_sb.sb_bsize_shift; |
| 494 | + int blocks_per_page = 1 << shift, sz, ret = 0; |
| 495 | + struct bio *bio = NULL; |
| 496 | + struct page *page; |
| 497 | + bool done = false; |
| 498 | + errseq_t since; |
| 499 | + |
| 500 | + memset(head, 0, sizeof(*head)); |
| 501 | + if (list_empty(&jd->extent_list)) |
| 502 | + gfs2_map_journal_extents(sdp, jd); |
| 503 | + |
| 504 | + since = filemap_sample_wb_err(mapping); |
| 505 | + list_for_each_entry(je, &jd->extent_list, list) { |
| 506 | + for (block = 0; block < je->blocks; block += blocks_per_page) { |
| 507 | + index = (je->lblock + block) >> shift; |
| 508 | + |
| 509 | + page = find_or_create_page(mapping, index, GFP_NOFS); |
| 510 | + if (!page) { |
| 511 | + ret = -ENOMEM; |
| 512 | + done = true; |
| 513 | + goto out; |
| 514 | + } |
| 515 | + |
| 516 | + if (bio) { |
| 517 | + sz = bio_add_page(bio, page, PAGE_SIZE, 0); |
| 518 | + if (sz == PAGE_SIZE) |
| 519 | + goto page_added; |
| 520 | + submit_idx = index; |
| 521 | + submit_bio(bio); |
| 522 | + bio = NULL; |
| 523 | + } |
| 524 | + |
| 525 | + bio = gfs2_log_alloc_bio(sdp, |
| 526 | + je->dblock + (index << shift), |
| 527 | + gfs2_end_log_read); |
| 528 | + bio->bi_opf = REQ_OP_READ; |
| 529 | + sz = bio_add_page(bio, page, PAGE_SIZE, 0); |
| 530 | + gfs2_assert_warn(sdp, sz == PAGE_SIZE); |
| 531 | + |
| 532 | +page_added: |
| 533 | + if (submit_idx <= read_idx + BIO_MAX_PAGES) { |
| 534 | + /* Keep at least one bio in flight */ |
| 535 | + continue; |
| 536 | + } |
| 537 | + |
| 538 | + gfs2_jhead_process_page(jd, read_idx++, head, &done); |
| 539 | + if (done) |
| 540 | + goto out; /* found */ |
| 541 | + } |
| 542 | + } |
| 543 | + |
| 544 | +out: |
| 545 | + if (bio) |
| 546 | + submit_bio(bio); |
| 547 | + while (read_idx <= index) |
| 548 | + gfs2_jhead_process_page(jd, read_idx++, head, &done); |
| 549 | + |
| 550 | + if (!ret) |
| 551 | + ret = filemap_check_wb_err(mapping, since); |
| 552 | + |
| 553 | + return ret; |
| 554 | +} |
| 555 | + |
378 | 556 | static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type,
|
379 | 557 | u32 ld_length, u32 ld_data1)
|
380 | 558 | {
|
|
0 commit comments