static int last_log_lsn(struct ntfs_log *log)
{
	int err;
	bool usa_error = false;
	bool replace_page = false;
	bool reuse_page = log->l_flags & NTFSLOG_REUSE_TAIL;
	bool wrapped_file, wrapped;

	u32 page_cnt = 1, page_pos = 1;
	u32 page_off = 0, page_off1 = 0, saved_off = 0;
	u32 final_off, second_off, final_off_prev = 0, second_off_prev = 0;
	u32 first_file_off = 0, second_file_off = 0;
	u32 part_io_count = 0;
	u32 tails = 0;
	u32 this_off, curpage_off, nextpage_off, remain_pages;

	u64 expected_seq, seq_base = 0, lsn_base = 0;
	u64 best_lsn, best_lsn1, best_lsn2;
	u64 lsn_cur, lsn1, lsn2;
	u64 last_ok_lsn = reuse_page ? log->last_lsn : 0;

	u16 cur_pos, best_page_pos;

	struct RECORD_PAGE_HDR *page = NULL;
	struct RECORD_PAGE_HDR *tst_page = NULL;
	struct RECORD_PAGE_HDR *first_tail = NULL;
	struct RECORD_PAGE_HDR *second_tail = NULL;
	struct RECORD_PAGE_HDR *tail_page = NULL;
	struct RECORD_PAGE_HDR *second_tail_prev = NULL;
	struct RECORD_PAGE_HDR *first_tail_prev = NULL;
	struct RECORD_PAGE_HDR *page_bufs = NULL;
	struct RECORD_PAGE_HDR *best_page;

	if (log->major_ver >= 2) {
		final_off = 0x02 * log->page_size;
		second_off = 0x12 * log->page_size;

		// 0x10 == 0x12 - 0x2
		page_bufs = kmalloc(log->page_size * 0x10, GFP_NOFS);
		if (!page_bufs)
			return -ENOMEM;
	} else {
		second_off = log->first_page - log->page_size;
		final_off = second_off - log->page_size;
	}

next_tail:
	/* Read second tail page (at pos 3/0x12000). */
	if (read_log_page(log, second_off, &second_tail, &usa_error) ||
	    usa_error || second_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) {
		kfree(second_tail);
		second_tail = NULL;
		second_file_off = 0;
		lsn2 = 0;
	} else {
		second_file_off = hdr_file_off(log, second_tail);
		lsn2 = le64_to_cpu(second_tail->record_hdr.last_end_lsn);
	}

	/* Read first tail page (at pos 2/0x2000). */
	if (read_log_page(log, final_off, &first_tail, &usa_error) ||
	    usa_error || first_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) {
		kfree(first_tail);
		first_tail = NULL;
		first_file_off = 0;
		lsn1 = 0;
	} else {
		first_file_off = hdr_file_off(log, first_tail);
		lsn1 = le64_to_cpu(first_tail->record_hdr.last_end_lsn);
	}

	if (log->major_ver < 2) {
		int best_page;

		first_tail_prev = first_tail;
		final_off_prev = first_file_off;
		second_tail_prev = second_tail;
		second_off_prev = second_file_off;
		tails = 1;

		if (!first_tail && !second_tail)
			goto tail_read;

		if (first_tail && second_tail)
			best_page = lsn1 < lsn2 ? 1 : 0;
		else if (first_tail)
			best_page = 0;
		else
			best_page = 1;

		page_off = best_page ? second_file_off : first_file_off;
		seq_base = (best_page ? lsn2 : lsn1) >> log->file_data_bits;
		goto tail_read;
	}

	best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0;
	best_lsn2 =
		second_tail ? base_lsn(log, second_tail, second_file_off) : 0;

	if (first_tail && second_tail) {
		if (best_lsn1 > best_lsn2) {
			best_lsn = best_lsn1;
			best_page = first_tail;
			this_off = first_file_off;
		} else {
			best_lsn = best_lsn2;
			best_page = second_tail;
			this_off = second_file_off;
		}
	} else if (first_tail) {
		best_lsn = best_lsn1;
		best_page = first_tail;
		this_off = first_file_off;
	} else if (second_tail) {
		best_lsn = best_lsn2;
		best_page = second_tail;
		this_off = second_file_off;
	} else {
		goto tail_read;
	}

	best_page_pos = le16_to_cpu(best_page->page_pos);

	if (!tails) {
		if (best_page_pos == page_pos) {
			seq_base = best_lsn >> log->file_data_bits;
			saved_off = page_off = le32_to_cpu(best_page->file_off);
			lsn_base = best_lsn;

			memmove(page_bufs, best_page, log->page_size);

			page_cnt = le16_to_cpu(best_page->page_count);
			if (page_cnt > 1)
				page_pos += 1;

			tails = 1;
		}
	} else if (seq_base == (best_lsn >> log->file_data_bits) &&
		   saved_off + log->page_size == this_off &&
		   lsn_base < best_lsn &&
		   (page_pos != page_cnt || best_page_pos == page_pos ||
		    best_page_pos == 1) &&
		   (page_pos >= page_cnt || best_page_pos == page_pos)) {
		u16 bppc = le16_to_cpu(best_page->page_count);

		saved_off += log->page_size;
		lsn_base = best_lsn;

		memmove(Add2Ptr(page_bufs, tails * log->page_size), best_page,
			log->page_size);

		tails += 1;

		if (best_page_pos != bppc) {
			page_cnt = bppc;
			page_pos = best_page_pos;

			if (page_cnt > 1)
				page_pos += 1;
		} else {
			page_pos = page_cnt = 1;
		}
	} else {
		kfree(first_tail);
		kfree(second_tail);
		goto tail_read;
	}

	kfree(first_tail_prev);
	first_tail_prev = first_tail;
	final_off_prev = first_file_off;
	first_tail = NULL;

	kfree(second_tail_prev);
	second_tail_prev = second_tail;
	second_off_prev = second_file_off;
	second_tail = NULL;

	final_off += log->page_size;
	second_off += log->page_size;

	if (tails < 0x10)
		goto next_tail;
tail_read:
	first_tail = first_tail_prev;
	final_off = final_off_prev;

	second_tail = second_tail_prev;
	second_off = second_off_prev;

	page_cnt = page_pos = 1;

	curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off)
					       : log->next_page;

	wrapped_file =
		curpage_off == log->first_page &&
		!(log->l_flags & (NTFSLOG_NO_LAST_LSN | NTFSLOG_REUSE_TAIL));

	expected_seq = wrapped_file ? (log->seq_num + 1) : log->seq_num;

	nextpage_off = curpage_off;

