logfile.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 743 行 · 第 1/2 页
C
743 行
BUG_ON((pos + size) & ~PAGE_CACHE_MASK); do { page = ntfs_map_page(vi->i_mapping, idx); if (IS_ERR(page)) { ntfs_error(vi->i_sb, "Error mapping $LogFile " "page (index %lu).", idx); goto err_out; } size = min_t(int, to_read, PAGE_CACHE_SIZE); memcpy((u8*)trp + have_read, page_address(page), size); ntfs_unmap_page(page); have_read += size; to_read -= size; idx++; } while (to_read > 0); } /* Perform the multi sector transfer deprotection on the buffer. */ if (post_read_mst_fixup((NTFS_RECORD*)trp, le32_to_cpu(rp->system_page_size))) { ntfs_error(vi->i_sb, "Multi sector transfer error detected in " "$LogFile restart page."); goto err_out; } /* 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."); return ret;err_out: ntfs_free(trp); return FALSE;}/** * ntfs_ckeck_logfile - check in the journal if the volume is consistent * @log_vi: struct inode of loaded journal $LogFile to check * * Check the $LogFile journal for consistency and return TRUE if it is * consistent and FALSE if not. * * At present we only check the two restart pages and ignore the log record * pages. * * Note that the MstProtected flag is not set on the $LogFile inode and hence * when reading pages they are not deprotected. This is because we do not know * 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. */BOOL ntfs_check_logfile(struct inode *log_vi){ s64 size, pos, rstr1_pos, rstr2_pos; ntfs_volume *vol = NTFS_SB(log_vi->i_sb); struct address_space *mapping = log_vi->i_mapping; struct page *page = NULL; u8 *kaddr = NULL; RESTART_PAGE_HEADER *rstr1_ph = NULL; RESTART_PAGE_HEADER *rstr2_ph = NULL; int log_page_size, log_page_mask, ofs; BOOL logfile_is_empty = TRUE; BOOL rstr1_found = FALSE; BOOL rstr2_found = FALSE; u8 log_page_bits; ntfs_debug("Entering."); /* An empty $LogFile must have been clean before it got emptied. */ if (NVolLogFileEmpty(vol)) goto is_empty; size = log_vi->i_size; /* Make sure the file doesn't exceed the maximum allowed size. */ if (size > MaxLogFileSize) size = MaxLogFileSize; /* * Truncate size to a multiple of the page cache size or the default * log page size if the page cache size is between the default log page * log page size if the page cache size is between the default log page * size and twice that. */ if (PAGE_CACHE_SIZE >= DefaultLogPageSize && PAGE_CACHE_SIZE <= DefaultLogPageSize * 2) log_page_size = DefaultLogPageSize; else log_page_size = PAGE_CACHE_SIZE; log_page_mask = log_page_size - 1; /* * Use generic_ffs() instead of ffs() to enable the compiler to * optimize log_page_size and log_page_bits into constants. */ log_page_bits = generic_ffs(log_page_size) - 1; size &= ~(log_page_size - 1); /* * Ensure the log file is big enough to store at least the two restart * pages and the minimum number of log record pages. */ if (size < log_page_size * 2 || (size - log_page_size * 2) >> log_page_bits < MinLogRecordPages) { ntfs_error(vol->sb, "$LogFile is too small."); return FALSE; } /* * Read through the file looking for a restart page. Since the restart * page header is at the beginning of a page we only need to search at * what could be the beginning of a page (for each page size) rather * than scanning the whole file byte by byte. If all potential places * contain empty and uninitialzed records, the log file can be assumed * to be empty. */ for (pos = 0; pos < size; pos <<= 1) { pgoff_t idx = pos >> PAGE_CACHE_SHIFT; if (!page || page->index != idx) { if (page) ntfs_unmap_page(page); page = ntfs_map_page(mapping, idx); if (IS_ERR(page)) { ntfs_error(vol->sb, "Error mapping $LogFile " "page (index %lu).", idx); return FALSE; } } kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK); /* * A non-empty block means the logfile is not empty while an * empty block after a non-empty block has been encountered * means we are done. */ if (!ntfs_is_empty_recordp((le32*)kaddr)) logfile_is_empty = FALSE; else if (!logfile_is_empty) break; /* * A log record page means there cannot be a restart page after * this so no need to continue searching. */ if (ntfs_is_rcrd_recordp((le32*)kaddr)) 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 (!pos) pos = NTFS_BLOCK_SIZE >> 1; 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. */ if (!ntfs_check_and_load_restart_page(log_vi, (RESTART_PAGE_HEADER*)kaddr, pos, !pos ? &rstr1_ph : &rstr2_ph)) { /* Error output already done inside the function. */ goto err_out; } /* * We have a valid restart page. The next one must be after * a whole system page size as specified by the valid restart * page. */ if (!pos) pos = le32_to_cpu(rstr1_ph->system_page_size) >> 1; } if (page) { ntfs_unmap_page(page); page = NULL; } if (logfile_is_empty) { NVolSetLogFileEmpty(vol);is_empty: ntfs_debug("Done. ($LogFile is empty.)"); return TRUE; } if (!rstr1_found || !rstr2_found) { ntfs_error(vol->sb, "Did not find two restart pages in " "$LogFile."); goto err_out; } /* * 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. */ ntfs_debug("Done."); return TRUE;err_out: if (page) ntfs_unmap_page(page); if (rstr1_ph) ntfs_free(rstr1_ph); if (rstr2_ph) ntfs_free(rstr2_ph); return FALSE;}/** * ntfs_is_logfile_clean - check in the journal if the volume is clean * @log_vi: struct inode of loaded journal $LogFile to check * * Analyze the $LogFile journal and return TRUE if it indicates the volume was * shutdown cleanly and FALSE if not. * * At present we only look at the two restart pages and ignore the log record * pages. This is a little bit crude in that there will be a very small number * of cases where we think that a volume is dirty when in fact it is clean. * This should only affect volumes that have not been shutdown cleanly but did * not have any pending, non-check-pointed i/o, i.e. they were completely idle * at least for the five seconds preceeding the unclean shutdown. * * This function assumes that the $LogFile journal has already been consistency * checked by a call to ntfs_check_logfile() and in particular if the $LogFile * is empty this function requires that NVolLogFileEmpty() is true otherwise an * empty volume will be reported as dirty. */BOOL ntfs_is_logfile_clean(struct inode *log_vi){ ntfs_volume *vol = NTFS_SB(log_vi->i_sb); struct page *page; RESTART_PAGE_HEADER *rp; RESTART_AREA *ra; ntfs_debug("Entering."); /* An empty $LogFile must have been clean before it got emptied. */ if (NVolLogFileEmpty(vol)) { ntfs_debug("Done. ($LogFile is empty.)"); 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)."); 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)); /* * If the $LogFile has active clients, i.e. it is open, and we do not * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags, * we assume there was an unclean shutdown. */ if (ra->client_in_use_list != LOGFILE_NO_CLIENT && !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { ntfs_debug("Done. $LogFile indicates a dirty shutdown."); goto err_out; } ntfs_unmap_page(page); /* $LogFile indicates a clean shutdown. */ ntfs_debug("Done. $LogFile indicates a clean shutdown."); return TRUE;err_out: ntfs_unmap_page(page); return FALSE;}/** * ntfs_empty_logfile - empty the contents of the $LogFile journal * @log_vi: struct inode of loaded journal $LogFile to empty * * Empty the contents of the $LogFile journal @log_vi and return TRUE on * success and FALSE on error. * * This function assumes that the $LogFile journal has already been consistency * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean() * has been used to ensure that the $LogFile is clean. */BOOL ntfs_empty_logfile(struct inode *log_vi){ ntfs_volume *vol = NTFS_SB(log_vi->i_sb); struct address_space *mapping; pgoff_t idx, end; ntfs_debug("Entering."); if (NVolLogFileEmpty(vol)) goto done; mapping = log_vi->i_mapping; end = (log_vi->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; for (idx = 0; idx < end; ++idx) { struct page *page; u8 *kaddr; /* Find or create the current page. (The page is locked.) */ page = grab_cache_page(mapping, idx); if (unlikely(!page)) { ntfs_error(vol->sb, "Insufficient memory to grab " "$LogFile page (index %lu).", idx); return FALSE; } /* * Set all bytes in the page to 0xff. It doesn't matter if we * go beyond i_size, because ntfs_writepage() will take care of * that for us. */ kaddr = (u8*)kmap_atomic(page, KM_USER0); memset(kaddr, 0xff, PAGE_CACHE_SIZE); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); /* * If the page has buffers, mark them uptodate since buffer * state and not page state is definitive in 2.6 kernels. */ if (page_has_buffers(page)) { struct buffer_head *bh, *head; bh = head = page_buffers(page); do { set_buffer_uptodate(bh); } while ((bh = bh->b_this_page) != head); } /* Now that buffers are uptodate, set the page uptodate, too. */ SetPageUptodate(page); /* * Set the page and all its buffers dirty and mark the inode * dirty, too. The VM will write the page later on. */ set_page_dirty(page); /* Finally unlock and release the page. */ unlock_page(page); page_cache_release(page); } /* We set the flag so we do not clear the log file again on remount. */ NVolSetLogFileEmpty(vol);done: ntfs_debug("Done."); return TRUE;}#endif /* NTFS_RW */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?