diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-09-08 11:12:28 -0400 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-09-08 11:12:28 -0400 |
commit | e7a1033b946f4f2622f2b338ab107f559aad542c (patch) | |
tree | 333b235d6903392d269e0e5cab807631ab652854 /fs/ntfs/logfile.c | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
NTFS: Support more clean journal ($LogFile) states.
- Support journals ($LogFile) which have been modified by chkdsk. This
means users can boot into Windows after we marked the volume dirty.
The Windows boot will run chkdsk and then reboot. The user can then
immediately boot into Linux rather than having to do a full Windows
boot first before rebooting into Linux and we will recognize such a
journal and empty it as it is clean by definition.
- Support journals ($LogFile) with only one restart page as well as
journals with two different restart pages. We sanity check both and
either use the only sane one or the more recent one of the two in the
case that both are valid.
Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
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 | /** |