next_page:
	tail_page = NULL;
	/* Read the next log page. */
	err = read_log_page(log, curpage_off, &page, &usa_error);

	/* Compute the next log page offset the file. */
	nextpage_off = next_page_off(log, curpage_off);
	wrapped = nextpage_off == log->first_page;

	if (tails > 1) {
		struct RECORD_PAGE_HDR *cur_page =
			Add2Ptr(page_bufs, curpage_off - page_off);

		if (curpage_off == saved_off) {
			tail_page = cur_page;
			goto use_tail_page;
		}

		if (page_off > curpage_off || curpage_off >= saved_off)
			goto use_tail_page;

		if (page_off1)
			goto use_cur_page;

		if (!err && !usa_error &&
		    page->rhdr.sign == NTFS_RCRD_SIGNATURE &&
		    cur_page->rhdr.lsn == page->rhdr.lsn &&
		    cur_page->record_hdr.next_record_off ==
			    page->record_hdr.next_record_off &&
		    ((page_pos == page_cnt &&
		      le16_to_cpu(page->page_pos) == 1) ||
		     (page_pos != page_cnt &&
		      le16_to_cpu(page->page_pos) == page_pos + 1 &&
		      le16_to_cpu(page->page_count) == page_cnt))) {
			cur_page = NULL;
			goto use_tail_page;
		}

		page_off1 = page_off;

use_cur_page:

		lsn_cur = le64_to_cpu(cur_page->rhdr.lsn);

		if (last_ok_lsn !=
			    le64_to_cpu(cur_page->record_hdr.last_end_lsn) &&
		    ((lsn_cur >> log->file_data_bits) +
		     ((curpage_off <
		       (lsn_to_vbo(log, lsn_cur) & ~log->page_mask))
			      ? 1
			      : 0)) != expected_seq) {
			goto check_tail;
		}

		if (!is_log_record_end(cur_page)) {
			tail_page = NULL;
			last_ok_lsn = lsn_cur;
			goto next_page_1;
		}

		log->seq_num = expected_seq;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;
		log->last_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn);
		log->ra->current_lsn = cur_page->record_hdr.last_end_lsn;

		if (log->record_header_len <=
		    log->page_size -
			    le16_to_cpu(cur_page->record_hdr.next_record_off)) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		if (wrapped_file)
			log->l_flags |= NTFSLOG_WRAPPED;

		last_ok_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn);
		goto next_page_1;
	}

	/*
	 * If we are at the expected first page of a transfer check to see
	 * if either tail copy is at this offset.
	 * If this page is the last page of a transfer, check if we wrote
	 * a subsequent tail copy.
	 */
	if (page_cnt == page_pos || page_cnt == page_pos + 1) {
		/*
		 * Check if the offset matches either the first or second
		 * tail copy. It is possible it will match both.
		 */
		if (curpage_off == final_off)
			tail_page = first_tail;

		/*
		 * If we already matched on the first page then
		 * check the ending lsn's.
		 */
		if (curpage_off == second_off) {
			if (!tail_page ||
			    (second_tail &&
			     le64_to_cpu(second_tail->record_hdr.last_end_lsn) >
				     le64_to_cpu(first_tail->record_hdr
							 .last_end_lsn))) {
				tail_page = second_tail;
			}
		}
	}

