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 + -
显示快捷键?