diff options
Diffstat (limited to 'fs/ntfs/logfile.c')
| -rw-r--r-- | fs/ntfs/logfile.c | 251 |
1 files changed, 136 insertions, 115 deletions
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index 8edb8e20fb08..0173e95500d9 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c | |||
| @@ -121,7 +121,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi, | |||
| 121 | */ | 121 | */ |
| 122 | if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { | 122 | if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { |
| 123 | ntfs_error(vi->i_sb, "$LogFile restart page is not modified " | 123 | ntfs_error(vi->i_sb, "$LogFile restart page is not modified " |
| 124 | "chkdsk but a chkdsk LSN is specified."); | 124 | "by chkdsk but a chkdsk LSN is specified."); |
| 125 | return FALSE; | 125 | return FALSE; |
| 126 | } | 126 | } |
| 127 | ntfs_debug("Done."); | 127 | ntfs_debug("Done."); |
| @@ -312,10 +312,12 @@ err_out: | |||
| 312 | * @vi: $LogFile inode to which the restart page belongs | 312 | * @vi: $LogFile inode to which the restart page belongs |
| 313 | * @rp: restart page to check | 313 | * @rp: restart page to check |
| 314 | * @pos: position in @vi at which the restart page resides | 314 | * @pos: position in @vi at which the restart page resides |
| 315 | * @wrp: copy of the multi sector transfer deprotected restart page | 315 | * @wrp: [OUT] copy of the multi sector transfer deprotected restart page |
| 316 | * @lsn: [OUT] set to the current logfile lsn on success | ||
| 316 | * | 317 | * |
| 317 | * Check the restart page @rp for consistency and return TRUE if it is | 318 | * Check the restart page @rp for consistency and return 0 if it is consistent |
| 318 | * consistent and FALSE otherwise. | 319 | * and -errno otherwise. The restart page may have been modified by chkdsk in |
| 320 | * which case its magic is CHKD instead of RSTR. | ||
| 319 | * | 321 | * |
| 320 | * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not | 322 | * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not |
| 321 | * require the full restart page. | 323 | * require the full restart page. |
| @@ -323,25 +325,33 @@ err_out: | |||
| 323 | * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a | 325 | * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a |
| 324 | * copy of the complete multi sector transfer deprotected page. On failure, | 326 | * copy of the complete multi sector transfer deprotected page. On failure, |
| 325 | * *@wrp is undefined. | 327 | * *@wrp is undefined. |
| 328 | * | ||
| 329 | * Simillarly, if @lsn is not NULL, on succes *@lsn will be set to the current | ||
| 330 | * logfile lsn according to this restart page. On failure, *@lsn is undefined. | ||
| 331 | * | ||
| 332 | * The following error codes are defined: | ||
| 333 | * -EINVAL - The restart page is inconsistent. | ||
| 334 | * -ENOMEM - Not enough memory to load the restart page. | ||
| 335 | * -EIO - Failed to reading from $LogFile. | ||
| 326 | */ | 336 | */ |
| 327 | static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | 337 | static int ntfs_check_and_load_restart_page(struct inode *vi, |
| 328 | RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp) | 338 | RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp, |
| 339 | LSN *lsn) | ||
| 329 | { | 340 | { |
| 330 | RESTART_AREA *ra; | 341 | RESTART_AREA *ra; |
| 331 | RESTART_PAGE_HEADER *trp; | 342 | RESTART_PAGE_HEADER *trp; |
| 332 | int size; | 343 | int size, err; |
| 333 | BOOL ret; | ||
| 334 | 344 | ||
| 335 | ntfs_debug("Entering."); | 345 | ntfs_debug("Entering."); |
| 336 | /* Check the restart page header for consistency. */ | 346 | /* Check the restart page header for consistency. */ |
| 337 | if (!ntfs_check_restart_page_header(vi, rp, pos)) { | 347 | if (!ntfs_check_restart_page_header(vi, rp, pos)) { |
| 338 | /* Error output already done inside the function. */ | 348 | /* Error output already done inside the function. */ |
| 339 | return FALSE; | 349 | return -EINVAL; |
| 340 | } | 350 | } |
| 341 | /* Check the restart area for consistency. */ | 351 | /* Check the restart area for consistency. */ |
| 342 | if (!ntfs_check_restart_area(vi, rp)) { | 352 | if (!ntfs_check_restart_area(vi, rp)) { |
| 343 | /* Error output already done inside the function. */ | 353 | /* Error output already done inside the function. */ |
| 344 | return FALSE; | 354 | return -EINVAL; |
| 345 | } | 355 | } |
| 346 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); | 356 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); |
| 347 | /* | 357 | /* |
| @@ -352,7 +362,7 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
| 352 | if (!trp) { | 362 | if (!trp) { |
| 353 | ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " | 363 | ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " |
| 354 | "restart page buffer."); | 364 | "restart page buffer."); |
| 355 | return FALSE; | 365 | return -ENOMEM; |
| 356 | } | 366 | } |
| 357 | /* | 367 | /* |
| 358 | * Read the whole of the restart page into the buffer. If it fits | 368 | * Read the whole of the restart page into the buffer. If it fits |
| @@ -379,6 +389,9 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
| 379 | if (IS_ERR(page)) { | 389 | if (IS_ERR(page)) { |
| 380 | ntfs_error(vi->i_sb, "Error mapping $LogFile " | 390 | ntfs_error(vi->i_sb, "Error mapping $LogFile " |
| 381 | "page (index %lu).", idx); | 391 | "page (index %lu).", idx); |
| 392 | err = PTR_ERR(page); | ||
| 393 | if (err != -EIO && err != -ENOMEM) | ||
| 394 | err = -EIO; | ||
| 382 | goto err_out; | 395 | goto err_out; |
| 383 | } | 396 | } |
| 384 | size = min_t(int, to_read, PAGE_CACHE_SIZE); | 397 | size = min_t(int, to_read, PAGE_CACHE_SIZE); |
| @@ -392,29 +405,57 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
| 392 | /* Perform the multi sector transfer deprotection on the buffer. */ | 405 | /* Perform the multi sector transfer deprotection on the buffer. */ |
| 393 | if (post_read_mst_fixup((NTFS_RECORD*)trp, | 406 | if (post_read_mst_fixup((NTFS_RECORD*)trp, |
| 394 | le32_to_cpu(rp->system_page_size))) { | 407 | le32_to_cpu(rp->system_page_size))) { |
| 395 | ntfs_error(vi->i_sb, "Multi sector transfer error detected in " | 408 | /* |
| 396 | "$LogFile restart page."); | 409 | * A multi sector tranfer error was detected. We only need to |
| 397 | goto err_out; | 410 | * abort if the restart page contents exceed the multi sector |
| 411 | * transfer fixup of the first sector. | ||
| 412 | */ | ||
| 413 | if (le16_to_cpu(rp->restart_area_offset) + | ||
| 414 | le16_to_cpu(ra->restart_area_length) > | ||
| 415 | NTFS_BLOCK_SIZE - sizeof(u16)) { | ||
| 416 | ntfs_error(vi->i_sb, "Multi sector transfer error " | ||
| 417 | "detected in $LogFile restart page."); | ||
| 418 | err = -EINVAL; | ||
| 419 | goto err_out; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | /* | ||
| 423 | * If the restart page is modified by chkdsk or there are no active | ||
| 424 | * logfile clients, the logfile is consistent. Otherwise, need to | ||
| 425 | * check the log client records for consistency, too. | ||
| 426 | */ | ||
| 427 | err = 0; | ||
| 428 | if (ntfs_is_rstr_record(rp->magic) && | ||
| 429 | ra->client_in_use_list != LOGFILE_NO_CLIENT) { | ||
| 430 | if (!ntfs_check_log_client_array(vi, trp)) { | ||
| 431 | err = -EINVAL; | ||
| 432 | goto err_out; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | if (lsn) { | ||
| 436 | if (ntfs_is_rstr_record(rp->magic)) | ||
| 437 | *lsn = sle64_to_cpu(ra->current_lsn); | ||
| 438 | else /* if (ntfs_is_chkd_record(rp->magic)) */ | ||
| 439 | *lsn = sle64_to_cpu(rp->chkdsk_lsn); | ||
| 398 | } | 440 | } |
| 399 | /* Check the log client records for consistency. */ | ||
| 400 | ret = ntfs_check_log_client_array(vi, trp); | ||
| 401 | if (ret && wrp) | ||
| 402 | *wrp = trp; | ||
| 403 | else | ||
| 404 | ntfs_free(trp); | ||
| 405 | ntfs_debug("Done."); | 441 | ntfs_debug("Done."); |
| 406 | return ret; | 442 | if (wrp) |
| 443 | *wrp = trp; | ||
| 444 | else { | ||
| 407 | err_out: | 445 | err_out: |
| 408 | ntfs_free(trp); | 446 | ntfs_free(trp); |
| 409 | return FALSE; | 447 | } |
| 448 | return err; | ||
| 410 | } | 449 | } |
| 411 | 450 | ||
| 412 | /** | 451 | /** |
| 413 | * ntfs_check_logfile - check the journal for consistency | 452 | * ntfs_check_logfile - check the journal for consistency |
| 414 | * @log_vi: struct inode of loaded journal $LogFile to check | 453 | * @log_vi: struct inode of loaded journal $LogFile to check |
| 454 | * @rp: [OUT] on success this is a copy of the current restart page | ||
| 415 | * | 455 | * |
| 416 | * Check the $LogFile journal for consistency and return TRUE if it is | 456 | * Check the $LogFile journal for consistency and return TRUE if it is |
| 417 | * consistent and FALSE if not. | 457 | * consistent and FALSE if not. On success, the current restart page is |
| 458 | * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it. | ||
| 418 | * | 459 | * |
| 419 | * At present we only check the two restart pages and ignore the log record | 460 | * At present we only check the two restart pages and ignore the log record |
| 420 | * pages. | 461 | * pages. |
| @@ -424,19 +465,18 @@ err_out: | |||
| 424 | * if the $LogFile was created on a system with a different page size to ours | 465 | * if the $LogFile was created on a system with a different page size to ours |
| 425 | * yet and mst deprotection would fail if our page size is smaller. | 466 | * yet and mst deprotection would fail if our page size is smaller. |
| 426 | */ | 467 | */ |
| 427 | BOOL ntfs_check_logfile(struct inode *log_vi) | 468 | BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp) |
| 428 | { | 469 | { |
| 429 | s64 size, pos, rstr1_pos, rstr2_pos; | 470 | s64 size, pos; |
| 471 | LSN rstr1_lsn, rstr2_lsn; | ||
| 430 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); | 472 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); |
| 431 | struct address_space *mapping = log_vi->i_mapping; | 473 | struct address_space *mapping = log_vi->i_mapping; |
| 432 | struct page *page = NULL; | 474 | struct page *page = NULL; |
| 433 | u8 *kaddr = NULL; | 475 | u8 *kaddr = NULL; |
| 434 | RESTART_PAGE_HEADER *rstr1_ph = NULL; | 476 | RESTART_PAGE_HEADER *rstr1_ph = NULL; |
| 435 | RESTART_PAGE_HEADER *rstr2_ph = NULL; | 477 | RESTART_PAGE_HEADER *rstr2_ph = NULL; |
| 436 | int log_page_size, log_page_mask, ofs; | 478 | int log_page_size, log_page_mask, err; |
| 437 | BOOL logfile_is_empty = TRUE; | 479 | BOOL logfile_is_empty = TRUE; |
| 438 | BOOL rstr1_found = FALSE; | ||
| 439 | BOOL rstr2_found = FALSE; | ||
| 440 | u8 log_page_bits; | 480 | u8 log_page_bits; |
| 441 | 481 | ||
| 442 | ntfs_debug("Entering."); | 482 | ntfs_debug("Entering."); |
| @@ -491,7 +531,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi) | |||
| 491 | if (IS_ERR(page)) { | 531 | if (IS_ERR(page)) { |
| 492 | ntfs_error(vol->sb, "Error mapping $LogFile " | 532 | ntfs_error(vol->sb, "Error mapping $LogFile " |
| 493 | "page (index %lu).", idx); | 533 | "page (index %lu).", idx); |
| 494 | return FALSE; | 534 | goto err_out; |
| 495 | } | 535 | } |
| 496 | } | 536 | } |
| 497 | kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK); | 537 | kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK); |
| @@ -510,99 +550,95 @@ BOOL ntfs_check_logfile(struct inode *log_vi) | |||
| 510 | */ | 550 | */ |
| 511 | if (ntfs_is_rcrd_recordp((le32*)kaddr)) | 551 | if (ntfs_is_rcrd_recordp((le32*)kaddr)) |
| 512 | break; | 552 | break; |
| 513 | /* | 553 | /* If not a (modified by chkdsk) restart page, continue. */ |
| 514 | * A modified by chkdsk restart page means we cannot handle | 554 | if (!ntfs_is_rstr_recordp((le32*)kaddr) && |
| 515 | * this log file. | 555 | !ntfs_is_chkd_recordp((le32*)kaddr)) { |
| 516 | */ | ||
| 517 | if (ntfs_is_chkd_recordp((le32*)kaddr)) { | ||
| 518 | ntfs_error(vol->sb, "$LogFile has been modified by " | ||
| 519 | "chkdsk. Mount this volume in " | ||
| 520 | "Windows."); | ||
| 521 | goto err_out; | ||
| 522 | } | ||
| 523 | /* If not a restart page, continue. */ | ||
| 524 | if (!ntfs_is_rstr_recordp((le32*)kaddr)) { | ||
| 525 | /* Skip to the minimum page size for the next one. */ | ||
| 526 | if (!pos) | 556 | if (!pos) |
| 527 | pos = NTFS_BLOCK_SIZE >> 1; | 557 | pos = NTFS_BLOCK_SIZE >> 1; |
| 528 | continue; | 558 | continue; |
| 529 | } | 559 | } |
| 530 | /* We now know we have a restart page. */ | ||
| 531 | if (!pos) { | ||
| 532 | rstr1_found = TRUE; | ||
| 533 | rstr1_pos = pos; | ||
| 534 | } else { | ||
| 535 | if (rstr2_found) { | ||
| 536 | ntfs_error(vol->sb, "Found more than two " | ||
| 537 | "restart pages in $LogFile."); | ||
| 538 | goto err_out; | ||
| 539 | } | ||
| 540 | rstr2_found = TRUE; | ||
| 541 | rstr2_pos = pos; | ||
| 542 | } | ||
| 543 | /* | 560 | /* |
| 544 | * Check the restart page for consistency and get a copy of the | 561 | * Check the (modified by chkdsk) restart page for consistency |
| 545 | * complete multi sector transfer deprotected restart page. | 562 | * and get a copy of the complete multi sector transfer |
| 563 | * deprotected restart page. | ||
| 546 | */ | 564 | */ |
| 547 | if (!ntfs_check_and_load_restart_page(log_vi, | 565 | err = ntfs_check_and_load_restart_page(log_vi, |
| 548 | (RESTART_PAGE_HEADER*)kaddr, pos, | 566 | (RESTART_PAGE_HEADER*)kaddr, pos, |
| 549 | !pos ? &rstr1_ph : &rstr2_ph)) { | 567 | !rstr1_ph ? &rstr1_ph : &rstr2_ph, |
| 550 | /* Error output already done inside the function. */ | 568 | !rstr1_ph ? &rstr1_lsn : &rstr2_lsn); |
| 551 | goto err_out; | 569 | if (!err) { |
| 570 | /* | ||
| 571 | * If we have now found the first (modified by chkdsk) | ||
| 572 | * restart page, continue looking for the second one. | ||
| 573 | */ | ||
| 574 | if (!pos) { | ||
| 575 | pos = NTFS_BLOCK_SIZE >> 1; | ||
| 576 | continue; | ||
| 577 | } | ||
| 578 | /* | ||
| 579 | * We have now found the second (modified by chkdsk) | ||
| 580 | * restart page, so we can stop looking. | ||
| 581 | */ | ||
| 582 | break; | ||
| 552 | } | 583 | } |
| 553 | /* | 584 | /* |
| 554 | * We have a valid restart page. The next one must be after | 585 | * Error output already done inside the function. Note, we do |
| 555 | * a whole system page size as specified by the valid restart | 586 | * not abort if the restart page was invalid as we might still |
| 556 | * page. | 587 | * find a valid one further in the file. |
| 557 | */ | 588 | */ |
| 589 | if (err != -EINVAL) { | ||
| 590 | ntfs_unmap_page(page); | ||
| 591 | goto err_out; | ||
| 592 | } | ||
| 593 | /* Continue looking. */ | ||
| 558 | if (!pos) | 594 | if (!pos) |
| 559 | pos = le32_to_cpu(rstr1_ph->system_page_size) >> 1; | 595 | pos = NTFS_BLOCK_SIZE >> 1; |
| 560 | } | 596 | } |
| 561 | if (page) { | 597 | if (page) |
| 562 | ntfs_unmap_page(page); | 598 | ntfs_unmap_page(page); |
| 563 | page = NULL; | ||
| 564 | } | ||
| 565 | if (logfile_is_empty) { | 599 | if (logfile_is_empty) { |
| 566 | NVolSetLogFileEmpty(vol); | 600 | NVolSetLogFileEmpty(vol); |
| 567 | is_empty: | 601 | is_empty: |
| 568 | ntfs_debug("Done. ($LogFile is empty.)"); | 602 | ntfs_debug("Done. ($LogFile is empty.)"); |
| 569 | return TRUE; | 603 | return TRUE; |
| 570 | } | 604 | } |
| 571 | if (!rstr1_found || !rstr2_found) { | 605 | if (!rstr1_ph) { |
| 572 | ntfs_error(vol->sb, "Did not find two restart pages in " | 606 | BUG_ON(rstr2_ph); |
| 573 | "$LogFile."); | 607 | ntfs_error(vol->sb, "Did not find any restart pages in " |
| 574 | goto err_out; | 608 | "$LogFile and it was not empty."); |
| 609 | return FALSE; | ||
| 610 | } | ||
| 611 | /* If both restart pages were found, use the more recent one. */ | ||
| 612 | if (rstr2_ph) { | ||
| 613 | /* | ||
| 614 | * If the second restart area is more recent, switch to it. | ||
| 615 | * Otherwise just throw it away. | ||
| 616 | */ | ||
| 617 | if (rstr2_lsn > rstr1_lsn) { | ||
| 618 | ntfs_free(rstr1_ph); | ||
| 619 | rstr1_ph = rstr2_ph; | ||
| 620 | /* rstr1_lsn = rstr2_lsn; */ | ||
| 621 | } else | ||
| 622 | ntfs_free(rstr2_ph); | ||
| 623 | rstr2_ph = NULL; | ||
| 575 | } | 624 | } |
| 576 | /* | ||
| 577 | * The two restart areas must be identical except for the update | ||
| 578 | * sequence number. | ||
| 579 | */ | ||
| 580 | ofs = le16_to_cpu(rstr1_ph->usa_ofs); | ||
| 581 | if (memcmp(rstr1_ph, rstr2_ph, ofs) || (ofs += sizeof(u16), | ||
| 582 | memcmp((u8*)rstr1_ph + ofs, (u8*)rstr2_ph + ofs, | ||
| 583 | le32_to_cpu(rstr1_ph->system_page_size) - ofs))) { | ||
| 584 | ntfs_error(vol->sb, "The two restart pages in $LogFile do not " | ||
| 585 | "match."); | ||
| 586 | goto err_out; | ||
| 587 | } | ||
| 588 | ntfs_free(rstr1_ph); | ||
| 589 | ntfs_free(rstr2_ph); | ||
| 590 | /* All consistency checks passed. */ | 625 | /* All consistency checks passed. */ |
| 626 | if (rp) | ||
| 627 | *rp = rstr1_ph; | ||
| 628 | else | ||
| 629 | ntfs_free(rstr1_ph); | ||
| 591 | ntfs_debug("Done."); | 630 | ntfs_debug("Done."); |
| 592 | return TRUE; | 631 | return TRUE; |
| 593 | err_out: | 632 | err_out: |
| 594 | if (page) | ||
| 595 | ntfs_unmap_page(page); | ||
| 596 | if (rstr1_ph) | 633 | if (rstr1_ph) |
| 597 | ntfs_free(rstr1_ph); | 634 | ntfs_free(rstr1_ph); |
| 598 | if (rstr2_ph) | ||
| 599 | ntfs_free(rstr2_ph); | ||
| 600 | return FALSE; | 635 | return FALSE; |
| 601 | } | 636 | } |
| 602 | 637 | ||
| 603 | /** | 638 | /** |
| 604 | * ntfs_is_logfile_clean - check in the journal if the volume is clean | 639 | * ntfs_is_logfile_clean - check in the journal if the volume is clean |
| 605 | * @log_vi: struct inode of loaded journal $LogFile to check | 640 | * @log_vi: struct inode of loaded journal $LogFile to check |
| 641 | * @rp: copy of the current restart page | ||
| 606 | * | 642 | * |
| 607 | * Analyze the $LogFile journal and return TRUE if it indicates the volume was | 643 | * Analyze the $LogFile journal and return TRUE if it indicates the volume was |
| 608 | * shutdown cleanly and FALSE if not. | 644 | * shutdown cleanly and FALSE if not. |
| @@ -619,11 +655,9 @@ err_out: | |||
| 619 | * is empty this function requires that NVolLogFileEmpty() is true otherwise an | 655 | * is empty this function requires that NVolLogFileEmpty() is true otherwise an |
| 620 | * empty volume will be reported as dirty. | 656 | * empty volume will be reported as dirty. |
| 621 | */ | 657 | */ |
| 622 | BOOL ntfs_is_logfile_clean(struct inode *log_vi) | 658 | BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp) |
| 623 | { | 659 | { |
| 624 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); | 660 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); |
| 625 | struct page *page; | ||
| 626 | RESTART_PAGE_HEADER *rp; | ||
| 627 | RESTART_AREA *ra; | 661 | RESTART_AREA *ra; |
| 628 | 662 | ||
| 629 | ntfs_debug("Entering."); | 663 | ntfs_debug("Entering."); |
| @@ -632,24 +666,15 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi) | |||
| 632 | ntfs_debug("Done. ($LogFile is empty.)"); | 666 | ntfs_debug("Done. ($LogFile is empty.)"); |
| 633 | return TRUE; | 667 | return TRUE; |
| 634 | } | 668 | } |
| 635 | /* | 669 | BUG_ON(!rp); |
| 636 | * Read the first restart page. It will be possibly incomplete and | 670 | if (!ntfs_is_rstr_record(rp->magic) && |
| 637 | * will not be multi sector transfer deprotected but we only need the | 671 | !ntfs_is_chkd_record(rp->magic)) { |
| 638 | * first NTFS_BLOCK_SIZE bytes so it does not matter. | 672 | ntfs_error(vol->sb, "Restart page buffer is invalid. This is " |
| 639 | */ | 673 | "probably a bug in that the $LogFile should " |
| 640 | page = ntfs_map_page(log_vi->i_mapping, 0); | 674 | "have been consistency checked before calling " |
| 641 | if (IS_ERR(page)) { | 675 | "this function."); |
| 642 | ntfs_error(vol->sb, "Error mapping $LogFile page (index 0)."); | ||
| 643 | return FALSE; | 676 | return FALSE; |
| 644 | } | 677 | } |
| 645 | rp = (RESTART_PAGE_HEADER*)page_address(page); | ||
| 646 | if (!ntfs_is_rstr_record(rp->magic)) { | ||
| 647 | ntfs_error(vol->sb, "No restart page found at offset zero in " | ||
| 648 | "$LogFile. This is probably a bug in that " | ||
| 649 | "the $LogFile should have been consistency " | ||
| 650 | "checked before calling this function."); | ||
| 651 | goto err_out; | ||
| 652 | } | ||
| 653 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); | 678 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); |
| 654 | /* | 679 | /* |
| 655 | * If the $LogFile has active clients, i.e. it is open, and we do not | 680 | * If the $LogFile has active clients, i.e. it is open, and we do not |
| @@ -659,15 +684,11 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi) | |||
| 659 | if (ra->client_in_use_list != LOGFILE_NO_CLIENT && | 684 | if (ra->client_in_use_list != LOGFILE_NO_CLIENT && |
| 660 | !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { | 685 | !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { |
| 661 | ntfs_debug("Done. $LogFile indicates a dirty shutdown."); | 686 | ntfs_debug("Done. $LogFile indicates a dirty shutdown."); |
| 662 | goto err_out; | 687 | return FALSE; |
| 663 | } | 688 | } |
| 664 | ntfs_unmap_page(page); | ||
| 665 | /* $LogFile indicates a clean shutdown. */ | 689 | /* $LogFile indicates a clean shutdown. */ |
| 666 | ntfs_debug("Done. $LogFile indicates a clean shutdown."); | 690 | ntfs_debug("Done. $LogFile indicates a clean shutdown."); |
| 667 | return TRUE; | 691 | return TRUE; |
| 668 | err_out: | ||
| 669 | ntfs_unmap_page(page); | ||
| 670 | return FALSE; | ||
| 671 | } | 692 | } |
| 672 | 693 | ||
| 673 | /** | 694 | /** |