use_tail_page:
	if (tail_page) {
		/* We have a candidate for a tail copy. */
		lsn_cur = le64_to_cpu(tail_page->record_hdr.last_end_lsn);

		if (last_ok_lsn < lsn_cur) {
			/*
			 * If the sequence number is not expected,
			 * then don't use the tail copy.
			 */
			if (expected_seq != (lsn_cur >> log->file_data_bits))
				tail_page = NULL;
		} else if (last_ok_lsn > lsn_cur) {
			/*
			 * If the last lsn is greater than the one on
			 * this page then forget this tail.
			 */
			tail_page = NULL;
		}
	}

	/*
	 *If we have an error on the current page,
	 * we will break of this loop.
	 */
	if (err || usa_error)
		goto check_tail;

	/*
	 * Done if the last lsn on this page doesn't match the previous known
	 * last lsn or the sequence number is not expected.
	 */
	lsn_cur = le64_to_cpu(page->rhdr.lsn);
	if (last_ok_lsn != lsn_cur &&
	    expected_seq != (lsn_cur >> log->file_data_bits)) {
		goto check_tail;
	}

	/*
	 * Check that the page position and page count values are correct.
	 * If this is the first page of a transfer the position must be 1
	 * and the count will be unknown.
	 */
	if (page_cnt == page_pos) {
		if (page->page_pos != cpu_to_le16(1) &&
		    (!reuse_page || page->page_pos != page->page_count)) {
			/*
			 * If the current page is the first page we are
			 * looking at and we are reusing this page then
			 * it can be either the first or last page of a
			 * transfer. Otherwise it can only be the first.
			 */
			goto check_tail;
		}
	} else if (le16_to_cpu(page->page_count) != page_cnt ||
		   le16_to_cpu(page->page_pos) != page_pos + 1) {
		/*
		 * The page position better be 1 more than the last page
		 * position and the page count better match.
		 */
		goto check_tail;
	}

	/*
	 * We have a valid page the file and may have a valid page
	 * the tail copy area.
	 * If the tail page was written after the page the file then
	 * break of the loop.
	 */
	if (tail_page &&
	    le64_to_cpu(tail_page->record_hdr.last_end_lsn) > lsn_cur) {
		/* Remember if we will replace the page. */
		replace_page = true;
		goto check_tail;
	}

	tail_page = NULL;

	if (is_log_record_end(page)) {
		/*
		 * Since we have read this page we know the sequence number
		 * is the same as our expected value.
		 */
		log->seq_num = expected_seq;
		log->last_lsn = le64_to_cpu(page->record_hdr.last_end_lsn);
		log->ra->current_lsn = page->record_hdr.last_end_lsn;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;

		/*
		 * If there is room on this page for another header then
		 * remember we want to reuse the page.
		 */
		if (log->record_header_len <=
		    log->page_size -
			    le16_to_cpu(page->record_hdr.next_record_off)) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		/* Remember if we wrapped the log file. */
		if (wrapped_file)
			log->l_flags |= NTFSLOG_WRAPPED;
	}

	/*
	 * Remember the last page count and position.
	 * Also remember the last known lsn.
	 */
	page_cnt = le16_to_cpu(page->page_count);
	page_pos = le16_to_cpu(page->page_pos);
	last_ok_lsn = le64_to_cpu(page->rhdr.lsn);

