a1d312de7780e (Thomas Gleixner 2019-05-22 09:51:42 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 5) * Copyright (c) 2002-2007 Anton Altaparmakov
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) #ifdef NTFS_RW
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) #include <linux/types.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) #include <linux/fs.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) #include <linux/highmem.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) #include <linux/buffer_head.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) #include <linux/bitops.h>
02d5341ae53d3 (Robert P. J. Day 2009-06-16 15:33:35 -0700 15) #include <linux/log2.h>
2f8b544477e62 (Christoph Hellwig 2016-11-01 07:40:13 -0600 16) #include <linux/bio.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) #include "attrib.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) #include "aops.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) #include "debug.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) #include "logfile.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) #include "malloc.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #include "volume.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24) #include "ntfs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) * ntfs_check_restart_page_header - check the page header for consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) * @vi: $LogFile inode to which the restart page header belongs
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) * @rp: restart page header to check
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) * @pos: position in @vi at which the restart page header resides
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) *
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 32) * Check the restart page header @rp for consistency and return 'true' if it is
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 33) * consistent and 'false' otherwise.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) * require the full restart page.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 38) static bool ntfs_check_restart_page_header(struct inode *vi,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) RESTART_PAGE_HEADER *rp, s64 pos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) u32 logfile_system_page_size, logfile_log_page_size;
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 42) u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 43) bool have_usa = true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47) * If the system or log page sizes are smaller than the ntfs block size
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48) * or either is not a power of 2 we cannot handle this log file.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 49) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 50) logfile_system_page_size = le32_to_cpu(rp->system_page_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) logfile_log_page_size = le32_to_cpu(rp->log_page_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52) if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) logfile_log_page_size < NTFS_BLOCK_SIZE ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) logfile_system_page_size &
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) (logfile_system_page_size - 1) ||
02d5341ae53d3 (Robert P. J. Day 2009-06-16 15:33:35 -0700 56) !is_power_of_2(logfile_log_page_size)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 57) ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 58) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61) * We must be either at !pos (1st restart page) or at pos = system page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) * size (2nd restart page).
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) if (pos && pos != logfile_system_page_size) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) ntfs_error(vi->i_sb, "Found restart area in incorrect "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) "position in $LogFile.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 67) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) /* We only know how to handle version 1.1. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) if (sle16_to_cpu(rp->major_ver) != 1 ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) sle16_to_cpu(rp->minor_ver) != 1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ntfs_error(vi->i_sb, "$LogFile version %i.%i is not "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) "supported. (This driver supports version "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) "1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) (int)sle16_to_cpu(rp->minor_ver));
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 76) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) }
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 78) /*
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 79) * If chkdsk has been run the restart page may not be protected by an
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 80) * update sequence array.
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 81) */
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 82) if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 83) have_usa = false;
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 84) goto skip_usa_checks;
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 85) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) /* Verify the size of the update sequence array. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87) usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88) if (usa_count != le16_to_cpu(rp->usa_count)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) ntfs_error(vi->i_sb, "$LogFile restart page specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) "inconsistent update sequence array count.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 91) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) /* Verify the position of the update sequence array. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) usa_ofs = le16_to_cpu(rp->usa_ofs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) usa_end = usa_ofs + usa_count * sizeof(u16);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) ntfs_error(vi->i_sb, "$LogFile restart page specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) "inconsistent update sequence array offset.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 100) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 101) }
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 102) skip_usa_checks:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104) * Verify the position of the restart area. It must be:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) * - aligned to 8-byte boundary,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) * - after the update sequence array, and
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) * - within the system page size.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109) ra_ofs = le16_to_cpu(rp->restart_area_offset);
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 110) if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 111) ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) ra_ofs > logfile_system_page_size) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) ntfs_error(vi->i_sb, "$LogFile restart page specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) "inconsistent restart area offset.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 115) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 116) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119) * set.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 120) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121) if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122) ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 123) "by chkdsk but a chkdsk LSN is specified.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 124) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) ntfs_debug("Done.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 127) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) * ntfs_check_restart_area - check the restart area for consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132) * @vi: $LogFile inode to which the restart page belongs
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 133) * @rp: restart page whose restart area to check
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 135) * Check the restart area of the restart page @rp for consistency and return
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 136) * 'true' if it is consistent and 'false' otherwise.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) * This function assumes that the restart page header has already been
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139) * consistency checked.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) * require the full restart page.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 144) static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146) u64 file_size;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) RESTART_AREA *ra;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) u16 ra_ofs, ra_len, ca_ofs;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149) u8 fs_bits;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) ra_ofs = le16_to_cpu(rp->restart_area_offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 153) ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 154) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) * Everything before ra->file_size must be before the first word
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156) * protected by an update sequence number. This ensures that it is
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 157) * safe to access ra->client_array_offset.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) if (ra_ofs + offsetof(RESTART_AREA, file_size) >
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) NTFS_BLOCK_SIZE - sizeof(u16)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) "inconsistent file offset.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 163) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166) * Now that we can access ra->client_array_offset, make sure everything
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167) * up to the log client array is before the first word protected by an
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) * update sequence number. This ensures we can access all of the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) * restart area elements safely. Also, the client array offset must be
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) * aligned to an 8-byte boundary.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172) ca_ofs = le16_to_cpu(ra->client_array_offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 173) if (((ca_ofs + 7) & ~7) != ca_ofs ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 174) ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 175) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) "inconsistent client array offset.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 177) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 180) * The restart area must end within the system page size both when
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 181) * calculated manually and as specified by ra->restart_area_length.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 182) * Also, the calculated length must not exceed the specified length.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 183) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 184) ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 185) sizeof(LOG_CLIENT_RECORD);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186) if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187) ra_ofs + le16_to_cpu(ra->restart_area_length) >
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188) le32_to_cpu(rp->system_page_size) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189) ra_len > le16_to_cpu(ra->restart_area_length)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190) ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191) "of the system page size specified by the "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 192) "restart page header and/or the specified "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 193) "restart area length is inconsistent.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 194) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 195) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 196) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 197) * The ra->client_free_list and ra->client_in_use_list must be either
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198) * LOGFILE_NO_CLIENT or less than ra->log_clients or they are
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 199) * overflowing the client array.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 200) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201) if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 202) le16_to_cpu(ra->client_free_list) >=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 203) le16_to_cpu(ra->log_clients)) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204) (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 205) le16_to_cpu(ra->client_in_use_list) >=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 206) le16_to_cpu(ra->log_clients))) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 207) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 208) "overflowing client free and/or in use lists.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 209) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 210) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 211) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 212) * Check ra->seq_number_bits against ra->file_size for consistency.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 213) * We cannot just use ffs() because the file size is not a power of 2.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 214) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 215) file_size = (u64)sle64_to_cpu(ra->file_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 216) fs_bits = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 217) while (file_size) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 218) file_size >>= 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 219) fs_bits++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 220) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 221) if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) "inconsistent sequence number bits.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 224) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 226) /* The log record header length must be a multiple of 8. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 227) if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 228) le16_to_cpu(ra->log_record_header_length)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 229) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 230) "inconsistent log record header length.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 231) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 232) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 233) /* Dito for the log page data offset. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235) le16_to_cpu(ra->log_page_data_offset)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) ntfs_error(vi->i_sb, "$LogFile restart area specifies "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 237) "inconsistent log page data offset.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 238) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 239) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 240) ntfs_debug("Done.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 241) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 242) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 243)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 244) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) * ntfs_check_log_client_array - check the log client array for consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246) * @vi: $LogFile inode to which the restart page belongs
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) * @rp: restart page whose log client array to check
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 249) * Check the log client array of the restart page @rp for consistency and
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 250) * return 'true' if it is consistent and 'false' otherwise.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 251) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252) * This function assumes that the restart page header and the restart area have
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 253) * already been consistency checked.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 254) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 255) * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256) * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 257) * restart page and the page must be multi sector transfer deprotected.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 258) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 259) static bool ntfs_check_log_client_array(struct inode *vi,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 260) RESTART_PAGE_HEADER *rp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 261) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 262) RESTART_AREA *ra;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 263) LOG_CLIENT_RECORD *ca, *cr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 264) u16 nr_clients, idx;
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 265) bool in_free_list, idx_is_first;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 266)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 267) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 268) ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 269) ca = (LOG_CLIENT_RECORD*)((u8*)ra +
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 270) le16_to_cpu(ra->client_array_offset));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 271) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 272) * Check the ra->client_free_list first and then check the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 273) * ra->client_in_use_list. Check each of the log client records in
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 274) * each of the lists and check that the array does not overflow the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 275) * ra->log_clients value. Also keep track of the number of records
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 276) * visited as there cannot be more than ra->log_clients records and
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 277) * that way we detect eventual loops in within a list.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 278) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279) nr_clients = le16_to_cpu(ra->log_clients);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 280) idx = le16_to_cpu(ra->client_free_list);
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 281) in_free_list = true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 282) check_list:
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 283) for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284) idx = le16_to_cpu(cr->next_client)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 285) if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 286) goto err_out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 287) /* Set @cr to the current log client record. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 288) cr = ca + idx;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 289) /* The first log client record must not have a prev_client. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 290) if (idx_is_first) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 291) if (cr->prev_client != LOGFILE_NO_CLIENT)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 292) goto err_out;
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 293) idx_is_first = false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 294) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 295) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 296) /* Switch to and check the in use list if we just did the free list. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 297) if (in_free_list) {
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 298) in_free_list = false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 299) idx = le16_to_cpu(ra->client_in_use_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 300) goto check_list;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 301) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 302) ntfs_debug("Done.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 303) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 304) err_out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 305) ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 306) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 307) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 308)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 309) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 310) * ntfs_check_and_load_restart_page - check the restart page for consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 311) * @vi: $LogFile inode to which the restart page belongs
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 312) * @rp: restart page to check
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 313) * @pos: position in @vi at which the restart page resides
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 314) * @wrp: [OUT] copy of the multi sector transfer deprotected restart page
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 315) * @lsn: [OUT] set to the current logfile lsn on success
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 316) *
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 317) * Check the restart page @rp for consistency and return 0 if it is consistent
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 318) * and -errno otherwise. The restart page may have been modified by chkdsk in
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 319) * which case its magic is CHKD instead of RSTR.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 320) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 321) * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 322) * require the full restart page.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 323) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 324) * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 325) * copy of the complete multi sector transfer deprotected page. On failure,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 326) * *@wrp is undefined.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 327) *
af901ca181d92 (André Goddard Rosa 2009-11-14 13:09:05 -0200 328) * Simillarly, if @lsn is not NULL, on success *@lsn will be set to the current
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 329) * logfile lsn according to this restart page. On failure, *@lsn is undefined.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 330) *
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 331) * The following error codes are defined:
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 332) * -EINVAL - The restart page is inconsistent.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 333) * -ENOMEM - Not enough memory to load the restart page.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 334) * -EIO - Failed to reading from $LogFile.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 335) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 336) static int ntfs_check_and_load_restart_page(struct inode *vi,
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 337) RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 338) LSN *lsn)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 339) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 340) RESTART_AREA *ra;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 341) RESTART_PAGE_HEADER *trp;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 342) int size, err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 343)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 344) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 345) /* Check the restart page header for consistency. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 346) if (!ntfs_check_restart_page_header(vi, rp, pos)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 347) /* Error output already done inside the function. */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 348) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 349) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 350) /* Check the restart area for consistency. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 351) if (!ntfs_check_restart_area(vi, rp)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 352) /* Error output already done inside the function. */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 353) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 354) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 355) ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 356) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 357) * Allocate a buffer to store the whole restart page so we can multi
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 358) * sector transfer deprotect it.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 359) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 360) trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 361) if (!trp) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 362) ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363) "restart page buffer.");
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 364) return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 366) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 367) * Read the whole of the restart page into the buffer. If it fits
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368) * completely inside @rp, just copy it from there. Otherwise map all
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369) * the required pages and copy the data from them.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370) */
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 371) size = PAGE_SIZE - (pos & ~PAGE_MASK);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) if (size >= le32_to_cpu(rp->system_page_size)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 373) memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 374) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 375) pgoff_t idx;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 376) struct page *page;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 377) int have_read, to_read;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 378)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 379) /* First copy what we already have in @rp. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 380) memcpy(trp, rp, size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 381) /* Copy the remaining data one page at a time. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 382) have_read = size;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 383) to_read = le32_to_cpu(rp->system_page_size) - size;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 384) idx = (pos + size) >> PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 385) BUG_ON((pos + size) & ~PAGE_MASK);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 386) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 387) page = ntfs_map_page(vi->i_mapping, idx);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 388) if (IS_ERR(page)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 389) ntfs_error(vi->i_sb, "Error mapping $LogFile "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 390) "page (index %lu).", idx);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 391) err = PTR_ERR(page);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 392) if (err != -EIO && err != -ENOMEM)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 393) err = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 394) goto err_out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 395) }
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 396) size = min_t(int, to_read, PAGE_SIZE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 397) memcpy((u8*)trp + have_read, page_address(page), size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 398) ntfs_unmap_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 399) have_read += size;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 400) to_read -= size;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 401) idx++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 402) } while (to_read > 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 403) }
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 404) /*
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 405) * Perform the multi sector transfer deprotection on the buffer if the
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 406) * restart page is protected.
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 407) */
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 408) if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 409) && post_read_mst_fixup((NTFS_RECORD*)trp,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 410) le32_to_cpu(rp->system_page_size))) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 411) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 412) * A multi sector tranfer error was detected. We only need to
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 413) * abort if the restart page contents exceed the multi sector
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 414) * transfer fixup of the first sector.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 415) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 416) if (le16_to_cpu(rp->restart_area_offset) +
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 417) le16_to_cpu(ra->restart_area_length) >
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 418) NTFS_BLOCK_SIZE - sizeof(u16)) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 419) ntfs_error(vi->i_sb, "Multi sector transfer error "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 420) "detected in $LogFile restart page.");
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 421) err = -EINVAL;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 422) goto err_out;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 423) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 424) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 425) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 426) * If the restart page is modified by chkdsk or there are no active
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 427) * logfile clients, the logfile is consistent. Otherwise, need to
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 428) * check the log client records for consistency, too.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 429) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 430) err = 0;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 431) if (ntfs_is_rstr_record(rp->magic) &&
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 432) ra->client_in_use_list != LOGFILE_NO_CLIENT) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 433) if (!ntfs_check_log_client_array(vi, trp)) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 434) err = -EINVAL;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 435) goto err_out;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 436) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 437) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 438) if (lsn) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 439) if (ntfs_is_rstr_record(rp->magic))
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 440) *lsn = sle64_to_cpu(ra->current_lsn);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 441) else /* if (ntfs_is_chkd_record(rp->magic)) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 442) *lsn = sle64_to_cpu(rp->chkdsk_lsn);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 443) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 444) ntfs_debug("Done.");
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 445) if (wrp)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 446) *wrp = trp;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 447) else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 448) err_out:
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 449) ntfs_free(trp);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 450) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 451) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 452) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 453)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 454) /**
3bd1f4a173a34 (Anton Altaparmakov 2005-06-25 16:51:58 +0100 455) * ntfs_check_logfile - check the journal for consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 456) * @log_vi: struct inode of loaded journal $LogFile to check
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 457) * @rp: [OUT] on success this is a copy of the current restart page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 458) *
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 459) * Check the $LogFile journal for consistency and return 'true' if it is
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 460) * consistent and 'false' if not. On success, the current restart page is
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 461) * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 462) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 463) * At present we only check the two restart pages and ignore the log record
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 464) * pages.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 465) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 466) * Note that the MstProtected flag is not set on the $LogFile inode and hence
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 467) * when reading pages they are not deprotected. This is because we do not know
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 468) * if the $LogFile was created on a system with a different page size to ours
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 469) * yet and mst deprotection would fail if our page size is smaller.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 470) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 471) bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 472) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 473) s64 size, pos;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 474) LSN rstr1_lsn, rstr2_lsn;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 475) ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 476) struct address_space *mapping = log_vi->i_mapping;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 477) struct page *page = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 478) u8 *kaddr = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 479) RESTART_PAGE_HEADER *rstr1_ph = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 480) RESTART_PAGE_HEADER *rstr2_ph = NULL;
3f10c2fa40e44 (Alex Shi 2020-12-14 19:03:31 -0800 481) int log_page_size, err;
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 482) bool logfile_is_empty = true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 483) u8 log_page_bits;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 484)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 485) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 486) /* An empty $LogFile must have been clean before it got emptied. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 487) if (NVolLogFileEmpty(vol))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 488) goto is_empty;
66129f88c4cc7 (Anton Altaparmakov 2004-11-11 12:34:00 +0000 489) size = i_size_read(log_vi);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 490) /* Make sure the file doesn't exceed the maximum allowed size. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 491) if (size > MaxLogFileSize)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 492) size = MaxLogFileSize;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 493) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 494) * Truncate size to a multiple of the page cache size or the default
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 495) * log page size if the page cache size is between the default log page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 496) * log page size if the page cache size is between the default log page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 497) * size and twice that.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 498) */
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 499) if (PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 500) DefaultLogPageSize * 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 501) log_page_size = DefaultLogPageSize;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 502) else
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 503) log_page_size = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 504) /*
b9a2838cc26c4 (Akinobu Mita 2006-03-26 01:39:53 -0800 505) * Use ntfs_ffs() instead of ffs() to enable the compiler to
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 506) * optimize log_page_size and log_page_bits into constants.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 507) */
b9a2838cc26c4 (Akinobu Mita 2006-03-26 01:39:53 -0800 508) log_page_bits = ntfs_ffs(log_page_size) - 1;
3bd1f4a173a34 (Anton Altaparmakov 2005-06-25 16:51:58 +0100 509) size &= ~(s64)(log_page_size - 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 510) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 511) * Ensure the log file is big enough to store at least the two restart
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 512) * pages and the minimum number of log record pages.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 513) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 514) if (size < log_page_size * 2 || (size - log_page_size * 2) >>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 515) log_page_bits < MinLogRecordPages) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 516) ntfs_error(vol->sb, "$LogFile is too small.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 517) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 518) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 519) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 520) * Read through the file looking for a restart page. Since the restart
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 521) * page header is at the beginning of a page we only need to search at
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 522) * what could be the beginning of a page (for each page size) rather
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 523) * than scanning the whole file byte by byte. If all potential places
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 524) * contain empty and uninitialzed records, the log file can be assumed
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 525) * to be empty.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 526) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 527) for (pos = 0; pos < size; pos <<= 1) {
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 528) pgoff_t idx = pos >> PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 529) if (!page || page->index != idx) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 530) if (page)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 531) ntfs_unmap_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 532) page = ntfs_map_page(mapping, idx);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 533) if (IS_ERR(page)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 534) ntfs_error(vol->sb, "Error mapping $LogFile "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 535) "page (index %lu).", idx);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 536) goto err_out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 537) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 538) }
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 539) kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 540) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 541) * A non-empty block means the logfile is not empty while an
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 542) * empty block after a non-empty block has been encountered
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 543) * means we are done.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 544) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 545) if (!ntfs_is_empty_recordp((le32*)kaddr))
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 546) logfile_is_empty = false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 547) else if (!logfile_is_empty)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 548) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 549) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 550) * A log record page means there cannot be a restart page after
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 551) * this so no need to continue searching.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 552) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 553) if (ntfs_is_rcrd_recordp((le32*)kaddr))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 554) break;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 555) /* If not a (modified by chkdsk) restart page, continue. */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 556) if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 557) !ntfs_is_chkd_recordp((le32*)kaddr)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 558) if (!pos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 559) pos = NTFS_BLOCK_SIZE >> 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 560) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 561) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 562) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 563) * Check the (modified by chkdsk) restart page for consistency
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 564) * and get a copy of the complete multi sector transfer
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 565) * deprotected restart page.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 566) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 567) err = ntfs_check_and_load_restart_page(log_vi,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 568) (RESTART_PAGE_HEADER*)kaddr, pos,
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 569) !rstr1_ph ? &rstr1_ph : &rstr2_ph,
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 570) !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 571) if (!err) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 572) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 573) * If we have now found the first (modified by chkdsk)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 574) * restart page, continue looking for the second one.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 575) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 576) if (!pos) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 577) pos = NTFS_BLOCK_SIZE >> 1;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 578) continue;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 579) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 580) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 581) * We have now found the second (modified by chkdsk)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 582) * restart page, so we can stop looking.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 583) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 584) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 585) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 586) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 587) * Error output already done inside the function. Note, we do
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 588) * not abort if the restart page was invalid as we might still
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 589) * find a valid one further in the file.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 590) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 591) if (err != -EINVAL) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 592) ntfs_unmap_page(page);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 593) goto err_out;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 594) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 595) /* Continue looking. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 596) if (!pos)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 597) pos = NTFS_BLOCK_SIZE >> 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 598) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 599) if (page)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 600) ntfs_unmap_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 601) if (logfile_is_empty) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 602) NVolSetLogFileEmpty(vol);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 603) is_empty:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 604) ntfs_debug("Done. ($LogFile is empty.)");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 605) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 606) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 607) if (!rstr1_ph) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 608) BUG_ON(rstr2_ph);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 609) ntfs_error(vol->sb, "Did not find any restart pages in "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 610) "$LogFile and it was not empty.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 611) return false;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 612) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 613) /* If both restart pages were found, use the more recent one. */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 614) if (rstr2_ph) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 615) /*
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 616) * If the second restart area is more recent, switch to it.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 617) * Otherwise just throw it away.
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 618) */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 619) if (rstr2_lsn > rstr1_lsn) {
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 620) ntfs_debug("Using second restart page as it is more "
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 621) "recent.");
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 622) ntfs_free(rstr1_ph);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 623) rstr1_ph = rstr2_ph;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 624) /* rstr1_lsn = rstr2_lsn; */
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 625) } else {
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 626) ntfs_debug("Using first restart page as it is more "
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 627) "recent.");
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 628) ntfs_free(rstr2_ph);
5a8c0cc32bb6e (Anton Altaparmakov 2005-09-26 10:48:54 +0100 629) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 630) rstr2_ph = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 631) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 632) /* All consistency checks passed. */
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 633) if (rp)
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 634) *rp = rstr1_ph;
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 635) else
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 636) ntfs_free(rstr1_ph);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 637) ntfs_debug("Done.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 638) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 639) err_out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 640) if (rstr1_ph)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 641) ntfs_free(rstr1_ph);
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 642) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 643) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 644)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 645) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 646) * ntfs_is_logfile_clean - check in the journal if the volume is clean
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 647) * @log_vi: struct inode of loaded journal $LogFile to check
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 648) * @rp: copy of the current restart page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 649) *
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 650) * Analyze the $LogFile journal and return 'true' if it indicates the volume was
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 651) * shutdown cleanly and 'false' if not.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 652) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 653) * At present we only look at the two restart pages and ignore the log record
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 654) * pages. This is a little bit crude in that there will be a very small number
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 655) * of cases where we think that a volume is dirty when in fact it is clean.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 656) * This should only affect volumes that have not been shutdown cleanly but did
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 657) * not have any pending, non-check-pointed i/o, i.e. they were completely idle
25985edcedea6 (Lucas De Marchi 2011-03-30 22:57:33 -0300 658) * at least for the five seconds preceding the unclean shutdown.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 659) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 660) * This function assumes that the $LogFile journal has already been consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 661) * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 662) * is empty this function requires that NVolLogFileEmpty() is true otherwise an
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 663) * empty volume will be reported as dirty.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 664) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 665) bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 666) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 667) ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 668) RESTART_AREA *ra;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 669)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 670) ntfs_debug("Entering.");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 671) /* An empty $LogFile must have been clean before it got emptied. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 672) if (NVolLogFileEmpty(vol)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 673) ntfs_debug("Done. ($LogFile is empty.)");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 674) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 675) }
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 676) BUG_ON(!rp);
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 677) if (!ntfs_is_rstr_record(rp->magic) &&
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 678) !ntfs_is_chkd_record(rp->magic)) {
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 679) ntfs_error(vol->sb, "Restart page buffer is invalid. This is "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 680) "probably a bug in that the $LogFile should "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 681) "have been consistency checked before calling "
e7a1033b946f4 (Anton Altaparmakov 2005-09-08 16:12:28 +0100 682) "this function.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 683) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 684) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 685) ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 686) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 687) * If the $LogFile has active clients, i.e. it is open, and we do not
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 688) * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 689) * we assume there was an unclean shutdown.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 690) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 691) if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 692) !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 693) ntfs_debug("Done. $LogFile indicates a dirty shutdown.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 694) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 695) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 696) /* $LogFile indicates a clean shutdown. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 697) ntfs_debug("Done. $LogFile indicates a clean shutdown.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 698) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 699) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 700)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 701) /**
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 702) * ntfs_empty_logfile - empty the contents of the $LogFile journal
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 703) * @log_vi: struct inode of loaded journal $LogFile to empty
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 704) *
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 705) * Empty the contents of the $LogFile journal @log_vi and return 'true' on
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 706) * success and 'false' on error.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 707) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 708) * This function assumes that the $LogFile journal has already been consistency
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 709) * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 710) * has been used to ensure that the $LogFile is clean.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 711) */
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 712) bool ntfs_empty_logfile(struct inode *log_vi)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 713) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 714) VCN vcn, end_vcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 715) ntfs_inode *log_ni = NTFS_I(log_vi);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 716) ntfs_volume *vol = log_ni->vol;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 717) struct super_block *sb = vol->sb;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 718) runlist_element *rl;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 719) unsigned long flags;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 720) unsigned block_size, block_size_bits;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 721) int err;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 722) bool should_wait = true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 723)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 724) ntfs_debug("Entering.");
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 725) if (NVolLogFileEmpty(vol)) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 726) ntfs_debug("Done.");
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 727) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 728) }
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 729) /*
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 730) * We cannot use ntfs_attr_set() because we may be still in the middle
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 731) * of a mount operation. Thus we do the emptying by hand by first
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 732) * zapping the page cache pages for the $LogFile/$DATA attribute and
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 733) * then emptying each of the buffers in each of the clusters specified
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 734) * by the runlist by hand.
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 735) */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 736) block_size = sb->s_blocksize;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 737) block_size_bits = sb->s_blocksize_bits;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 738) vcn = 0;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 739) read_lock_irqsave(&log_ni->size_lock, flags);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 740) end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 741) vol->cluster_size_bits;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 742) read_unlock_irqrestore(&log_ni->size_lock, flags);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 743) truncate_inode_pages(log_vi->i_mapping, 0);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 744) down_write(&log_ni->runlist.lock);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 745) rl = log_ni->runlist.rl;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 746) if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 747) map_vcn:
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 748) err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 749) if (err) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 750) ntfs_error(sb, "Failed to map runlist fragment (error "
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 751) "%d).", -err);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 752) goto err;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 753) }
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 754) rl = log_ni->runlist.rl;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 755) BUG_ON(!rl || vcn < rl->vcn || !rl->length);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 756) }
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 757) /* Seek to the runlist element containing @vcn. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 758) while (rl->length && vcn >= rl[1].vcn)
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 759) rl++;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 760) do {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 761) LCN lcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 762) sector_t block, end_block;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 763) s64 len;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 764)
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 765) /*
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 766) * If this run is not mapped map it now and start again as the
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 767) * runlist will have been updated.
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 768) */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 769) lcn = rl->lcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 770) if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 771) vcn = rl->vcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 772) goto map_vcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 773) }
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 774) /* If this run is not valid abort with an error. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 775) if (unlikely(!rl->length || lcn < LCN_HOLE))
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 776) goto rl_err;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 777) /* Skip holes. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 778) if (lcn == LCN_HOLE)
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 779) continue;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 780) block = lcn << vol->cluster_size_bits >> block_size_bits;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 781) len = rl->length;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 782) if (rl[1].vcn > end_vcn)
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 783) len = end_vcn - rl->vcn;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 784) end_block = (lcn + len) << vol->cluster_size_bits >>
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 785) block_size_bits;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 786) /* Iterate over the blocks in the run and empty them. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 787) do {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 788) struct buffer_head *bh;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 789)
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 790) /* Obtain the buffer, possibly not uptodate. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 791) bh = sb_getblk(sb, block);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 792) BUG_ON(!bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 793) /* Setup buffer i/o submission. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 794) lock_buffer(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 795) bh->b_end_io = end_buffer_write_sync;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 796) get_bh(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 797) /* Set the entire contents of the buffer to 0xff. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 798) memset(bh->b_data, -1, block_size);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 799) if (!buffer_uptodate(bh))
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 800) set_buffer_uptodate(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 801) if (buffer_dirty(bh))
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 802) clear_buffer_dirty(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 803) /*
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 804) * Submit the buffer and wait for i/o to complete but
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 805) * only for the first buffer so we do not miss really
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 806) * serious i/o errors. Once the first buffer has
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 807) * completed ignore errors afterwards as we can assume
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 808) * that if one buffer worked all of them will work.
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 809) */
2a222ca992c35 (Mike Christie 2016-06-05 14:31:43 -0500 810) submit_bh(REQ_OP_WRITE, 0, bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 811) if (should_wait) {
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 812) should_wait = false;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 813) wait_on_buffer(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 814) if (unlikely(!buffer_uptodate(bh)))
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 815) goto io_err;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 816) }
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 817) brelse(bh);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 818) } while (++block < end_block);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 819) } while ((++rl)->vcn < end_vcn);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 820) up_write(&log_ni->runlist.lock);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 821) /*
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 822) * Zap the pages again just in case any got instantiated whilst we were
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 823) * emptying the blocks by hand. FIXME: We may not have completed
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 824) * writing to all the buffer heads yet so this may happen too early.
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 825) * We really should use a kernel thread to do the emptying
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 826) * asynchronously and then we can also set the volume dirty and output
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 827) * an error message if emptying should fail.
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 828) */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 829) truncate_inode_pages(log_vi->i_mapping, 0);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 830) /* Set the flag so we do not have to do it again on remount. */
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 831) NVolSetLogFileEmpty(vol);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 832) ntfs_debug("Done.");
c49c31115067b (Richard Knutsson 2006-09-30 23:27:12 -0700 833) return true;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 834) io_err:
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 835) ntfs_error(sb, "Failed to write buffer. Unmount and run chkdsk.");
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 836) goto dirty_err;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 837) rl_err:
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 838) ntfs_error(sb, "Runlist is corrupt. Unmount and run chkdsk.");
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 839) dirty_err:
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 840) NVolSetErrors(vol);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 841) err = -EIO;
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 842) err:
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 843) up_write(&log_ni->runlist.lock);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 844) ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 845) -err);
bfab36e81611e (Anton Altaparmakov 2007-10-12 09:37:15 +0100 846) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 847) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 848)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 849) #endif /* NTFS_RW */