diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 13 | ||||
-rw-r--r-- | fs/ntfs/Makefile | 2 | ||||
-rw-r--r-- | fs/ntfs/logfile.c | 251 | ||||
-rw-r--r-- | fs/ntfs/logfile.h | 8 | ||||
-rw-r--r-- | fs/ntfs/super.c | 16 |
5 files changed, 167 insertions, 123 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 9eecc9939dfe..cceec3e9e2de 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -22,6 +22,19 @@ ToDo/Notes: | |||
22 | - Enable the code for setting the NT4 compatibility flag when we start | 22 | - Enable the code for setting the NT4 compatibility flag when we start |
23 | making NTFS 1.2 specific modifications. | 23 | making NTFS 1.2 specific modifications. |
24 | 24 | ||
25 | 2.1.24-WIP | ||
26 | |||
27 | - Support journals ($LogFile) which have been modified by chkdsk. This | ||
28 | means users can boot into Windows after we marked the volume dirty. | ||
29 | The Windows boot will run chkdsk and then reboot. The user can then | ||
30 | immediately boot into Linux rather than having to do a full Windows | ||
31 | boot first before rebooting into Linux and we will recognize such a | ||
32 | journal and empty it as it is clean by definition. | ||
33 | - Support journals ($LogFile) with only one restart page as well as | ||
34 | journals with two different restart pages. We sanity check both and | ||
35 | either use the only sane one or the more recent one of the two in the | ||
36 | case that both are valid. | ||
37 | |||
25 | 2.1.23 - Implement extension of resident files and make writing safe as well as | 38 | 2.1.23 - Implement extension of resident files and make writing safe as well as |
26 | many bug fixes, cleanups, and enhancements... | 39 | many bug fixes, cleanups, and enhancements... |
27 | 40 | ||
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index f083f27d8b69..ce970dacf908 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile | |||
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ | |||
6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ | 6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ |
7 | unistr.o upcase.o | 7 | unistr.o upcase.o |
8 | 8 | ||
9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.23\" | 9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24-WIP\" |
10 | 10 | ||
11 | ifeq ($(CONFIG_NTFS_DEBUG),y) | 11 | ifeq ($(CONFIG_NTFS_DEBUG),y) |
12 | EXTRA_CFLAGS += -DDEBUG | 12 | EXTRA_CFLAGS += -DDEBUG |
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 | /** |
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h index 4ee4378de061..42388f95ea6d 100644 --- a/fs/ntfs/logfile.h +++ b/fs/ntfs/logfile.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * logfile.h - Defines for NTFS kernel journal ($LogFile) handling. Part of | 2 | * logfile.h - Defines for NTFS kernel journal ($LogFile) handling. Part of |
3 | * the Linux-NTFS project. | 3 | * the Linux-NTFS project. |
4 | * | 4 | * |
5 | * Copyright (c) 2000-2004 Anton Altaparmakov | 5 | * Copyright (c) 2000-2005 Anton Altaparmakov |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License as published | 8 | * modify it under the terms of the GNU General Public License as published |
@@ -296,9 +296,11 @@ typedef struct { | |||
296 | /* sizeof() = 160 (0xa0) bytes */ | 296 | /* sizeof() = 160 (0xa0) bytes */ |
297 | } __attribute__ ((__packed__)) LOG_CLIENT_RECORD; | 297 | } __attribute__ ((__packed__)) LOG_CLIENT_RECORD; |
298 | 298 | ||
299 | extern BOOL ntfs_check_logfile(struct inode *log_vi); | 299 | extern BOOL ntfs_check_logfile(struct inode *log_vi, |
300 | RESTART_PAGE_HEADER **rp); | ||
300 | 301 | ||
301 | extern BOOL ntfs_is_logfile_clean(struct inode *log_vi); | 302 | extern BOOL ntfs_is_logfile_clean(struct inode *log_vi, |
303 | const RESTART_PAGE_HEADER *rp); | ||
302 | 304 | ||
303 | extern BOOL ntfs_empty_logfile(struct inode *log_vi); | 305 | extern BOOL ntfs_empty_logfile(struct inode *log_vi); |
304 | 306 | ||
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 41aa8eb6755b..bf8569d503a6 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -1133,7 +1133,8 @@ mft_unmap_out: | |||
1133 | * | 1133 | * |
1134 | * Return TRUE on success or FALSE on error. | 1134 | * Return TRUE on success or FALSE on error. |
1135 | */ | 1135 | */ |
1136 | static BOOL load_and_check_logfile(ntfs_volume *vol) | 1136 | static BOOL load_and_check_logfile(ntfs_volume *vol, |
1137 | RESTART_PAGE_HEADER **rp) | ||
1137 | { | 1138 | { |
1138 | struct inode *tmp_ino; | 1139 | struct inode *tmp_ino; |
1139 | 1140 | ||
@@ -1145,7 +1146,7 @@ static BOOL load_and_check_logfile(ntfs_volume *vol) | |||
1145 | /* Caller will display error message. */ | 1146 | /* Caller will display error message. */ |
1146 | return FALSE; | 1147 | return FALSE; |
1147 | } | 1148 | } |
1148 | if (!ntfs_check_logfile(tmp_ino)) { | 1149 | if (!ntfs_check_logfile(tmp_ino, rp)) { |
1149 | iput(tmp_ino); | 1150 | iput(tmp_ino); |
1150 | /* ntfs_check_logfile() will have displayed error output. */ | 1151 | /* ntfs_check_logfile() will have displayed error output. */ |
1151 | return FALSE; | 1152 | return FALSE; |
@@ -1687,6 +1688,7 @@ static BOOL load_system_files(ntfs_volume *vol) | |||
1687 | struct super_block *sb = vol->sb; | 1688 | struct super_block *sb = vol->sb; |
1688 | MFT_RECORD *m; | 1689 | MFT_RECORD *m; |
1689 | VOLUME_INFORMATION *vi; | 1690 | VOLUME_INFORMATION *vi; |
1691 | RESTART_PAGE_HEADER *rp; | ||
1690 | ntfs_attr_search_ctx *ctx; | 1692 | ntfs_attr_search_ctx *ctx; |
1691 | #ifdef NTFS_RW | 1693 | #ifdef NTFS_RW |
1692 | int err; | 1694 | int err; |
@@ -1841,8 +1843,9 @@ get_ctx_vol_failed: | |||
1841 | * Get the inode for the logfile, check it and determine if the volume | 1843 | * Get the inode for the logfile, check it and determine if the volume |
1842 | * was shutdown cleanly. | 1844 | * was shutdown cleanly. |
1843 | */ | 1845 | */ |
1844 | if (!load_and_check_logfile(vol) || | 1846 | rp = NULL; |
1845 | !ntfs_is_logfile_clean(vol->logfile_ino)) { | 1847 | if (!load_and_check_logfile(vol, &rp) || |
1848 | !ntfs_is_logfile_clean(vol->logfile_ino, rp)) { | ||
1846 | static const char *es1a = "Failed to load $LogFile"; | 1849 | static const char *es1a = "Failed to load $LogFile"; |
1847 | static const char *es1b = "$LogFile is not clean"; | 1850 | static const char *es1b = "$LogFile is not clean"; |
1848 | static const char *es2 = ". Mount in Windows."; | 1851 | static const char *es2 = ". Mount in Windows."; |
@@ -1857,6 +1860,10 @@ get_ctx_vol_failed: | |||
1857 | "continue nor on_errors=" | 1860 | "continue nor on_errors=" |
1858 | "remount-ro was specified%s", | 1861 | "remount-ro was specified%s", |
1859 | es1, es2); | 1862 | es1, es2); |
1863 | if (vol->logfile_ino) { | ||
1864 | BUG_ON(!rp); | ||
1865 | ntfs_free(rp); | ||
1866 | } | ||
1860 | goto iput_logfile_err_out; | 1867 | goto iput_logfile_err_out; |
1861 | } | 1868 | } |
1862 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; | 1869 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; |
@@ -1867,6 +1874,7 @@ get_ctx_vol_failed: | |||
1867 | /* This will prevent a read-write remount. */ | 1874 | /* This will prevent a read-write remount. */ |
1868 | NVolSetErrors(vol); | 1875 | NVolSetErrors(vol); |
1869 | } | 1876 | } |
1877 | ntfs_free(rp); | ||
1870 | #endif /* NTFS_RW */ | 1878 | #endif /* NTFS_RW */ |
1871 | /* Get the root directory inode so we can do path lookups. */ | 1879 | /* Get the root directory inode so we can do path lookups. */ |
1872 | vol->root_ino = ntfs_iget(sb, FILE_root); | 1880 | vol->root_ino = ntfs_iget(sb, FILE_root); |