next_page_1:

	if (wrapped) {
		expected_seq += 1;
		wrapped_file = 1;
	}

	curpage_off = nextpage_off;
	kfree(page);
	page = NULL;
	reuse_page = 0;
	goto next_page;

check_tail:
	if (tail_page) {
		log->seq_num = expected_seq;
		log->last_lsn = le64_to_cpu(tail_page->record_hdr.last_end_lsn);
		log->ra->current_lsn = tail_page->record_hdr.last_end_lsn;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;

		if (log->page_size -
			    le16_to_cpu(
				    tail_page->record_hdr.next_record_off) >=
		    log->record_header_len) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		if (wrapped)
			log->l_flags |= NTFSLOG_WRAPPED;
	}

	/* Remember that the partial IO will start at the next page. */
	second_off = nextpage_off;

	/*
	 * If the next page is the first page of the file then update
	 * the sequence number for log records which begon the next page.
	 */
	if (wrapped)
		expected_seq += 1;

	/*
	 * If we have a tail copy or are performing single page I/O we can
	 * immediately look at the next page.
	 */
	if (replace_page || (log->ra->flags & RESTART_SINGLE_PAGE_IO)) {
		page_cnt = 2;
		page_pos = 1;
		goto check_valid;
	}

	if (page_pos != page_cnt)
		goto check_valid;
	/*
	 * If the next page causes us to wrap to the beginning of the log
	 * file then we know which page to check next.
	 */
	if (wrapped) {
		page_cnt = 2;
		page_pos = 1;
		goto check_valid;
	}

	cur_pos = 2;

next_test_page:
	kfree(tst_page);
	tst_page = NULL;

	/* Walk through the file, reading log pages. */
	err = read_log_page(log, nextpage_off, &tst_page, &usa_error);

	/*
	 * If we get a USA error then assume that we correctly found
	 * the end of the original transfer.
	 */
	if (usa_error)
		goto file_is_valid;

	/*
	 * If we were able to read the page, we examine it to see if it
	 * is the same or different Io block.
	 */
	if (err)
		goto next_test_page_1;

	if (le16_to_cpu(tst_page->page_pos) == cur_pos &&
	    check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) {
		page_cnt = le16_to_cpu(tst_page->page_count) + 1;
		page_pos = le16_to_cpu(tst_page->page_pos);
		goto check_valid;
	} else {
		goto file_is_valid;
	}

next_test_page_1:

	nextpage_off = next_page_off(log, curpage_off);
	wrapped = nextpage_off == log->first_page;

	if (wrapped) {
		expected_seq += 1;
		page_cnt = 2;
		page_pos = 1;
	}

	cur_pos += 1;
	part_io_count += 1;
	if (!wrapped)
		goto next_test_page;

check_valid:
	/* Skip over the remaining pages this transfer. */
	remain_pages = page_cnt - page_pos - 1;
	part_io_count += remain_pages;

	while (remain_pages--) {
		nextpage_off = next_page_off(log, curpage_off);
		wrapped = nextpage_off == log->first_page;

		if (wrapped)
			expected_seq += 1;
	}

	/* Call our routine to check this log page. */
	kfree(tst_page);
	tst_page = NULL;

	err = read_log_page(log, nextpage_off, &tst_page, &usa_error);
	if (!err && !usa_error &&
	    check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) {
		err = -EINVAL;
		goto out;
	}

