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