Lines Matching +full:page +full:- +full:size

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
5 * Copyright (c) 2002-2007 Anton Altaparmakov
27 * ntfs_check_restart_page_header - check the page header for consistency
28 * @vi: $LogFile inode to which the restart page header belongs
29 * @rp: restart page header to check
30 * @pos: position in @vi at which the restart page header resides
32 * Check the restart page header @rp for consistency and return 'true' if it is
36 * require the full restart page.
47 * If the system or log page sizes are smaller than the ntfs block size in ntfs_check_restart_page_header()
50 logfile_system_page_size = le32_to_cpu(rp->system_page_size); in ntfs_check_restart_page_header()
51 logfile_log_page_size = le32_to_cpu(rp->log_page_size); in ntfs_check_restart_page_header()
55 (logfile_system_page_size - 1) || in ntfs_check_restart_page_header()
57 ntfs_error(vi->i_sb, "$LogFile uses unsupported page size."); in ntfs_check_restart_page_header()
61 * We must be either at !pos (1st restart page) or at pos = system page in ntfs_check_restart_page_header()
62 * size (2nd restart page). in ntfs_check_restart_page_header()
65 ntfs_error(vi->i_sb, "Found restart area in incorrect " in ntfs_check_restart_page_header()
70 if (sle16_to_cpu(rp->major_ver) != 1 || in ntfs_check_restart_page_header()
71 sle16_to_cpu(rp->minor_ver) != 1) { in ntfs_check_restart_page_header()
72 ntfs_error(vi->i_sb, "$LogFile version %i.%i is not " in ntfs_check_restart_page_header()
74 "1.1 only.)", (int)sle16_to_cpu(rp->major_ver), in ntfs_check_restart_page_header()
75 (int)sle16_to_cpu(rp->minor_ver)); in ntfs_check_restart_page_header()
79 * If chkdsk has been run the restart page may not be protected by an in ntfs_check_restart_page_header()
82 if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) { in ntfs_check_restart_page_header()
86 /* Verify the size of the update sequence array. */ in ntfs_check_restart_page_header()
88 if (usa_count != le16_to_cpu(rp->usa_count)) { in ntfs_check_restart_page_header()
89 ntfs_error(vi->i_sb, "$LogFile restart page specifies " in ntfs_check_restart_page_header()
94 usa_ofs = le16_to_cpu(rp->usa_ofs); in ntfs_check_restart_page_header()
97 usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) { in ntfs_check_restart_page_header()
98 ntfs_error(vi->i_sb, "$LogFile restart page specifies " in ntfs_check_restart_page_header()
105 * - aligned to 8-byte boundary, in ntfs_check_restart_page_header()
106 * - after the update sequence array, and in ntfs_check_restart_page_header()
107 * - within the system page size. in ntfs_check_restart_page_header()
109 ra_ofs = le16_to_cpu(rp->restart_area_offset); in ntfs_check_restart_page_header()
113 ntfs_error(vi->i_sb, "$LogFile restart page specifies " in ntfs_check_restart_page_header()
121 if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { in ntfs_check_restart_page_header()
122 ntfs_error(vi->i_sb, "$LogFile restart page is not modified " in ntfs_check_restart_page_header()
131 * ntfs_check_restart_area - check the restart area for consistency
132 * @vi: $LogFile inode to which the restart page belongs
133 * @rp: restart page whose restart area to check
135 * Check the restart area of the restart page @rp for consistency and return
138 * This function assumes that the restart page header has already been
142 * require the full restart page.
152 ra_ofs = le16_to_cpu(rp->restart_area_offset); in ntfs_check_restart_area()
155 * Everything before ra->file_size must be before the first word in ntfs_check_restart_area()
157 * safe to access ra->client_array_offset. in ntfs_check_restart_area()
160 NTFS_BLOCK_SIZE - sizeof(u16)) { in ntfs_check_restart_area()
161 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
166 * Now that we can access ra->client_array_offset, make sure everything in ntfs_check_restart_area()
170 * aligned to an 8-byte boundary. in ntfs_check_restart_area()
172 ca_ofs = le16_to_cpu(ra->client_array_offset); in ntfs_check_restart_area()
174 ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) { in ntfs_check_restart_area()
175 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
180 * The restart area must end within the system page size both when in ntfs_check_restart_area()
181 * calculated manually and as specified by ra->restart_area_length. in ntfs_check_restart_area()
184 ra_len = ca_ofs + le16_to_cpu(ra->log_clients) * in ntfs_check_restart_area()
186 if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) || in ntfs_check_restart_area()
187 ra_ofs + le16_to_cpu(ra->restart_area_length) > in ntfs_check_restart_area()
188 le32_to_cpu(rp->system_page_size) || in ntfs_check_restart_area()
189 ra_len > le16_to_cpu(ra->restart_area_length)) { in ntfs_check_restart_area()
190 ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds " in ntfs_check_restart_area()
191 "of the system page size specified by the " in ntfs_check_restart_area()
192 "restart page header and/or the specified " in ntfs_check_restart_area()
197 * The ra->client_free_list and ra->client_in_use_list must be either in ntfs_check_restart_area()
198 * LOGFILE_NO_CLIENT or less than ra->log_clients or they are in ntfs_check_restart_area()
201 if ((ra->client_free_list != LOGFILE_NO_CLIENT && in ntfs_check_restart_area()
202 le16_to_cpu(ra->client_free_list) >= in ntfs_check_restart_area()
203 le16_to_cpu(ra->log_clients)) || in ntfs_check_restart_area()
204 (ra->client_in_use_list != LOGFILE_NO_CLIENT && in ntfs_check_restart_area()
205 le16_to_cpu(ra->client_in_use_list) >= in ntfs_check_restart_area()
206 le16_to_cpu(ra->log_clients))) { in ntfs_check_restart_area()
207 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
212 * Check ra->seq_number_bits against ra->file_size for consistency. in ntfs_check_restart_area()
213 * We cannot just use ffs() because the file size is not a power of 2. in ntfs_check_restart_area()
215 file_size = (u64)sle64_to_cpu(ra->file_size); in ntfs_check_restart_area()
221 if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) { in ntfs_check_restart_area()
222 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
227 if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) != in ntfs_check_restart_area()
228 le16_to_cpu(ra->log_record_header_length)) { in ntfs_check_restart_area()
229 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
233 /* Dito for the log page data offset. */ in ntfs_check_restart_area()
234 if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) != in ntfs_check_restart_area()
235 le16_to_cpu(ra->log_page_data_offset)) { in ntfs_check_restart_area()
236 ntfs_error(vi->i_sb, "$LogFile restart area specifies " in ntfs_check_restart_area()
237 "inconsistent log page data offset."); in ntfs_check_restart_area()
245 * ntfs_check_log_client_array - check the log client array for consistency
246 * @vi: $LogFile inode to which the restart page belongs
247 * @rp: restart page whose log client array to check
249 * Check the log client array of the restart page @rp for consistency and
252 * This function assumes that the restart page header and the restart area have
256 * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
257 * restart page and the page must be multi sector transfer deprotected.
268 ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); in ntfs_check_log_client_array()
270 le16_to_cpu(ra->client_array_offset)); in ntfs_check_log_client_array()
272 * Check the ra->client_free_list first and then check the in ntfs_check_log_client_array()
273 * ra->client_in_use_list. Check each of the log client records in in ntfs_check_log_client_array()
275 * ra->log_clients value. Also keep track of the number of records in ntfs_check_log_client_array()
276 * visited as there cannot be more than ra->log_clients records and in ntfs_check_log_client_array()
279 nr_clients = le16_to_cpu(ra->log_clients); in ntfs_check_log_client_array()
280 idx = le16_to_cpu(ra->client_free_list); in ntfs_check_log_client_array()
283 for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--, in ntfs_check_log_client_array()
284 idx = le16_to_cpu(cr->next_client)) { in ntfs_check_log_client_array()
285 if (!nr_clients || idx >= le16_to_cpu(ra->log_clients)) in ntfs_check_log_client_array()
291 if (cr->prev_client != LOGFILE_NO_CLIENT) in ntfs_check_log_client_array()
299 idx = le16_to_cpu(ra->client_in_use_list); in ntfs_check_log_client_array()
305 ntfs_error(vi->i_sb, "$LogFile log client array is corrupt."); in ntfs_check_log_client_array()
310 * ntfs_check_and_load_restart_page - check the restart page for consistency
311 * @vi: $LogFile inode to which the restart page belongs
312 * @rp: restart page to check
313 * @pos: position in @vi at which the restart page resides
314 * @wrp: [OUT] copy of the multi sector transfer deprotected restart page
317 * Check the restart page @rp for consistency and return 0 if it is consistent
318 * and -errno otherwise. The restart page may have been modified by chkdsk in
322 * require the full restart page.
325 * copy of the complete multi sector transfer deprotected page. On failure,
329 * logfile lsn according to this restart page. On failure, *@lsn is undefined.
332 * -EINVAL - The restart page is inconsistent.
333 * -ENOMEM - Not enough memory to load the restart page.
334 * -EIO - Failed to reading from $LogFile.
342 int size, err; in ntfs_check_and_load_restart_page() local
345 /* Check the restart page header for consistency. */ in ntfs_check_and_load_restart_page()
348 return -EINVAL; in ntfs_check_and_load_restart_page()
353 return -EINVAL; in ntfs_check_and_load_restart_page()
355 ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); in ntfs_check_and_load_restart_page()
357 * Allocate a buffer to store the whole restart page so we can multi in ntfs_check_and_load_restart_page()
360 trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size)); in ntfs_check_and_load_restart_page()
362 ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " in ntfs_check_and_load_restart_page()
363 "restart page buffer."); in ntfs_check_and_load_restart_page()
364 return -ENOMEM; in ntfs_check_and_load_restart_page()
367 * Read the whole of the restart page into the buffer. If it fits in ntfs_check_and_load_restart_page()
371 size = PAGE_SIZE - (pos & ~PAGE_MASK); in ntfs_check_and_load_restart_page()
372 if (size >= le32_to_cpu(rp->system_page_size)) { in ntfs_check_and_load_restart_page()
373 memcpy(trp, rp, le32_to_cpu(rp->system_page_size)); in ntfs_check_and_load_restart_page()
376 struct page *page; in ntfs_check_and_load_restart_page() local
380 memcpy(trp, rp, size); in ntfs_check_and_load_restart_page()
381 /* Copy the remaining data one page at a time. */ in ntfs_check_and_load_restart_page()
382 have_read = size; in ntfs_check_and_load_restart_page()
383 to_read = le32_to_cpu(rp->system_page_size) - size; in ntfs_check_and_load_restart_page()
384 idx = (pos + size) >> PAGE_SHIFT; in ntfs_check_and_load_restart_page()
385 BUG_ON((pos + size) & ~PAGE_MASK); in ntfs_check_and_load_restart_page()
387 page = ntfs_map_page(vi->i_mapping, idx); in ntfs_check_and_load_restart_page()
388 if (IS_ERR(page)) { in ntfs_check_and_load_restart_page()
389 ntfs_error(vi->i_sb, "Error mapping $LogFile " in ntfs_check_and_load_restart_page()
390 "page (index %lu).", idx); in ntfs_check_and_load_restart_page()
391 err = PTR_ERR(page); in ntfs_check_and_load_restart_page()
392 if (err != -EIO && err != -ENOMEM) in ntfs_check_and_load_restart_page()
393 err = -EIO; in ntfs_check_and_load_restart_page()
396 size = min_t(int, to_read, PAGE_SIZE); in ntfs_check_and_load_restart_page()
397 memcpy((u8*)trp + have_read, page_address(page), size); in ntfs_check_and_load_restart_page()
398 ntfs_unmap_page(page); in ntfs_check_and_load_restart_page()
399 have_read += size; in ntfs_check_and_load_restart_page()
400 to_read -= size; in ntfs_check_and_load_restart_page()
406 * restart page is protected. in ntfs_check_and_load_restart_page()
408 if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) in ntfs_check_and_load_restart_page()
410 le32_to_cpu(rp->system_page_size))) { in ntfs_check_and_load_restart_page()
413 * abort if the restart page contents exceed the multi sector in ntfs_check_and_load_restart_page()
416 if (le16_to_cpu(rp->restart_area_offset) + in ntfs_check_and_load_restart_page()
417 le16_to_cpu(ra->restart_area_length) > in ntfs_check_and_load_restart_page()
418 NTFS_BLOCK_SIZE - sizeof(u16)) { in ntfs_check_and_load_restart_page()
419 ntfs_error(vi->i_sb, "Multi sector transfer error " in ntfs_check_and_load_restart_page()
420 "detected in $LogFile restart page."); in ntfs_check_and_load_restart_page()
421 err = -EINVAL; in ntfs_check_and_load_restart_page()
426 * If the restart page is modified by chkdsk or there are no active in ntfs_check_and_load_restart_page()
431 if (ntfs_is_rstr_record(rp->magic) && in ntfs_check_and_load_restart_page()
432 ra->client_in_use_list != LOGFILE_NO_CLIENT) { in ntfs_check_and_load_restart_page()
434 err = -EINVAL; in ntfs_check_and_load_restart_page()
439 if (ntfs_is_rstr_record(rp->magic)) in ntfs_check_and_load_restart_page()
440 *lsn = sle64_to_cpu(ra->current_lsn); in ntfs_check_and_load_restart_page()
441 else /* if (ntfs_is_chkd_record(rp->magic)) */ in ntfs_check_and_load_restart_page()
442 *lsn = sle64_to_cpu(rp->chkdsk_lsn); in ntfs_check_and_load_restart_page()
455 * ntfs_check_logfile - check the journal for consistency
457 * @rp: [OUT] on success this is a copy of the current restart page
460 * consistent and 'false' if not. On success, the current restart page is
468 * if the $LogFile was created on a system with a different page size to ours
469 * yet and mst deprotection would fail if our page size is smaller.
473 s64 size, pos; in ntfs_check_logfile() local
475 ntfs_volume *vol = NTFS_SB(log_vi->i_sb); in ntfs_check_logfile()
476 struct address_space *mapping = log_vi->i_mapping; in ntfs_check_logfile()
477 struct page *page = NULL; in ntfs_check_logfile() local
489 size = i_size_read(log_vi); in ntfs_check_logfile()
490 /* Make sure the file doesn't exceed the maximum allowed size. */ in ntfs_check_logfile()
491 if (size > MaxLogFileSize) in ntfs_check_logfile()
492 size = MaxLogFileSize; in ntfs_check_logfile()
494 * Truncate size to a multiple of the page cache size or the default in ntfs_check_logfile()
495 * log page size if the page cache size is between the default log page in ntfs_check_logfile()
496 * log page size if the page cache size is between the default log page in ntfs_check_logfile()
497 * size and twice that. in ntfs_check_logfile()
508 log_page_bits = ntfs_ffs(log_page_size) - 1; in ntfs_check_logfile()
509 size &= ~(s64)(log_page_size - 1); in ntfs_check_logfile()
514 if (size < log_page_size * 2 || (size - log_page_size * 2) >> in ntfs_check_logfile()
516 ntfs_error(vol->sb, "$LogFile is too small."); in ntfs_check_logfile()
520 * Read through the file looking for a restart page. Since the restart in ntfs_check_logfile()
521 * page header is at the beginning of a page we only need to search at in ntfs_check_logfile()
522 * what could be the beginning of a page (for each page size) rather in ntfs_check_logfile()
527 for (pos = 0; pos < size; pos <<= 1) { in ntfs_check_logfile()
529 if (!page || page->index != idx) { in ntfs_check_logfile()
530 if (page) in ntfs_check_logfile()
531 ntfs_unmap_page(page); in ntfs_check_logfile()
532 page = ntfs_map_page(mapping, idx); in ntfs_check_logfile()
533 if (IS_ERR(page)) { in ntfs_check_logfile()
534 ntfs_error(vol->sb, "Error mapping $LogFile " in ntfs_check_logfile()
535 "page (index %lu).", idx); in ntfs_check_logfile()
539 kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK); in ntfs_check_logfile()
541 * A non-empty block means the logfile is not empty while an in ntfs_check_logfile()
542 * empty block after a non-empty block has been encountered in ntfs_check_logfile()
550 * A log record page means there cannot be a restart page after in ntfs_check_logfile()
555 /* If not a (modified by chkdsk) restart page, continue. */ in ntfs_check_logfile()
563 * Check the (modified by chkdsk) restart page for consistency in ntfs_check_logfile()
565 * deprotected restart page. in ntfs_check_logfile()
574 * restart page, continue looking for the second one. in ntfs_check_logfile()
582 * restart page, so we can stop looking. in ntfs_check_logfile()
588 * not abort if the restart page was invalid as we might still in ntfs_check_logfile()
591 if (err != -EINVAL) { in ntfs_check_logfile()
592 ntfs_unmap_page(page); in ntfs_check_logfile()
599 if (page) in ntfs_check_logfile()
600 ntfs_unmap_page(page); in ntfs_check_logfile()
609 ntfs_error(vol->sb, "Did not find any restart pages in " in ntfs_check_logfile()
620 ntfs_debug("Using second restart page as it is more " in ntfs_check_logfile()
626 ntfs_debug("Using first restart page as it is more " in ntfs_check_logfile()
646 * ntfs_is_logfile_clean - check in the journal if the volume is clean
648 * @rp: copy of the current restart page
657 * not have any pending, non-check-pointed i/o, i.e. they were completely idle
667 ntfs_volume *vol = NTFS_SB(log_vi->i_sb); in ntfs_is_logfile_clean()
677 if (!ntfs_is_rstr_record(rp->magic) && in ntfs_is_logfile_clean()
678 !ntfs_is_chkd_record(rp->magic)) { in ntfs_is_logfile_clean()
679 ntfs_error(vol->sb, "Restart page buffer is invalid. This is " in ntfs_is_logfile_clean()
685 ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); in ntfs_is_logfile_clean()
691 if (ra->client_in_use_list != LOGFILE_NO_CLIENT && in ntfs_is_logfile_clean()
692 !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { in ntfs_is_logfile_clean()
702 * ntfs_empty_logfile - empty the contents of the $LogFile journal
716 ntfs_volume *vol = log_ni->vol; in ntfs_empty_logfile()
717 struct super_block *sb = vol->sb; in ntfs_empty_logfile()
732 * zapping the page cache pages for the $LogFile/$DATA attribute and in ntfs_empty_logfile()
736 block_size = sb->s_blocksize; in ntfs_empty_logfile()
737 block_size_bits = sb->s_blocksize_bits; in ntfs_empty_logfile()
739 read_lock_irqsave(&log_ni->size_lock, flags); in ntfs_empty_logfile()
740 end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >> in ntfs_empty_logfile()
741 vol->cluster_size_bits; in ntfs_empty_logfile()
742 read_unlock_irqrestore(&log_ni->size_lock, flags); in ntfs_empty_logfile()
743 truncate_inode_pages(log_vi->i_mapping, 0); in ntfs_empty_logfile()
744 down_write(&log_ni->runlist.lock); in ntfs_empty_logfile()
745 rl = log_ni->runlist.rl; in ntfs_empty_logfile()
746 if (unlikely(!rl || vcn < rl->vcn || !rl->length)) { in ntfs_empty_logfile()
751 "%d).", -err); in ntfs_empty_logfile()
754 rl = log_ni->runlist.rl; in ntfs_empty_logfile()
755 BUG_ON(!rl || vcn < rl->vcn || !rl->length); in ntfs_empty_logfile()
758 while (rl->length && vcn >= rl[1].vcn) in ntfs_empty_logfile()
769 lcn = rl->lcn; in ntfs_empty_logfile()
771 vcn = rl->vcn; in ntfs_empty_logfile()
775 if (unlikely(!rl->length || lcn < LCN_HOLE)) in ntfs_empty_logfile()
780 block = lcn << vol->cluster_size_bits >> block_size_bits; in ntfs_empty_logfile()
781 len = rl->length; in ntfs_empty_logfile()
783 len = end_vcn - rl->vcn; in ntfs_empty_logfile()
784 end_block = (lcn + len) << vol->cluster_size_bits >> in ntfs_empty_logfile()
795 bh->b_end_io = end_buffer_write_sync; in ntfs_empty_logfile()
798 memset(bh->b_data, -1, block_size); in ntfs_empty_logfile()
819 } while ((++rl)->vcn < end_vcn); in ntfs_empty_logfile()
820 up_write(&log_ni->runlist.lock); in ntfs_empty_logfile()
829 truncate_inode_pages(log_vi->i_mapping, 0); in ntfs_empty_logfile()
841 err = -EIO; in ntfs_empty_logfile()
843 up_write(&log_ni->runlist.lock); in ntfs_empty_logfile()
845 -err); in ntfs_empty_logfile()