file_is_valid:

	/* We have a valid file. */
	if (page_off1 || tail_page) {
		struct RECORD_PAGE_HDR *tmp_page;

		if (sb_rdonly(log->ni->mi.sbi->sb)) {
			err = -EROFS;
			goto out;
		}

		if (page_off1) {
			tmp_page = Add2Ptr(page_bufs, page_off1 - page_off);
			tails -= (page_off1 - page_off) / log->page_size;
			if (!tail_page)
				tails -= 1;
		} else {
			tmp_page = tail_page;
			tails = 1;
		}

		while (tails--) {
			u64 off = hdr_file_off(log, tmp_page);

			if (!page) {
				page = kmalloc(log->page_size, GFP_NOFS);
				if (!page)
					return -ENOMEM;
			}

			/*
			 * Correct page and copy the data from this page
			 * into it and flush it to disk.
			 */
			memcpy(page, tmp_page, log->page_size);

			/* Fill last flushed lsn value flush the page. */
			if (log->major_ver < 2)
				page->rhdr.lsn = page->record_hdr.last_end_lsn;
			else
				page->file_off = 0;

			page->page_pos = page->page_count = cpu_to_le16(1);

			ntfs_fix_pre_write(&page->rhdr, log->page_size);

			err = ntfs_sb_write_run(log->ni->mi.sbi,
						&log->ni->file.run, off, page,
						log->page_size, 0);

			if (err)
				goto out;

			if (part_io_count && second_off == off) {
				second_off += log->page_size;
				part_io_count -= 1;
			}

			tmp_page = Add2Ptr(tmp_page, log->page_size);
		}
	}

	if (part_io_count) {
		if (sb_rdonly(log->ni->mi.sbi->sb)) {
			err = -EROFS;
			goto out;
		}
	}

