|
@@ -121,7 +121,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
|
|
*/
|
|
*/
|
|
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
|
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
|
ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
|
|
ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
|
|
- "chkdsk but a chkdsk LSN is specified.");
|
|
|
|
|
|
+ "by chkdsk but a chkdsk LSN is specified.");
|
|
return FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
ntfs_debug("Done.");
|
|
ntfs_debug("Done.");
|
|
@@ -312,10 +312,12 @@ err_out:
|
|
* @vi: $LogFile inode to which the restart page belongs
|
|
* @vi: $LogFile inode to which the restart page belongs
|
|
* @rp: restart page to check
|
|
* @rp: restart page to check
|
|
* @pos: position in @vi at which the restart page resides
|
|
* @pos: position in @vi at which the restart page resides
|
|
- * @wrp: copy of the multi sector transfer deprotected restart page
|
|
|
|
|
|
+ * @wrp: [OUT] copy of the multi sector transfer deprotected restart page
|
|
|
|
+ * @lsn: [OUT] set to the current logfile lsn on success
|
|
*
|
|
*
|
|
- * Check the restart page @rp for consistency and return TRUE if it is
|
|
|
|
- * consistent and FALSE otherwise.
|
|
|
|
|
|
+ * Check the restart page @rp for consistency and return 0 if it is consistent
|
|
|
|
+ * and -errno otherwise. The restart page may have been modified by chkdsk in
|
|
|
|
+ * which case its magic is CHKD instead of RSTR.
|
|
*
|
|
*
|
|
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
|
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
|
* require the full restart page.
|
|
* require the full restart page.
|
|
@@ -323,25 +325,33 @@ err_out:
|
|
* If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
|
|
* If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
|
|
* copy of the complete multi sector transfer deprotected page. On failure,
|
|
* copy of the complete multi sector transfer deprotected page. On failure,
|
|
* *@wrp is undefined.
|
|
* *@wrp is undefined.
|
|
|
|
+ *
|
|
|
|
+ * Simillarly, if @lsn is not NULL, on succes *@lsn will be set to the current
|
|
|
|
+ * logfile lsn according to this restart page. On failure, *@lsn is undefined.
|
|
|
|
+ *
|
|
|
|
+ * The following error codes are defined:
|
|
|
|
+ * -EINVAL - The restart page is inconsistent.
|
|
|
|
+ * -ENOMEM - Not enough memory to load the restart page.
|
|
|
|
+ * -EIO - Failed to reading from $LogFile.
|
|
*/
|
|
*/
|
|
-static BOOL ntfs_check_and_load_restart_page(struct inode *vi,
|
|
|
|
- RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp)
|
|
|
|
|
|
+static int ntfs_check_and_load_restart_page(struct inode *vi,
|
|
|
|
+ RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
|
|
|
|
+ LSN *lsn)
|
|
{
|
|
{
|
|
RESTART_AREA *ra;
|
|
RESTART_AREA *ra;
|
|
RESTART_PAGE_HEADER *trp;
|
|
RESTART_PAGE_HEADER *trp;
|
|
- int size;
|
|
|
|
- BOOL ret;
|
|
|
|
|
|
+ int size, err;
|
|
|
|
|
|
ntfs_debug("Entering.");
|
|
ntfs_debug("Entering.");
|
|
/* Check the restart page header for consistency. */
|
|
/* Check the restart page header for consistency. */
|
|
if (!ntfs_check_restart_page_header(vi, rp, pos)) {
|
|
if (!ntfs_check_restart_page_header(vi, rp, pos)) {
|
|
/* Error output already done inside the function. */
|
|
/* Error output already done inside the function. */
|
|
- return FALSE;
|
|
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
/* Check the restart area for consistency. */
|
|
/* Check the restart area for consistency. */
|
|
if (!ntfs_check_restart_area(vi, rp)) {
|
|
if (!ntfs_check_restart_area(vi, rp)) {
|
|
/* Error output already done inside the function. */
|
|
/* Error output already done inside the function. */
|
|
- return FALSE;
|
|
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
|
/*
|
|
/*
|
|
@@ -352,7 +362,7 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi,
|
|
if (!trp) {
|
|
if (!trp) {
|
|
ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
|
|
ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
|
|
"restart page buffer.");
|
|
"restart page buffer.");
|
|
- return FALSE;
|
|
|
|
|
|
+ return -ENOMEM;
|
|
}
|
|
}
|
|
/*
|
|
/*
|
|
* Read the whole of the restart page into the buffer. If it fits
|
|
* 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,
|
|
if (IS_ERR(page)) {
|
|
if (IS_ERR(page)) {
|
|
ntfs_error(vi->i_sb, "Error mapping $LogFile "
|
|
ntfs_error(vi->i_sb, "Error mapping $LogFile "
|
|
"page (index %lu).", idx);
|
|
"page (index %lu).", idx);
|
|
|
|
+ err = PTR_ERR(page);
|
|
|
|
+ if (err != -EIO && err != -ENOMEM)
|
|
|
|
+ err = -EIO;
|
|
goto err_out;
|
|
goto err_out;
|
|
}
|
|
}
|
|
size = min_t(int, to_read, PAGE_CACHE_SIZE);
|
|
size = min_t(int, to_read, PAGE_CACHE_SIZE);
|
|
@@ -392,29 +405,57 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi,
|
|
/* Perform the multi sector transfer deprotection on the buffer. */
|
|
/* Perform the multi sector transfer deprotection on the buffer. */
|
|
if (post_read_mst_fixup((NTFS_RECORD*)trp,
|
|
if (post_read_mst_fixup((NTFS_RECORD*)trp,
|
|
le32_to_cpu(rp->system_page_size))) {
|
|
le32_to_cpu(rp->system_page_size))) {
|
|
- ntfs_error(vi->i_sb, "Multi sector transfer error detected in "
|
|
|
|
- "$LogFile restart page.");
|
|
|
|
- goto err_out;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * A multi sector tranfer error was detected. We only need to
|
|
|
|
+ * abort if the restart page contents exceed the multi sector
|
|
|
|
+ * transfer fixup of the first sector.
|
|
|
|
+ */
|
|
|
|
+ if (le16_to_cpu(rp->restart_area_offset) +
|
|
|
|
+ le16_to_cpu(ra->restart_area_length) >
|
|
|
|
+ NTFS_BLOCK_SIZE - sizeof(u16)) {
|
|
|
|
+ ntfs_error(vi->i_sb, "Multi sector transfer error "
|
|
|
|
+ "detected in $LogFile restart page.");
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto err_out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * If the restart page is modified by chkdsk or there are no active
|
|
|
|
+ * logfile clients, the logfile is consistent. Otherwise, need to
|
|
|
|
+ * check the log client records for consistency, too.
|
|
|
|
+ */
|
|
|
|
+ err = 0;
|
|
|
|
+ if (ntfs_is_rstr_record(rp->magic) &&
|
|
|
|
+ ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
|
|
|
+ if (!ntfs_check_log_client_array(vi, trp)) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto err_out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (lsn) {
|
|
|
|
+ if (ntfs_is_rstr_record(rp->magic))
|
|
|
|
+ *lsn = sle64_to_cpu(ra->current_lsn);
|
|
|
|
+ else /* if (ntfs_is_chkd_record(rp->magic)) */
|
|
|
|
+ *lsn = sle64_to_cpu(rp->chkdsk_lsn);
|
|
}
|
|
}
|
|
- /* Check the log client records for consistency. */
|
|
|
|
- ret = ntfs_check_log_client_array(vi, trp);
|
|
|
|
- if (ret && wrp)
|
|
|
|
- *wrp = trp;
|
|
|
|
- else
|
|
|
|
- ntfs_free(trp);
|
|
|
|
ntfs_debug("Done.");
|
|
ntfs_debug("Done.");
|
|
- return ret;
|
|
|
|
|
|
+ if (wrp)
|
|
|
|
+ *wrp = trp;
|
|
|
|
+ else {
|
|
err_out:
|
|
err_out:
|
|
- ntfs_free(trp);
|
|
|
|
- return FALSE;
|
|
|
|
|
|
+ ntfs_free(trp);
|
|
|
|
+ }
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* ntfs_check_logfile - check the journal for consistency
|
|
* ntfs_check_logfile - check the journal for consistency
|
|
* @log_vi: struct inode of loaded journal $LogFile to check
|
|
* @log_vi: struct inode of loaded journal $LogFile to check
|
|
|
|
+ * @rp: [OUT] on success this is a copy of the current restart page
|
|
*
|
|
*
|
|
* Check the $LogFile journal for consistency and return TRUE if it is
|
|
* Check the $LogFile journal for consistency and return TRUE if it is
|
|
- * consistent and FALSE if not.
|
|
|
|
|
|
+ * consistent and FALSE if not. On success, the current restart page is
|
|
|
|
+ * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
|
|
*
|
|
*
|
|
* At present we only check the two restart pages and ignore the log record
|
|
* At present we only check the two restart pages and ignore the log record
|
|
* pages.
|
|
* pages.
|
|
@@ -424,19 +465,18 @@ err_out:
|
|
* if the $LogFile was created on a system with a different page size to ours
|
|
* if the $LogFile was created on a system with a different page size to ours
|
|
* yet and mst deprotection would fail if our page size is smaller.
|
|
* yet and mst deprotection would fail if our page size is smaller.
|
|
*/
|
|
*/
|
|
-BOOL ntfs_check_logfile(struct inode *log_vi)
|
|
|
|
|
|
+BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
|
|
{
|
|
{
|
|
- s64 size, pos, rstr1_pos, rstr2_pos;
|
|
|
|
|
|
+ s64 size, pos;
|
|
|
|
+ LSN rstr1_lsn, rstr2_lsn;
|
|
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
|
|
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
|
|
struct address_space *mapping = log_vi->i_mapping;
|
|
struct address_space *mapping = log_vi->i_mapping;
|
|
struct page *page = NULL;
|
|
struct page *page = NULL;
|
|
u8 *kaddr = NULL;
|
|
u8 *kaddr = NULL;
|
|
RESTART_PAGE_HEADER *rstr1_ph = NULL;
|
|
RESTART_PAGE_HEADER *rstr1_ph = NULL;
|
|
RESTART_PAGE_HEADER *rstr2_ph = NULL;
|
|
RESTART_PAGE_HEADER *rstr2_ph = NULL;
|
|
- int log_page_size, log_page_mask, ofs;
|
|
|
|
|
|
+ int log_page_size, log_page_mask, err;
|
|
BOOL logfile_is_empty = TRUE;
|
|
BOOL logfile_is_empty = TRUE;
|
|
- BOOL rstr1_found = FALSE;
|
|
|
|
- BOOL rstr2_found = FALSE;
|
|
|
|
u8 log_page_bits;
|
|
u8 log_page_bits;
|
|
|
|
|
|
ntfs_debug("Entering.");
|
|
ntfs_debug("Entering.");
|
|
@@ -491,7 +531,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
|
|
if (IS_ERR(page)) {
|
|
if (IS_ERR(page)) {
|
|
ntfs_error(vol->sb, "Error mapping $LogFile "
|
|
ntfs_error(vol->sb, "Error mapping $LogFile "
|
|
"page (index %lu).", idx);
|
|
"page (index %lu).", idx);
|
|
- return FALSE;
|
|
|
|
|
|
+ goto err_out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK);
|
|
kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK);
|
|
@@ -510,99 +550,95 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
|
|
*/
|
|
*/
|
|
if (ntfs_is_rcrd_recordp((le32*)kaddr))
|
|
if (ntfs_is_rcrd_recordp((le32*)kaddr))
|
|
break;
|
|
break;
|
|
- /*
|
|
|
|
- * A modified by chkdsk restart page means we cannot handle
|
|
|
|
- * this log file.
|
|
|
|
- */
|
|
|
|
- if (ntfs_is_chkd_recordp((le32*)kaddr)) {
|
|
|
|
- ntfs_error(vol->sb, "$LogFile has been modified by "
|
|
|
|
- "chkdsk. Mount this volume in "
|
|
|
|
- "Windows.");
|
|
|
|
- goto err_out;
|
|
|
|
- }
|
|
|
|
- /* If not a restart page, continue. */
|
|
|
|
- if (!ntfs_is_rstr_recordp((le32*)kaddr)) {
|
|
|
|
- /* Skip to the minimum page size for the next one. */
|
|
|
|
|
|
+ /* If not a (modified by chkdsk) restart page, continue. */
|
|
|
|
+ if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
|
|
|
|
+ !ntfs_is_chkd_recordp((le32*)kaddr)) {
|
|
if (!pos)
|
|
if (!pos)
|
|
pos = NTFS_BLOCK_SIZE >> 1;
|
|
pos = NTFS_BLOCK_SIZE >> 1;
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- /* We now know we have a restart page. */
|
|
|
|
- if (!pos) {
|
|
|
|
- rstr1_found = TRUE;
|
|
|
|
- rstr1_pos = pos;
|
|
|
|
- } else {
|
|
|
|
- if (rstr2_found) {
|
|
|
|
- ntfs_error(vol->sb, "Found more than two "
|
|
|
|
- "restart pages in $LogFile.");
|
|
|
|
- goto err_out;
|
|
|
|
- }
|
|
|
|
- rstr2_found = TRUE;
|
|
|
|
- rstr2_pos = pos;
|
|
|
|
- }
|
|
|
|
/*
|
|
/*
|
|
- * Check the restart page for consistency and get a copy of the
|
|
|
|
- * complete multi sector transfer deprotected restart page.
|
|
|
|
|
|
+ * Check the (modified by chkdsk) restart page for consistency
|
|
|
|
+ * and get a copy of the complete multi sector transfer
|
|
|
|
+ * deprotected restart page.
|
|
*/
|
|
*/
|
|
- if (!ntfs_check_and_load_restart_page(log_vi,
|
|
|
|
|
|
+ err = ntfs_check_and_load_restart_page(log_vi,
|
|
(RESTART_PAGE_HEADER*)kaddr, pos,
|
|
(RESTART_PAGE_HEADER*)kaddr, pos,
|
|
- !pos ? &rstr1_ph : &rstr2_ph)) {
|
|
|
|
- /* Error output already done inside the function. */
|
|
|
|
- goto err_out;
|
|
|
|
|
|
+ !rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
|
|
|
+ !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
|
|
|
|
+ if (!err) {
|
|
|
|
+ /*
|
|
|
|
+ * If we have now found the first (modified by chkdsk)
|
|
|
|
+ * restart page, continue looking for the second one.
|
|
|
|
+ */
|
|
|
|
+ if (!pos) {
|
|
|
|
+ pos = NTFS_BLOCK_SIZE >> 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * We have now found the second (modified by chkdsk)
|
|
|
|
+ * restart page, so we can stop looking.
|
|
|
|
+ */
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
/*
|
|
/*
|
|
- * We have a valid restart page. The next one must be after
|
|
|
|
- * a whole system page size as specified by the valid restart
|
|
|
|
- * page.
|
|
|
|
|
|
+ * Error output already done inside the function. Note, we do
|
|
|
|
+ * not abort if the restart page was invalid as we might still
|
|
|
|
+ * find a valid one further in the file.
|
|
*/
|
|
*/
|
|
|
|
+ if (err != -EINVAL) {
|
|
|
|
+ ntfs_unmap_page(page);
|
|
|
|
+ goto err_out;
|
|
|
|
+ }
|
|
|
|
+ /* Continue looking. */
|
|
if (!pos)
|
|
if (!pos)
|
|
- pos = le32_to_cpu(rstr1_ph->system_page_size) >> 1;
|
|
|
|
|
|
+ pos = NTFS_BLOCK_SIZE >> 1;
|
|
}
|
|
}
|
|
- if (page) {
|
|
|
|
|
|
+ if (page)
|
|
ntfs_unmap_page(page);
|
|
ntfs_unmap_page(page);
|
|
- page = NULL;
|
|
|
|
- }
|
|
|
|
if (logfile_is_empty) {
|
|
if (logfile_is_empty) {
|
|
NVolSetLogFileEmpty(vol);
|
|
NVolSetLogFileEmpty(vol);
|
|
is_empty:
|
|
is_empty:
|
|
ntfs_debug("Done. ($LogFile is empty.)");
|
|
ntfs_debug("Done. ($LogFile is empty.)");
|
|
return TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
- if (!rstr1_found || !rstr2_found) {
|
|
|
|
- ntfs_error(vol->sb, "Did not find two restart pages in "
|
|
|
|
- "$LogFile.");
|
|
|
|
- goto err_out;
|
|
|
|
|
|
+ if (!rstr1_ph) {
|
|
|
|
+ BUG_ON(rstr2_ph);
|
|
|
|
+ ntfs_error(vol->sb, "Did not find any restart pages in "
|
|
|
|
+ "$LogFile and it was not empty.");
|
|
|
|
+ return FALSE;
|
|
|
|
+ }
|
|
|
|
+ /* If both restart pages were found, use the more recent one. */
|
|
|
|
+ if (rstr2_ph) {
|
|
|
|
+ /*
|
|
|
|
+ * If the second restart area is more recent, switch to it.
|
|
|
|
+ * Otherwise just throw it away.
|
|
|
|
+ */
|
|
|
|
+ if (rstr2_lsn > rstr1_lsn) {
|
|
|
|
+ ntfs_free(rstr1_ph);
|
|
|
|
+ rstr1_ph = rstr2_ph;
|
|
|
|
+ /* rstr1_lsn = rstr2_lsn; */
|
|
|
|
+ } else
|
|
|
|
+ ntfs_free(rstr2_ph);
|
|
|
|
+ rstr2_ph = NULL;
|
|
}
|
|
}
|
|
- /*
|
|
|
|
- * The two restart areas must be identical except for the update
|
|
|
|
- * sequence number.
|
|
|
|
- */
|
|
|
|
- ofs = le16_to_cpu(rstr1_ph->usa_ofs);
|
|
|
|
- if (memcmp(rstr1_ph, rstr2_ph, ofs) || (ofs += sizeof(u16),
|
|
|
|
- memcmp((u8*)rstr1_ph + ofs, (u8*)rstr2_ph + ofs,
|
|
|
|
- le32_to_cpu(rstr1_ph->system_page_size) - ofs))) {
|
|
|
|
- ntfs_error(vol->sb, "The two restart pages in $LogFile do not "
|
|
|
|
- "match.");
|
|
|
|
- goto err_out;
|
|
|
|
- }
|
|
|
|
- ntfs_free(rstr1_ph);
|
|
|
|
- ntfs_free(rstr2_ph);
|
|
|
|
/* All consistency checks passed. */
|
|
/* All consistency checks passed. */
|
|
|
|
+ if (rp)
|
|
|
|
+ *rp = rstr1_ph;
|
|
|
|
+ else
|
|
|
|
+ ntfs_free(rstr1_ph);
|
|
ntfs_debug("Done.");
|
|
ntfs_debug("Done.");
|
|
return TRUE;
|
|
return TRUE;
|
|
err_out:
|
|
err_out:
|
|
- if (page)
|
|
|
|
- ntfs_unmap_page(page);
|
|
|
|
if (rstr1_ph)
|
|
if (rstr1_ph)
|
|
ntfs_free(rstr1_ph);
|
|
ntfs_free(rstr1_ph);
|
|
- if (rstr2_ph)
|
|
|
|
- ntfs_free(rstr2_ph);
|
|
|
|
return FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* ntfs_is_logfile_clean - check in the journal if the volume is clean
|
|
* ntfs_is_logfile_clean - check in the journal if the volume is clean
|
|
* @log_vi: struct inode of loaded journal $LogFile to check
|
|
* @log_vi: struct inode of loaded journal $LogFile to check
|
|
|
|
+ * @rp: copy of the current restart page
|
|
*
|
|
*
|
|
* Analyze the $LogFile journal and return TRUE if it indicates the volume was
|
|
* Analyze the $LogFile journal and return TRUE if it indicates the volume was
|
|
* shutdown cleanly and FALSE if not.
|
|
* shutdown cleanly and FALSE if not.
|
|
@@ -619,11 +655,9 @@ err_out:
|
|
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
|
|
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
|
|
* empty volume will be reported as dirty.
|
|
* empty volume will be reported as dirty.
|
|
*/
|
|
*/
|
|
-BOOL ntfs_is_logfile_clean(struct inode *log_vi)
|
|
|
|
|
|
+BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
|
|
{
|
|
{
|
|
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
|
|
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
|
|
- struct page *page;
|
|
|
|
- RESTART_PAGE_HEADER *rp;
|
|
|
|
RESTART_AREA *ra;
|
|
RESTART_AREA *ra;
|
|
|
|
|
|
ntfs_debug("Entering.");
|
|
ntfs_debug("Entering.");
|
|
@@ -632,24 +666,15 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi)
|
|
ntfs_debug("Done. ($LogFile is empty.)");
|
|
ntfs_debug("Done. ($LogFile is empty.)");
|
|
return TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
- /*
|
|
|
|
- * Read the first restart page. It will be possibly incomplete and
|
|
|
|
- * will not be multi sector transfer deprotected but we only need the
|
|
|
|
- * first NTFS_BLOCK_SIZE bytes so it does not matter.
|
|
|
|
- */
|
|
|
|
- page = ntfs_map_page(log_vi->i_mapping, 0);
|
|
|
|
- if (IS_ERR(page)) {
|
|
|
|
- ntfs_error(vol->sb, "Error mapping $LogFile page (index 0).");
|
|
|
|
|
|
+ BUG_ON(!rp);
|
|
|
|
+ if (!ntfs_is_rstr_record(rp->magic) &&
|
|
|
|
+ !ntfs_is_chkd_record(rp->magic)) {
|
|
|
|
+ ntfs_error(vol->sb, "Restart page buffer is invalid. This is "
|
|
|
|
+ "probably a bug in that the $LogFile should "
|
|
|
|
+ "have been consistency checked before calling "
|
|
|
|
+ "this function.");
|
|
return FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
- rp = (RESTART_PAGE_HEADER*)page_address(page);
|
|
|
|
- if (!ntfs_is_rstr_record(rp->magic)) {
|
|
|
|
- ntfs_error(vol->sb, "No restart page found at offset zero in "
|
|
|
|
- "$LogFile. This is probably a bug in that "
|
|
|
|
- "the $LogFile should have been consistency "
|
|
|
|
- "checked before calling this function.");
|
|
|
|
- goto err_out;
|
|
|
|
- }
|
|
|
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
|
/*
|
|
/*
|
|
* If the $LogFile has active clients, i.e. it is open, and we do not
|
|
* 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)
|
|
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
|
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
|
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
|
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
|
ntfs_debug("Done. $LogFile indicates a dirty shutdown.");
|
|
ntfs_debug("Done. $LogFile indicates a dirty shutdown.");
|
|
- goto err_out;
|
|
|
|
|
|
+ return FALSE;
|
|
}
|
|
}
|
|
- ntfs_unmap_page(page);
|
|
|
|
/* $LogFile indicates a clean shutdown. */
|
|
/* $LogFile indicates a clean shutdown. */
|
|
ntfs_debug("Done. $LogFile indicates a clean shutdown.");
|
|
ntfs_debug("Done. $LogFile indicates a clean shutdown.");
|
|
return TRUE;
|
|
return TRUE;
|
|
-err_out:
|
|
|
|
- ntfs_unmap_page(page);
|
|
|
|
- return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|