out:
	kfree(second_tail);
	kfree(first_tail);
	kfree(page);
	kfree(tst_page);
	kfree(page_bufs);

	return err;
}
static int last_log_lsn(struct ntfs_log *log)
{
	int err;
	bool usa_error = false;
	bool replace_page = false;
	bool reuse_page = log->l_flags & NTFSLOG_REUSE_TAIL;
	bool wrapped_file, wrapped;

	u32 page_cnt = 1, page_pos = 1;
	u32 page_off = 0, page_off1 = 0, saved_off = 0;
	u32 final_off, second_off, final_off_prev = 0, second_off_prev = 0;
	u32 first_file_off = 0, second_file_off = 0;
	u32 part_io_count = 0;
	u32 tails = 0;
	u32 this_off, curpage_off, nextpage_off, remain_pages;

	u64 expected_seq, seq_base = 0, lsn_base = 0;
	u64 best_lsn, best_lsn1, best_lsn2;
	u64 lsn_cur, lsn1, lsn2;
	u64 last_ok_lsn = reuse_page ? log->last_lsn : 0;

	u16 cur_pos, best_page_pos;

	struct RECORD_PAGE_HDR *page = NULL;
	struct RECORD_PAGE_HDR *tst_page = NULL;
	struct RECORD_PAGE_HDR *first_tail = NULL;
	struct RECORD_PAGE_HDR *second_tail = NULL;
	struct RECORD_PAGE_HDR *tail_page = NULL;
	struct RECORD_PAGE_HDR *second_tail_prev = NULL;
	struct RECORD_PAGE_HDR *first_tail_prev = NULL;
	struct RECORD_PAGE_HDR *page_bufs = NULL;
	struct RECORD_PAGE_HDR *best_page;

	if (log->major_ver >= 2) {
		final_off = 0x02 * log->page_size;
		second_off = 0x12 * log->page_size;

		 
		page_bufs = kmalloc(log->page_size * 0x10, GFP_NOFS);
		if (!page_bufs)
			return -ENOMEM;
	} else {
		second_off = log->first_page - log->page_size;
		final_off = second_off - log->page_size;
	}

next_tail:
	 
	if (read_log_page(log, second_off, &second_tail, &usa_error) ||
	    usa_error || second_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) {
		kfree(second_tail);
		second_tail = NULL;
		second_file_off = 0;
		lsn2 = 0;
	} else {
		second_file_off = hdr_file_off(log, second_tail);
		lsn2 = le64_to_cpu(second_tail->record_hdr.last_end_lsn);
	}

	 
	if (read_log_page(log, final_off, &first_tail, &usa_error) ||
	    usa_error || first_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) {
		kfree(first_tail);
		first_tail = NULL;
		first_file_off = 0;
		lsn1 = 0;
	} else {
		first_file_off = hdr_file_off(log, first_tail);
		lsn1 = le64_to_cpu(first_tail->record_hdr.last_end_lsn);
	}

	if (log->major_ver < 2) {
		int best_page;

		first_tail_prev = first_tail;
		final_off_prev = first_file_off;
		second_tail_prev = second_tail;
		second_off_prev = second_file_off;
		tails = 1;

		if (!first_tail && !second_tail)
			goto tail_read;

		if (first_tail && second_tail)
			best_page = lsn1 < lsn2 ? 1 : 0;
		else if (first_tail)
			best_page = 0;
		else
			best_page = 1;

		page_off = best_page ? second_file_off : first_file_off;
		seq_base = (best_page ? lsn2 : lsn1) >> log->file_data_bits;
		goto tail_read;
	}

	best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0;
	best_lsn2 =
		second_tail ? base_lsn(log, second_tail, second_file_off) : 0;

	if (first_tail && second_tail) {
		if (best_lsn1 > best_lsn2) {
			best_lsn = best_lsn1;
			best_page = first_tail;
			this_off = first_file_off;
		} else {
			best_lsn = best_lsn2;
			best_page = second_tail;
			this_off = second_file_off;
		}
	} else if (first_tail) {
		best_lsn = best_lsn1;
		best_page = first_tail;
		this_off = first_file_off;
	} else if (second_tail) {
		best_lsn = best_lsn2;
		best_page = second_tail;
		this_off = second_file_off;
	} else {
		goto tail_read;
	}

	best_page_pos = le16_to_cpu(best_page->page_pos);

	if (!tails) {
		if (best_page_pos == page_pos) {
			seq_base = best_lsn >> log->file_data_bits;
			saved_off = page_off = le32_to_cpu(best_page->file_off);
			lsn_base = best_lsn;

			memmove(page_bufs, best_page, log->page_size);

			page_cnt = le16_to_cpu(best_page->page_count);
			if (page_cnt > 1)
				page_pos += 1;

			tails = 1;
		}
	} else if (seq_base == (best_lsn >> log->file_data_bits) &&
		   saved_off + log->page_size == this_off &&
		   lsn_base < best_lsn &&
		   (page_pos != page_cnt || best_page_pos == page_pos ||
		    best_page_pos == 1) &&
		   (page_pos >= page_cnt || best_page_pos == page_pos)) {
		u16 bppc = le16_to_cpu(best_page->page_count);

		saved_off += log->page_size;
		lsn_base = best_lsn;

		memmove(Add2Ptr(page_bufs, tails * log->page_size), best_page,
			log->page_size);

		tails += 1;

		if (best_page_pos != bppc) {
			page_cnt = bppc;
			page_pos = best_page_pos;

			if (page_cnt > 1)
				page_pos += 1;
		} else {
			page_pos = page_cnt = 1;
		}
	} else {
		kfree(first_tail);
		kfree(second_tail);
		goto tail_read;
	}

	kfree(first_tail_prev);
	first_tail_prev = first_tail;
	final_off_prev = first_file_off;
	first_tail = NULL;

	kfree(second_tail_prev);
	second_tail_prev = second_tail;
	second_off_prev = second_file_off;
	second_tail = NULL;

	final_off += log->page_size;
	second_off += log->page_size;

	if (tails < 0x10)
		goto next_tail;
tail_read:
	first_tail = first_tail_prev;
	final_off = final_off_prev;

	second_tail = second_tail_prev;
	second_off = second_off_prev;

	page_cnt = page_pos = 1;

	curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off)
					       : log->next_page;

	wrapped_file =
		curpage_off == log->first_page &&
		!(log->l_flags & (NTFSLOG_NO_LAST_LSN | NTFSLOG_REUSE_TAIL));

	expected_seq = wrapped_file ? (log->seq_num + 1) : log->seq_num;

	nextpage_off = curpage_off;

next_page:
	tail_page = NULL;
	 
	err = read_log_page(log, curpage_off, &page, &usa_error);

	 
	nextpage_off = next_page_off(log, curpage_off);
	wrapped = nextpage_off == log->first_page;

	if (tails > 1) {
		struct RECORD_PAGE_HDR *cur_page =
			Add2Ptr(page_bufs, curpage_off - page_off);

		if (curpage_off == saved_off) {
			tail_page = cur_page;
			goto use_tail_page;
		}

		if (page_off > curpage_off || curpage_off >= saved_off)
			goto use_tail_page;

		if (page_off1)
			goto use_cur_page;

		if (!err && !usa_error &&
		    page->rhdr.sign == NTFS_RCRD_SIGNATURE &&
		    cur_page->rhdr.lsn == page->rhdr.lsn &&
		    cur_page->record_hdr.next_record_off ==
			    page->record_hdr.next_record_off &&
		    ((page_pos == page_cnt &&
		      le16_to_cpu(page->page_pos) == 1) ||
		     (page_pos != page_cnt &&
		      le16_to_cpu(page->page_pos) == page_pos + 1 &&
		      le16_to_cpu(page->page_count) == page_cnt))) {
			cur_page = NULL;
			goto use_tail_page;
		}

		page_off1 = page_off;

use_cur_page:

		lsn_cur = le64_to_cpu(cur_page->rhdr.lsn);

		if (last_ok_lsn !=
			    le64_to_cpu(cur_page->record_hdr.last_end_lsn) &&
		    ((lsn_cur >> log->file_data_bits) +
		     ((curpage_off <
		       (lsn_to_vbo(log, lsn_cur) & ~log->page_mask))
			      ? 1
			      : 0)) != expected_seq) {
			goto check_tail;
		}

		if (!is_log_record_end(cur_page)) {
			tail_page = NULL;
			last_ok_lsn = lsn_cur;
			goto next_page_1;
		}

		log->seq_num = expected_seq;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;
		log->last_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn);
		log->ra->current_lsn = cur_page->record_hdr.last_end_lsn;

		if (log->record_header_len <=
		    log->page_size -
			    le16_to_cpu(cur_page->record_hdr.next_record_off)) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		if (wrapped_file)
			log->l_flags |= NTFSLOG_WRAPPED;

		last_ok_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn);
		goto next_page_1;
	}

	 
	if (page_cnt == page_pos || page_cnt == page_pos + 1) {
		 
		if (curpage_off == final_off)
			tail_page = first_tail;

		 
		if (curpage_off == second_off) {
			if (!tail_page ||
			    (second_tail &&
			     le64_to_cpu(second_tail->record_hdr.last_end_lsn) >
				     le64_to_cpu(first_tail->record_hdr
							 .last_end_lsn))) {
				tail_page = second_tail;
			}
		}
	}

use_tail_page:
	if (tail_page) {
		 
		lsn_cur = le64_to_cpu(tail_page->record_hdr.last_end_lsn);

		if (last_ok_lsn < lsn_cur) {
			 
			if (expected_seq != (lsn_cur >> log->file_data_bits))
				tail_page = NULL;
		} else if (last_ok_lsn > lsn_cur) {
			 
			tail_page = NULL;
		}
	}

	 
	if (err || usa_error)
		goto check_tail;

	 
	lsn_cur = le64_to_cpu(page->rhdr.lsn);
	if (last_ok_lsn != lsn_cur &&
	    expected_seq != (lsn_cur >> log->file_data_bits)) {
		goto check_tail;
	}

	 
	if (page_cnt == page_pos) {
		if (page->page_pos != cpu_to_le16(1) &&
		    (!reuse_page || page->page_pos != page->page_count)) {
			 
			goto check_tail;
		}
	} else if (le16_to_cpu(page->page_count) != page_cnt ||
		   le16_to_cpu(page->page_pos) != page_pos + 1) {
		 
		goto check_tail;
	}

	 
	if (tail_page &&
	    le64_to_cpu(tail_page->record_hdr.last_end_lsn) > lsn_cur) {
		 
		replace_page = true;
		goto check_tail;
	}

	tail_page = NULL;

	if (is_log_record_end(page)) {
		 
		log->seq_num = expected_seq;
		log->last_lsn = le64_to_cpu(page->record_hdr.last_end_lsn);
		log->ra->current_lsn = page->record_hdr.last_end_lsn;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;

		 
		if (log->record_header_len <=
		    log->page_size -
			    le16_to_cpu(page->record_hdr.next_record_off)) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		 
		if (wrapped_file)
			log->l_flags |= NTFSLOG_WRAPPED;
	}

	 
	page_cnt = le16_to_cpu(page->page_count);
	page_pos = le16_to_cpu(page->page_pos);
	last_ok_lsn = le64_to_cpu(page->rhdr.lsn);

next_page_1:

	if (wrapped) {
		expected_seq += 1;
		wrapped_file = 1;
	}

	curpage_off = nextpage_off;
	kfree(page);
	page = NULL;
	reuse_page = 0;
	goto next_page;

check_tail:
	if (tail_page) {
		log->seq_num = expected_seq;
		log->last_lsn = le64_to_cpu(tail_page->record_hdr.last_end_lsn);
		log->ra->current_lsn = tail_page->record_hdr.last_end_lsn;
		log->l_flags &= ~NTFSLOG_NO_LAST_LSN;

		if (log->page_size -
			    le16_to_cpu(
				    tail_page->record_hdr.next_record_off) >=
		    log->record_header_len) {
			log->l_flags |= NTFSLOG_REUSE_TAIL;
			log->next_page = curpage_off;
		} else {
			log->l_flags &= ~NTFSLOG_REUSE_TAIL;
			log->next_page = nextpage_off;
		}

		if (wrapped)
			log->l_flags |= NTFSLOG_WRAPPED;
	}

	 
	second_off = nextpage_off;

	 
	if (wrapped)
		expected_seq += 1;

	 
	if (replace_page || (log->ra->flags & RESTART_SINGLE_PAGE_IO)) {
		page_cnt = 2;
		page_pos = 1;
		goto check_valid;
	}

	if (page_pos != page_cnt)
		goto check_valid;
	 
	if (wrapped) {
		page_cnt = 2;
		page_pos = 1;
		goto check_valid;
	}

	cur_pos = 2;

next_test_page:
	kfree(tst_page);
	tst_page = NULL;

	 
	err = read_log_page(log, nextpage_off, &tst_page, &usa_error);

	 
	if (usa_error)
		goto file_is_valid;

	 
	if (err)
		goto next_test_page_1;

	if (le16_to_cpu(tst_page->page_pos) == cur_pos &&
	    check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) {
		page_cnt = le16_to_cpu(tst_page->page_count) + 1;
		page_pos = le16_to_cpu(tst_page->page_pos);
		goto check_valid;
	} else {
		goto file_is_valid;
	}

next_test_page_1:

	nextpage_off = next_page_off(log, curpage_off);
	wrapped = nextpage_off == log->first_page;

	if (wrapped) {
		expected_seq += 1;
		page_cnt = 2;
		page_pos = 1;
	}

	cur_pos += 1;
	part_io_count += 1;
	if (!wrapped)
		goto next_test_page;

check_valid:
	 
	remain_pages = page_cnt - page_pos - 1;
	part_io_count += remain_pages;

	while (remain_pages--) {
		nextpage_off = next_page_off(log, curpage_off);
		wrapped = nextpage_off == log->first_page;

		if (wrapped)
			expected_seq += 1;
	}

	 
	kfree(tst_page);
	tst_page = NULL;

	err = read_log_page(log, nextpage_off, &tst_page, &usa_error);
	if (!err && !usa_error &&
	    check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) {
		err = -EINVAL;
		goto out;
	}

file_is_valid:

	 
	if (page_off1 || tail_page) {
		struct RECORD_PAGE_HDR *tmp_page;

		if (sb_rdonly(log->ni->mi.sbi->sb)) {
			err = -EROFS;
			goto out;
		}

		if (page_off1) {
			tmp_page = Add2Ptr(page_bufs, page_off1 - page_off);
			tails -= (page_off1 - page_off) / log->page_size;
			if (!tail_page)
				tails -= 1;
		} else {
			tmp_page = tail_page;
			tails = 1;
		}

		while (tails--) {
			u64 off = hdr_file_off(log, tmp_page);

			if (!page) {
				page = kmalloc(log->page_size, GFP_NOFS);
				if (!page)
					return -ENOMEM;
			}

			 
			memcpy(page, tmp_page, log->page_size);

			 
			if (log->major_ver < 2)
				page->rhdr.lsn = page->record_hdr.last_end_lsn;
			else
				page->file_off = 0;

			page->page_pos = page->page_count = cpu_to_le16(1);

			ntfs_fix_pre_write(&page->rhdr, log->page_size);

			err = ntfs_sb_write_run(log->ni->mi.sbi,
						&log->ni->file.run, off, page,
						log->page_size, 0);

			if (err)
				goto out;

			if (part_io_count && second_off == off) {
				second_off += log->page_size;
				part_io_count -= 1;
			}

			tmp_page = Add2Ptr(tmp_page, log->page_size);
		}
	}

	if (part_io_count) {
		if (sb_rdonly(log->ni->mi.sbi->sb)) {
			err = -EROFS;
			goto out;
		}
	}

out:
	kfree(second_tail);
	kfree(first_tail);
	kfree(page);
	kfree(tst_page);
	kfree(page_bufs);

	return err;
}