1b46acd6aSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0 2b46acd6aSKonstantin Komarov /* 3b46acd6aSKonstantin Komarov * 4b46acd6aSKonstantin Komarov * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 5b46acd6aSKonstantin Komarov * 6b46acd6aSKonstantin Komarov */ 7b46acd6aSKonstantin Komarov 8b46acd6aSKonstantin Komarov #include <linux/blkdev.h> 9b46acd6aSKonstantin Komarov #include <linux/buffer_head.h> 10b46acd6aSKonstantin Komarov #include <linux/fs.h> 11b46acd6aSKonstantin Komarov #include <linux/hash.h> 12b46acd6aSKonstantin Komarov #include <linux/nls.h> 13b46acd6aSKonstantin Komarov #include <linux/random.h> 14b46acd6aSKonstantin Komarov #include <linux/ratelimit.h> 15b46acd6aSKonstantin Komarov #include <linux/slab.h> 16b46acd6aSKonstantin Komarov 17b46acd6aSKonstantin Komarov #include "debug.h" 18b46acd6aSKonstantin Komarov #include "ntfs.h" 19b46acd6aSKonstantin Komarov #include "ntfs_fs.h" 20b46acd6aSKonstantin Komarov 21b46acd6aSKonstantin Komarov /* 22b46acd6aSKonstantin Komarov * LOG FILE structs 23b46acd6aSKonstantin Komarov */ 24b46acd6aSKonstantin Komarov 25b46acd6aSKonstantin Komarov // clang-format off 26b46acd6aSKonstantin Komarov 27b46acd6aSKonstantin Komarov #define MaxLogFileSize 0x100000000ull 28b46acd6aSKonstantin Komarov #define DefaultLogPageSize 4096 29b46acd6aSKonstantin Komarov #define MinLogRecordPages 0x30 30b46acd6aSKonstantin Komarov 31b46acd6aSKonstantin Komarov struct RESTART_HDR { 32b46acd6aSKonstantin Komarov struct NTFS_RECORD_HEADER rhdr; // 'RSTR' 33*e8b8e97fSKari Argillander __le32 sys_page_size; // 0x10: Page size of the system which initialized the log. 34*e8b8e97fSKari Argillander __le32 page_size; // 0x14: Log page size used for this log file. 35b46acd6aSKonstantin Komarov __le16 ra_off; // 0x18: 36b46acd6aSKonstantin Komarov __le16 minor_ver; // 0x1A: 37b46acd6aSKonstantin Komarov __le16 major_ver; // 0x1C: 38b46acd6aSKonstantin Komarov __le16 fixups[]; 39b46acd6aSKonstantin Komarov }; 40b46acd6aSKonstantin Komarov 41b46acd6aSKonstantin Komarov #define LFS_NO_CLIENT 0xffff 42b46acd6aSKonstantin Komarov #define LFS_NO_CLIENT_LE cpu_to_le16(0xffff) 43b46acd6aSKonstantin Komarov 44b46acd6aSKonstantin Komarov struct CLIENT_REC { 45b46acd6aSKonstantin Komarov __le64 oldest_lsn; 46b46acd6aSKonstantin Komarov __le64 restart_lsn; // 0x08: 47b46acd6aSKonstantin Komarov __le16 prev_client; // 0x10: 48b46acd6aSKonstantin Komarov __le16 next_client; // 0x12: 49b46acd6aSKonstantin Komarov __le16 seq_num; // 0x14: 50*e8b8e97fSKari Argillander u8 align[6]; // 0x16: 51*e8b8e97fSKari Argillander __le32 name_bytes; // 0x1C: In bytes. 52*e8b8e97fSKari Argillander __le16 name[32]; // 0x20: Name of client. 53b46acd6aSKonstantin Komarov }; 54b46acd6aSKonstantin Komarov 55b46acd6aSKonstantin Komarov static_assert(sizeof(struct CLIENT_REC) == 0x60); 56b46acd6aSKonstantin Komarov 57b46acd6aSKonstantin Komarov /* Two copies of these will exist at the beginning of the log file */ 58b46acd6aSKonstantin Komarov struct RESTART_AREA { 59*e8b8e97fSKari Argillander __le64 current_lsn; // 0x00: Current logical end of log file. 60*e8b8e97fSKari Argillander __le16 log_clients; // 0x08: Maximum number of clients. 61*e8b8e97fSKari Argillander __le16 client_idx[2]; // 0x0A: Free/use index into the client record arrays. 62*e8b8e97fSKari Argillander __le16 flags; // 0x0E: See RESTART_SINGLE_PAGE_IO. 63*e8b8e97fSKari Argillander __le32 seq_num_bits; // 0x10: The number of bits in sequence number. 64b46acd6aSKonstantin Komarov __le16 ra_len; // 0x14: 65b46acd6aSKonstantin Komarov __le16 client_off; // 0x16: 66b46acd6aSKonstantin Komarov __le64 l_size; // 0x18: Usable log file size. 67b46acd6aSKonstantin Komarov __le32 last_lsn_data_len; // 0x20: 68*e8b8e97fSKari Argillander __le16 rec_hdr_len; // 0x24: Log page data offset. 69*e8b8e97fSKari Argillander __le16 data_off; // 0x26: Log page data length. 70b46acd6aSKonstantin Komarov __le32 open_log_count; // 0x28: 71b46acd6aSKonstantin Komarov __le32 align[5]; // 0x2C: 72b46acd6aSKonstantin Komarov struct CLIENT_REC clients[]; // 0x40: 73b46acd6aSKonstantin Komarov }; 74b46acd6aSKonstantin Komarov 75b46acd6aSKonstantin Komarov struct LOG_REC_HDR { 76b46acd6aSKonstantin Komarov __le16 redo_op; // 0x00: NTFS_LOG_OPERATION 77b46acd6aSKonstantin Komarov __le16 undo_op; // 0x02: NTFS_LOG_OPERATION 78*e8b8e97fSKari Argillander __le16 redo_off; // 0x04: Offset to Redo record. 79*e8b8e97fSKari Argillander __le16 redo_len; // 0x06: Redo length. 80*e8b8e97fSKari Argillander __le16 undo_off; // 0x08: Offset to Undo record. 81*e8b8e97fSKari Argillander __le16 undo_len; // 0x0A: Undo length. 82b46acd6aSKonstantin Komarov __le16 target_attr; // 0x0C: 83b46acd6aSKonstantin Komarov __le16 lcns_follow; // 0x0E: 84b46acd6aSKonstantin Komarov __le16 record_off; // 0x10: 85b46acd6aSKonstantin Komarov __le16 attr_off; // 0x12: 86b46acd6aSKonstantin Komarov __le16 cluster_off; // 0x14: 87b46acd6aSKonstantin Komarov __le16 reserved; // 0x16: 88b46acd6aSKonstantin Komarov __le64 target_vcn; // 0x18: 89b46acd6aSKonstantin Komarov __le64 page_lcns[]; // 0x20: 90b46acd6aSKonstantin Komarov }; 91b46acd6aSKonstantin Komarov 92b46acd6aSKonstantin Komarov static_assert(sizeof(struct LOG_REC_HDR) == 0x20); 93b46acd6aSKonstantin Komarov 94b46acd6aSKonstantin Komarov #define RESTART_ENTRY_ALLOCATED 0xFFFFFFFF 95b46acd6aSKonstantin Komarov #define RESTART_ENTRY_ALLOCATED_LE cpu_to_le32(0xFFFFFFFF) 96b46acd6aSKonstantin Komarov 97b46acd6aSKonstantin Komarov struct RESTART_TABLE { 98b46acd6aSKonstantin Komarov __le16 size; // 0x00: In bytes 99*e8b8e97fSKari Argillander __le16 used; // 0x02: Entries 100*e8b8e97fSKari Argillander __le16 total; // 0x04: Entries 101b46acd6aSKonstantin Komarov __le16 res[3]; // 0x06: 102b46acd6aSKonstantin Komarov __le32 free_goal; // 0x0C: 103*e8b8e97fSKari Argillander __le32 first_free; // 0x10: 104*e8b8e97fSKari Argillander __le32 last_free; // 0x14: 105b46acd6aSKonstantin Komarov 106b46acd6aSKonstantin Komarov }; 107b46acd6aSKonstantin Komarov 108b46acd6aSKonstantin Komarov static_assert(sizeof(struct RESTART_TABLE) == 0x18); 109b46acd6aSKonstantin Komarov 110b46acd6aSKonstantin Komarov struct ATTR_NAME_ENTRY { 111*e8b8e97fSKari Argillander __le16 off; // Offset in the Open attribute Table. 112b46acd6aSKonstantin Komarov __le16 name_bytes; 113b46acd6aSKonstantin Komarov __le16 name[]; 114b46acd6aSKonstantin Komarov }; 115b46acd6aSKonstantin Komarov 116b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY { 117b46acd6aSKonstantin Komarov __le32 next; // 0x00: RESTART_ENTRY_ALLOCATED if allocated 118b46acd6aSKonstantin Komarov __le32 bytes_per_index; // 0x04: 119b46acd6aSKonstantin Komarov enum ATTR_TYPE type; // 0x08: 120b46acd6aSKonstantin Komarov u8 is_dirty_pages; // 0x0C: 121b46acd6aSKonstantin Komarov u8 is_attr_name; // 0x0B: Faked field to manage 'ptr' 122b46acd6aSKonstantin Komarov u8 name_len; // 0x0C: Faked field to manage 'ptr' 123b46acd6aSKonstantin Komarov u8 res; 124b46acd6aSKonstantin Komarov struct MFT_REF ref; // 0x10: File Reference of file containing attribute 125b46acd6aSKonstantin Komarov __le64 open_record_lsn; // 0x18: 126b46acd6aSKonstantin Komarov void *ptr; // 0x20: 127b46acd6aSKonstantin Komarov }; 128b46acd6aSKonstantin Komarov 129b46acd6aSKonstantin Komarov /* 32 bit version of 'struct OPEN_ATTR_ENRTY' */ 130b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY_32 { 131b46acd6aSKonstantin Komarov __le32 next; // 0x00: RESTART_ENTRY_ALLOCATED if allocated 132b46acd6aSKonstantin Komarov __le32 ptr; // 0x04: 133b46acd6aSKonstantin Komarov struct MFT_REF ref; // 0x08: 134b46acd6aSKonstantin Komarov __le64 open_record_lsn; // 0x10: 135b46acd6aSKonstantin Komarov u8 is_dirty_pages; // 0x18: 136*e8b8e97fSKari Argillander u8 is_attr_name; // 0x19: 137b46acd6aSKonstantin Komarov u8 res1[2]; 138b46acd6aSKonstantin Komarov enum ATTR_TYPE type; // 0x1C: 139*e8b8e97fSKari Argillander u8 name_len; // 0x20: In wchar 140b46acd6aSKonstantin Komarov u8 res2[3]; 141b46acd6aSKonstantin Komarov __le32 AttributeName; // 0x24: 142b46acd6aSKonstantin Komarov __le32 bytes_per_index; // 0x28: 143b46acd6aSKonstantin Komarov }; 144b46acd6aSKonstantin Komarov 145b46acd6aSKonstantin Komarov #define SIZEOF_OPENATTRIBUTEENTRY0 0x2c 146b46acd6aSKonstantin Komarov // static_assert( 0x2C == sizeof(struct OPEN_ATTR_ENRTY_32) ); 147b46acd6aSKonstantin Komarov static_assert(sizeof(struct OPEN_ATTR_ENRTY) < SIZEOF_OPENATTRIBUTEENTRY0); 148b46acd6aSKonstantin Komarov 149b46acd6aSKonstantin Komarov /* 150*e8b8e97fSKari Argillander * One entry exists in the Dirty Pages Table for each page which is dirty at 151*e8b8e97fSKari Argillander * the time the Restart Area is written. 152b46acd6aSKonstantin Komarov */ 153b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY { 154b46acd6aSKonstantin Komarov __le32 next; // 0x00: RESTART_ENTRY_ALLOCATED if allocated 155b46acd6aSKonstantin Komarov __le32 target_attr; // 0x04: Index into the Open attribute Table 156b46acd6aSKonstantin Komarov __le32 transfer_len; // 0x08: 157b46acd6aSKonstantin Komarov __le32 lcns_follow; // 0x0C: 158b46acd6aSKonstantin Komarov __le64 vcn; // 0x10: Vcn of dirty page 159b46acd6aSKonstantin Komarov __le64 oldest_lsn; // 0x18: 160b46acd6aSKonstantin Komarov __le64 page_lcns[]; // 0x20: 161b46acd6aSKonstantin Komarov }; 162b46acd6aSKonstantin Komarov 163b46acd6aSKonstantin Komarov static_assert(sizeof(struct DIR_PAGE_ENTRY) == 0x20); 164b46acd6aSKonstantin Komarov 165b46acd6aSKonstantin Komarov /* 32 bit version of 'struct DIR_PAGE_ENTRY' */ 166b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY_32 { 167b46acd6aSKonstantin Komarov __le32 next; // 0x00: RESTART_ENTRY_ALLOCATED if allocated 168b46acd6aSKonstantin Komarov __le32 target_attr; // 0x04: Index into the Open attribute Table 169b46acd6aSKonstantin Komarov __le32 transfer_len; // 0x08: 170b46acd6aSKonstantin Komarov __le32 lcns_follow; // 0x0C: 171b46acd6aSKonstantin Komarov __le32 reserved; // 0x10: 172b46acd6aSKonstantin Komarov __le32 vcn_low; // 0x14: Vcn of dirty page 173b46acd6aSKonstantin Komarov __le32 vcn_hi; // 0x18: Vcn of dirty page 174b46acd6aSKonstantin Komarov __le32 oldest_lsn_low; // 0x1C: 175b46acd6aSKonstantin Komarov __le32 oldest_lsn_hi; // 0x1C: 176b46acd6aSKonstantin Komarov __le32 page_lcns_low; // 0x24: 177b46acd6aSKonstantin Komarov __le32 page_lcns_hi; // 0x24: 178b46acd6aSKonstantin Komarov }; 179b46acd6aSKonstantin Komarov 180b46acd6aSKonstantin Komarov static_assert(offsetof(struct DIR_PAGE_ENTRY_32, vcn_low) == 0x14); 181b46acd6aSKonstantin Komarov static_assert(sizeof(struct DIR_PAGE_ENTRY_32) == 0x2c); 182b46acd6aSKonstantin Komarov 183b46acd6aSKonstantin Komarov enum transact_state { 184b46acd6aSKonstantin Komarov TransactionUninitialized = 0, 185b46acd6aSKonstantin Komarov TransactionActive, 186b46acd6aSKonstantin Komarov TransactionPrepared, 187b46acd6aSKonstantin Komarov TransactionCommitted 188b46acd6aSKonstantin Komarov }; 189b46acd6aSKonstantin Komarov 190b46acd6aSKonstantin Komarov struct TRANSACTION_ENTRY { 191b46acd6aSKonstantin Komarov __le32 next; // 0x00: RESTART_ENTRY_ALLOCATED if allocated 192b46acd6aSKonstantin Komarov u8 transact_state; // 0x04: 193b46acd6aSKonstantin Komarov u8 reserved[3]; // 0x05: 194b46acd6aSKonstantin Komarov __le64 first_lsn; // 0x08: 195b46acd6aSKonstantin Komarov __le64 prev_lsn; // 0x10: 196b46acd6aSKonstantin Komarov __le64 undo_next_lsn; // 0x18: 197b46acd6aSKonstantin Komarov __le32 undo_records; // 0x20: Number of undo log records pending abort 198b46acd6aSKonstantin Komarov __le32 undo_len; // 0x24: Total undo size 199b46acd6aSKonstantin Komarov }; 200b46acd6aSKonstantin Komarov 201b46acd6aSKonstantin Komarov static_assert(sizeof(struct TRANSACTION_ENTRY) == 0x28); 202b46acd6aSKonstantin Komarov 203b46acd6aSKonstantin Komarov struct NTFS_RESTART { 204b46acd6aSKonstantin Komarov __le32 major_ver; // 0x00: 205b46acd6aSKonstantin Komarov __le32 minor_ver; // 0x04: 206b46acd6aSKonstantin Komarov __le64 check_point_start; // 0x08: 207b46acd6aSKonstantin Komarov __le64 open_attr_table_lsn; // 0x10: 208b46acd6aSKonstantin Komarov __le64 attr_names_lsn; // 0x18: 209b46acd6aSKonstantin Komarov __le64 dirty_pages_table_lsn; // 0x20: 210b46acd6aSKonstantin Komarov __le64 transact_table_lsn; // 0x28: 211b46acd6aSKonstantin Komarov __le32 open_attr_len; // 0x30: In bytes 212b46acd6aSKonstantin Komarov __le32 attr_names_len; // 0x34: In bytes 213b46acd6aSKonstantin Komarov __le32 dirty_pages_len; // 0x38: In bytes 214b46acd6aSKonstantin Komarov __le32 transact_table_len; // 0x3C: In bytes 215b46acd6aSKonstantin Komarov }; 216b46acd6aSKonstantin Komarov 217b46acd6aSKonstantin Komarov static_assert(sizeof(struct NTFS_RESTART) == 0x40); 218b46acd6aSKonstantin Komarov 219b46acd6aSKonstantin Komarov struct NEW_ATTRIBUTE_SIZES { 220b46acd6aSKonstantin Komarov __le64 alloc_size; 221b46acd6aSKonstantin Komarov __le64 valid_size; 222b46acd6aSKonstantin Komarov __le64 data_size; 223b46acd6aSKonstantin Komarov __le64 total_size; 224b46acd6aSKonstantin Komarov }; 225b46acd6aSKonstantin Komarov 226b46acd6aSKonstantin Komarov struct BITMAP_RANGE { 227b46acd6aSKonstantin Komarov __le32 bitmap_off; 228b46acd6aSKonstantin Komarov __le32 bits; 229b46acd6aSKonstantin Komarov }; 230b46acd6aSKonstantin Komarov 231b46acd6aSKonstantin Komarov struct LCN_RANGE { 232b46acd6aSKonstantin Komarov __le64 lcn; 233b46acd6aSKonstantin Komarov __le64 len; 234b46acd6aSKonstantin Komarov }; 235b46acd6aSKonstantin Komarov 236*e8b8e97fSKari Argillander /* The following type defines the different log record types. */ 237b46acd6aSKonstantin Komarov #define LfsClientRecord cpu_to_le32(1) 238b46acd6aSKonstantin Komarov #define LfsClientRestart cpu_to_le32(2) 239b46acd6aSKonstantin Komarov 240*e8b8e97fSKari Argillander /* This is used to uniquely identify a client for a particular log file. */ 241b46acd6aSKonstantin Komarov struct CLIENT_ID { 242b46acd6aSKonstantin Komarov __le16 seq_num; 243b46acd6aSKonstantin Komarov __le16 client_idx; 244b46acd6aSKonstantin Komarov }; 245b46acd6aSKonstantin Komarov 246*e8b8e97fSKari Argillander /* This is the header that begins every Log Record in the log file. */ 247b46acd6aSKonstantin Komarov struct LFS_RECORD_HDR { 248b46acd6aSKonstantin Komarov __le64 this_lsn; // 0x00: 249b46acd6aSKonstantin Komarov __le64 client_prev_lsn; // 0x08: 250b46acd6aSKonstantin Komarov __le64 client_undo_next_lsn; // 0x10: 251b46acd6aSKonstantin Komarov __le32 client_data_len; // 0x18: 252*e8b8e97fSKari Argillander struct CLIENT_ID client; // 0x1C: Owner of this log record. 253*e8b8e97fSKari Argillander __le32 record_type; // 0x20: LfsClientRecord or LfsClientRestart. 254b46acd6aSKonstantin Komarov __le32 transact_id; // 0x24: 255b46acd6aSKonstantin Komarov __le16 flags; // 0x28: LOG_RECORD_MULTI_PAGE 256b46acd6aSKonstantin Komarov u8 align[6]; // 0x2A: 257b46acd6aSKonstantin Komarov }; 258b46acd6aSKonstantin Komarov 259b46acd6aSKonstantin Komarov #define LOG_RECORD_MULTI_PAGE cpu_to_le16(1) 260b46acd6aSKonstantin Komarov 261b46acd6aSKonstantin Komarov static_assert(sizeof(struct LFS_RECORD_HDR) == 0x30); 262b46acd6aSKonstantin Komarov 263b46acd6aSKonstantin Komarov struct LFS_RECORD { 264*e8b8e97fSKari Argillander __le16 next_record_off; // 0x00: Offset of the free space in the page, 265b46acd6aSKonstantin Komarov u8 align[6]; // 0x02: 266*e8b8e97fSKari Argillander __le64 last_end_lsn; // 0x08: lsn for the last log record which ends on the page, 267b46acd6aSKonstantin Komarov }; 268b46acd6aSKonstantin Komarov 269b46acd6aSKonstantin Komarov static_assert(sizeof(struct LFS_RECORD) == 0x10); 270b46acd6aSKonstantin Komarov 271b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR { 272b46acd6aSKonstantin Komarov struct NTFS_RECORD_HEADER rhdr; // 'RCRD' 273b46acd6aSKonstantin Komarov __le32 rflags; // 0x10: See LOG_PAGE_LOG_RECORD_END 274b46acd6aSKonstantin Komarov __le16 page_count; // 0x14: 275b46acd6aSKonstantin Komarov __le16 page_pos; // 0x16: 276*e8b8e97fSKari Argillander struct LFS_RECORD record_hdr; // 0x18: 277*e8b8e97fSKari Argillander __le16 fixups[10]; // 0x28: 278*e8b8e97fSKari Argillander __le32 file_off; // 0x3c: Used when major version >= 2 279b46acd6aSKonstantin Komarov }; 280b46acd6aSKonstantin Komarov 281b46acd6aSKonstantin Komarov // clang-format on 282b46acd6aSKonstantin Komarov 283*e8b8e97fSKari Argillander // Page contains the end of a log record. 284b46acd6aSKonstantin Komarov #define LOG_PAGE_LOG_RECORD_END cpu_to_le32(0x00000001) 285b46acd6aSKonstantin Komarov 286b46acd6aSKonstantin Komarov static inline bool is_log_record_end(const struct RECORD_PAGE_HDR *hdr) 287b46acd6aSKonstantin Komarov { 288b46acd6aSKonstantin Komarov return hdr->rflags & LOG_PAGE_LOG_RECORD_END; 289b46acd6aSKonstantin Komarov } 290b46acd6aSKonstantin Komarov 291b46acd6aSKonstantin Komarov static_assert(offsetof(struct RECORD_PAGE_HDR, file_off) == 0x3c); 292b46acd6aSKonstantin Komarov 293b46acd6aSKonstantin Komarov /* 294b46acd6aSKonstantin Komarov * END of NTFS LOG structures 295b46acd6aSKonstantin Komarov */ 296b46acd6aSKonstantin Komarov 297*e8b8e97fSKari Argillander /* Define some tuning parameters to keep the restart tables a reasonable size. */ 298b46acd6aSKonstantin Komarov #define INITIAL_NUMBER_TRANSACTIONS 5 299b46acd6aSKonstantin Komarov 300b46acd6aSKonstantin Komarov enum NTFS_LOG_OPERATION { 301b46acd6aSKonstantin Komarov 302b46acd6aSKonstantin Komarov Noop = 0x00, 303b46acd6aSKonstantin Komarov CompensationLogRecord = 0x01, 304b46acd6aSKonstantin Komarov InitializeFileRecordSegment = 0x02, 305b46acd6aSKonstantin Komarov DeallocateFileRecordSegment = 0x03, 306b46acd6aSKonstantin Komarov WriteEndOfFileRecordSegment = 0x04, 307b46acd6aSKonstantin Komarov CreateAttribute = 0x05, 308b46acd6aSKonstantin Komarov DeleteAttribute = 0x06, 309b46acd6aSKonstantin Komarov UpdateResidentValue = 0x07, 310b46acd6aSKonstantin Komarov UpdateNonresidentValue = 0x08, 311b46acd6aSKonstantin Komarov UpdateMappingPairs = 0x09, 312b46acd6aSKonstantin Komarov DeleteDirtyClusters = 0x0A, 313b46acd6aSKonstantin Komarov SetNewAttributeSizes = 0x0B, 314b46acd6aSKonstantin Komarov AddIndexEntryRoot = 0x0C, 315b46acd6aSKonstantin Komarov DeleteIndexEntryRoot = 0x0D, 316b46acd6aSKonstantin Komarov AddIndexEntryAllocation = 0x0E, 317b46acd6aSKonstantin Komarov DeleteIndexEntryAllocation = 0x0F, 318b46acd6aSKonstantin Komarov WriteEndOfIndexBuffer = 0x10, 319b46acd6aSKonstantin Komarov SetIndexEntryVcnRoot = 0x11, 320b46acd6aSKonstantin Komarov SetIndexEntryVcnAllocation = 0x12, 321b46acd6aSKonstantin Komarov UpdateFileNameRoot = 0x13, 322b46acd6aSKonstantin Komarov UpdateFileNameAllocation = 0x14, 323b46acd6aSKonstantin Komarov SetBitsInNonresidentBitMap = 0x15, 324b46acd6aSKonstantin Komarov ClearBitsInNonresidentBitMap = 0x16, 325b46acd6aSKonstantin Komarov HotFix = 0x17, 326b46acd6aSKonstantin Komarov EndTopLevelAction = 0x18, 327b46acd6aSKonstantin Komarov PrepareTransaction = 0x19, 328b46acd6aSKonstantin Komarov CommitTransaction = 0x1A, 329b46acd6aSKonstantin Komarov ForgetTransaction = 0x1B, 330b46acd6aSKonstantin Komarov OpenNonresidentAttribute = 0x1C, 331b46acd6aSKonstantin Komarov OpenAttributeTableDump = 0x1D, 332b46acd6aSKonstantin Komarov AttributeNamesDump = 0x1E, 333b46acd6aSKonstantin Komarov DirtyPageTableDump = 0x1F, 334b46acd6aSKonstantin Komarov TransactionTableDump = 0x20, 335b46acd6aSKonstantin Komarov UpdateRecordDataRoot = 0x21, 336b46acd6aSKonstantin Komarov UpdateRecordDataAllocation = 0x22, 337b46acd6aSKonstantin Komarov 338b46acd6aSKonstantin Komarov UpdateRelativeDataInIndex = 339b46acd6aSKonstantin Komarov 0x23, // NtOfsRestartUpdateRelativeDataInIndex 340b46acd6aSKonstantin Komarov UpdateRelativeDataInIndex2 = 0x24, 341b46acd6aSKonstantin Komarov ZeroEndOfFileRecord = 0x25, 342b46acd6aSKonstantin Komarov }; 343b46acd6aSKonstantin Komarov 344b46acd6aSKonstantin Komarov /* 345*e8b8e97fSKari Argillander * Array for log records which require a target attribute. 346*e8b8e97fSKari Argillander * A true indicates that the corresponding restart operation 347*e8b8e97fSKari Argillander * requires a target attribute. 348b46acd6aSKonstantin Komarov */ 349b46acd6aSKonstantin Komarov static const u8 AttributeRequired[] = { 350b46acd6aSKonstantin Komarov 0xFC, 0xFB, 0xFF, 0x10, 0x06, 351b46acd6aSKonstantin Komarov }; 352b46acd6aSKonstantin Komarov 353b46acd6aSKonstantin Komarov static inline bool is_target_required(u16 op) 354b46acd6aSKonstantin Komarov { 355b46acd6aSKonstantin Komarov bool ret = op <= UpdateRecordDataAllocation && 356b46acd6aSKonstantin Komarov (AttributeRequired[op >> 3] >> (op & 7) & 1); 357b46acd6aSKonstantin Komarov return ret; 358b46acd6aSKonstantin Komarov } 359b46acd6aSKonstantin Komarov 360b46acd6aSKonstantin Komarov static inline bool can_skip_action(enum NTFS_LOG_OPERATION op) 361b46acd6aSKonstantin Komarov { 362b46acd6aSKonstantin Komarov switch (op) { 363b46acd6aSKonstantin Komarov case Noop: 364b46acd6aSKonstantin Komarov case DeleteDirtyClusters: 365b46acd6aSKonstantin Komarov case HotFix: 366b46acd6aSKonstantin Komarov case EndTopLevelAction: 367b46acd6aSKonstantin Komarov case PrepareTransaction: 368b46acd6aSKonstantin Komarov case CommitTransaction: 369b46acd6aSKonstantin Komarov case ForgetTransaction: 370b46acd6aSKonstantin Komarov case CompensationLogRecord: 371b46acd6aSKonstantin Komarov case OpenNonresidentAttribute: 372b46acd6aSKonstantin Komarov case OpenAttributeTableDump: 373b46acd6aSKonstantin Komarov case AttributeNamesDump: 374b46acd6aSKonstantin Komarov case DirtyPageTableDump: 375b46acd6aSKonstantin Komarov case TransactionTableDump: 376b46acd6aSKonstantin Komarov return true; 377b46acd6aSKonstantin Komarov default: 378b46acd6aSKonstantin Komarov return false; 379b46acd6aSKonstantin Komarov } 380b46acd6aSKonstantin Komarov } 381b46acd6aSKonstantin Komarov 382b46acd6aSKonstantin Komarov enum { lcb_ctx_undo_next, lcb_ctx_prev, lcb_ctx_next }; 383b46acd6aSKonstantin Komarov 384*e8b8e97fSKari Argillander /* Bytes per restart table. */ 385b46acd6aSKonstantin Komarov static inline u32 bytes_per_rt(const struct RESTART_TABLE *rt) 386b46acd6aSKonstantin Komarov { 387b46acd6aSKonstantin Komarov return le16_to_cpu(rt->used) * le16_to_cpu(rt->size) + 388b46acd6aSKonstantin Komarov sizeof(struct RESTART_TABLE); 389b46acd6aSKonstantin Komarov } 390b46acd6aSKonstantin Komarov 391*e8b8e97fSKari Argillander /* Log record length. */ 392b46acd6aSKonstantin Komarov static inline u32 lrh_length(const struct LOG_REC_HDR *lr) 393b46acd6aSKonstantin Komarov { 394b46acd6aSKonstantin Komarov u16 t16 = le16_to_cpu(lr->lcns_follow); 395b46acd6aSKonstantin Komarov 396b46acd6aSKonstantin Komarov return struct_size(lr, page_lcns, max_t(u16, 1, t16)); 397b46acd6aSKonstantin Komarov } 398b46acd6aSKonstantin Komarov 399b46acd6aSKonstantin Komarov struct lcb { 400*e8b8e97fSKari Argillander struct LFS_RECORD_HDR *lrh; // Log record header of the current lsn. 401b46acd6aSKonstantin Komarov struct LOG_REC_HDR *log_rec; 402b46acd6aSKonstantin Komarov u32 ctx_mode; // lcb_ctx_undo_next/lcb_ctx_prev/lcb_ctx_next 403b46acd6aSKonstantin Komarov struct CLIENT_ID client; 404*e8b8e97fSKari Argillander bool alloc; // If true the we should deallocate 'log_rec'. 405b46acd6aSKonstantin Komarov }; 406b46acd6aSKonstantin Komarov 407b46acd6aSKonstantin Komarov static void lcb_put(struct lcb *lcb) 408b46acd6aSKonstantin Komarov { 409b46acd6aSKonstantin Komarov if (lcb->alloc) 410195c52bdSKari Argillander kfree(lcb->log_rec); 411195c52bdSKari Argillander kfree(lcb->lrh); 412195c52bdSKari Argillander kfree(lcb); 413b46acd6aSKonstantin Komarov } 414b46acd6aSKonstantin Komarov 415*e8b8e97fSKari Argillander /* Find the oldest lsn from active clients. */ 416b46acd6aSKonstantin Komarov static inline void oldest_client_lsn(const struct CLIENT_REC *ca, 417b46acd6aSKonstantin Komarov __le16 next_client, u64 *oldest_lsn) 418b46acd6aSKonstantin Komarov { 419b46acd6aSKonstantin Komarov while (next_client != LFS_NO_CLIENT_LE) { 420b46acd6aSKonstantin Komarov const struct CLIENT_REC *cr = ca + le16_to_cpu(next_client); 421b46acd6aSKonstantin Komarov u64 lsn = le64_to_cpu(cr->oldest_lsn); 422b46acd6aSKonstantin Komarov 423*e8b8e97fSKari Argillander /* Ignore this block if it's oldest lsn is 0. */ 424b46acd6aSKonstantin Komarov if (lsn && lsn < *oldest_lsn) 425b46acd6aSKonstantin Komarov *oldest_lsn = lsn; 426b46acd6aSKonstantin Komarov 427b46acd6aSKonstantin Komarov next_client = cr->next_client; 428b46acd6aSKonstantin Komarov } 429b46acd6aSKonstantin Komarov } 430b46acd6aSKonstantin Komarov 431b46acd6aSKonstantin Komarov static inline bool is_rst_page_hdr_valid(u32 file_off, 432b46acd6aSKonstantin Komarov const struct RESTART_HDR *rhdr) 433b46acd6aSKonstantin Komarov { 434b46acd6aSKonstantin Komarov u32 sys_page = le32_to_cpu(rhdr->sys_page_size); 435b46acd6aSKonstantin Komarov u32 page_size = le32_to_cpu(rhdr->page_size); 436b46acd6aSKonstantin Komarov u32 end_usa; 437b46acd6aSKonstantin Komarov u16 ro; 438b46acd6aSKonstantin Komarov 439b46acd6aSKonstantin Komarov if (sys_page < SECTOR_SIZE || page_size < SECTOR_SIZE || 440b46acd6aSKonstantin Komarov sys_page & (sys_page - 1) || page_size & (page_size - 1)) { 441b46acd6aSKonstantin Komarov return false; 442b46acd6aSKonstantin Komarov } 443b46acd6aSKonstantin Komarov 444*e8b8e97fSKari Argillander /* Check that if the file offset isn't 0, it is the system page size. */ 445b46acd6aSKonstantin Komarov if (file_off && file_off != sys_page) 446b46acd6aSKonstantin Komarov return false; 447b46acd6aSKonstantin Komarov 448*e8b8e97fSKari Argillander /* Check support version 1.1+. */ 449b46acd6aSKonstantin Komarov if (le16_to_cpu(rhdr->major_ver) <= 1 && !rhdr->minor_ver) 450b46acd6aSKonstantin Komarov return false; 451b46acd6aSKonstantin Komarov 452b46acd6aSKonstantin Komarov if (le16_to_cpu(rhdr->major_ver) > 2) 453b46acd6aSKonstantin Komarov return false; 454b46acd6aSKonstantin Komarov 455b46acd6aSKonstantin Komarov ro = le16_to_cpu(rhdr->ra_off); 456fa3cacf5SKari Argillander if (!IS_ALIGNED(ro, 8) || ro > sys_page) 457b46acd6aSKonstantin Komarov return false; 458b46acd6aSKonstantin Komarov 459b46acd6aSKonstantin Komarov end_usa = ((sys_page >> SECTOR_SHIFT) + 1) * sizeof(short); 460b46acd6aSKonstantin Komarov end_usa += le16_to_cpu(rhdr->rhdr.fix_off); 461b46acd6aSKonstantin Komarov 462b46acd6aSKonstantin Komarov if (ro < end_usa) 463b46acd6aSKonstantin Komarov return false; 464b46acd6aSKonstantin Komarov 465b46acd6aSKonstantin Komarov return true; 466b46acd6aSKonstantin Komarov } 467b46acd6aSKonstantin Komarov 468b46acd6aSKonstantin Komarov static inline bool is_rst_area_valid(const struct RESTART_HDR *rhdr) 469b46acd6aSKonstantin Komarov { 470b46acd6aSKonstantin Komarov const struct RESTART_AREA *ra; 471b46acd6aSKonstantin Komarov u16 cl, fl, ul; 472b46acd6aSKonstantin Komarov u32 off, l_size, file_dat_bits, file_size_round; 473b46acd6aSKonstantin Komarov u16 ro = le16_to_cpu(rhdr->ra_off); 474b46acd6aSKonstantin Komarov u32 sys_page = le32_to_cpu(rhdr->sys_page_size); 475b46acd6aSKonstantin Komarov 476b46acd6aSKonstantin Komarov if (ro + offsetof(struct RESTART_AREA, l_size) > 477b46acd6aSKonstantin Komarov SECTOR_SIZE - sizeof(short)) 478b46acd6aSKonstantin Komarov return false; 479b46acd6aSKonstantin Komarov 480b46acd6aSKonstantin Komarov ra = Add2Ptr(rhdr, ro); 481b46acd6aSKonstantin Komarov cl = le16_to_cpu(ra->log_clients); 482b46acd6aSKonstantin Komarov 483b46acd6aSKonstantin Komarov if (cl > 1) 484b46acd6aSKonstantin Komarov return false; 485b46acd6aSKonstantin Komarov 486b46acd6aSKonstantin Komarov off = le16_to_cpu(ra->client_off); 487b46acd6aSKonstantin Komarov 488fa3cacf5SKari Argillander if (!IS_ALIGNED(off, 8) || ro + off > SECTOR_SIZE - sizeof(short)) 489b46acd6aSKonstantin Komarov return false; 490b46acd6aSKonstantin Komarov 491b46acd6aSKonstantin Komarov off += cl * sizeof(struct CLIENT_REC); 492b46acd6aSKonstantin Komarov 493b46acd6aSKonstantin Komarov if (off > sys_page) 494b46acd6aSKonstantin Komarov return false; 495b46acd6aSKonstantin Komarov 496b46acd6aSKonstantin Komarov /* 497b46acd6aSKonstantin Komarov * Check the restart length field and whether the entire 498*e8b8e97fSKari Argillander * restart area is contained that length. 499b46acd6aSKonstantin Komarov */ 500b46acd6aSKonstantin Komarov if (le16_to_cpu(rhdr->ra_off) + le16_to_cpu(ra->ra_len) > sys_page || 501b46acd6aSKonstantin Komarov off > le16_to_cpu(ra->ra_len)) { 502b46acd6aSKonstantin Komarov return false; 503b46acd6aSKonstantin Komarov } 504b46acd6aSKonstantin Komarov 505b46acd6aSKonstantin Komarov /* 506b46acd6aSKonstantin Komarov * As a final check make sure that the use list and the free list 507*e8b8e97fSKari Argillander * are either empty or point to a valid client. 508b46acd6aSKonstantin Komarov */ 509b46acd6aSKonstantin Komarov fl = le16_to_cpu(ra->client_idx[0]); 510b46acd6aSKonstantin Komarov ul = le16_to_cpu(ra->client_idx[1]); 511b46acd6aSKonstantin Komarov if ((fl != LFS_NO_CLIENT && fl >= cl) || 512b46acd6aSKonstantin Komarov (ul != LFS_NO_CLIENT && ul >= cl)) 513b46acd6aSKonstantin Komarov return false; 514b46acd6aSKonstantin Komarov 515*e8b8e97fSKari Argillander /* Make sure the sequence number bits match the log file size. */ 516b46acd6aSKonstantin Komarov l_size = le64_to_cpu(ra->l_size); 517b46acd6aSKonstantin Komarov 518b46acd6aSKonstantin Komarov file_dat_bits = sizeof(u64) * 8 - le32_to_cpu(ra->seq_num_bits); 519b46acd6aSKonstantin Komarov file_size_round = 1u << (file_dat_bits + 3); 520b46acd6aSKonstantin Komarov if (file_size_round != l_size && 521b46acd6aSKonstantin Komarov (file_size_round < l_size || (file_size_round / 2) > l_size)) { 522b46acd6aSKonstantin Komarov return false; 523b46acd6aSKonstantin Komarov } 524b46acd6aSKonstantin Komarov 525*e8b8e97fSKari Argillander /* The log page data offset and record header length must be quad-aligned. */ 526fa3cacf5SKari Argillander if (!IS_ALIGNED(le16_to_cpu(ra->data_off), 8) || 527fa3cacf5SKari Argillander !IS_ALIGNED(le16_to_cpu(ra->rec_hdr_len), 8)) 528b46acd6aSKonstantin Komarov return false; 529b46acd6aSKonstantin Komarov 530b46acd6aSKonstantin Komarov return true; 531b46acd6aSKonstantin Komarov } 532b46acd6aSKonstantin Komarov 533b46acd6aSKonstantin Komarov static inline bool is_client_area_valid(const struct RESTART_HDR *rhdr, 534b46acd6aSKonstantin Komarov bool usa_error) 535b46acd6aSKonstantin Komarov { 536b46acd6aSKonstantin Komarov u16 ro = le16_to_cpu(rhdr->ra_off); 537b46acd6aSKonstantin Komarov const struct RESTART_AREA *ra = Add2Ptr(rhdr, ro); 538b46acd6aSKonstantin Komarov u16 ra_len = le16_to_cpu(ra->ra_len); 539b46acd6aSKonstantin Komarov const struct CLIENT_REC *ca; 540b46acd6aSKonstantin Komarov u32 i; 541b46acd6aSKonstantin Komarov 542b46acd6aSKonstantin Komarov if (usa_error && ra_len + ro > SECTOR_SIZE - sizeof(short)) 543b46acd6aSKonstantin Komarov return false; 544b46acd6aSKonstantin Komarov 545*e8b8e97fSKari Argillander /* Find the start of the client array. */ 546b46acd6aSKonstantin Komarov ca = Add2Ptr(ra, le16_to_cpu(ra->client_off)); 547b46acd6aSKonstantin Komarov 548b46acd6aSKonstantin Komarov /* 549*e8b8e97fSKari Argillander * Start with the free list. 550*e8b8e97fSKari Argillander * Check that all the clients are valid and that there isn't a cycle. 551*e8b8e97fSKari Argillander * Do the in-use list on the second pass. 552b46acd6aSKonstantin Komarov */ 553b46acd6aSKonstantin Komarov for (i = 0; i < 2; i++) { 554b46acd6aSKonstantin Komarov u16 client_idx = le16_to_cpu(ra->client_idx[i]); 555b46acd6aSKonstantin Komarov bool first_client = true; 556b46acd6aSKonstantin Komarov u16 clients = le16_to_cpu(ra->log_clients); 557b46acd6aSKonstantin Komarov 558b46acd6aSKonstantin Komarov while (client_idx != LFS_NO_CLIENT) { 559b46acd6aSKonstantin Komarov const struct CLIENT_REC *cr; 560b46acd6aSKonstantin Komarov 561b46acd6aSKonstantin Komarov if (!clients || 562b46acd6aSKonstantin Komarov client_idx >= le16_to_cpu(ra->log_clients)) 563b46acd6aSKonstantin Komarov return false; 564b46acd6aSKonstantin Komarov 565b46acd6aSKonstantin Komarov clients -= 1; 566b46acd6aSKonstantin Komarov cr = ca + client_idx; 567b46acd6aSKonstantin Komarov 568b46acd6aSKonstantin Komarov client_idx = le16_to_cpu(cr->next_client); 569b46acd6aSKonstantin Komarov 570b46acd6aSKonstantin Komarov if (first_client) { 571b46acd6aSKonstantin Komarov first_client = false; 572b46acd6aSKonstantin Komarov if (cr->prev_client != LFS_NO_CLIENT_LE) 573b46acd6aSKonstantin Komarov return false; 574b46acd6aSKonstantin Komarov } 575b46acd6aSKonstantin Komarov } 576b46acd6aSKonstantin Komarov } 577b46acd6aSKonstantin Komarov 578b46acd6aSKonstantin Komarov return true; 579b46acd6aSKonstantin Komarov } 580b46acd6aSKonstantin Komarov 581b46acd6aSKonstantin Komarov /* 582b46acd6aSKonstantin Komarov * remove_client 583b46acd6aSKonstantin Komarov * 584*e8b8e97fSKari Argillander * Remove a client record from a client record list an restart area. 585b46acd6aSKonstantin Komarov */ 586b46acd6aSKonstantin Komarov static inline void remove_client(struct CLIENT_REC *ca, 587b46acd6aSKonstantin Komarov const struct CLIENT_REC *cr, __le16 *head) 588b46acd6aSKonstantin Komarov { 589b46acd6aSKonstantin Komarov if (cr->prev_client == LFS_NO_CLIENT_LE) 590b46acd6aSKonstantin Komarov *head = cr->next_client; 591b46acd6aSKonstantin Komarov else 592b46acd6aSKonstantin Komarov ca[le16_to_cpu(cr->prev_client)].next_client = cr->next_client; 593b46acd6aSKonstantin Komarov 594b46acd6aSKonstantin Komarov if (cr->next_client != LFS_NO_CLIENT_LE) 595b46acd6aSKonstantin Komarov ca[le16_to_cpu(cr->next_client)].prev_client = cr->prev_client; 596b46acd6aSKonstantin Komarov } 597b46acd6aSKonstantin Komarov 598b46acd6aSKonstantin Komarov /* 599*e8b8e97fSKari Argillander * add_client - Add a client record to the start of a list. 600b46acd6aSKonstantin Komarov */ 601b46acd6aSKonstantin Komarov static inline void add_client(struct CLIENT_REC *ca, u16 index, __le16 *head) 602b46acd6aSKonstantin Komarov { 603b46acd6aSKonstantin Komarov struct CLIENT_REC *cr = ca + index; 604b46acd6aSKonstantin Komarov 605b46acd6aSKonstantin Komarov cr->prev_client = LFS_NO_CLIENT_LE; 606b46acd6aSKonstantin Komarov cr->next_client = *head; 607b46acd6aSKonstantin Komarov 608b46acd6aSKonstantin Komarov if (*head != LFS_NO_CLIENT_LE) 609b46acd6aSKonstantin Komarov ca[le16_to_cpu(*head)].prev_client = cpu_to_le16(index); 610b46acd6aSKonstantin Komarov 611b46acd6aSKonstantin Komarov *head = cpu_to_le16(index); 612b46acd6aSKonstantin Komarov } 613b46acd6aSKonstantin Komarov 614b46acd6aSKonstantin Komarov static inline void *enum_rstbl(struct RESTART_TABLE *t, void *c) 615b46acd6aSKonstantin Komarov { 616b46acd6aSKonstantin Komarov __le32 *e; 617b46acd6aSKonstantin Komarov u32 bprt; 618b46acd6aSKonstantin Komarov u16 rsize = t ? le16_to_cpu(t->size) : 0; 619b46acd6aSKonstantin Komarov 620b46acd6aSKonstantin Komarov if (!c) { 621b46acd6aSKonstantin Komarov if (!t || !t->total) 622b46acd6aSKonstantin Komarov return NULL; 623b46acd6aSKonstantin Komarov e = Add2Ptr(t, sizeof(struct RESTART_TABLE)); 624b46acd6aSKonstantin Komarov } else { 625b46acd6aSKonstantin Komarov e = Add2Ptr(c, rsize); 626b46acd6aSKonstantin Komarov } 627b46acd6aSKonstantin Komarov 628*e8b8e97fSKari Argillander /* Loop until we hit the first one allocated, or the end of the list. */ 629b46acd6aSKonstantin Komarov for (bprt = bytes_per_rt(t); PtrOffset(t, e) < bprt; 630b46acd6aSKonstantin Komarov e = Add2Ptr(e, rsize)) { 631b46acd6aSKonstantin Komarov if (*e == RESTART_ENTRY_ALLOCATED_LE) 632b46acd6aSKonstantin Komarov return e; 633b46acd6aSKonstantin Komarov } 634b46acd6aSKonstantin Komarov return NULL; 635b46acd6aSKonstantin Komarov } 636b46acd6aSKonstantin Komarov 637b46acd6aSKonstantin Komarov /* 638*e8b8e97fSKari Argillander * find_dp - Search for a @vcn in Dirty Page Table. 639b46acd6aSKonstantin Komarov */ 640b46acd6aSKonstantin Komarov static inline struct DIR_PAGE_ENTRY *find_dp(struct RESTART_TABLE *dptbl, 641b46acd6aSKonstantin Komarov u32 target_attr, u64 vcn) 642b46acd6aSKonstantin Komarov { 643b46acd6aSKonstantin Komarov __le32 ta = cpu_to_le32(target_attr); 644b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY *dp = NULL; 645b46acd6aSKonstantin Komarov 646b46acd6aSKonstantin Komarov while ((dp = enum_rstbl(dptbl, dp))) { 647b46acd6aSKonstantin Komarov u64 dp_vcn = le64_to_cpu(dp->vcn); 648b46acd6aSKonstantin Komarov 649b46acd6aSKonstantin Komarov if (dp->target_attr == ta && vcn >= dp_vcn && 650b46acd6aSKonstantin Komarov vcn < dp_vcn + le32_to_cpu(dp->lcns_follow)) { 651b46acd6aSKonstantin Komarov return dp; 652b46acd6aSKonstantin Komarov } 653b46acd6aSKonstantin Komarov } 654b46acd6aSKonstantin Komarov return NULL; 655b46acd6aSKonstantin Komarov } 656b46acd6aSKonstantin Komarov 657b46acd6aSKonstantin Komarov static inline u32 norm_file_page(u32 page_size, u32 *l_size, bool use_default) 658b46acd6aSKonstantin Komarov { 659b46acd6aSKonstantin Komarov if (use_default) 660b46acd6aSKonstantin Komarov page_size = DefaultLogPageSize; 661b46acd6aSKonstantin Komarov 662*e8b8e97fSKari Argillander /* Round the file size down to a system page boundary. */ 663b46acd6aSKonstantin Komarov *l_size &= ~(page_size - 1); 664b46acd6aSKonstantin Komarov 665*e8b8e97fSKari Argillander /* File should contain at least 2 restart pages and MinLogRecordPages pages. */ 666b46acd6aSKonstantin Komarov if (*l_size < (MinLogRecordPages + 2) * page_size) 667b46acd6aSKonstantin Komarov return 0; 668b46acd6aSKonstantin Komarov 669b46acd6aSKonstantin Komarov return page_size; 670b46acd6aSKonstantin Komarov } 671b46acd6aSKonstantin Komarov 672b46acd6aSKonstantin Komarov static bool check_log_rec(const struct LOG_REC_HDR *lr, u32 bytes, u32 tr, 673b46acd6aSKonstantin Komarov u32 bytes_per_attr_entry) 674b46acd6aSKonstantin Komarov { 675b46acd6aSKonstantin Komarov u16 t16; 676b46acd6aSKonstantin Komarov 677b46acd6aSKonstantin Komarov if (bytes < sizeof(struct LOG_REC_HDR)) 678b46acd6aSKonstantin Komarov return false; 679b46acd6aSKonstantin Komarov if (!tr) 680b46acd6aSKonstantin Komarov return false; 681b46acd6aSKonstantin Komarov 682b46acd6aSKonstantin Komarov if ((tr - sizeof(struct RESTART_TABLE)) % 683b46acd6aSKonstantin Komarov sizeof(struct TRANSACTION_ENTRY)) 684b46acd6aSKonstantin Komarov return false; 685b46acd6aSKonstantin Komarov 686b46acd6aSKonstantin Komarov if (le16_to_cpu(lr->redo_off) & 7) 687b46acd6aSKonstantin Komarov return false; 688b46acd6aSKonstantin Komarov 689b46acd6aSKonstantin Komarov if (le16_to_cpu(lr->undo_off) & 7) 690b46acd6aSKonstantin Komarov return false; 691b46acd6aSKonstantin Komarov 692b46acd6aSKonstantin Komarov if (lr->target_attr) 693b46acd6aSKonstantin Komarov goto check_lcns; 694b46acd6aSKonstantin Komarov 695b46acd6aSKonstantin Komarov if (is_target_required(le16_to_cpu(lr->redo_op))) 696b46acd6aSKonstantin Komarov return false; 697b46acd6aSKonstantin Komarov 698b46acd6aSKonstantin Komarov if (is_target_required(le16_to_cpu(lr->undo_op))) 699b46acd6aSKonstantin Komarov return false; 700b46acd6aSKonstantin Komarov 701b46acd6aSKonstantin Komarov check_lcns: 702b46acd6aSKonstantin Komarov if (!lr->lcns_follow) 703b46acd6aSKonstantin Komarov goto check_length; 704b46acd6aSKonstantin Komarov 705b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lr->target_attr); 706b46acd6aSKonstantin Komarov if ((t16 - sizeof(struct RESTART_TABLE)) % bytes_per_attr_entry) 707b46acd6aSKonstantin Komarov return false; 708b46acd6aSKonstantin Komarov 709b46acd6aSKonstantin Komarov check_length: 710b46acd6aSKonstantin Komarov if (bytes < lrh_length(lr)) 711b46acd6aSKonstantin Komarov return false; 712b46acd6aSKonstantin Komarov 713b46acd6aSKonstantin Komarov return true; 714b46acd6aSKonstantin Komarov } 715b46acd6aSKonstantin Komarov 716b46acd6aSKonstantin Komarov static bool check_rstbl(const struct RESTART_TABLE *rt, size_t bytes) 717b46acd6aSKonstantin Komarov { 718b46acd6aSKonstantin Komarov u32 ts; 719b46acd6aSKonstantin Komarov u32 i, off; 720b46acd6aSKonstantin Komarov u16 rsize = le16_to_cpu(rt->size); 721b46acd6aSKonstantin Komarov u16 ne = le16_to_cpu(rt->used); 722b46acd6aSKonstantin Komarov u32 ff = le32_to_cpu(rt->first_free); 723b46acd6aSKonstantin Komarov u32 lf = le32_to_cpu(rt->last_free); 724b46acd6aSKonstantin Komarov 725b46acd6aSKonstantin Komarov ts = rsize * ne + sizeof(struct RESTART_TABLE); 726b46acd6aSKonstantin Komarov 727b46acd6aSKonstantin Komarov if (!rsize || rsize > bytes || 728b46acd6aSKonstantin Komarov rsize + sizeof(struct RESTART_TABLE) > bytes || bytes < ts || 729b46acd6aSKonstantin Komarov le16_to_cpu(rt->total) > ne || ff > ts || lf > ts || 730b46acd6aSKonstantin Komarov (ff && ff < sizeof(struct RESTART_TABLE)) || 731b46acd6aSKonstantin Komarov (lf && lf < sizeof(struct RESTART_TABLE))) { 732b46acd6aSKonstantin Komarov return false; 733b46acd6aSKonstantin Komarov } 734b46acd6aSKonstantin Komarov 735*e8b8e97fSKari Argillander /* 736*e8b8e97fSKari Argillander * Verify each entry is either allocated or points 737*e8b8e97fSKari Argillander * to a valid offset the table. 738b46acd6aSKonstantin Komarov */ 739b46acd6aSKonstantin Komarov for (i = 0; i < ne; i++) { 740b46acd6aSKonstantin Komarov off = le32_to_cpu(*(__le32 *)Add2Ptr( 741b46acd6aSKonstantin Komarov rt, i * rsize + sizeof(struct RESTART_TABLE))); 742b46acd6aSKonstantin Komarov 743b46acd6aSKonstantin Komarov if (off != RESTART_ENTRY_ALLOCATED && off && 744b46acd6aSKonstantin Komarov (off < sizeof(struct RESTART_TABLE) || 745b46acd6aSKonstantin Komarov ((off - sizeof(struct RESTART_TABLE)) % rsize))) { 746b46acd6aSKonstantin Komarov return false; 747b46acd6aSKonstantin Komarov } 748b46acd6aSKonstantin Komarov } 749b46acd6aSKonstantin Komarov 750*e8b8e97fSKari Argillander /* 751*e8b8e97fSKari Argillander * Walk through the list headed by the first entry to make 752*e8b8e97fSKari Argillander * sure none of the entries are currently being used. 753b46acd6aSKonstantin Komarov */ 754b46acd6aSKonstantin Komarov for (off = ff; off;) { 755b46acd6aSKonstantin Komarov if (off == RESTART_ENTRY_ALLOCATED) 756b46acd6aSKonstantin Komarov return false; 757b46acd6aSKonstantin Komarov 758b46acd6aSKonstantin Komarov off = le32_to_cpu(*(__le32 *)Add2Ptr(rt, off)); 759b46acd6aSKonstantin Komarov } 760b46acd6aSKonstantin Komarov 761b46acd6aSKonstantin Komarov return true; 762b46acd6aSKonstantin Komarov } 763b46acd6aSKonstantin Komarov 764b46acd6aSKonstantin Komarov /* 765*e8b8e97fSKari Argillander * free_rsttbl_idx - Free a previously allocated index a Restart Table. 766b46acd6aSKonstantin Komarov */ 767b46acd6aSKonstantin Komarov static inline void free_rsttbl_idx(struct RESTART_TABLE *rt, u32 off) 768b46acd6aSKonstantin Komarov { 769b46acd6aSKonstantin Komarov __le32 *e; 770b46acd6aSKonstantin Komarov u32 lf = le32_to_cpu(rt->last_free); 771b46acd6aSKonstantin Komarov __le32 off_le = cpu_to_le32(off); 772b46acd6aSKonstantin Komarov 773b46acd6aSKonstantin Komarov e = Add2Ptr(rt, off); 774b46acd6aSKonstantin Komarov 775b46acd6aSKonstantin Komarov if (off < le32_to_cpu(rt->free_goal)) { 776b46acd6aSKonstantin Komarov *e = rt->first_free; 777b46acd6aSKonstantin Komarov rt->first_free = off_le; 778b46acd6aSKonstantin Komarov if (!lf) 779b46acd6aSKonstantin Komarov rt->last_free = off_le; 780b46acd6aSKonstantin Komarov } else { 781b46acd6aSKonstantin Komarov if (lf) 782b46acd6aSKonstantin Komarov *(__le32 *)Add2Ptr(rt, lf) = off_le; 783b46acd6aSKonstantin Komarov else 784b46acd6aSKonstantin Komarov rt->first_free = off_le; 785b46acd6aSKonstantin Komarov 786b46acd6aSKonstantin Komarov rt->last_free = off_le; 787b46acd6aSKonstantin Komarov *e = 0; 788b46acd6aSKonstantin Komarov } 789b46acd6aSKonstantin Komarov 790b46acd6aSKonstantin Komarov le16_sub_cpu(&rt->total, 1); 791b46acd6aSKonstantin Komarov } 792b46acd6aSKonstantin Komarov 793b46acd6aSKonstantin Komarov static inline struct RESTART_TABLE *init_rsttbl(u16 esize, u16 used) 794b46acd6aSKonstantin Komarov { 795b46acd6aSKonstantin Komarov __le32 *e, *last_free; 796b46acd6aSKonstantin Komarov u32 off; 797b46acd6aSKonstantin Komarov u32 bytes = esize * used + sizeof(struct RESTART_TABLE); 798b46acd6aSKonstantin Komarov u32 lf = sizeof(struct RESTART_TABLE) + (used - 1) * esize; 799195c52bdSKari Argillander struct RESTART_TABLE *t = kzalloc(bytes, GFP_NOFS); 800b46acd6aSKonstantin Komarov 801a1b04d38SDan Carpenter if (!t) 802a1b04d38SDan Carpenter return NULL; 803a1b04d38SDan Carpenter 804b46acd6aSKonstantin Komarov t->size = cpu_to_le16(esize); 805b46acd6aSKonstantin Komarov t->used = cpu_to_le16(used); 806b46acd6aSKonstantin Komarov t->free_goal = cpu_to_le32(~0u); 807b46acd6aSKonstantin Komarov t->first_free = cpu_to_le32(sizeof(struct RESTART_TABLE)); 808b46acd6aSKonstantin Komarov t->last_free = cpu_to_le32(lf); 809b46acd6aSKonstantin Komarov 810b46acd6aSKonstantin Komarov e = (__le32 *)(t + 1); 811b46acd6aSKonstantin Komarov last_free = Add2Ptr(t, lf); 812b46acd6aSKonstantin Komarov 813b46acd6aSKonstantin Komarov for (off = sizeof(struct RESTART_TABLE) + esize; e < last_free; 814b46acd6aSKonstantin Komarov e = Add2Ptr(e, esize), off += esize) { 815b46acd6aSKonstantin Komarov *e = cpu_to_le32(off); 816b46acd6aSKonstantin Komarov } 817b46acd6aSKonstantin Komarov return t; 818b46acd6aSKonstantin Komarov } 819b46acd6aSKonstantin Komarov 820b46acd6aSKonstantin Komarov static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl, 821b46acd6aSKonstantin Komarov u32 add, u32 free_goal) 822b46acd6aSKonstantin Komarov { 823b46acd6aSKonstantin Komarov u16 esize = le16_to_cpu(tbl->size); 824b46acd6aSKonstantin Komarov __le32 osize = cpu_to_le32(bytes_per_rt(tbl)); 825b46acd6aSKonstantin Komarov u32 used = le16_to_cpu(tbl->used); 826a1b04d38SDan Carpenter struct RESTART_TABLE *rt; 827a1b04d38SDan Carpenter 828a1b04d38SDan Carpenter rt = init_rsttbl(esize, used + add); 829a1b04d38SDan Carpenter if (!rt) 830a1b04d38SDan Carpenter return NULL; 831b46acd6aSKonstantin Komarov 832b46acd6aSKonstantin Komarov memcpy(rt + 1, tbl + 1, esize * used); 833b46acd6aSKonstantin Komarov 834b46acd6aSKonstantin Komarov rt->free_goal = free_goal == ~0u 835b46acd6aSKonstantin Komarov ? cpu_to_le32(~0u) 836b46acd6aSKonstantin Komarov : cpu_to_le32(sizeof(struct RESTART_TABLE) + 837b46acd6aSKonstantin Komarov free_goal * esize); 838b46acd6aSKonstantin Komarov 839b46acd6aSKonstantin Komarov if (tbl->first_free) { 840b46acd6aSKonstantin Komarov rt->first_free = tbl->first_free; 841b46acd6aSKonstantin Komarov *(__le32 *)Add2Ptr(rt, le32_to_cpu(tbl->last_free)) = osize; 842b46acd6aSKonstantin Komarov } else { 843b46acd6aSKonstantin Komarov rt->first_free = osize; 844b46acd6aSKonstantin Komarov } 845b46acd6aSKonstantin Komarov 846b46acd6aSKonstantin Komarov rt->total = tbl->total; 847b46acd6aSKonstantin Komarov 848195c52bdSKari Argillander kfree(tbl); 849b46acd6aSKonstantin Komarov return rt; 850b46acd6aSKonstantin Komarov } 851b46acd6aSKonstantin Komarov 852b46acd6aSKonstantin Komarov /* 853b46acd6aSKonstantin Komarov * alloc_rsttbl_idx 854b46acd6aSKonstantin Komarov * 855*e8b8e97fSKari Argillander * Allocate an index from within a previously initialized Restart Table. 856b46acd6aSKonstantin Komarov */ 857b46acd6aSKonstantin Komarov static inline void *alloc_rsttbl_idx(struct RESTART_TABLE **tbl) 858b46acd6aSKonstantin Komarov { 859b46acd6aSKonstantin Komarov u32 off; 860b46acd6aSKonstantin Komarov __le32 *e; 861b46acd6aSKonstantin Komarov struct RESTART_TABLE *t = *tbl; 862b46acd6aSKonstantin Komarov 863a1b04d38SDan Carpenter if (!t->first_free) { 864b46acd6aSKonstantin Komarov *tbl = t = extend_rsttbl(t, 16, ~0u); 865a1b04d38SDan Carpenter if (!t) 866a1b04d38SDan Carpenter return NULL; 867a1b04d38SDan Carpenter } 868b46acd6aSKonstantin Komarov 869b46acd6aSKonstantin Komarov off = le32_to_cpu(t->first_free); 870b46acd6aSKonstantin Komarov 871b46acd6aSKonstantin Komarov /* Dequeue this entry and zero it. */ 872b46acd6aSKonstantin Komarov e = Add2Ptr(t, off); 873b46acd6aSKonstantin Komarov 874b46acd6aSKonstantin Komarov t->first_free = *e; 875b46acd6aSKonstantin Komarov 876b46acd6aSKonstantin Komarov memset(e, 0, le16_to_cpu(t->size)); 877b46acd6aSKonstantin Komarov 878b46acd6aSKonstantin Komarov *e = RESTART_ENTRY_ALLOCATED_LE; 879b46acd6aSKonstantin Komarov 880b46acd6aSKonstantin Komarov /* If list is going empty, then we fix the last_free as well. */ 881b46acd6aSKonstantin Komarov if (!t->first_free) 882b46acd6aSKonstantin Komarov t->last_free = 0; 883b46acd6aSKonstantin Komarov 884b46acd6aSKonstantin Komarov le16_add_cpu(&t->total, 1); 885b46acd6aSKonstantin Komarov 886b46acd6aSKonstantin Komarov return Add2Ptr(t, off); 887b46acd6aSKonstantin Komarov } 888b46acd6aSKonstantin Komarov 889b46acd6aSKonstantin Komarov /* 890b46acd6aSKonstantin Komarov * alloc_rsttbl_from_idx 891b46acd6aSKonstantin Komarov * 892*e8b8e97fSKari Argillander * Allocate a specific index from within a previously initialized Restart Table. 893b46acd6aSKonstantin Komarov */ 894b46acd6aSKonstantin Komarov static inline void *alloc_rsttbl_from_idx(struct RESTART_TABLE **tbl, u32 vbo) 895b46acd6aSKonstantin Komarov { 896b46acd6aSKonstantin Komarov u32 off; 897b46acd6aSKonstantin Komarov __le32 *e; 898b46acd6aSKonstantin Komarov struct RESTART_TABLE *rt = *tbl; 899b46acd6aSKonstantin Komarov u32 bytes = bytes_per_rt(rt); 900b46acd6aSKonstantin Komarov u16 esize = le16_to_cpu(rt->size); 901b46acd6aSKonstantin Komarov 902*e8b8e97fSKari Argillander /* If the entry is not the table, we will have to extend the table. */ 903b46acd6aSKonstantin Komarov if (vbo >= bytes) { 904b46acd6aSKonstantin Komarov /* 905*e8b8e97fSKari Argillander * Extend the size by computing the number of entries between 906*e8b8e97fSKari Argillander * the existing size and the desired index and adding 1 to that. 907b46acd6aSKonstantin Komarov */ 908b46acd6aSKonstantin Komarov u32 bytes2idx = vbo - bytes; 909b46acd6aSKonstantin Komarov 910*e8b8e97fSKari Argillander /* 911*e8b8e97fSKari Argillander * There should always be an integral number of entries 912*e8b8e97fSKari Argillander * being added. Now extend the table. 913*e8b8e97fSKari Argillander */ 914b46acd6aSKonstantin Komarov *tbl = rt = extend_rsttbl(rt, bytes2idx / esize + 1, bytes); 915b46acd6aSKonstantin Komarov if (!rt) 916b46acd6aSKonstantin Komarov return NULL; 917b46acd6aSKonstantin Komarov } 918b46acd6aSKonstantin Komarov 919*e8b8e97fSKari Argillander /* See if the entry is already allocated, and just return if it is. */ 920b46acd6aSKonstantin Komarov e = Add2Ptr(rt, vbo); 921b46acd6aSKonstantin Komarov 922b46acd6aSKonstantin Komarov if (*e == RESTART_ENTRY_ALLOCATED_LE) 923b46acd6aSKonstantin Komarov return e; 924b46acd6aSKonstantin Komarov 925b46acd6aSKonstantin Komarov /* 926b46acd6aSKonstantin Komarov * Walk through the table, looking for the entry we're 927*e8b8e97fSKari Argillander * interested and the previous entry. 928b46acd6aSKonstantin Komarov */ 929b46acd6aSKonstantin Komarov off = le32_to_cpu(rt->first_free); 930b46acd6aSKonstantin Komarov e = Add2Ptr(rt, off); 931b46acd6aSKonstantin Komarov 932b46acd6aSKonstantin Komarov if (off == vbo) { 933b46acd6aSKonstantin Komarov /* this is a match */ 934b46acd6aSKonstantin Komarov rt->first_free = *e; 935b46acd6aSKonstantin Komarov goto skip_looking; 936b46acd6aSKonstantin Komarov } 937b46acd6aSKonstantin Komarov 938b46acd6aSKonstantin Komarov /* 939*e8b8e97fSKari Argillander * Need to walk through the list looking for the predecessor 940*e8b8e97fSKari Argillander * of our entry. 941b46acd6aSKonstantin Komarov */ 942b46acd6aSKonstantin Komarov for (;;) { 943b46acd6aSKonstantin Komarov /* Remember the entry just found */ 944b46acd6aSKonstantin Komarov u32 last_off = off; 945b46acd6aSKonstantin Komarov __le32 *last_e = e; 946b46acd6aSKonstantin Komarov 947*e8b8e97fSKari Argillander /* Should never run of entries. */ 948b46acd6aSKonstantin Komarov 949*e8b8e97fSKari Argillander /* Lookup up the next entry the list. */ 950b46acd6aSKonstantin Komarov off = le32_to_cpu(*last_e); 951b46acd6aSKonstantin Komarov e = Add2Ptr(rt, off); 952b46acd6aSKonstantin Komarov 953*e8b8e97fSKari Argillander /* If this is our match we are done. */ 954b46acd6aSKonstantin Komarov if (off == vbo) { 955b46acd6aSKonstantin Komarov *last_e = *e; 956b46acd6aSKonstantin Komarov 957*e8b8e97fSKari Argillander /* 958*e8b8e97fSKari Argillander * If this was the last entry, we update that 959*e8b8e97fSKari Argillander * table as well. 960*e8b8e97fSKari Argillander */ 961b46acd6aSKonstantin Komarov if (le32_to_cpu(rt->last_free) == off) 962b46acd6aSKonstantin Komarov rt->last_free = cpu_to_le32(last_off); 963b46acd6aSKonstantin Komarov break; 964b46acd6aSKonstantin Komarov } 965b46acd6aSKonstantin Komarov } 966b46acd6aSKonstantin Komarov 967b46acd6aSKonstantin Komarov skip_looking: 968*e8b8e97fSKari Argillander /* If the list is now empty, we fix the last_free as well. */ 969b46acd6aSKonstantin Komarov if (!rt->first_free) 970b46acd6aSKonstantin Komarov rt->last_free = 0; 971b46acd6aSKonstantin Komarov 972*e8b8e97fSKari Argillander /* Zero this entry. */ 973b46acd6aSKonstantin Komarov memset(e, 0, esize); 974b46acd6aSKonstantin Komarov *e = RESTART_ENTRY_ALLOCATED_LE; 975b46acd6aSKonstantin Komarov 976b46acd6aSKonstantin Komarov le16_add_cpu(&rt->total, 1); 977b46acd6aSKonstantin Komarov 978b46acd6aSKonstantin Komarov return e; 979b46acd6aSKonstantin Komarov } 980b46acd6aSKonstantin Komarov 981b46acd6aSKonstantin Komarov #define RESTART_SINGLE_PAGE_IO cpu_to_le16(0x0001) 982b46acd6aSKonstantin Komarov 983b46acd6aSKonstantin Komarov #define NTFSLOG_WRAPPED 0x00000001 984b46acd6aSKonstantin Komarov #define NTFSLOG_MULTIPLE_PAGE_IO 0x00000002 985b46acd6aSKonstantin Komarov #define NTFSLOG_NO_LAST_LSN 0x00000004 986b46acd6aSKonstantin Komarov #define NTFSLOG_REUSE_TAIL 0x00000010 987b46acd6aSKonstantin Komarov #define NTFSLOG_NO_OLDEST_LSN 0x00000020 988b46acd6aSKonstantin Komarov 989*e8b8e97fSKari Argillander /* Helper struct to work with NTFS $LogFile. */ 990b46acd6aSKonstantin Komarov struct ntfs_log { 991b46acd6aSKonstantin Komarov struct ntfs_inode *ni; 992b46acd6aSKonstantin Komarov 993b46acd6aSKonstantin Komarov u32 l_size; 994b46acd6aSKonstantin Komarov u32 sys_page_size; 995b46acd6aSKonstantin Komarov u32 sys_page_mask; 996b46acd6aSKonstantin Komarov u32 page_size; 997b46acd6aSKonstantin Komarov u32 page_mask; // page_size - 1 998b46acd6aSKonstantin Komarov u8 page_bits; 999b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *one_page_buf; 1000b46acd6aSKonstantin Komarov 1001b46acd6aSKonstantin Komarov struct RESTART_TABLE *open_attr_tbl; 1002b46acd6aSKonstantin Komarov u32 transaction_id; 1003b46acd6aSKonstantin Komarov u32 clst_per_page; 1004b46acd6aSKonstantin Komarov 1005b46acd6aSKonstantin Komarov u32 first_page; 1006b46acd6aSKonstantin Komarov u32 next_page; 1007b46acd6aSKonstantin Komarov u32 ra_off; 1008b46acd6aSKonstantin Komarov u32 data_off; 1009b46acd6aSKonstantin Komarov u32 restart_size; 1010b46acd6aSKonstantin Komarov u32 data_size; 1011b46acd6aSKonstantin Komarov u16 record_header_len; 1012b46acd6aSKonstantin Komarov u64 seq_num; 1013b46acd6aSKonstantin Komarov u32 seq_num_bits; 1014b46acd6aSKonstantin Komarov u32 file_data_bits; 1015b46acd6aSKonstantin Komarov u32 seq_num_mask; /* (1 << file_data_bits) - 1 */ 1016b46acd6aSKonstantin Komarov 1017*e8b8e97fSKari Argillander struct RESTART_AREA *ra; /* In-memory image of the next restart area. */ 1018*e8b8e97fSKari Argillander u32 ra_size; /* The usable size of the restart area. */ 1019b46acd6aSKonstantin Komarov 1020b46acd6aSKonstantin Komarov /* 1021b46acd6aSKonstantin Komarov * If true, then the in-memory restart area is to be written 1022*e8b8e97fSKari Argillander * to the first position on the disk. 1023b46acd6aSKonstantin Komarov */ 1024b46acd6aSKonstantin Komarov bool init_ra; 1025*e8b8e97fSKari Argillander bool set_dirty; /* True if we need to set dirty flag. */ 1026b46acd6aSKonstantin Komarov 1027b46acd6aSKonstantin Komarov u64 oldest_lsn; 1028b46acd6aSKonstantin Komarov 1029b46acd6aSKonstantin Komarov u32 oldest_lsn_off; 1030b46acd6aSKonstantin Komarov u64 last_lsn; 1031b46acd6aSKonstantin Komarov 1032b46acd6aSKonstantin Komarov u32 total_avail; 1033b46acd6aSKonstantin Komarov u32 total_avail_pages; 1034b46acd6aSKonstantin Komarov u32 total_undo_commit; 1035b46acd6aSKonstantin Komarov u32 max_current_avail; 1036b46acd6aSKonstantin Komarov u32 current_avail; 1037b46acd6aSKonstantin Komarov u32 reserved; 1038b46acd6aSKonstantin Komarov 1039b46acd6aSKonstantin Komarov short major_ver; 1040b46acd6aSKonstantin Komarov short minor_ver; 1041b46acd6aSKonstantin Komarov 1042b46acd6aSKonstantin Komarov u32 l_flags; /* See NTFSLOG_XXX */ 1043*e8b8e97fSKari Argillander u32 current_openlog_count; /* On-disk value for open_log_count. */ 1044b46acd6aSKonstantin Komarov 1045b46acd6aSKonstantin Komarov struct CLIENT_ID client_id; 1046b46acd6aSKonstantin Komarov u32 client_undo_commit; 1047b46acd6aSKonstantin Komarov }; 1048b46acd6aSKonstantin Komarov 1049b46acd6aSKonstantin Komarov static inline u32 lsn_to_vbo(struct ntfs_log *log, const u64 lsn) 1050b46acd6aSKonstantin Komarov { 1051b46acd6aSKonstantin Komarov u32 vbo = (lsn << log->seq_num_bits) >> (log->seq_num_bits - 3); 1052b46acd6aSKonstantin Komarov 1053b46acd6aSKonstantin Komarov return vbo; 1054b46acd6aSKonstantin Komarov } 1055b46acd6aSKonstantin Komarov 1056*e8b8e97fSKari Argillander /* Compute the offset in the log file of the next log page. */ 1057b46acd6aSKonstantin Komarov static inline u32 next_page_off(struct ntfs_log *log, u32 off) 1058b46acd6aSKonstantin Komarov { 1059b46acd6aSKonstantin Komarov off = (off & ~log->sys_page_mask) + log->page_size; 1060b46acd6aSKonstantin Komarov return off >= log->l_size ? log->first_page : off; 1061b46acd6aSKonstantin Komarov } 1062b46acd6aSKonstantin Komarov 1063b46acd6aSKonstantin Komarov static inline u32 lsn_to_page_off(struct ntfs_log *log, u64 lsn) 1064b46acd6aSKonstantin Komarov { 1065b46acd6aSKonstantin Komarov return (((u32)lsn) << 3) & log->page_mask; 1066b46acd6aSKonstantin Komarov } 1067b46acd6aSKonstantin Komarov 1068b46acd6aSKonstantin Komarov static inline u64 vbo_to_lsn(struct ntfs_log *log, u32 off, u64 Seq) 1069b46acd6aSKonstantin Komarov { 1070b46acd6aSKonstantin Komarov return (off >> 3) + (Seq << log->file_data_bits); 1071b46acd6aSKonstantin Komarov } 1072b46acd6aSKonstantin Komarov 1073b46acd6aSKonstantin Komarov static inline bool is_lsn_in_file(struct ntfs_log *log, u64 lsn) 1074b46acd6aSKonstantin Komarov { 1075b46acd6aSKonstantin Komarov return lsn >= log->oldest_lsn && 1076b46acd6aSKonstantin Komarov lsn <= le64_to_cpu(log->ra->current_lsn); 1077b46acd6aSKonstantin Komarov } 1078b46acd6aSKonstantin Komarov 1079b46acd6aSKonstantin Komarov static inline u32 hdr_file_off(struct ntfs_log *log, 1080b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *hdr) 1081b46acd6aSKonstantin Komarov { 1082b46acd6aSKonstantin Komarov if (log->major_ver < 2) 1083b46acd6aSKonstantin Komarov return le64_to_cpu(hdr->rhdr.lsn); 1084b46acd6aSKonstantin Komarov 1085b46acd6aSKonstantin Komarov return le32_to_cpu(hdr->file_off); 1086b46acd6aSKonstantin Komarov } 1087b46acd6aSKonstantin Komarov 1088b46acd6aSKonstantin Komarov static inline u64 base_lsn(struct ntfs_log *log, 1089b46acd6aSKonstantin Komarov const struct RECORD_PAGE_HDR *hdr, u64 lsn) 1090b46acd6aSKonstantin Komarov { 1091b46acd6aSKonstantin Komarov u64 h_lsn = le64_to_cpu(hdr->rhdr.lsn); 1092b46acd6aSKonstantin Komarov u64 ret = (((h_lsn >> log->file_data_bits) + 1093b46acd6aSKonstantin Komarov (lsn < (lsn_to_vbo(log, h_lsn) & ~log->page_mask) ? 1 : 0)) 1094b46acd6aSKonstantin Komarov << log->file_data_bits) + 1095b46acd6aSKonstantin Komarov ((((is_log_record_end(hdr) && 1096b46acd6aSKonstantin Komarov h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) 1097b46acd6aSKonstantin Komarov ? le16_to_cpu(hdr->record_hdr.next_record_off) 1098b46acd6aSKonstantin Komarov : log->page_size) + 1099b46acd6aSKonstantin Komarov lsn) >> 1100b46acd6aSKonstantin Komarov 3); 1101b46acd6aSKonstantin Komarov 1102b46acd6aSKonstantin Komarov return ret; 1103b46acd6aSKonstantin Komarov } 1104b46acd6aSKonstantin Komarov 1105b46acd6aSKonstantin Komarov static inline bool verify_client_lsn(struct ntfs_log *log, 1106b46acd6aSKonstantin Komarov const struct CLIENT_REC *client, u64 lsn) 1107b46acd6aSKonstantin Komarov { 1108b46acd6aSKonstantin Komarov return lsn >= le64_to_cpu(client->oldest_lsn) && 1109b46acd6aSKonstantin Komarov lsn <= le64_to_cpu(log->ra->current_lsn) && lsn; 1110b46acd6aSKonstantin Komarov } 1111b46acd6aSKonstantin Komarov 1112b46acd6aSKonstantin Komarov struct restart_info { 1113b46acd6aSKonstantin Komarov u64 last_lsn; 1114b46acd6aSKonstantin Komarov struct RESTART_HDR *r_page; 1115b46acd6aSKonstantin Komarov u32 vbo; 1116b46acd6aSKonstantin Komarov bool chkdsk_was_run; 1117b46acd6aSKonstantin Komarov bool valid_page; 1118b46acd6aSKonstantin Komarov bool initialized; 1119b46acd6aSKonstantin Komarov bool restart; 1120b46acd6aSKonstantin Komarov }; 1121b46acd6aSKonstantin Komarov 1122b46acd6aSKonstantin Komarov static int read_log_page(struct ntfs_log *log, u32 vbo, 1123b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR **buffer, bool *usa_error) 1124b46acd6aSKonstantin Komarov { 1125b46acd6aSKonstantin Komarov int err = 0; 1126b46acd6aSKonstantin Komarov u32 page_idx = vbo >> log->page_bits; 1127b46acd6aSKonstantin Komarov u32 page_off = vbo & log->page_mask; 1128b46acd6aSKonstantin Komarov u32 bytes = log->page_size - page_off; 1129b46acd6aSKonstantin Komarov void *to_free = NULL; 1130b46acd6aSKonstantin Komarov u32 page_vbo = page_idx << log->page_bits; 1131b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *page_buf; 1132b46acd6aSKonstantin Komarov struct ntfs_inode *ni = log->ni; 1133b46acd6aSKonstantin Komarov bool bBAAD; 1134b46acd6aSKonstantin Komarov 1135b46acd6aSKonstantin Komarov if (vbo >= log->l_size) 1136b46acd6aSKonstantin Komarov return -EINVAL; 1137b46acd6aSKonstantin Komarov 1138b46acd6aSKonstantin Komarov if (!*buffer) { 1139195c52bdSKari Argillander to_free = kmalloc(bytes, GFP_NOFS); 1140b46acd6aSKonstantin Komarov if (!to_free) 1141b46acd6aSKonstantin Komarov return -ENOMEM; 1142b46acd6aSKonstantin Komarov *buffer = to_free; 1143b46acd6aSKonstantin Komarov } 1144b46acd6aSKonstantin Komarov 1145b46acd6aSKonstantin Komarov page_buf = page_off ? log->one_page_buf : *buffer; 1146b46acd6aSKonstantin Komarov 1147b46acd6aSKonstantin Komarov err = ntfs_read_run_nb(ni->mi.sbi, &ni->file.run, page_vbo, page_buf, 1148b46acd6aSKonstantin Komarov log->page_size, NULL); 1149b46acd6aSKonstantin Komarov if (err) 1150b46acd6aSKonstantin Komarov goto out; 1151b46acd6aSKonstantin Komarov 1152b46acd6aSKonstantin Komarov if (page_buf->rhdr.sign != NTFS_FFFF_SIGNATURE) 1153b46acd6aSKonstantin Komarov ntfs_fix_post_read(&page_buf->rhdr, PAGE_SIZE, false); 1154b46acd6aSKonstantin Komarov 1155b46acd6aSKonstantin Komarov if (page_buf != *buffer) 1156b46acd6aSKonstantin Komarov memcpy(*buffer, Add2Ptr(page_buf, page_off), bytes); 1157b46acd6aSKonstantin Komarov 1158b46acd6aSKonstantin Komarov bBAAD = page_buf->rhdr.sign == NTFS_BAAD_SIGNATURE; 1159b46acd6aSKonstantin Komarov 1160b46acd6aSKonstantin Komarov if (usa_error) 1161b46acd6aSKonstantin Komarov *usa_error = bBAAD; 1162b46acd6aSKonstantin Komarov /* Check that the update sequence array for this page is valid */ 1163b46acd6aSKonstantin Komarov /* If we don't allow errors, raise an error status */ 1164b46acd6aSKonstantin Komarov else if (bBAAD) 1165b46acd6aSKonstantin Komarov err = -EINVAL; 1166b46acd6aSKonstantin Komarov 1167b46acd6aSKonstantin Komarov out: 1168b46acd6aSKonstantin Komarov if (err && to_free) { 1169195c52bdSKari Argillander kfree(to_free); 1170b46acd6aSKonstantin Komarov *buffer = NULL; 1171b46acd6aSKonstantin Komarov } 1172b46acd6aSKonstantin Komarov 1173b46acd6aSKonstantin Komarov return err; 1174b46acd6aSKonstantin Komarov } 1175b46acd6aSKonstantin Komarov 1176b46acd6aSKonstantin Komarov /* 1177b46acd6aSKonstantin Komarov * log_read_rst 1178b46acd6aSKonstantin Komarov * 1179*e8b8e97fSKari Argillander * It walks through 512 blocks of the file looking for a valid 1180*e8b8e97fSKari Argillander * restart page header. It will stop the first time we find a 1181*e8b8e97fSKari Argillander * valid page header. 1182b46acd6aSKonstantin Komarov */ 1183b46acd6aSKonstantin Komarov static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first, 1184b46acd6aSKonstantin Komarov struct restart_info *info) 1185b46acd6aSKonstantin Komarov { 1186b46acd6aSKonstantin Komarov u32 skip, vbo; 1187195c52bdSKari Argillander struct RESTART_HDR *r_page = kmalloc(DefaultLogPageSize, GFP_NOFS); 1188b46acd6aSKonstantin Komarov 1189b46acd6aSKonstantin Komarov if (!r_page) 1190b46acd6aSKonstantin Komarov return -ENOMEM; 1191b46acd6aSKonstantin Komarov 1192b46acd6aSKonstantin Komarov memset(info, 0, sizeof(struct restart_info)); 1193b46acd6aSKonstantin Komarov 1194*e8b8e97fSKari Argillander /* Determine which restart area we are looking for. */ 1195b46acd6aSKonstantin Komarov if (first) { 1196b46acd6aSKonstantin Komarov vbo = 0; 1197b46acd6aSKonstantin Komarov skip = 512; 1198b46acd6aSKonstantin Komarov } else { 1199b46acd6aSKonstantin Komarov vbo = 512; 1200b46acd6aSKonstantin Komarov skip = 0; 1201b46acd6aSKonstantin Komarov } 1202b46acd6aSKonstantin Komarov 1203*e8b8e97fSKari Argillander /* Loop continuously until we succeed. */ 1204b46acd6aSKonstantin Komarov for (; vbo < l_size; vbo = 2 * vbo + skip, skip = 0) { 1205b46acd6aSKonstantin Komarov bool usa_error; 1206b46acd6aSKonstantin Komarov u32 sys_page_size; 1207b46acd6aSKonstantin Komarov bool brst, bchk; 1208b46acd6aSKonstantin Komarov struct RESTART_AREA *ra; 1209b46acd6aSKonstantin Komarov 1210*e8b8e97fSKari Argillander /* Read a page header at the current offset. */ 1211b46acd6aSKonstantin Komarov if (read_log_page(log, vbo, (struct RECORD_PAGE_HDR **)&r_page, 1212b46acd6aSKonstantin Komarov &usa_error)) { 1213*e8b8e97fSKari Argillander /* Ignore any errors. */ 1214b46acd6aSKonstantin Komarov continue; 1215b46acd6aSKonstantin Komarov } 1216b46acd6aSKonstantin Komarov 1217*e8b8e97fSKari Argillander /* Exit if the signature is a log record page. */ 1218b46acd6aSKonstantin Komarov if (r_page->rhdr.sign == NTFS_RCRD_SIGNATURE) { 1219b46acd6aSKonstantin Komarov info->initialized = true; 1220b46acd6aSKonstantin Komarov break; 1221b46acd6aSKonstantin Komarov } 1222b46acd6aSKonstantin Komarov 1223b46acd6aSKonstantin Komarov brst = r_page->rhdr.sign == NTFS_RSTR_SIGNATURE; 1224b46acd6aSKonstantin Komarov bchk = r_page->rhdr.sign == NTFS_CHKD_SIGNATURE; 1225b46acd6aSKonstantin Komarov 1226b46acd6aSKonstantin Komarov if (!bchk && !brst) { 1227b46acd6aSKonstantin Komarov if (r_page->rhdr.sign != NTFS_FFFF_SIGNATURE) { 1228b46acd6aSKonstantin Komarov /* 1229b46acd6aSKonstantin Komarov * Remember if the signature does not 1230*e8b8e97fSKari Argillander * indicate uninitialized file. 1231b46acd6aSKonstantin Komarov */ 1232b46acd6aSKonstantin Komarov info->initialized = true; 1233b46acd6aSKonstantin Komarov } 1234b46acd6aSKonstantin Komarov continue; 1235b46acd6aSKonstantin Komarov } 1236b46acd6aSKonstantin Komarov 1237b46acd6aSKonstantin Komarov ra = NULL; 1238b46acd6aSKonstantin Komarov info->valid_page = false; 1239b46acd6aSKonstantin Komarov info->initialized = true; 1240b46acd6aSKonstantin Komarov info->vbo = vbo; 1241b46acd6aSKonstantin Komarov 1242*e8b8e97fSKari Argillander /* Let's check the restart area if this is a valid page. */ 1243b46acd6aSKonstantin Komarov if (!is_rst_page_hdr_valid(vbo, r_page)) 1244b46acd6aSKonstantin Komarov goto check_result; 1245b46acd6aSKonstantin Komarov ra = Add2Ptr(r_page, le16_to_cpu(r_page->ra_off)); 1246b46acd6aSKonstantin Komarov 1247b46acd6aSKonstantin Komarov if (!is_rst_area_valid(r_page)) 1248b46acd6aSKonstantin Komarov goto check_result; 1249b46acd6aSKonstantin Komarov 1250b46acd6aSKonstantin Komarov /* 1251b46acd6aSKonstantin Komarov * We have a valid restart page header and restart area. 1252b46acd6aSKonstantin Komarov * If chkdsk was run or we have no clients then we have 1253*e8b8e97fSKari Argillander * no more checking to do. 1254b46acd6aSKonstantin Komarov */ 1255b46acd6aSKonstantin Komarov if (bchk || ra->client_idx[1] == LFS_NO_CLIENT_LE) { 1256b46acd6aSKonstantin Komarov info->valid_page = true; 1257b46acd6aSKonstantin Komarov goto check_result; 1258b46acd6aSKonstantin Komarov } 1259b46acd6aSKonstantin Komarov 1260*e8b8e97fSKari Argillander /* Read the entire restart area. */ 1261b46acd6aSKonstantin Komarov sys_page_size = le32_to_cpu(r_page->sys_page_size); 1262b46acd6aSKonstantin Komarov if (DefaultLogPageSize != sys_page_size) { 1263195c52bdSKari Argillander kfree(r_page); 1264195c52bdSKari Argillander r_page = kzalloc(sys_page_size, GFP_NOFS); 1265b46acd6aSKonstantin Komarov if (!r_page) 1266b46acd6aSKonstantin Komarov return -ENOMEM; 1267b46acd6aSKonstantin Komarov 1268b46acd6aSKonstantin Komarov if (read_log_page(log, vbo, 1269b46acd6aSKonstantin Komarov (struct RECORD_PAGE_HDR **)&r_page, 1270b46acd6aSKonstantin Komarov &usa_error)) { 1271*e8b8e97fSKari Argillander /* Ignore any errors. */ 1272195c52bdSKari Argillander kfree(r_page); 1273b46acd6aSKonstantin Komarov r_page = NULL; 1274b46acd6aSKonstantin Komarov continue; 1275b46acd6aSKonstantin Komarov } 1276b46acd6aSKonstantin Komarov } 1277b46acd6aSKonstantin Komarov 1278b46acd6aSKonstantin Komarov if (is_client_area_valid(r_page, usa_error)) { 1279b46acd6aSKonstantin Komarov info->valid_page = true; 1280b46acd6aSKonstantin Komarov ra = Add2Ptr(r_page, le16_to_cpu(r_page->ra_off)); 1281b46acd6aSKonstantin Komarov } 1282b46acd6aSKonstantin Komarov 1283b46acd6aSKonstantin Komarov check_result: 1284*e8b8e97fSKari Argillander /* 1285*e8b8e97fSKari Argillander * If chkdsk was run then update the caller's 1286*e8b8e97fSKari Argillander * values and return. 1287*e8b8e97fSKari Argillander */ 1288b46acd6aSKonstantin Komarov if (r_page->rhdr.sign == NTFS_CHKD_SIGNATURE) { 1289b46acd6aSKonstantin Komarov info->chkdsk_was_run = true; 1290b46acd6aSKonstantin Komarov info->last_lsn = le64_to_cpu(r_page->rhdr.lsn); 1291b46acd6aSKonstantin Komarov info->restart = true; 1292b46acd6aSKonstantin Komarov info->r_page = r_page; 1293b46acd6aSKonstantin Komarov return 0; 1294b46acd6aSKonstantin Komarov } 1295b46acd6aSKonstantin Komarov 1296*e8b8e97fSKari Argillander /* 1297*e8b8e97fSKari Argillander * If we have a valid page then copy the values 1298*e8b8e97fSKari Argillander * we need from it. 1299*e8b8e97fSKari Argillander */ 1300b46acd6aSKonstantin Komarov if (info->valid_page) { 1301b46acd6aSKonstantin Komarov info->last_lsn = le64_to_cpu(ra->current_lsn); 1302b46acd6aSKonstantin Komarov info->restart = true; 1303b46acd6aSKonstantin Komarov info->r_page = r_page; 1304b46acd6aSKonstantin Komarov return 0; 1305b46acd6aSKonstantin Komarov } 1306b46acd6aSKonstantin Komarov } 1307b46acd6aSKonstantin Komarov 1308195c52bdSKari Argillander kfree(r_page); 1309b46acd6aSKonstantin Komarov 1310b46acd6aSKonstantin Komarov return 0; 1311b46acd6aSKonstantin Komarov } 1312b46acd6aSKonstantin Komarov 1313b46acd6aSKonstantin Komarov /* 1314*e8b8e97fSKari Argillander * Ilog_init_pg_hdr - Init @log from restart page header. 1315b46acd6aSKonstantin Komarov */ 1316b46acd6aSKonstantin Komarov static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size, 1317b46acd6aSKonstantin Komarov u32 page_size, u16 major_ver, u16 minor_ver) 1318b46acd6aSKonstantin Komarov { 1319b46acd6aSKonstantin Komarov log->sys_page_size = sys_page_size; 1320b46acd6aSKonstantin Komarov log->sys_page_mask = sys_page_size - 1; 1321b46acd6aSKonstantin Komarov log->page_size = page_size; 1322b46acd6aSKonstantin Komarov log->page_mask = page_size - 1; 1323b46acd6aSKonstantin Komarov log->page_bits = blksize_bits(page_size); 1324b46acd6aSKonstantin Komarov 1325b46acd6aSKonstantin Komarov log->clst_per_page = log->page_size >> log->ni->mi.sbi->cluster_bits; 1326b46acd6aSKonstantin Komarov if (!log->clst_per_page) 1327b46acd6aSKonstantin Komarov log->clst_per_page = 1; 1328b46acd6aSKonstantin Komarov 1329b46acd6aSKonstantin Komarov log->first_page = major_ver >= 2 1330b46acd6aSKonstantin Komarov ? 0x22 * page_size 1331b46acd6aSKonstantin Komarov : ((sys_page_size << 1) + (page_size << 1)); 1332b46acd6aSKonstantin Komarov log->major_ver = major_ver; 1333b46acd6aSKonstantin Komarov log->minor_ver = minor_ver; 1334b46acd6aSKonstantin Komarov } 1335b46acd6aSKonstantin Komarov 1336b46acd6aSKonstantin Komarov /* 1337*e8b8e97fSKari Argillander * log_create - Init @log in cases when we don't have a restart area to use. 1338b46acd6aSKonstantin Komarov */ 1339b46acd6aSKonstantin Komarov static void log_create(struct ntfs_log *log, u32 l_size, const u64 last_lsn, 1340b46acd6aSKonstantin Komarov u32 open_log_count, bool wrapped, bool use_multi_page) 1341b46acd6aSKonstantin Komarov { 1342b46acd6aSKonstantin Komarov log->l_size = l_size; 1343*e8b8e97fSKari Argillander /* All file offsets must be quadword aligned. */ 1344b46acd6aSKonstantin Komarov log->file_data_bits = blksize_bits(l_size) - 3; 1345b46acd6aSKonstantin Komarov log->seq_num_mask = (8 << log->file_data_bits) - 1; 1346b46acd6aSKonstantin Komarov log->seq_num_bits = sizeof(u64) * 8 - log->file_data_bits; 1347b46acd6aSKonstantin Komarov log->seq_num = (last_lsn >> log->file_data_bits) + 2; 1348b46acd6aSKonstantin Komarov log->next_page = log->first_page; 1349b46acd6aSKonstantin Komarov log->oldest_lsn = log->seq_num << log->file_data_bits; 1350b46acd6aSKonstantin Komarov log->oldest_lsn_off = 0; 1351b46acd6aSKonstantin Komarov log->last_lsn = log->oldest_lsn; 1352b46acd6aSKonstantin Komarov 1353b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_NO_LAST_LSN | NTFSLOG_NO_OLDEST_LSN; 1354b46acd6aSKonstantin Komarov 1355*e8b8e97fSKari Argillander /* Set the correct flags for the I/O and indicate if we have wrapped. */ 1356b46acd6aSKonstantin Komarov if (wrapped) 1357b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED; 1358b46acd6aSKonstantin Komarov 1359b46acd6aSKonstantin Komarov if (use_multi_page) 1360b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_MULTIPLE_PAGE_IO; 1361b46acd6aSKonstantin Komarov 1362*e8b8e97fSKari Argillander /* Compute the log page values. */ 1363fa3cacf5SKari Argillander log->data_off = ALIGN( 1364b46acd6aSKonstantin Komarov offsetof(struct RECORD_PAGE_HDR, fixups) + 1365fa3cacf5SKari Argillander sizeof(short) * ((log->page_size >> SECTOR_SHIFT) + 1), 8); 1366b46acd6aSKonstantin Komarov log->data_size = log->page_size - log->data_off; 1367b46acd6aSKonstantin Komarov log->record_header_len = sizeof(struct LFS_RECORD_HDR); 1368b46acd6aSKonstantin Komarov 1369*e8b8e97fSKari Argillander /* Remember the different page sizes for reservation. */ 1370b46acd6aSKonstantin Komarov log->reserved = log->data_size - log->record_header_len; 1371b46acd6aSKonstantin Komarov 1372b46acd6aSKonstantin Komarov /* Compute the restart page values. */ 1373fa3cacf5SKari Argillander log->ra_off = ALIGN( 1374b46acd6aSKonstantin Komarov offsetof(struct RESTART_HDR, fixups) + 1375fa3cacf5SKari Argillander sizeof(short) * ((log->sys_page_size >> SECTOR_SHIFT) + 1), 8); 1376b46acd6aSKonstantin Komarov log->restart_size = log->sys_page_size - log->ra_off; 1377b46acd6aSKonstantin Komarov log->ra_size = struct_size(log->ra, clients, 1); 1378b46acd6aSKonstantin Komarov log->current_openlog_count = open_log_count; 1379b46acd6aSKonstantin Komarov 1380b46acd6aSKonstantin Komarov /* 1381b46acd6aSKonstantin Komarov * The total available log file space is the number of 1382*e8b8e97fSKari Argillander * log file pages times the space available on each page. 1383b46acd6aSKonstantin Komarov */ 1384b46acd6aSKonstantin Komarov log->total_avail_pages = log->l_size - log->first_page; 1385b46acd6aSKonstantin Komarov log->total_avail = log->total_avail_pages >> log->page_bits; 1386b46acd6aSKonstantin Komarov 1387b46acd6aSKonstantin Komarov /* 1388b46acd6aSKonstantin Komarov * We assume that we can't use the end of the page less than 1389*e8b8e97fSKari Argillander * the file record size. 1390*e8b8e97fSKari Argillander * Then we won't need to reserve more than the caller asks for. 1391b46acd6aSKonstantin Komarov */ 1392b46acd6aSKonstantin Komarov log->max_current_avail = log->total_avail * log->reserved; 1393b46acd6aSKonstantin Komarov log->total_avail = log->total_avail * log->data_size; 1394b46acd6aSKonstantin Komarov log->current_avail = log->max_current_avail; 1395b46acd6aSKonstantin Komarov } 1396b46acd6aSKonstantin Komarov 1397b46acd6aSKonstantin Komarov /* 1398*e8b8e97fSKari Argillander * log_create_ra - Fill a restart area from the values stored in @log. 1399b46acd6aSKonstantin Komarov */ 1400b46acd6aSKonstantin Komarov static struct RESTART_AREA *log_create_ra(struct ntfs_log *log) 1401b46acd6aSKonstantin Komarov { 1402b46acd6aSKonstantin Komarov struct CLIENT_REC *cr; 1403195c52bdSKari Argillander struct RESTART_AREA *ra = kzalloc(log->restart_size, GFP_NOFS); 1404b46acd6aSKonstantin Komarov 1405b46acd6aSKonstantin Komarov if (!ra) 1406b46acd6aSKonstantin Komarov return NULL; 1407b46acd6aSKonstantin Komarov 1408b46acd6aSKonstantin Komarov ra->current_lsn = cpu_to_le64(log->last_lsn); 1409b46acd6aSKonstantin Komarov ra->log_clients = cpu_to_le16(1); 1410b46acd6aSKonstantin Komarov ra->client_idx[1] = LFS_NO_CLIENT_LE; 1411b46acd6aSKonstantin Komarov if (log->l_flags & NTFSLOG_MULTIPLE_PAGE_IO) 1412b46acd6aSKonstantin Komarov ra->flags = RESTART_SINGLE_PAGE_IO; 1413b46acd6aSKonstantin Komarov ra->seq_num_bits = cpu_to_le32(log->seq_num_bits); 1414b46acd6aSKonstantin Komarov ra->ra_len = cpu_to_le16(log->ra_size); 1415b46acd6aSKonstantin Komarov ra->client_off = cpu_to_le16(offsetof(struct RESTART_AREA, clients)); 1416b46acd6aSKonstantin Komarov ra->l_size = cpu_to_le64(log->l_size); 1417b46acd6aSKonstantin Komarov ra->rec_hdr_len = cpu_to_le16(log->record_header_len); 1418b46acd6aSKonstantin Komarov ra->data_off = cpu_to_le16(log->data_off); 1419b46acd6aSKonstantin Komarov ra->open_log_count = cpu_to_le32(log->current_openlog_count + 1); 1420b46acd6aSKonstantin Komarov 1421b46acd6aSKonstantin Komarov cr = ra->clients; 1422b46acd6aSKonstantin Komarov 1423b46acd6aSKonstantin Komarov cr->prev_client = LFS_NO_CLIENT_LE; 1424b46acd6aSKonstantin Komarov cr->next_client = LFS_NO_CLIENT_LE; 1425b46acd6aSKonstantin Komarov 1426b46acd6aSKonstantin Komarov return ra; 1427b46acd6aSKonstantin Komarov } 1428b46acd6aSKonstantin Komarov 1429b46acd6aSKonstantin Komarov static u32 final_log_off(struct ntfs_log *log, u64 lsn, u32 data_len) 1430b46acd6aSKonstantin Komarov { 1431b46acd6aSKonstantin Komarov u32 base_vbo = lsn << 3; 1432b46acd6aSKonstantin Komarov u32 final_log_off = (base_vbo & log->seq_num_mask) & ~log->page_mask; 1433b46acd6aSKonstantin Komarov u32 page_off = base_vbo & log->page_mask; 1434b46acd6aSKonstantin Komarov u32 tail = log->page_size - page_off; 1435b46acd6aSKonstantin Komarov 1436b46acd6aSKonstantin Komarov page_off -= 1; 1437b46acd6aSKonstantin Komarov 1438*e8b8e97fSKari Argillander /* Add the length of the header. */ 1439b46acd6aSKonstantin Komarov data_len += log->record_header_len; 1440b46acd6aSKonstantin Komarov 1441b46acd6aSKonstantin Komarov /* 1442*e8b8e97fSKari Argillander * If this lsn is contained this log page we are done. 1443*e8b8e97fSKari Argillander * Otherwise we need to walk through several log pages. 1444b46acd6aSKonstantin Komarov */ 1445b46acd6aSKonstantin Komarov if (data_len > tail) { 1446b46acd6aSKonstantin Komarov data_len -= tail; 1447b46acd6aSKonstantin Komarov tail = log->data_size; 1448b46acd6aSKonstantin Komarov page_off = log->data_off - 1; 1449b46acd6aSKonstantin Komarov 1450b46acd6aSKonstantin Komarov for (;;) { 1451b46acd6aSKonstantin Komarov final_log_off = next_page_off(log, final_log_off); 1452b46acd6aSKonstantin Komarov 1453*e8b8e97fSKari Argillander /* 1454*e8b8e97fSKari Argillander * We are done if the remaining bytes 1455*e8b8e97fSKari Argillander * fit on this page. 1456*e8b8e97fSKari Argillander */ 1457b46acd6aSKonstantin Komarov if (data_len <= tail) 1458b46acd6aSKonstantin Komarov break; 1459b46acd6aSKonstantin Komarov data_len -= tail; 1460b46acd6aSKonstantin Komarov } 1461b46acd6aSKonstantin Komarov } 1462b46acd6aSKonstantin Komarov 1463b46acd6aSKonstantin Komarov /* 1464b46acd6aSKonstantin Komarov * We add the remaining bytes to our starting position on this page 1465*e8b8e97fSKari Argillander * and then add that value to the file offset of this log page. 1466b46acd6aSKonstantin Komarov */ 1467b46acd6aSKonstantin Komarov return final_log_off + data_len + page_off; 1468b46acd6aSKonstantin Komarov } 1469b46acd6aSKonstantin Komarov 1470b46acd6aSKonstantin Komarov static int next_log_lsn(struct ntfs_log *log, const struct LFS_RECORD_HDR *rh, 1471b46acd6aSKonstantin Komarov u64 *lsn) 1472b46acd6aSKonstantin Komarov { 1473b46acd6aSKonstantin Komarov int err; 1474b46acd6aSKonstantin Komarov u64 this_lsn = le64_to_cpu(rh->this_lsn); 1475b46acd6aSKonstantin Komarov u32 vbo = lsn_to_vbo(log, this_lsn); 1476b46acd6aSKonstantin Komarov u32 end = 1477b46acd6aSKonstantin Komarov final_log_off(log, this_lsn, le32_to_cpu(rh->client_data_len)); 1478b46acd6aSKonstantin Komarov u32 hdr_off = end & ~log->sys_page_mask; 1479b46acd6aSKonstantin Komarov u64 seq = this_lsn >> log->file_data_bits; 1480b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *page = NULL; 1481b46acd6aSKonstantin Komarov 1482*e8b8e97fSKari Argillander /* Remember if we wrapped. */ 1483b46acd6aSKonstantin Komarov if (end <= vbo) 1484b46acd6aSKonstantin Komarov seq += 1; 1485b46acd6aSKonstantin Komarov 1486*e8b8e97fSKari Argillander /* Log page header for this page. */ 1487b46acd6aSKonstantin Komarov err = read_log_page(log, hdr_off, &page, NULL); 1488b46acd6aSKonstantin Komarov if (err) 1489b46acd6aSKonstantin Komarov return err; 1490b46acd6aSKonstantin Komarov 1491b46acd6aSKonstantin Komarov /* 1492b46acd6aSKonstantin Komarov * If the lsn we were given was not the last lsn on this page, 1493b46acd6aSKonstantin Komarov * then the starting offset for the next lsn is on a quad word 1494*e8b8e97fSKari Argillander * boundary following the last file offset for the current lsn. 1495*e8b8e97fSKari Argillander * Otherwise the file offset is the start of the data on the next page. 1496b46acd6aSKonstantin Komarov */ 1497b46acd6aSKonstantin Komarov if (this_lsn == le64_to_cpu(page->rhdr.lsn)) { 1498*e8b8e97fSKari Argillander /* If we wrapped, we need to increment the sequence number. */ 1499b46acd6aSKonstantin Komarov hdr_off = next_page_off(log, hdr_off); 1500b46acd6aSKonstantin Komarov if (hdr_off == log->first_page) 1501b46acd6aSKonstantin Komarov seq += 1; 1502b46acd6aSKonstantin Komarov 1503b46acd6aSKonstantin Komarov vbo = hdr_off + log->data_off; 1504b46acd6aSKonstantin Komarov } else { 1505fa3cacf5SKari Argillander vbo = ALIGN(end, 8); 1506b46acd6aSKonstantin Komarov } 1507b46acd6aSKonstantin Komarov 1508*e8b8e97fSKari Argillander /* Compute the lsn based on the file offset and the sequence count. */ 1509b46acd6aSKonstantin Komarov *lsn = vbo_to_lsn(log, vbo, seq); 1510b46acd6aSKonstantin Komarov 1511b46acd6aSKonstantin Komarov /* 1512*e8b8e97fSKari Argillander * If this lsn is within the legal range for the file, we return true. 1513*e8b8e97fSKari Argillander * Otherwise false indicates that there are no more lsn's. 1514b46acd6aSKonstantin Komarov */ 1515b46acd6aSKonstantin Komarov if (!is_lsn_in_file(log, *lsn)) 1516b46acd6aSKonstantin Komarov *lsn = 0; 1517b46acd6aSKonstantin Komarov 1518195c52bdSKari Argillander kfree(page); 1519b46acd6aSKonstantin Komarov 1520b46acd6aSKonstantin Komarov return 0; 1521b46acd6aSKonstantin Komarov } 1522b46acd6aSKonstantin Komarov 1523b46acd6aSKonstantin Komarov /* 1524*e8b8e97fSKari Argillander * current_log_avail - Calculate the number of bytes available for log records. 1525b46acd6aSKonstantin Komarov */ 1526b46acd6aSKonstantin Komarov static u32 current_log_avail(struct ntfs_log *log) 1527b46acd6aSKonstantin Komarov { 1528b46acd6aSKonstantin Komarov u32 oldest_off, next_free_off, free_bytes; 1529b46acd6aSKonstantin Komarov 1530b46acd6aSKonstantin Komarov if (log->l_flags & NTFSLOG_NO_LAST_LSN) { 1531*e8b8e97fSKari Argillander /* The entire file is available. */ 1532b46acd6aSKonstantin Komarov return log->max_current_avail; 1533b46acd6aSKonstantin Komarov } 1534b46acd6aSKonstantin Komarov 1535b46acd6aSKonstantin Komarov /* 1536b46acd6aSKonstantin Komarov * If there is a last lsn the restart area then we know that we will 1537*e8b8e97fSKari Argillander * have to compute the free range. 1538*e8b8e97fSKari Argillander * If there is no oldest lsn then start at the first page of the file. 1539b46acd6aSKonstantin Komarov */ 1540b46acd6aSKonstantin Komarov oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) 1541b46acd6aSKonstantin Komarov ? log->first_page 1542b46acd6aSKonstantin Komarov : (log->oldest_lsn_off & ~log->sys_page_mask); 1543b46acd6aSKonstantin Komarov 1544b46acd6aSKonstantin Komarov /* 1545*e8b8e97fSKari Argillander * We will use the next log page offset to compute the next free page. 1546*e8b8e97fSKari Argillander * If we are going to reuse this page go to the next page. 1547*e8b8e97fSKari Argillander * If we are at the first page then use the end of the file. 1548b46acd6aSKonstantin Komarov */ 1549b46acd6aSKonstantin Komarov next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) 1550b46acd6aSKonstantin Komarov ? log->next_page + log->page_size 1551b46acd6aSKonstantin Komarov : log->next_page == log->first_page 1552b46acd6aSKonstantin Komarov ? log->l_size 1553b46acd6aSKonstantin Komarov : log->next_page; 1554b46acd6aSKonstantin Komarov 1555*e8b8e97fSKari Argillander /* If the two offsets are the same then there is no available space. */ 1556b46acd6aSKonstantin Komarov if (oldest_off == next_free_off) 1557b46acd6aSKonstantin Komarov return 0; 1558b46acd6aSKonstantin Komarov /* 1559b46acd6aSKonstantin Komarov * If the free offset follows the oldest offset then subtract 1560*e8b8e97fSKari Argillander * this range from the total available pages. 1561b46acd6aSKonstantin Komarov */ 1562b46acd6aSKonstantin Komarov free_bytes = 1563b46acd6aSKonstantin Komarov oldest_off < next_free_off 1564b46acd6aSKonstantin Komarov ? log->total_avail_pages - (next_free_off - oldest_off) 1565b46acd6aSKonstantin Komarov : oldest_off - next_free_off; 1566b46acd6aSKonstantin Komarov 1567b46acd6aSKonstantin Komarov free_bytes >>= log->page_bits; 1568b46acd6aSKonstantin Komarov return free_bytes * log->reserved; 1569b46acd6aSKonstantin Komarov } 1570b46acd6aSKonstantin Komarov 1571b46acd6aSKonstantin Komarov static bool check_subseq_log_page(struct ntfs_log *log, 1572b46acd6aSKonstantin Komarov const struct RECORD_PAGE_HDR *rp, u32 vbo, 1573b46acd6aSKonstantin Komarov u64 seq) 1574b46acd6aSKonstantin Komarov { 1575b46acd6aSKonstantin Komarov u64 lsn_seq; 1576b46acd6aSKonstantin Komarov const struct NTFS_RECORD_HEADER *rhdr = &rp->rhdr; 1577b46acd6aSKonstantin Komarov u64 lsn = le64_to_cpu(rhdr->lsn); 1578b46acd6aSKonstantin Komarov 1579b46acd6aSKonstantin Komarov if (rhdr->sign == NTFS_FFFF_SIGNATURE || !rhdr->sign) 1580b46acd6aSKonstantin Komarov return false; 1581b46acd6aSKonstantin Komarov 1582b46acd6aSKonstantin Komarov /* 1583b46acd6aSKonstantin Komarov * If the last lsn on the page occurs was written after the page 1584*e8b8e97fSKari Argillander * that caused the original error then we have a fatal error. 1585b46acd6aSKonstantin Komarov */ 1586b46acd6aSKonstantin Komarov lsn_seq = lsn >> log->file_data_bits; 1587b46acd6aSKonstantin Komarov 1588b46acd6aSKonstantin Komarov /* 1589b46acd6aSKonstantin Komarov * If the sequence number for the lsn the page is equal or greater 1590*e8b8e97fSKari Argillander * than lsn we expect, then this is a subsequent write. 1591b46acd6aSKonstantin Komarov */ 1592b46acd6aSKonstantin Komarov return lsn_seq >= seq || 1593b46acd6aSKonstantin Komarov (lsn_seq == seq - 1 && log->first_page == vbo && 1594b46acd6aSKonstantin Komarov vbo != (lsn_to_vbo(log, lsn) & ~log->page_mask)); 1595b46acd6aSKonstantin Komarov } 1596b46acd6aSKonstantin Komarov 1597b46acd6aSKonstantin Komarov /* 1598b46acd6aSKonstantin Komarov * last_log_lsn 1599b46acd6aSKonstantin Komarov * 1600*e8b8e97fSKari Argillander * Walks through the log pages for a file, searching for the 1601*e8b8e97fSKari Argillander * last log page written to the file. 1602b46acd6aSKonstantin Komarov */ 1603b46acd6aSKonstantin Komarov static int last_log_lsn(struct ntfs_log *log) 1604b46acd6aSKonstantin Komarov { 1605b46acd6aSKonstantin Komarov int err; 1606b46acd6aSKonstantin Komarov bool usa_error = false; 1607b46acd6aSKonstantin Komarov bool replace_page = false; 1608b46acd6aSKonstantin Komarov bool reuse_page = log->l_flags & NTFSLOG_REUSE_TAIL; 1609b46acd6aSKonstantin Komarov bool wrapped_file, wrapped; 1610b46acd6aSKonstantin Komarov 1611b46acd6aSKonstantin Komarov u32 page_cnt = 1, page_pos = 1; 1612b46acd6aSKonstantin Komarov u32 page_off = 0, page_off1 = 0, saved_off = 0; 1613b46acd6aSKonstantin Komarov u32 final_off, second_off, final_off_prev = 0, second_off_prev = 0; 1614b46acd6aSKonstantin Komarov u32 first_file_off = 0, second_file_off = 0; 1615b46acd6aSKonstantin Komarov u32 part_io_count = 0; 1616b46acd6aSKonstantin Komarov u32 tails = 0; 1617b46acd6aSKonstantin Komarov u32 this_off, curpage_off, nextpage_off, remain_pages; 1618b46acd6aSKonstantin Komarov 1619b46acd6aSKonstantin Komarov u64 expected_seq, seq_base = 0, lsn_base = 0; 1620b46acd6aSKonstantin Komarov u64 best_lsn, best_lsn1, best_lsn2; 1621b46acd6aSKonstantin Komarov u64 lsn_cur, lsn1, lsn2; 1622b46acd6aSKonstantin Komarov u64 last_ok_lsn = reuse_page ? log->last_lsn : 0; 1623b46acd6aSKonstantin Komarov 1624b46acd6aSKonstantin Komarov u16 cur_pos, best_page_pos; 1625b46acd6aSKonstantin Komarov 1626b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *page = NULL; 1627b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *tst_page = NULL; 1628b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *first_tail = NULL; 1629b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *second_tail = NULL; 1630b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *tail_page = NULL; 1631b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *second_tail_prev = NULL; 1632b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *first_tail_prev = NULL; 1633b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *page_bufs = NULL; 1634b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *best_page; 1635b46acd6aSKonstantin Komarov 1636b46acd6aSKonstantin Komarov if (log->major_ver >= 2) { 1637b46acd6aSKonstantin Komarov final_off = 0x02 * log->page_size; 1638b46acd6aSKonstantin Komarov second_off = 0x12 * log->page_size; 1639b46acd6aSKonstantin Komarov 1640b46acd6aSKonstantin Komarov // 0x10 == 0x12 - 0x2 1641195c52bdSKari Argillander page_bufs = kmalloc(log->page_size * 0x10, GFP_NOFS); 1642b46acd6aSKonstantin Komarov if (!page_bufs) 1643b46acd6aSKonstantin Komarov return -ENOMEM; 1644b46acd6aSKonstantin Komarov } else { 1645b46acd6aSKonstantin Komarov second_off = log->first_page - log->page_size; 1646b46acd6aSKonstantin Komarov final_off = second_off - log->page_size; 1647b46acd6aSKonstantin Komarov } 1648b46acd6aSKonstantin Komarov 1649b46acd6aSKonstantin Komarov next_tail: 1650*e8b8e97fSKari Argillander /* Read second tail page (at pos 3/0x12000). */ 1651b46acd6aSKonstantin Komarov if (read_log_page(log, second_off, &second_tail, &usa_error) || 1652b46acd6aSKonstantin Komarov usa_error || second_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) { 1653195c52bdSKari Argillander kfree(second_tail); 1654b46acd6aSKonstantin Komarov second_tail = NULL; 1655b46acd6aSKonstantin Komarov second_file_off = 0; 1656b46acd6aSKonstantin Komarov lsn2 = 0; 1657b46acd6aSKonstantin Komarov } else { 1658b46acd6aSKonstantin Komarov second_file_off = hdr_file_off(log, second_tail); 1659b46acd6aSKonstantin Komarov lsn2 = le64_to_cpu(second_tail->record_hdr.last_end_lsn); 1660b46acd6aSKonstantin Komarov } 1661b46acd6aSKonstantin Komarov 1662*e8b8e97fSKari Argillander /* Read first tail page (at pos 2/0x2000). */ 1663b46acd6aSKonstantin Komarov if (read_log_page(log, final_off, &first_tail, &usa_error) || 1664b46acd6aSKonstantin Komarov usa_error || first_tail->rhdr.sign != NTFS_RCRD_SIGNATURE) { 1665195c52bdSKari Argillander kfree(first_tail); 1666b46acd6aSKonstantin Komarov first_tail = NULL; 1667b46acd6aSKonstantin Komarov first_file_off = 0; 1668b46acd6aSKonstantin Komarov lsn1 = 0; 1669b46acd6aSKonstantin Komarov } else { 1670b46acd6aSKonstantin Komarov first_file_off = hdr_file_off(log, first_tail); 1671b46acd6aSKonstantin Komarov lsn1 = le64_to_cpu(first_tail->record_hdr.last_end_lsn); 1672b46acd6aSKonstantin Komarov } 1673b46acd6aSKonstantin Komarov 1674b46acd6aSKonstantin Komarov if (log->major_ver < 2) { 1675b46acd6aSKonstantin Komarov int best_page; 1676b46acd6aSKonstantin Komarov 1677b46acd6aSKonstantin Komarov first_tail_prev = first_tail; 1678b46acd6aSKonstantin Komarov final_off_prev = first_file_off; 1679b46acd6aSKonstantin Komarov second_tail_prev = second_tail; 1680b46acd6aSKonstantin Komarov second_off_prev = second_file_off; 1681b46acd6aSKonstantin Komarov tails = 1; 1682b46acd6aSKonstantin Komarov 1683b46acd6aSKonstantin Komarov if (!first_tail && !second_tail) 1684b46acd6aSKonstantin Komarov goto tail_read; 1685b46acd6aSKonstantin Komarov 1686b46acd6aSKonstantin Komarov if (first_tail && second_tail) 1687b46acd6aSKonstantin Komarov best_page = lsn1 < lsn2 ? 1 : 0; 1688b46acd6aSKonstantin Komarov else if (first_tail) 1689b46acd6aSKonstantin Komarov best_page = 0; 1690b46acd6aSKonstantin Komarov else 1691b46acd6aSKonstantin Komarov best_page = 1; 1692b46acd6aSKonstantin Komarov 1693b46acd6aSKonstantin Komarov page_off = best_page ? second_file_off : first_file_off; 1694b46acd6aSKonstantin Komarov seq_base = (best_page ? lsn2 : lsn1) >> log->file_data_bits; 1695b46acd6aSKonstantin Komarov goto tail_read; 1696b46acd6aSKonstantin Komarov } 1697b46acd6aSKonstantin Komarov 1698b46acd6aSKonstantin Komarov best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0; 1699b46acd6aSKonstantin Komarov best_lsn2 = 1700b46acd6aSKonstantin Komarov second_tail ? base_lsn(log, second_tail, second_file_off) : 0; 1701b46acd6aSKonstantin Komarov 1702b46acd6aSKonstantin Komarov if (first_tail && second_tail) { 1703b46acd6aSKonstantin Komarov if (best_lsn1 > best_lsn2) { 1704b46acd6aSKonstantin Komarov best_lsn = best_lsn1; 1705b46acd6aSKonstantin Komarov best_page = first_tail; 1706b46acd6aSKonstantin Komarov this_off = first_file_off; 1707b46acd6aSKonstantin Komarov } else { 1708b46acd6aSKonstantin Komarov best_lsn = best_lsn2; 1709b46acd6aSKonstantin Komarov best_page = second_tail; 1710b46acd6aSKonstantin Komarov this_off = second_file_off; 1711b46acd6aSKonstantin Komarov } 1712b46acd6aSKonstantin Komarov } else if (first_tail) { 1713b46acd6aSKonstantin Komarov best_lsn = best_lsn1; 1714b46acd6aSKonstantin Komarov best_page = first_tail; 1715b46acd6aSKonstantin Komarov this_off = first_file_off; 1716b46acd6aSKonstantin Komarov } else if (second_tail) { 1717b46acd6aSKonstantin Komarov best_lsn = best_lsn2; 1718b46acd6aSKonstantin Komarov best_page = second_tail; 1719b46acd6aSKonstantin Komarov this_off = second_file_off; 1720b46acd6aSKonstantin Komarov } else { 1721b46acd6aSKonstantin Komarov goto tail_read; 1722b46acd6aSKonstantin Komarov } 1723b46acd6aSKonstantin Komarov 1724b46acd6aSKonstantin Komarov best_page_pos = le16_to_cpu(best_page->page_pos); 1725b46acd6aSKonstantin Komarov 1726b46acd6aSKonstantin Komarov if (!tails) { 1727b46acd6aSKonstantin Komarov if (best_page_pos == page_pos) { 1728b46acd6aSKonstantin Komarov seq_base = best_lsn >> log->file_data_bits; 1729b46acd6aSKonstantin Komarov saved_off = page_off = le32_to_cpu(best_page->file_off); 1730b46acd6aSKonstantin Komarov lsn_base = best_lsn; 1731b46acd6aSKonstantin Komarov 1732b46acd6aSKonstantin Komarov memmove(page_bufs, best_page, log->page_size); 1733b46acd6aSKonstantin Komarov 1734b46acd6aSKonstantin Komarov page_cnt = le16_to_cpu(best_page->page_count); 1735b46acd6aSKonstantin Komarov if (page_cnt > 1) 1736b46acd6aSKonstantin Komarov page_pos += 1; 1737b46acd6aSKonstantin Komarov 1738b46acd6aSKonstantin Komarov tails = 1; 1739b46acd6aSKonstantin Komarov } 1740b46acd6aSKonstantin Komarov } else if (seq_base == (best_lsn >> log->file_data_bits) && 1741b46acd6aSKonstantin Komarov saved_off + log->page_size == this_off && 1742b46acd6aSKonstantin Komarov lsn_base < best_lsn && 1743b46acd6aSKonstantin Komarov (page_pos != page_cnt || best_page_pos == page_pos || 1744b46acd6aSKonstantin Komarov best_page_pos == 1) && 1745b46acd6aSKonstantin Komarov (page_pos >= page_cnt || best_page_pos == page_pos)) { 1746b46acd6aSKonstantin Komarov u16 bppc = le16_to_cpu(best_page->page_count); 1747b46acd6aSKonstantin Komarov 1748b46acd6aSKonstantin Komarov saved_off += log->page_size; 1749b46acd6aSKonstantin Komarov lsn_base = best_lsn; 1750b46acd6aSKonstantin Komarov 1751b46acd6aSKonstantin Komarov memmove(Add2Ptr(page_bufs, tails * log->page_size), best_page, 1752b46acd6aSKonstantin Komarov log->page_size); 1753b46acd6aSKonstantin Komarov 1754b46acd6aSKonstantin Komarov tails += 1; 1755b46acd6aSKonstantin Komarov 1756b46acd6aSKonstantin Komarov if (best_page_pos != bppc) { 1757b46acd6aSKonstantin Komarov page_cnt = bppc; 1758b46acd6aSKonstantin Komarov page_pos = best_page_pos; 1759b46acd6aSKonstantin Komarov 1760b46acd6aSKonstantin Komarov if (page_cnt > 1) 1761b46acd6aSKonstantin Komarov page_pos += 1; 1762b46acd6aSKonstantin Komarov } else { 1763b46acd6aSKonstantin Komarov page_pos = page_cnt = 1; 1764b46acd6aSKonstantin Komarov } 1765b46acd6aSKonstantin Komarov } else { 1766195c52bdSKari Argillander kfree(first_tail); 1767195c52bdSKari Argillander kfree(second_tail); 1768b46acd6aSKonstantin Komarov goto tail_read; 1769b46acd6aSKonstantin Komarov } 1770b46acd6aSKonstantin Komarov 1771195c52bdSKari Argillander kfree(first_tail_prev); 1772b46acd6aSKonstantin Komarov first_tail_prev = first_tail; 1773b46acd6aSKonstantin Komarov final_off_prev = first_file_off; 1774b46acd6aSKonstantin Komarov first_tail = NULL; 1775b46acd6aSKonstantin Komarov 1776195c52bdSKari Argillander kfree(second_tail_prev); 1777b46acd6aSKonstantin Komarov second_tail_prev = second_tail; 1778b46acd6aSKonstantin Komarov second_off_prev = second_file_off; 1779b46acd6aSKonstantin Komarov second_tail = NULL; 1780b46acd6aSKonstantin Komarov 1781b46acd6aSKonstantin Komarov final_off += log->page_size; 1782b46acd6aSKonstantin Komarov second_off += log->page_size; 1783b46acd6aSKonstantin Komarov 1784b46acd6aSKonstantin Komarov if (tails < 0x10) 1785b46acd6aSKonstantin Komarov goto next_tail; 1786b46acd6aSKonstantin Komarov tail_read: 1787b46acd6aSKonstantin Komarov first_tail = first_tail_prev; 1788b46acd6aSKonstantin Komarov final_off = final_off_prev; 1789b46acd6aSKonstantin Komarov 1790b46acd6aSKonstantin Komarov second_tail = second_tail_prev; 1791b46acd6aSKonstantin Komarov second_off = second_off_prev; 1792b46acd6aSKonstantin Komarov 1793b46acd6aSKonstantin Komarov page_cnt = page_pos = 1; 1794b46acd6aSKonstantin Komarov 1795b46acd6aSKonstantin Komarov curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) 1796b46acd6aSKonstantin Komarov : log->next_page; 1797b46acd6aSKonstantin Komarov 1798b46acd6aSKonstantin Komarov wrapped_file = 1799b46acd6aSKonstantin Komarov curpage_off == log->first_page && 1800b46acd6aSKonstantin Komarov !(log->l_flags & (NTFSLOG_NO_LAST_LSN | NTFSLOG_REUSE_TAIL)); 1801b46acd6aSKonstantin Komarov 1802b46acd6aSKonstantin Komarov expected_seq = wrapped_file ? (log->seq_num + 1) : log->seq_num; 1803b46acd6aSKonstantin Komarov 1804b46acd6aSKonstantin Komarov nextpage_off = curpage_off; 1805b46acd6aSKonstantin Komarov 1806b46acd6aSKonstantin Komarov next_page: 1807b46acd6aSKonstantin Komarov tail_page = NULL; 1808*e8b8e97fSKari Argillander /* Read the next log page. */ 1809b46acd6aSKonstantin Komarov err = read_log_page(log, curpage_off, &page, &usa_error); 1810b46acd6aSKonstantin Komarov 1811*e8b8e97fSKari Argillander /* Compute the next log page offset the file. */ 1812b46acd6aSKonstantin Komarov nextpage_off = next_page_off(log, curpage_off); 1813b46acd6aSKonstantin Komarov wrapped = nextpage_off == log->first_page; 1814b46acd6aSKonstantin Komarov 1815b46acd6aSKonstantin Komarov if (tails > 1) { 1816b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *cur_page = 1817b46acd6aSKonstantin Komarov Add2Ptr(page_bufs, curpage_off - page_off); 1818b46acd6aSKonstantin Komarov 1819b46acd6aSKonstantin Komarov if (curpage_off == saved_off) { 1820b46acd6aSKonstantin Komarov tail_page = cur_page; 1821b46acd6aSKonstantin Komarov goto use_tail_page; 1822b46acd6aSKonstantin Komarov } 1823b46acd6aSKonstantin Komarov 1824b46acd6aSKonstantin Komarov if (page_off > curpage_off || curpage_off >= saved_off) 1825b46acd6aSKonstantin Komarov goto use_tail_page; 1826b46acd6aSKonstantin Komarov 1827b46acd6aSKonstantin Komarov if (page_off1) 1828b46acd6aSKonstantin Komarov goto use_cur_page; 1829b46acd6aSKonstantin Komarov 1830b46acd6aSKonstantin Komarov if (!err && !usa_error && 1831b46acd6aSKonstantin Komarov page->rhdr.sign == NTFS_RCRD_SIGNATURE && 1832b46acd6aSKonstantin Komarov cur_page->rhdr.lsn == page->rhdr.lsn && 1833b46acd6aSKonstantin Komarov cur_page->record_hdr.next_record_off == 1834b46acd6aSKonstantin Komarov page->record_hdr.next_record_off && 1835b46acd6aSKonstantin Komarov ((page_pos == page_cnt && 1836b46acd6aSKonstantin Komarov le16_to_cpu(page->page_pos) == 1) || 1837b46acd6aSKonstantin Komarov (page_pos != page_cnt && 1838b46acd6aSKonstantin Komarov le16_to_cpu(page->page_pos) == page_pos + 1 && 1839b46acd6aSKonstantin Komarov le16_to_cpu(page->page_count) == page_cnt))) { 1840b46acd6aSKonstantin Komarov cur_page = NULL; 1841b46acd6aSKonstantin Komarov goto use_tail_page; 1842b46acd6aSKonstantin Komarov } 1843b46acd6aSKonstantin Komarov 1844b46acd6aSKonstantin Komarov page_off1 = page_off; 1845b46acd6aSKonstantin Komarov 1846b46acd6aSKonstantin Komarov use_cur_page: 1847b46acd6aSKonstantin Komarov 1848b46acd6aSKonstantin Komarov lsn_cur = le64_to_cpu(cur_page->rhdr.lsn); 1849b46acd6aSKonstantin Komarov 1850b46acd6aSKonstantin Komarov if (last_ok_lsn != 1851b46acd6aSKonstantin Komarov le64_to_cpu(cur_page->record_hdr.last_end_lsn) && 1852b46acd6aSKonstantin Komarov ((lsn_cur >> log->file_data_bits) + 1853b46acd6aSKonstantin Komarov ((curpage_off < 1854b46acd6aSKonstantin Komarov (lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) 1855b46acd6aSKonstantin Komarov ? 1 1856b46acd6aSKonstantin Komarov : 0)) != expected_seq) { 1857b46acd6aSKonstantin Komarov goto check_tail; 1858b46acd6aSKonstantin Komarov } 1859b46acd6aSKonstantin Komarov 1860b46acd6aSKonstantin Komarov if (!is_log_record_end(cur_page)) { 1861b46acd6aSKonstantin Komarov tail_page = NULL; 1862b46acd6aSKonstantin Komarov last_ok_lsn = lsn_cur; 1863b46acd6aSKonstantin Komarov goto next_page_1; 1864b46acd6aSKonstantin Komarov } 1865b46acd6aSKonstantin Komarov 1866b46acd6aSKonstantin Komarov log->seq_num = expected_seq; 1867b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_NO_LAST_LSN; 1868b46acd6aSKonstantin Komarov log->last_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn); 1869b46acd6aSKonstantin Komarov log->ra->current_lsn = cur_page->record_hdr.last_end_lsn; 1870b46acd6aSKonstantin Komarov 1871b46acd6aSKonstantin Komarov if (log->record_header_len <= 1872b46acd6aSKonstantin Komarov log->page_size - 1873b46acd6aSKonstantin Komarov le16_to_cpu(cur_page->record_hdr.next_record_off)) { 1874b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_REUSE_TAIL; 1875b46acd6aSKonstantin Komarov log->next_page = curpage_off; 1876b46acd6aSKonstantin Komarov } else { 1877b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_REUSE_TAIL; 1878b46acd6aSKonstantin Komarov log->next_page = nextpage_off; 1879b46acd6aSKonstantin Komarov } 1880b46acd6aSKonstantin Komarov 1881b46acd6aSKonstantin Komarov if (wrapped_file) 1882b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED; 1883b46acd6aSKonstantin Komarov 1884b46acd6aSKonstantin Komarov last_ok_lsn = le64_to_cpu(cur_page->record_hdr.last_end_lsn); 1885b46acd6aSKonstantin Komarov goto next_page_1; 1886b46acd6aSKonstantin Komarov } 1887b46acd6aSKonstantin Komarov 1888b46acd6aSKonstantin Komarov /* 1889b46acd6aSKonstantin Komarov * If we are at the expected first page of a transfer check to see 1890*e8b8e97fSKari Argillander * if either tail copy is at this offset. 1891b46acd6aSKonstantin Komarov * If this page is the last page of a transfer, check if we wrote 1892*e8b8e97fSKari Argillander * a subsequent tail copy. 1893b46acd6aSKonstantin Komarov */ 1894b46acd6aSKonstantin Komarov if (page_cnt == page_pos || page_cnt == page_pos + 1) { 1895b46acd6aSKonstantin Komarov /* 1896b46acd6aSKonstantin Komarov * Check if the offset matches either the first or second 1897*e8b8e97fSKari Argillander * tail copy. It is possible it will match both. 1898b46acd6aSKonstantin Komarov */ 1899b46acd6aSKonstantin Komarov if (curpage_off == final_off) 1900b46acd6aSKonstantin Komarov tail_page = first_tail; 1901b46acd6aSKonstantin Komarov 1902b46acd6aSKonstantin Komarov /* 1903b46acd6aSKonstantin Komarov * If we already matched on the first page then 1904b46acd6aSKonstantin Komarov * check the ending lsn's. 1905b46acd6aSKonstantin Komarov */ 1906b46acd6aSKonstantin Komarov if (curpage_off == second_off) { 1907b46acd6aSKonstantin Komarov if (!tail_page || 1908b46acd6aSKonstantin Komarov (second_tail && 1909b46acd6aSKonstantin Komarov le64_to_cpu(second_tail->record_hdr.last_end_lsn) > 1910b46acd6aSKonstantin Komarov le64_to_cpu(first_tail->record_hdr 1911b46acd6aSKonstantin Komarov .last_end_lsn))) { 1912b46acd6aSKonstantin Komarov tail_page = second_tail; 1913b46acd6aSKonstantin Komarov } 1914b46acd6aSKonstantin Komarov } 1915b46acd6aSKonstantin Komarov } 1916b46acd6aSKonstantin Komarov 1917b46acd6aSKonstantin Komarov use_tail_page: 1918b46acd6aSKonstantin Komarov if (tail_page) { 1919*e8b8e97fSKari Argillander /* We have a candidate for a tail copy. */ 1920b46acd6aSKonstantin Komarov lsn_cur = le64_to_cpu(tail_page->record_hdr.last_end_lsn); 1921b46acd6aSKonstantin Komarov 1922b46acd6aSKonstantin Komarov if (last_ok_lsn < lsn_cur) { 1923b46acd6aSKonstantin Komarov /* 1924b46acd6aSKonstantin Komarov * If the sequence number is not expected, 1925*e8b8e97fSKari Argillander * then don't use the tail copy. 1926b46acd6aSKonstantin Komarov */ 1927b46acd6aSKonstantin Komarov if (expected_seq != (lsn_cur >> log->file_data_bits)) 1928b46acd6aSKonstantin Komarov tail_page = NULL; 1929b46acd6aSKonstantin Komarov } else if (last_ok_lsn > lsn_cur) { 1930b46acd6aSKonstantin Komarov /* 1931b46acd6aSKonstantin Komarov * If the last lsn is greater than the one on 1932*e8b8e97fSKari Argillander * this page then forget this tail. 1933b46acd6aSKonstantin Komarov */ 1934b46acd6aSKonstantin Komarov tail_page = NULL; 1935b46acd6aSKonstantin Komarov } 1936b46acd6aSKonstantin Komarov } 1937b46acd6aSKonstantin Komarov 1938*e8b8e97fSKari Argillander /* 1939*e8b8e97fSKari Argillander *If we have an error on the current page, 1940*e8b8e97fSKari Argillander * we will break of this loop. 1941*e8b8e97fSKari Argillander */ 1942b46acd6aSKonstantin Komarov if (err || usa_error) 1943b46acd6aSKonstantin Komarov goto check_tail; 1944b46acd6aSKonstantin Komarov 1945b46acd6aSKonstantin Komarov /* 1946b46acd6aSKonstantin Komarov * Done if the last lsn on this page doesn't match the previous known 1947*e8b8e97fSKari Argillander * last lsn or the sequence number is not expected. 1948b46acd6aSKonstantin Komarov */ 1949b46acd6aSKonstantin Komarov lsn_cur = le64_to_cpu(page->rhdr.lsn); 1950b46acd6aSKonstantin Komarov if (last_ok_lsn != lsn_cur && 1951b46acd6aSKonstantin Komarov expected_seq != (lsn_cur >> log->file_data_bits)) { 1952b46acd6aSKonstantin Komarov goto check_tail; 1953b46acd6aSKonstantin Komarov } 1954b46acd6aSKonstantin Komarov 1955b46acd6aSKonstantin Komarov /* 1956*e8b8e97fSKari Argillander * Check that the page position and page count values are correct. 1957b46acd6aSKonstantin Komarov * If this is the first page of a transfer the position must be 1 1958*e8b8e97fSKari Argillander * and the count will be unknown. 1959b46acd6aSKonstantin Komarov */ 1960b46acd6aSKonstantin Komarov if (page_cnt == page_pos) { 1961b46acd6aSKonstantin Komarov if (page->page_pos != cpu_to_le16(1) && 1962b46acd6aSKonstantin Komarov (!reuse_page || page->page_pos != page->page_count)) { 1963b46acd6aSKonstantin Komarov /* 1964b46acd6aSKonstantin Komarov * If the current page is the first page we are 1965b46acd6aSKonstantin Komarov * looking at and we are reusing this page then 1966b46acd6aSKonstantin Komarov * it can be either the first or last page of a 1967b46acd6aSKonstantin Komarov * transfer. Otherwise it can only be the first. 1968b46acd6aSKonstantin Komarov */ 1969b46acd6aSKonstantin Komarov goto check_tail; 1970b46acd6aSKonstantin Komarov } 1971b46acd6aSKonstantin Komarov } else if (le16_to_cpu(page->page_count) != page_cnt || 1972b46acd6aSKonstantin Komarov le16_to_cpu(page->page_pos) != page_pos + 1) { 1973b46acd6aSKonstantin Komarov /* 1974b46acd6aSKonstantin Komarov * The page position better be 1 more than the last page 1975*e8b8e97fSKari Argillander * position and the page count better match. 1976b46acd6aSKonstantin Komarov */ 1977b46acd6aSKonstantin Komarov goto check_tail; 1978b46acd6aSKonstantin Komarov } 1979b46acd6aSKonstantin Komarov 1980b46acd6aSKonstantin Komarov /* 1981b46acd6aSKonstantin Komarov * We have a valid page the file and may have a valid page 1982*e8b8e97fSKari Argillander * the tail copy area. 1983b46acd6aSKonstantin Komarov * If the tail page was written after the page the file then 1984*e8b8e97fSKari Argillander * break of the loop. 1985b46acd6aSKonstantin Komarov */ 1986b46acd6aSKonstantin Komarov if (tail_page && 1987b46acd6aSKonstantin Komarov le64_to_cpu(tail_page->record_hdr.last_end_lsn) > lsn_cur) { 1988*e8b8e97fSKari Argillander /* Remember if we will replace the page. */ 1989b46acd6aSKonstantin Komarov replace_page = true; 1990b46acd6aSKonstantin Komarov goto check_tail; 1991b46acd6aSKonstantin Komarov } 1992b46acd6aSKonstantin Komarov 1993b46acd6aSKonstantin Komarov tail_page = NULL; 1994b46acd6aSKonstantin Komarov 1995b46acd6aSKonstantin Komarov if (is_log_record_end(page)) { 1996b46acd6aSKonstantin Komarov /* 1997b46acd6aSKonstantin Komarov * Since we have read this page we know the sequence number 1998*e8b8e97fSKari Argillander * is the same as our expected value. 1999b46acd6aSKonstantin Komarov */ 2000b46acd6aSKonstantin Komarov log->seq_num = expected_seq; 2001b46acd6aSKonstantin Komarov log->last_lsn = le64_to_cpu(page->record_hdr.last_end_lsn); 2002b46acd6aSKonstantin Komarov log->ra->current_lsn = page->record_hdr.last_end_lsn; 2003b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_NO_LAST_LSN; 2004b46acd6aSKonstantin Komarov 2005b46acd6aSKonstantin Komarov /* 2006b46acd6aSKonstantin Komarov * If there is room on this page for another header then 2007*e8b8e97fSKari Argillander * remember we want to reuse the page. 2008b46acd6aSKonstantin Komarov */ 2009b46acd6aSKonstantin Komarov if (log->record_header_len <= 2010b46acd6aSKonstantin Komarov log->page_size - 2011b46acd6aSKonstantin Komarov le16_to_cpu(page->record_hdr.next_record_off)) { 2012b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_REUSE_TAIL; 2013b46acd6aSKonstantin Komarov log->next_page = curpage_off; 2014b46acd6aSKonstantin Komarov } else { 2015b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_REUSE_TAIL; 2016b46acd6aSKonstantin Komarov log->next_page = nextpage_off; 2017b46acd6aSKonstantin Komarov } 2018b46acd6aSKonstantin Komarov 2019*e8b8e97fSKari Argillander /* Remember if we wrapped the log file. */ 2020b46acd6aSKonstantin Komarov if (wrapped_file) 2021b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED; 2022b46acd6aSKonstantin Komarov } 2023b46acd6aSKonstantin Komarov 2024b46acd6aSKonstantin Komarov /* 2025b46acd6aSKonstantin Komarov * Remember the last page count and position. 2026*e8b8e97fSKari Argillander * Also remember the last known lsn. 2027b46acd6aSKonstantin Komarov */ 2028b46acd6aSKonstantin Komarov page_cnt = le16_to_cpu(page->page_count); 2029b46acd6aSKonstantin Komarov page_pos = le16_to_cpu(page->page_pos); 2030b46acd6aSKonstantin Komarov last_ok_lsn = le64_to_cpu(page->rhdr.lsn); 2031b46acd6aSKonstantin Komarov 2032b46acd6aSKonstantin Komarov next_page_1: 2033b46acd6aSKonstantin Komarov 2034b46acd6aSKonstantin Komarov if (wrapped) { 2035b46acd6aSKonstantin Komarov expected_seq += 1; 2036b46acd6aSKonstantin Komarov wrapped_file = 1; 2037b46acd6aSKonstantin Komarov } 2038b46acd6aSKonstantin Komarov 2039b46acd6aSKonstantin Komarov curpage_off = nextpage_off; 2040195c52bdSKari Argillander kfree(page); 2041b46acd6aSKonstantin Komarov page = NULL; 2042b46acd6aSKonstantin Komarov reuse_page = 0; 2043b46acd6aSKonstantin Komarov goto next_page; 2044b46acd6aSKonstantin Komarov 2045b46acd6aSKonstantin Komarov check_tail: 2046b46acd6aSKonstantin Komarov if (tail_page) { 2047b46acd6aSKonstantin Komarov log->seq_num = expected_seq; 2048b46acd6aSKonstantin Komarov log->last_lsn = le64_to_cpu(tail_page->record_hdr.last_end_lsn); 2049b46acd6aSKonstantin Komarov log->ra->current_lsn = tail_page->record_hdr.last_end_lsn; 2050b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_NO_LAST_LSN; 2051b46acd6aSKonstantin Komarov 2052b46acd6aSKonstantin Komarov if (log->page_size - 2053b46acd6aSKonstantin Komarov le16_to_cpu( 2054b46acd6aSKonstantin Komarov tail_page->record_hdr.next_record_off) >= 2055b46acd6aSKonstantin Komarov log->record_header_len) { 2056b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_REUSE_TAIL; 2057b46acd6aSKonstantin Komarov log->next_page = curpage_off; 2058b46acd6aSKonstantin Komarov } else { 2059b46acd6aSKonstantin Komarov log->l_flags &= ~NTFSLOG_REUSE_TAIL; 2060b46acd6aSKonstantin Komarov log->next_page = nextpage_off; 2061b46acd6aSKonstantin Komarov } 2062b46acd6aSKonstantin Komarov 2063b46acd6aSKonstantin Komarov if (wrapped) 2064b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED; 2065b46acd6aSKonstantin Komarov } 2066b46acd6aSKonstantin Komarov 2067*e8b8e97fSKari Argillander /* Remember that the partial IO will start at the next page. */ 2068b46acd6aSKonstantin Komarov second_off = nextpage_off; 2069b46acd6aSKonstantin Komarov 2070b46acd6aSKonstantin Komarov /* 2071b46acd6aSKonstantin Komarov * If the next page is the first page of the file then update 2072*e8b8e97fSKari Argillander * the sequence number for log records which begon the next page. 2073b46acd6aSKonstantin Komarov */ 2074b46acd6aSKonstantin Komarov if (wrapped) 2075b46acd6aSKonstantin Komarov expected_seq += 1; 2076b46acd6aSKonstantin Komarov 2077b46acd6aSKonstantin Komarov /* 2078b46acd6aSKonstantin Komarov * If we have a tail copy or are performing single page I/O we can 2079*e8b8e97fSKari Argillander * immediately look at the next page. 2080b46acd6aSKonstantin Komarov */ 2081b46acd6aSKonstantin Komarov if (replace_page || (log->ra->flags & RESTART_SINGLE_PAGE_IO)) { 2082b46acd6aSKonstantin Komarov page_cnt = 2; 2083b46acd6aSKonstantin Komarov page_pos = 1; 2084b46acd6aSKonstantin Komarov goto check_valid; 2085b46acd6aSKonstantin Komarov } 2086b46acd6aSKonstantin Komarov 2087b46acd6aSKonstantin Komarov if (page_pos != page_cnt) 2088b46acd6aSKonstantin Komarov goto check_valid; 2089b46acd6aSKonstantin Komarov /* 2090b46acd6aSKonstantin Komarov * If the next page causes us to wrap to the beginning of the log 2091b46acd6aSKonstantin Komarov * file then we know which page to check next. 2092b46acd6aSKonstantin Komarov */ 2093b46acd6aSKonstantin Komarov if (wrapped) { 2094b46acd6aSKonstantin Komarov page_cnt = 2; 2095b46acd6aSKonstantin Komarov page_pos = 1; 2096b46acd6aSKonstantin Komarov goto check_valid; 2097b46acd6aSKonstantin Komarov } 2098b46acd6aSKonstantin Komarov 2099b46acd6aSKonstantin Komarov cur_pos = 2; 2100b46acd6aSKonstantin Komarov 2101b46acd6aSKonstantin Komarov next_test_page: 2102195c52bdSKari Argillander kfree(tst_page); 2103b46acd6aSKonstantin Komarov tst_page = NULL; 2104b46acd6aSKonstantin Komarov 2105*e8b8e97fSKari Argillander /* Walk through the file, reading log pages. */ 2106b46acd6aSKonstantin Komarov err = read_log_page(log, nextpage_off, &tst_page, &usa_error); 2107b46acd6aSKonstantin Komarov 2108b46acd6aSKonstantin Komarov /* 2109b46acd6aSKonstantin Komarov * If we get a USA error then assume that we correctly found 2110*e8b8e97fSKari Argillander * the end of the original transfer. 2111b46acd6aSKonstantin Komarov */ 2112b46acd6aSKonstantin Komarov if (usa_error) 2113b46acd6aSKonstantin Komarov goto file_is_valid; 2114b46acd6aSKonstantin Komarov 2115b46acd6aSKonstantin Komarov /* 2116b46acd6aSKonstantin Komarov * If we were able to read the page, we examine it to see if it 2117*e8b8e97fSKari Argillander * is the same or different Io block. 2118b46acd6aSKonstantin Komarov */ 2119b46acd6aSKonstantin Komarov if (err) 2120b46acd6aSKonstantin Komarov goto next_test_page_1; 2121b46acd6aSKonstantin Komarov 2122b46acd6aSKonstantin Komarov if (le16_to_cpu(tst_page->page_pos) == cur_pos && 2123b46acd6aSKonstantin Komarov check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) { 2124b46acd6aSKonstantin Komarov page_cnt = le16_to_cpu(tst_page->page_count) + 1; 2125b46acd6aSKonstantin Komarov page_pos = le16_to_cpu(tst_page->page_pos); 2126b46acd6aSKonstantin Komarov goto check_valid; 2127b46acd6aSKonstantin Komarov } else { 2128b46acd6aSKonstantin Komarov goto file_is_valid; 2129b46acd6aSKonstantin Komarov } 2130b46acd6aSKonstantin Komarov 2131b46acd6aSKonstantin Komarov next_test_page_1: 2132b46acd6aSKonstantin Komarov 2133b46acd6aSKonstantin Komarov nextpage_off = next_page_off(log, curpage_off); 2134b46acd6aSKonstantin Komarov wrapped = nextpage_off == log->first_page; 2135b46acd6aSKonstantin Komarov 2136b46acd6aSKonstantin Komarov if (wrapped) { 2137b46acd6aSKonstantin Komarov expected_seq += 1; 2138b46acd6aSKonstantin Komarov page_cnt = 2; 2139b46acd6aSKonstantin Komarov page_pos = 1; 2140b46acd6aSKonstantin Komarov } 2141b46acd6aSKonstantin Komarov 2142b46acd6aSKonstantin Komarov cur_pos += 1; 2143b46acd6aSKonstantin Komarov part_io_count += 1; 2144b46acd6aSKonstantin Komarov if (!wrapped) 2145b46acd6aSKonstantin Komarov goto next_test_page; 2146b46acd6aSKonstantin Komarov 2147b46acd6aSKonstantin Komarov check_valid: 2148*e8b8e97fSKari Argillander /* Skip over the remaining pages this transfer. */ 2149b46acd6aSKonstantin Komarov remain_pages = page_cnt - page_pos - 1; 2150b46acd6aSKonstantin Komarov part_io_count += remain_pages; 2151b46acd6aSKonstantin Komarov 2152b46acd6aSKonstantin Komarov while (remain_pages--) { 2153b46acd6aSKonstantin Komarov nextpage_off = next_page_off(log, curpage_off); 2154b46acd6aSKonstantin Komarov wrapped = nextpage_off == log->first_page; 2155b46acd6aSKonstantin Komarov 2156b46acd6aSKonstantin Komarov if (wrapped) 2157b46acd6aSKonstantin Komarov expected_seq += 1; 2158b46acd6aSKonstantin Komarov } 2159b46acd6aSKonstantin Komarov 2160*e8b8e97fSKari Argillander /* Call our routine to check this log page. */ 2161195c52bdSKari Argillander kfree(tst_page); 2162b46acd6aSKonstantin Komarov tst_page = NULL; 2163b46acd6aSKonstantin Komarov 2164b46acd6aSKonstantin Komarov err = read_log_page(log, nextpage_off, &tst_page, &usa_error); 2165b46acd6aSKonstantin Komarov if (!err && !usa_error && 2166b46acd6aSKonstantin Komarov check_subseq_log_page(log, tst_page, nextpage_off, expected_seq)) { 2167b46acd6aSKonstantin Komarov err = -EINVAL; 2168b46acd6aSKonstantin Komarov goto out; 2169b46acd6aSKonstantin Komarov } 2170b46acd6aSKonstantin Komarov 2171b46acd6aSKonstantin Komarov file_is_valid: 2172b46acd6aSKonstantin Komarov 2173*e8b8e97fSKari Argillander /* We have a valid file. */ 2174b46acd6aSKonstantin Komarov if (page_off1 || tail_page) { 2175b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *tmp_page; 2176b46acd6aSKonstantin Komarov 2177b46acd6aSKonstantin Komarov if (sb_rdonly(log->ni->mi.sbi->sb)) { 2178b46acd6aSKonstantin Komarov err = -EROFS; 2179b46acd6aSKonstantin Komarov goto out; 2180b46acd6aSKonstantin Komarov } 2181b46acd6aSKonstantin Komarov 2182b46acd6aSKonstantin Komarov if (page_off1) { 2183b46acd6aSKonstantin Komarov tmp_page = Add2Ptr(page_bufs, page_off1 - page_off); 2184b46acd6aSKonstantin Komarov tails -= (page_off1 - page_off) / log->page_size; 2185b46acd6aSKonstantin Komarov if (!tail_page) 2186b46acd6aSKonstantin Komarov tails -= 1; 2187b46acd6aSKonstantin Komarov } else { 2188b46acd6aSKonstantin Komarov tmp_page = tail_page; 2189b46acd6aSKonstantin Komarov tails = 1; 2190b46acd6aSKonstantin Komarov } 2191b46acd6aSKonstantin Komarov 2192b46acd6aSKonstantin Komarov while (tails--) { 2193b46acd6aSKonstantin Komarov u64 off = hdr_file_off(log, tmp_page); 2194b46acd6aSKonstantin Komarov 2195b46acd6aSKonstantin Komarov if (!page) { 2196195c52bdSKari Argillander page = kmalloc(log->page_size, GFP_NOFS); 2197b46acd6aSKonstantin Komarov if (!page) 2198b46acd6aSKonstantin Komarov return -ENOMEM; 2199b46acd6aSKonstantin Komarov } 2200b46acd6aSKonstantin Komarov 2201b46acd6aSKonstantin Komarov /* 2202b46acd6aSKonstantin Komarov * Correct page and copy the data from this page 2203*e8b8e97fSKari Argillander * into it and flush it to disk. 2204b46acd6aSKonstantin Komarov */ 2205b46acd6aSKonstantin Komarov memcpy(page, tmp_page, log->page_size); 2206b46acd6aSKonstantin Komarov 2207*e8b8e97fSKari Argillander /* Fill last flushed lsn value flush the page. */ 2208b46acd6aSKonstantin Komarov if (log->major_ver < 2) 2209b46acd6aSKonstantin Komarov page->rhdr.lsn = page->record_hdr.last_end_lsn; 2210b46acd6aSKonstantin Komarov else 2211b46acd6aSKonstantin Komarov page->file_off = 0; 2212b46acd6aSKonstantin Komarov 2213b46acd6aSKonstantin Komarov page->page_pos = page->page_count = cpu_to_le16(1); 2214b46acd6aSKonstantin Komarov 2215b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&page->rhdr, log->page_size); 2216b46acd6aSKonstantin Komarov 2217b46acd6aSKonstantin Komarov err = ntfs_sb_write_run(log->ni->mi.sbi, 2218b46acd6aSKonstantin Komarov &log->ni->file.run, off, page, 2219b46acd6aSKonstantin Komarov log->page_size); 2220b46acd6aSKonstantin Komarov 2221b46acd6aSKonstantin Komarov if (err) 2222b46acd6aSKonstantin Komarov goto out; 2223b46acd6aSKonstantin Komarov 2224b46acd6aSKonstantin Komarov if (part_io_count && second_off == off) { 2225b46acd6aSKonstantin Komarov second_off += log->page_size; 2226b46acd6aSKonstantin Komarov part_io_count -= 1; 2227b46acd6aSKonstantin Komarov } 2228b46acd6aSKonstantin Komarov 2229b46acd6aSKonstantin Komarov tmp_page = Add2Ptr(tmp_page, log->page_size); 2230b46acd6aSKonstantin Komarov } 2231b46acd6aSKonstantin Komarov } 2232b46acd6aSKonstantin Komarov 2233b46acd6aSKonstantin Komarov if (part_io_count) { 2234b46acd6aSKonstantin Komarov if (sb_rdonly(log->ni->mi.sbi->sb)) { 2235b46acd6aSKonstantin Komarov err = -EROFS; 2236b46acd6aSKonstantin Komarov goto out; 2237b46acd6aSKonstantin Komarov } 2238b46acd6aSKonstantin Komarov } 2239b46acd6aSKonstantin Komarov 2240b46acd6aSKonstantin Komarov out: 2241195c52bdSKari Argillander kfree(second_tail); 2242195c52bdSKari Argillander kfree(first_tail); 2243195c52bdSKari Argillander kfree(page); 2244195c52bdSKari Argillander kfree(tst_page); 2245195c52bdSKari Argillander kfree(page_bufs); 2246b46acd6aSKonstantin Komarov 2247b46acd6aSKonstantin Komarov return err; 2248b46acd6aSKonstantin Komarov } 2249b46acd6aSKonstantin Komarov 2250b46acd6aSKonstantin Komarov /* 2251*e8b8e97fSKari Argillander * read_log_rec_buf - Copy a log record from the file to a buffer. 2252b46acd6aSKonstantin Komarov * 2253*e8b8e97fSKari Argillander * The log record may span several log pages and may even wrap the file. 2254b46acd6aSKonstantin Komarov */ 2255b46acd6aSKonstantin Komarov static int read_log_rec_buf(struct ntfs_log *log, 2256b46acd6aSKonstantin Komarov const struct LFS_RECORD_HDR *rh, void *buffer) 2257b46acd6aSKonstantin Komarov { 2258b46acd6aSKonstantin Komarov int err; 2259b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *ph = NULL; 2260b46acd6aSKonstantin Komarov u64 lsn = le64_to_cpu(rh->this_lsn); 2261b46acd6aSKonstantin Komarov u32 vbo = lsn_to_vbo(log, lsn) & ~log->page_mask; 2262b46acd6aSKonstantin Komarov u32 off = lsn_to_page_off(log, lsn) + log->record_header_len; 2263b46acd6aSKonstantin Komarov u32 data_len = le32_to_cpu(rh->client_data_len); 2264b46acd6aSKonstantin Komarov 2265b46acd6aSKonstantin Komarov /* 2266b46acd6aSKonstantin Komarov * While there are more bytes to transfer, 2267*e8b8e97fSKari Argillander * we continue to attempt to perform the read. 2268b46acd6aSKonstantin Komarov */ 2269b46acd6aSKonstantin Komarov for (;;) { 2270b46acd6aSKonstantin Komarov bool usa_error; 2271b46acd6aSKonstantin Komarov u32 tail = log->page_size - off; 2272b46acd6aSKonstantin Komarov 2273b46acd6aSKonstantin Komarov if (tail >= data_len) 2274b46acd6aSKonstantin Komarov tail = data_len; 2275b46acd6aSKonstantin Komarov 2276b46acd6aSKonstantin Komarov data_len -= tail; 2277b46acd6aSKonstantin Komarov 2278b46acd6aSKonstantin Komarov err = read_log_page(log, vbo, &ph, &usa_error); 2279b46acd6aSKonstantin Komarov if (err) 2280b46acd6aSKonstantin Komarov goto out; 2281b46acd6aSKonstantin Komarov 2282b46acd6aSKonstantin Komarov /* 2283b46acd6aSKonstantin Komarov * The last lsn on this page better be greater or equal 2284*e8b8e97fSKari Argillander * to the lsn we are copying. 2285b46acd6aSKonstantin Komarov */ 2286b46acd6aSKonstantin Komarov if (lsn > le64_to_cpu(ph->rhdr.lsn)) { 2287b46acd6aSKonstantin Komarov err = -EINVAL; 2288b46acd6aSKonstantin Komarov goto out; 2289b46acd6aSKonstantin Komarov } 2290b46acd6aSKonstantin Komarov 2291b46acd6aSKonstantin Komarov memcpy(buffer, Add2Ptr(ph, off), tail); 2292b46acd6aSKonstantin Komarov 2293*e8b8e97fSKari Argillander /* If there are no more bytes to transfer, we exit the loop. */ 2294b46acd6aSKonstantin Komarov if (!data_len) { 2295b46acd6aSKonstantin Komarov if (!is_log_record_end(ph) || 2296b46acd6aSKonstantin Komarov lsn > le64_to_cpu(ph->record_hdr.last_end_lsn)) { 2297b46acd6aSKonstantin Komarov err = -EINVAL; 2298b46acd6aSKonstantin Komarov goto out; 2299b46acd6aSKonstantin Komarov } 2300b46acd6aSKonstantin Komarov break; 2301b46acd6aSKonstantin Komarov } 2302b46acd6aSKonstantin Komarov 2303b46acd6aSKonstantin Komarov if (ph->rhdr.lsn == ph->record_hdr.last_end_lsn || 2304b46acd6aSKonstantin Komarov lsn > le64_to_cpu(ph->rhdr.lsn)) { 2305b46acd6aSKonstantin Komarov err = -EINVAL; 2306b46acd6aSKonstantin Komarov goto out; 2307b46acd6aSKonstantin Komarov } 2308b46acd6aSKonstantin Komarov 2309b46acd6aSKonstantin Komarov vbo = next_page_off(log, vbo); 2310b46acd6aSKonstantin Komarov off = log->data_off; 2311b46acd6aSKonstantin Komarov 2312b46acd6aSKonstantin Komarov /* 2313*e8b8e97fSKari Argillander * Adjust our pointer the user's buffer to transfer 2314*e8b8e97fSKari Argillander * the next block to. 2315b46acd6aSKonstantin Komarov */ 2316b46acd6aSKonstantin Komarov buffer = Add2Ptr(buffer, tail); 2317b46acd6aSKonstantin Komarov } 2318b46acd6aSKonstantin Komarov 2319b46acd6aSKonstantin Komarov out: 2320195c52bdSKari Argillander kfree(ph); 2321b46acd6aSKonstantin Komarov return err; 2322b46acd6aSKonstantin Komarov } 2323b46acd6aSKonstantin Komarov 2324b46acd6aSKonstantin Komarov static int read_rst_area(struct ntfs_log *log, struct NTFS_RESTART **rst_, 2325b46acd6aSKonstantin Komarov u64 *lsn) 2326b46acd6aSKonstantin Komarov { 2327b46acd6aSKonstantin Komarov int err; 2328b46acd6aSKonstantin Komarov struct LFS_RECORD_HDR *rh = NULL; 2329b46acd6aSKonstantin Komarov const struct CLIENT_REC *cr = 2330b46acd6aSKonstantin Komarov Add2Ptr(log->ra, le16_to_cpu(log->ra->client_off)); 2331b46acd6aSKonstantin Komarov u64 lsnr, lsnc = le64_to_cpu(cr->restart_lsn); 2332b46acd6aSKonstantin Komarov u32 len; 2333b46acd6aSKonstantin Komarov struct NTFS_RESTART *rst; 2334b46acd6aSKonstantin Komarov 2335b46acd6aSKonstantin Komarov *lsn = 0; 2336b46acd6aSKonstantin Komarov *rst_ = NULL; 2337b46acd6aSKonstantin Komarov 2338*e8b8e97fSKari Argillander /* If the client doesn't have a restart area, go ahead and exit now. */ 2339b46acd6aSKonstantin Komarov if (!lsnc) 2340b46acd6aSKonstantin Komarov return 0; 2341b46acd6aSKonstantin Komarov 2342b46acd6aSKonstantin Komarov err = read_log_page(log, lsn_to_vbo(log, lsnc), 2343b46acd6aSKonstantin Komarov (struct RECORD_PAGE_HDR **)&rh, NULL); 2344b46acd6aSKonstantin Komarov if (err) 2345b46acd6aSKonstantin Komarov return err; 2346b46acd6aSKonstantin Komarov 2347b46acd6aSKonstantin Komarov rst = NULL; 2348b46acd6aSKonstantin Komarov lsnr = le64_to_cpu(rh->this_lsn); 2349b46acd6aSKonstantin Komarov 2350b46acd6aSKonstantin Komarov if (lsnc != lsnr) { 2351*e8b8e97fSKari Argillander /* If the lsn values don't match, then the disk is corrupt. */ 2352b46acd6aSKonstantin Komarov err = -EINVAL; 2353b46acd6aSKonstantin Komarov goto out; 2354b46acd6aSKonstantin Komarov } 2355b46acd6aSKonstantin Komarov 2356b46acd6aSKonstantin Komarov *lsn = lsnr; 2357b46acd6aSKonstantin Komarov len = le32_to_cpu(rh->client_data_len); 2358b46acd6aSKonstantin Komarov 2359b46acd6aSKonstantin Komarov if (!len) { 2360b46acd6aSKonstantin Komarov err = 0; 2361b46acd6aSKonstantin Komarov goto out; 2362b46acd6aSKonstantin Komarov } 2363b46acd6aSKonstantin Komarov 2364b46acd6aSKonstantin Komarov if (len < sizeof(struct NTFS_RESTART)) { 2365b46acd6aSKonstantin Komarov err = -EINVAL; 2366b46acd6aSKonstantin Komarov goto out; 2367b46acd6aSKonstantin Komarov } 2368b46acd6aSKonstantin Komarov 2369195c52bdSKari Argillander rst = kmalloc(len, GFP_NOFS); 2370b46acd6aSKonstantin Komarov if (!rst) { 2371b46acd6aSKonstantin Komarov err = -ENOMEM; 2372b46acd6aSKonstantin Komarov goto out; 2373b46acd6aSKonstantin Komarov } 2374b46acd6aSKonstantin Komarov 2375*e8b8e97fSKari Argillander /* Copy the data into the 'rst' buffer. */ 2376b46acd6aSKonstantin Komarov err = read_log_rec_buf(log, rh, rst); 2377b46acd6aSKonstantin Komarov if (err) 2378b46acd6aSKonstantin Komarov goto out; 2379b46acd6aSKonstantin Komarov 2380b46acd6aSKonstantin Komarov *rst_ = rst; 2381b46acd6aSKonstantin Komarov rst = NULL; 2382b46acd6aSKonstantin Komarov 2383b46acd6aSKonstantin Komarov out: 2384195c52bdSKari Argillander kfree(rh); 2385195c52bdSKari Argillander kfree(rst); 2386b46acd6aSKonstantin Komarov 2387b46acd6aSKonstantin Komarov return err; 2388b46acd6aSKonstantin Komarov } 2389b46acd6aSKonstantin Komarov 2390b46acd6aSKonstantin Komarov static int find_log_rec(struct ntfs_log *log, u64 lsn, struct lcb *lcb) 2391b46acd6aSKonstantin Komarov { 2392b46acd6aSKonstantin Komarov int err; 2393b46acd6aSKonstantin Komarov struct LFS_RECORD_HDR *rh = lcb->lrh; 2394b46acd6aSKonstantin Komarov u32 rec_len, len; 2395b46acd6aSKonstantin Komarov 2396*e8b8e97fSKari Argillander /* Read the record header for this lsn. */ 2397b46acd6aSKonstantin Komarov if (!rh) { 2398b46acd6aSKonstantin Komarov err = read_log_page(log, lsn_to_vbo(log, lsn), 2399b46acd6aSKonstantin Komarov (struct RECORD_PAGE_HDR **)&rh, NULL); 2400b46acd6aSKonstantin Komarov 2401b46acd6aSKonstantin Komarov lcb->lrh = rh; 2402b46acd6aSKonstantin Komarov if (err) 2403b46acd6aSKonstantin Komarov return err; 2404b46acd6aSKonstantin Komarov } 2405b46acd6aSKonstantin Komarov 2406b46acd6aSKonstantin Komarov /* 2407b46acd6aSKonstantin Komarov * If the lsn the log record doesn't match the desired 2408*e8b8e97fSKari Argillander * lsn then the disk is corrupt. 2409b46acd6aSKonstantin Komarov */ 2410b46acd6aSKonstantin Komarov if (lsn != le64_to_cpu(rh->this_lsn)) 2411b46acd6aSKonstantin Komarov return -EINVAL; 2412b46acd6aSKonstantin Komarov 2413b46acd6aSKonstantin Komarov len = le32_to_cpu(rh->client_data_len); 2414b46acd6aSKonstantin Komarov 2415b46acd6aSKonstantin Komarov /* 2416*e8b8e97fSKari Argillander * Check that the length field isn't greater than the total 2417*e8b8e97fSKari Argillander * available space the log file. 2418b46acd6aSKonstantin Komarov */ 2419b46acd6aSKonstantin Komarov rec_len = len + log->record_header_len; 2420b46acd6aSKonstantin Komarov if (rec_len >= log->total_avail) 2421b46acd6aSKonstantin Komarov return -EINVAL; 2422b46acd6aSKonstantin Komarov 2423b46acd6aSKonstantin Komarov /* 2424b46acd6aSKonstantin Komarov * If the entire log record is on this log page, 2425*e8b8e97fSKari Argillander * put a pointer to the log record the context block. 2426b46acd6aSKonstantin Komarov */ 2427b46acd6aSKonstantin Komarov if (rh->flags & LOG_RECORD_MULTI_PAGE) { 2428195c52bdSKari Argillander void *lr = kmalloc(len, GFP_NOFS); 2429b46acd6aSKonstantin Komarov 2430b46acd6aSKonstantin Komarov if (!lr) 2431b46acd6aSKonstantin Komarov return -ENOMEM; 2432b46acd6aSKonstantin Komarov 2433b46acd6aSKonstantin Komarov lcb->log_rec = lr; 2434b46acd6aSKonstantin Komarov lcb->alloc = true; 2435b46acd6aSKonstantin Komarov 2436*e8b8e97fSKari Argillander /* Copy the data into the buffer returned. */ 2437b46acd6aSKonstantin Komarov err = read_log_rec_buf(log, rh, lr); 2438b46acd6aSKonstantin Komarov if (err) 2439b46acd6aSKonstantin Komarov return err; 2440b46acd6aSKonstantin Komarov } else { 2441*e8b8e97fSKari Argillander /* If beyond the end of the current page -> an error. */ 2442b46acd6aSKonstantin Komarov u32 page_off = lsn_to_page_off(log, lsn); 2443b46acd6aSKonstantin Komarov 2444b46acd6aSKonstantin Komarov if (page_off + len + log->record_header_len > log->page_size) 2445b46acd6aSKonstantin Komarov return -EINVAL; 2446b46acd6aSKonstantin Komarov 2447b46acd6aSKonstantin Komarov lcb->log_rec = Add2Ptr(rh, sizeof(struct LFS_RECORD_HDR)); 2448b46acd6aSKonstantin Komarov lcb->alloc = false; 2449b46acd6aSKonstantin Komarov } 2450b46acd6aSKonstantin Komarov 2451b46acd6aSKonstantin Komarov return 0; 2452b46acd6aSKonstantin Komarov } 2453b46acd6aSKonstantin Komarov 2454b46acd6aSKonstantin Komarov /* 2455*e8b8e97fSKari Argillander * read_log_rec_lcb - Init the query operation. 2456b46acd6aSKonstantin Komarov */ 2457b46acd6aSKonstantin Komarov static int read_log_rec_lcb(struct ntfs_log *log, u64 lsn, u32 ctx_mode, 2458b46acd6aSKonstantin Komarov struct lcb **lcb_) 2459b46acd6aSKonstantin Komarov { 2460b46acd6aSKonstantin Komarov int err; 2461b46acd6aSKonstantin Komarov const struct CLIENT_REC *cr; 2462b46acd6aSKonstantin Komarov struct lcb *lcb; 2463b46acd6aSKonstantin Komarov 2464b46acd6aSKonstantin Komarov switch (ctx_mode) { 2465b46acd6aSKonstantin Komarov case lcb_ctx_undo_next: 2466b46acd6aSKonstantin Komarov case lcb_ctx_prev: 2467b46acd6aSKonstantin Komarov case lcb_ctx_next: 2468b46acd6aSKonstantin Komarov break; 2469b46acd6aSKonstantin Komarov default: 2470b46acd6aSKonstantin Komarov return -EINVAL; 2471b46acd6aSKonstantin Komarov } 2472b46acd6aSKonstantin Komarov 2473*e8b8e97fSKari Argillander /* Check that the given lsn is the legal range for this client. */ 2474b46acd6aSKonstantin Komarov cr = Add2Ptr(log->ra, le16_to_cpu(log->ra->client_off)); 2475b46acd6aSKonstantin Komarov 2476b46acd6aSKonstantin Komarov if (!verify_client_lsn(log, cr, lsn)) 2477b46acd6aSKonstantin Komarov return -EINVAL; 2478b46acd6aSKonstantin Komarov 2479195c52bdSKari Argillander lcb = kzalloc(sizeof(struct lcb), GFP_NOFS); 2480b46acd6aSKonstantin Komarov if (!lcb) 2481b46acd6aSKonstantin Komarov return -ENOMEM; 2482b46acd6aSKonstantin Komarov lcb->client = log->client_id; 2483b46acd6aSKonstantin Komarov lcb->ctx_mode = ctx_mode; 2484b46acd6aSKonstantin Komarov 2485*e8b8e97fSKari Argillander /* Find the log record indicated by the given lsn. */ 2486b46acd6aSKonstantin Komarov err = find_log_rec(log, lsn, lcb); 2487b46acd6aSKonstantin Komarov if (err) 2488b46acd6aSKonstantin Komarov goto out; 2489b46acd6aSKonstantin Komarov 2490b46acd6aSKonstantin Komarov *lcb_ = lcb; 2491b46acd6aSKonstantin Komarov return 0; 2492b46acd6aSKonstantin Komarov 2493b46acd6aSKonstantin Komarov out: 2494b46acd6aSKonstantin Komarov lcb_put(lcb); 2495b46acd6aSKonstantin Komarov *lcb_ = NULL; 2496b46acd6aSKonstantin Komarov return err; 2497b46acd6aSKonstantin Komarov } 2498b46acd6aSKonstantin Komarov 2499b46acd6aSKonstantin Komarov /* 2500b46acd6aSKonstantin Komarov * find_client_next_lsn 2501b46acd6aSKonstantin Komarov * 2502*e8b8e97fSKari Argillander * Attempt to find the next lsn to return to a client based on the context mode. 2503b46acd6aSKonstantin Komarov */ 2504b46acd6aSKonstantin Komarov static int find_client_next_lsn(struct ntfs_log *log, struct lcb *lcb, u64 *lsn) 2505b46acd6aSKonstantin Komarov { 2506b46acd6aSKonstantin Komarov int err; 2507b46acd6aSKonstantin Komarov u64 next_lsn; 2508b46acd6aSKonstantin Komarov struct LFS_RECORD_HDR *hdr; 2509b46acd6aSKonstantin Komarov 2510b46acd6aSKonstantin Komarov hdr = lcb->lrh; 2511b46acd6aSKonstantin Komarov *lsn = 0; 2512b46acd6aSKonstantin Komarov 2513b46acd6aSKonstantin Komarov if (lcb_ctx_next != lcb->ctx_mode) 2514b46acd6aSKonstantin Komarov goto check_undo_next; 2515b46acd6aSKonstantin Komarov 2516*e8b8e97fSKari Argillander /* Loop as long as another lsn can be found. */ 2517b46acd6aSKonstantin Komarov for (;;) { 2518b46acd6aSKonstantin Komarov u64 current_lsn; 2519b46acd6aSKonstantin Komarov 2520b46acd6aSKonstantin Komarov err = next_log_lsn(log, hdr, ¤t_lsn); 2521b46acd6aSKonstantin Komarov if (err) 2522b46acd6aSKonstantin Komarov goto out; 2523b46acd6aSKonstantin Komarov 2524b46acd6aSKonstantin Komarov if (!current_lsn) 2525b46acd6aSKonstantin Komarov break; 2526b46acd6aSKonstantin Komarov 2527b46acd6aSKonstantin Komarov if (hdr != lcb->lrh) 2528195c52bdSKari Argillander kfree(hdr); 2529b46acd6aSKonstantin Komarov 2530b46acd6aSKonstantin Komarov hdr = NULL; 2531b46acd6aSKonstantin Komarov err = read_log_page(log, lsn_to_vbo(log, current_lsn), 2532b46acd6aSKonstantin Komarov (struct RECORD_PAGE_HDR **)&hdr, NULL); 2533b46acd6aSKonstantin Komarov if (err) 2534b46acd6aSKonstantin Komarov goto out; 2535b46acd6aSKonstantin Komarov 2536b46acd6aSKonstantin Komarov if (memcmp(&hdr->client, &lcb->client, 2537b46acd6aSKonstantin Komarov sizeof(struct CLIENT_ID))) { 2538b46acd6aSKonstantin Komarov /*err = -EINVAL; */ 2539b46acd6aSKonstantin Komarov } else if (LfsClientRecord == hdr->record_type) { 2540195c52bdSKari Argillander kfree(lcb->lrh); 2541b46acd6aSKonstantin Komarov lcb->lrh = hdr; 2542b46acd6aSKonstantin Komarov *lsn = current_lsn; 2543b46acd6aSKonstantin Komarov return 0; 2544b46acd6aSKonstantin Komarov } 2545b46acd6aSKonstantin Komarov } 2546b46acd6aSKonstantin Komarov 2547b46acd6aSKonstantin Komarov out: 2548b46acd6aSKonstantin Komarov if (hdr != lcb->lrh) 2549195c52bdSKari Argillander kfree(hdr); 2550b46acd6aSKonstantin Komarov return err; 2551b46acd6aSKonstantin Komarov 2552b46acd6aSKonstantin Komarov check_undo_next: 2553b46acd6aSKonstantin Komarov if (lcb_ctx_undo_next == lcb->ctx_mode) 2554b46acd6aSKonstantin Komarov next_lsn = le64_to_cpu(hdr->client_undo_next_lsn); 2555b46acd6aSKonstantin Komarov else if (lcb_ctx_prev == lcb->ctx_mode) 2556b46acd6aSKonstantin Komarov next_lsn = le64_to_cpu(hdr->client_prev_lsn); 2557b46acd6aSKonstantin Komarov else 2558b46acd6aSKonstantin Komarov return 0; 2559b46acd6aSKonstantin Komarov 2560b46acd6aSKonstantin Komarov if (!next_lsn) 2561b46acd6aSKonstantin Komarov return 0; 2562b46acd6aSKonstantin Komarov 2563b46acd6aSKonstantin Komarov if (!verify_client_lsn( 2564b46acd6aSKonstantin Komarov log, Add2Ptr(log->ra, le16_to_cpu(log->ra->client_off)), 2565b46acd6aSKonstantin Komarov next_lsn)) 2566b46acd6aSKonstantin Komarov return 0; 2567b46acd6aSKonstantin Komarov 2568b46acd6aSKonstantin Komarov hdr = NULL; 2569b46acd6aSKonstantin Komarov err = read_log_page(log, lsn_to_vbo(log, next_lsn), 2570b46acd6aSKonstantin Komarov (struct RECORD_PAGE_HDR **)&hdr, NULL); 2571b46acd6aSKonstantin Komarov if (err) 2572b46acd6aSKonstantin Komarov return err; 2573195c52bdSKari Argillander kfree(lcb->lrh); 2574b46acd6aSKonstantin Komarov lcb->lrh = hdr; 2575b46acd6aSKonstantin Komarov 2576b46acd6aSKonstantin Komarov *lsn = next_lsn; 2577b46acd6aSKonstantin Komarov 2578b46acd6aSKonstantin Komarov return 0; 2579b46acd6aSKonstantin Komarov } 2580b46acd6aSKonstantin Komarov 2581b46acd6aSKonstantin Komarov static int read_next_log_rec(struct ntfs_log *log, struct lcb *lcb, u64 *lsn) 2582b46acd6aSKonstantin Komarov { 2583b46acd6aSKonstantin Komarov int err; 2584b46acd6aSKonstantin Komarov 2585b46acd6aSKonstantin Komarov err = find_client_next_lsn(log, lcb, lsn); 2586b46acd6aSKonstantin Komarov if (err) 2587b46acd6aSKonstantin Komarov return err; 2588b46acd6aSKonstantin Komarov 2589b46acd6aSKonstantin Komarov if (!*lsn) 2590b46acd6aSKonstantin Komarov return 0; 2591b46acd6aSKonstantin Komarov 2592b46acd6aSKonstantin Komarov if (lcb->alloc) 2593195c52bdSKari Argillander kfree(lcb->log_rec); 2594b46acd6aSKonstantin Komarov 2595b46acd6aSKonstantin Komarov lcb->log_rec = NULL; 2596b46acd6aSKonstantin Komarov lcb->alloc = false; 2597195c52bdSKari Argillander kfree(lcb->lrh); 2598b46acd6aSKonstantin Komarov lcb->lrh = NULL; 2599b46acd6aSKonstantin Komarov 2600b46acd6aSKonstantin Komarov return find_log_rec(log, *lsn, lcb); 2601b46acd6aSKonstantin Komarov } 2602b46acd6aSKonstantin Komarov 2603b46acd6aSKonstantin Komarov static inline bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes) 2604b46acd6aSKonstantin Komarov { 2605b46acd6aSKonstantin Komarov __le16 mask; 2606b46acd6aSKonstantin Komarov u32 min_de, de_off, used, total; 2607b46acd6aSKonstantin Komarov const struct NTFS_DE *e; 2608b46acd6aSKonstantin Komarov 2609b46acd6aSKonstantin Komarov if (hdr_has_subnode(hdr)) { 2610b46acd6aSKonstantin Komarov min_de = sizeof(struct NTFS_DE) + sizeof(u64); 2611b46acd6aSKonstantin Komarov mask = NTFS_IE_HAS_SUBNODES; 2612b46acd6aSKonstantin Komarov } else { 2613b46acd6aSKonstantin Komarov min_de = sizeof(struct NTFS_DE); 2614b46acd6aSKonstantin Komarov mask = 0; 2615b46acd6aSKonstantin Komarov } 2616b46acd6aSKonstantin Komarov 2617b46acd6aSKonstantin Komarov de_off = le32_to_cpu(hdr->de_off); 2618b46acd6aSKonstantin Komarov used = le32_to_cpu(hdr->used); 2619b46acd6aSKonstantin Komarov total = le32_to_cpu(hdr->total); 2620b46acd6aSKonstantin Komarov 2621b46acd6aSKonstantin Komarov if (de_off > bytes - min_de || used > bytes || total > bytes || 2622b46acd6aSKonstantin Komarov de_off + min_de > used || used > total) { 2623b46acd6aSKonstantin Komarov return false; 2624b46acd6aSKonstantin Komarov } 2625b46acd6aSKonstantin Komarov 2626b46acd6aSKonstantin Komarov e = Add2Ptr(hdr, de_off); 2627b46acd6aSKonstantin Komarov for (;;) { 2628b46acd6aSKonstantin Komarov u16 esize = le16_to_cpu(e->size); 2629b46acd6aSKonstantin Komarov struct NTFS_DE *next = Add2Ptr(e, esize); 2630b46acd6aSKonstantin Komarov 2631b46acd6aSKonstantin Komarov if (esize < min_de || PtrOffset(hdr, next) > used || 2632b46acd6aSKonstantin Komarov (e->flags & NTFS_IE_HAS_SUBNODES) != mask) { 2633b46acd6aSKonstantin Komarov return false; 2634b46acd6aSKonstantin Komarov } 2635b46acd6aSKonstantin Komarov 2636b46acd6aSKonstantin Komarov if (de_is_last(e)) 2637b46acd6aSKonstantin Komarov break; 2638b46acd6aSKonstantin Komarov 2639b46acd6aSKonstantin Komarov e = next; 2640b46acd6aSKonstantin Komarov } 2641b46acd6aSKonstantin Komarov 2642b46acd6aSKonstantin Komarov return true; 2643b46acd6aSKonstantin Komarov } 2644b46acd6aSKonstantin Komarov 2645b46acd6aSKonstantin Komarov static inline bool check_index_buffer(const struct INDEX_BUFFER *ib, u32 bytes) 2646b46acd6aSKonstantin Komarov { 2647b46acd6aSKonstantin Komarov u16 fo; 2648b46acd6aSKonstantin Komarov const struct NTFS_RECORD_HEADER *r = &ib->rhdr; 2649b46acd6aSKonstantin Komarov 2650b46acd6aSKonstantin Komarov if (r->sign != NTFS_INDX_SIGNATURE) 2651b46acd6aSKonstantin Komarov return false; 2652b46acd6aSKonstantin Komarov 2653b46acd6aSKonstantin Komarov fo = (SECTOR_SIZE - ((bytes >> SECTOR_SHIFT) + 1) * sizeof(short)); 2654b46acd6aSKonstantin Komarov 2655b46acd6aSKonstantin Komarov if (le16_to_cpu(r->fix_off) > fo) 2656b46acd6aSKonstantin Komarov return false; 2657b46acd6aSKonstantin Komarov 2658b46acd6aSKonstantin Komarov if ((le16_to_cpu(r->fix_num) - 1) * SECTOR_SIZE != bytes) 2659b46acd6aSKonstantin Komarov return false; 2660b46acd6aSKonstantin Komarov 2661b46acd6aSKonstantin Komarov return check_index_header(&ib->ihdr, 2662b46acd6aSKonstantin Komarov bytes - offsetof(struct INDEX_BUFFER, ihdr)); 2663b46acd6aSKonstantin Komarov } 2664b46acd6aSKonstantin Komarov 2665b46acd6aSKonstantin Komarov static inline bool check_index_root(const struct ATTRIB *attr, 2666b46acd6aSKonstantin Komarov struct ntfs_sb_info *sbi) 2667b46acd6aSKonstantin Komarov { 2668b46acd6aSKonstantin Komarov bool ret; 2669b46acd6aSKonstantin Komarov const struct INDEX_ROOT *root = resident_data(attr); 2670b46acd6aSKonstantin Komarov u8 index_bits = le32_to_cpu(root->index_block_size) >= sbi->cluster_size 2671b46acd6aSKonstantin Komarov ? sbi->cluster_bits 2672b46acd6aSKonstantin Komarov : SECTOR_SHIFT; 2673b46acd6aSKonstantin Komarov u8 block_clst = root->index_block_clst; 2674b46acd6aSKonstantin Komarov 2675b46acd6aSKonstantin Komarov if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) || 2676b46acd6aSKonstantin Komarov (root->type != ATTR_NAME && root->type != ATTR_ZERO) || 2677b46acd6aSKonstantin Komarov (root->type == ATTR_NAME && 2678b46acd6aSKonstantin Komarov root->rule != NTFS_COLLATION_TYPE_FILENAME) || 2679b46acd6aSKonstantin Komarov (le32_to_cpu(root->index_block_size) != 2680b46acd6aSKonstantin Komarov (block_clst << index_bits)) || 2681b46acd6aSKonstantin Komarov (block_clst != 1 && block_clst != 2 && block_clst != 4 && 2682b46acd6aSKonstantin Komarov block_clst != 8 && block_clst != 0x10 && block_clst != 0x20 && 2683b46acd6aSKonstantin Komarov block_clst != 0x40 && block_clst != 0x80)) { 2684b46acd6aSKonstantin Komarov return false; 2685b46acd6aSKonstantin Komarov } 2686b46acd6aSKonstantin Komarov 2687b46acd6aSKonstantin Komarov ret = check_index_header(&root->ihdr, 2688b46acd6aSKonstantin Komarov le32_to_cpu(attr->res.data_size) - 2689b46acd6aSKonstantin Komarov offsetof(struct INDEX_ROOT, ihdr)); 2690b46acd6aSKonstantin Komarov return ret; 2691b46acd6aSKonstantin Komarov } 2692b46acd6aSKonstantin Komarov 2693b46acd6aSKonstantin Komarov static inline bool check_attr(const struct MFT_REC *rec, 2694b46acd6aSKonstantin Komarov const struct ATTRIB *attr, 2695b46acd6aSKonstantin Komarov struct ntfs_sb_info *sbi) 2696b46acd6aSKonstantin Komarov { 2697b46acd6aSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 2698b46acd6aSKonstantin Komarov u32 rsize = 0; 2699b46acd6aSKonstantin Komarov u64 dsize, svcn, evcn; 2700b46acd6aSKonstantin Komarov u16 run_off; 2701b46acd6aSKonstantin Komarov 2702*e8b8e97fSKari Argillander /* Check the fixed part of the attribute record header. */ 2703b46acd6aSKonstantin Komarov if (asize >= sbi->record_size || 2704b46acd6aSKonstantin Komarov asize + PtrOffset(rec, attr) >= sbi->record_size || 2705b46acd6aSKonstantin Komarov (attr->name_len && 2706b46acd6aSKonstantin Komarov le16_to_cpu(attr->name_off) + attr->name_len * sizeof(short) > 2707b46acd6aSKonstantin Komarov asize)) { 2708b46acd6aSKonstantin Komarov return false; 2709b46acd6aSKonstantin Komarov } 2710b46acd6aSKonstantin Komarov 2711*e8b8e97fSKari Argillander /* Check the attribute fields. */ 2712b46acd6aSKonstantin Komarov switch (attr->non_res) { 2713b46acd6aSKonstantin Komarov case 0: 2714b46acd6aSKonstantin Komarov rsize = le32_to_cpu(attr->res.data_size); 2715b46acd6aSKonstantin Komarov if (rsize >= asize || 2716b46acd6aSKonstantin Komarov le16_to_cpu(attr->res.data_off) + rsize > asize) { 2717b46acd6aSKonstantin Komarov return false; 2718b46acd6aSKonstantin Komarov } 2719b46acd6aSKonstantin Komarov break; 2720b46acd6aSKonstantin Komarov 2721b46acd6aSKonstantin Komarov case 1: 2722b46acd6aSKonstantin Komarov dsize = le64_to_cpu(attr->nres.data_size); 2723b46acd6aSKonstantin Komarov svcn = le64_to_cpu(attr->nres.svcn); 2724b46acd6aSKonstantin Komarov evcn = le64_to_cpu(attr->nres.evcn); 2725b46acd6aSKonstantin Komarov run_off = le16_to_cpu(attr->nres.run_off); 2726b46acd6aSKonstantin Komarov 2727b46acd6aSKonstantin Komarov if (svcn > evcn + 1 || run_off >= asize || 2728b46acd6aSKonstantin Komarov le64_to_cpu(attr->nres.valid_size) > dsize || 2729b46acd6aSKonstantin Komarov dsize > le64_to_cpu(attr->nres.alloc_size)) { 2730b46acd6aSKonstantin Komarov return false; 2731b46acd6aSKonstantin Komarov } 2732b46acd6aSKonstantin Komarov 2733b46acd6aSKonstantin Komarov if (run_unpack(NULL, sbi, 0, svcn, evcn, svcn, 2734b46acd6aSKonstantin Komarov Add2Ptr(attr, run_off), asize - run_off) < 0) { 2735b46acd6aSKonstantin Komarov return false; 2736b46acd6aSKonstantin Komarov } 2737b46acd6aSKonstantin Komarov 2738b46acd6aSKonstantin Komarov return true; 2739b46acd6aSKonstantin Komarov 2740b46acd6aSKonstantin Komarov default: 2741b46acd6aSKonstantin Komarov return false; 2742b46acd6aSKonstantin Komarov } 2743b46acd6aSKonstantin Komarov 2744b46acd6aSKonstantin Komarov switch (attr->type) { 2745b46acd6aSKonstantin Komarov case ATTR_NAME: 2746b46acd6aSKonstantin Komarov if (fname_full_size(Add2Ptr( 2747b46acd6aSKonstantin Komarov attr, le16_to_cpu(attr->res.data_off))) > asize) { 2748b46acd6aSKonstantin Komarov return false; 2749b46acd6aSKonstantin Komarov } 2750b46acd6aSKonstantin Komarov break; 2751b46acd6aSKonstantin Komarov 2752b46acd6aSKonstantin Komarov case ATTR_ROOT: 2753b46acd6aSKonstantin Komarov return check_index_root(attr, sbi); 2754b46acd6aSKonstantin Komarov 2755b46acd6aSKonstantin Komarov case ATTR_STD: 2756b46acd6aSKonstantin Komarov if (rsize < sizeof(struct ATTR_STD_INFO5) && 2757b46acd6aSKonstantin Komarov rsize != sizeof(struct ATTR_STD_INFO)) { 2758b46acd6aSKonstantin Komarov return false; 2759b46acd6aSKonstantin Komarov } 2760b46acd6aSKonstantin Komarov break; 2761b46acd6aSKonstantin Komarov 2762b46acd6aSKonstantin Komarov case ATTR_LIST: 2763b46acd6aSKonstantin Komarov case ATTR_ID: 2764b46acd6aSKonstantin Komarov case ATTR_SECURE: 2765b46acd6aSKonstantin Komarov case ATTR_LABEL: 2766b46acd6aSKonstantin Komarov case ATTR_VOL_INFO: 2767b46acd6aSKonstantin Komarov case ATTR_DATA: 2768b46acd6aSKonstantin Komarov case ATTR_ALLOC: 2769b46acd6aSKonstantin Komarov case ATTR_BITMAP: 2770b46acd6aSKonstantin Komarov case ATTR_REPARSE: 2771b46acd6aSKonstantin Komarov case ATTR_EA_INFO: 2772b46acd6aSKonstantin Komarov case ATTR_EA: 2773b46acd6aSKonstantin Komarov case ATTR_PROPERTYSET: 2774b46acd6aSKonstantin Komarov case ATTR_LOGGED_UTILITY_STREAM: 2775b46acd6aSKonstantin Komarov break; 2776b46acd6aSKonstantin Komarov 2777b46acd6aSKonstantin Komarov default: 2778b46acd6aSKonstantin Komarov return false; 2779b46acd6aSKonstantin Komarov } 2780b46acd6aSKonstantin Komarov 2781b46acd6aSKonstantin Komarov return true; 2782b46acd6aSKonstantin Komarov } 2783b46acd6aSKonstantin Komarov 2784b46acd6aSKonstantin Komarov static inline bool check_file_record(const struct MFT_REC *rec, 2785b46acd6aSKonstantin Komarov const struct MFT_REC *rec2, 2786b46acd6aSKonstantin Komarov struct ntfs_sb_info *sbi) 2787b46acd6aSKonstantin Komarov { 2788b46acd6aSKonstantin Komarov const struct ATTRIB *attr; 2789b46acd6aSKonstantin Komarov u16 fo = le16_to_cpu(rec->rhdr.fix_off); 2790b46acd6aSKonstantin Komarov u16 fn = le16_to_cpu(rec->rhdr.fix_num); 2791b46acd6aSKonstantin Komarov u16 ao = le16_to_cpu(rec->attr_off); 2792b46acd6aSKonstantin Komarov u32 rs = sbi->record_size; 2793b46acd6aSKonstantin Komarov 2794*e8b8e97fSKari Argillander /* Check the file record header for consistency. */ 2795b46acd6aSKonstantin Komarov if (rec->rhdr.sign != NTFS_FILE_SIGNATURE || 2796b46acd6aSKonstantin Komarov fo > (SECTOR_SIZE - ((rs >> SECTOR_SHIFT) + 1) * sizeof(short)) || 2797b46acd6aSKonstantin Komarov (fn - 1) * SECTOR_SIZE != rs || ao < MFTRECORD_FIXUP_OFFSET_1 || 2798b46acd6aSKonstantin Komarov ao > sbi->record_size - SIZEOF_RESIDENT || !is_rec_inuse(rec) || 2799b46acd6aSKonstantin Komarov le32_to_cpu(rec->total) != rs) { 2800b46acd6aSKonstantin Komarov return false; 2801b46acd6aSKonstantin Komarov } 2802b46acd6aSKonstantin Komarov 2803*e8b8e97fSKari Argillander /* Loop to check all of the attributes. */ 2804b46acd6aSKonstantin Komarov for (attr = Add2Ptr(rec, ao); attr->type != ATTR_END; 2805b46acd6aSKonstantin Komarov attr = Add2Ptr(attr, le32_to_cpu(attr->size))) { 2806b46acd6aSKonstantin Komarov if (check_attr(rec, attr, sbi)) 2807b46acd6aSKonstantin Komarov continue; 2808b46acd6aSKonstantin Komarov return false; 2809b46acd6aSKonstantin Komarov } 2810b46acd6aSKonstantin Komarov 2811b46acd6aSKonstantin Komarov return true; 2812b46acd6aSKonstantin Komarov } 2813b46acd6aSKonstantin Komarov 2814b46acd6aSKonstantin Komarov static inline int check_lsn(const struct NTFS_RECORD_HEADER *hdr, 2815b46acd6aSKonstantin Komarov const u64 *rlsn) 2816b46acd6aSKonstantin Komarov { 2817b46acd6aSKonstantin Komarov u64 lsn; 2818b46acd6aSKonstantin Komarov 2819b46acd6aSKonstantin Komarov if (!rlsn) 2820b46acd6aSKonstantin Komarov return true; 2821b46acd6aSKonstantin Komarov 2822b46acd6aSKonstantin Komarov lsn = le64_to_cpu(hdr->lsn); 2823b46acd6aSKonstantin Komarov 2824b46acd6aSKonstantin Komarov if (hdr->sign == NTFS_HOLE_SIGNATURE) 2825b46acd6aSKonstantin Komarov return false; 2826b46acd6aSKonstantin Komarov 2827b46acd6aSKonstantin Komarov if (*rlsn > lsn) 2828b46acd6aSKonstantin Komarov return true; 2829b46acd6aSKonstantin Komarov 2830b46acd6aSKonstantin Komarov return false; 2831b46acd6aSKonstantin Komarov } 2832b46acd6aSKonstantin Komarov 2833b46acd6aSKonstantin Komarov static inline bool check_if_attr(const struct MFT_REC *rec, 2834b46acd6aSKonstantin Komarov const struct LOG_REC_HDR *lrh) 2835b46acd6aSKonstantin Komarov { 2836b46acd6aSKonstantin Komarov u16 ro = le16_to_cpu(lrh->record_off); 2837b46acd6aSKonstantin Komarov u16 o = le16_to_cpu(rec->attr_off); 2838b46acd6aSKonstantin Komarov const struct ATTRIB *attr = Add2Ptr(rec, o); 2839b46acd6aSKonstantin Komarov 2840b46acd6aSKonstantin Komarov while (o < ro) { 2841b46acd6aSKonstantin Komarov u32 asize; 2842b46acd6aSKonstantin Komarov 2843b46acd6aSKonstantin Komarov if (attr->type == ATTR_END) 2844b46acd6aSKonstantin Komarov break; 2845b46acd6aSKonstantin Komarov 2846b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr->size); 2847b46acd6aSKonstantin Komarov if (!asize) 2848b46acd6aSKonstantin Komarov break; 2849b46acd6aSKonstantin Komarov 2850b46acd6aSKonstantin Komarov o += asize; 2851b46acd6aSKonstantin Komarov attr = Add2Ptr(attr, asize); 2852b46acd6aSKonstantin Komarov } 2853b46acd6aSKonstantin Komarov 2854b46acd6aSKonstantin Komarov return o == ro; 2855b46acd6aSKonstantin Komarov } 2856b46acd6aSKonstantin Komarov 2857b46acd6aSKonstantin Komarov static inline bool check_if_index_root(const struct MFT_REC *rec, 2858b46acd6aSKonstantin Komarov const struct LOG_REC_HDR *lrh) 2859b46acd6aSKonstantin Komarov { 2860b46acd6aSKonstantin Komarov u16 ro = le16_to_cpu(lrh->record_off); 2861b46acd6aSKonstantin Komarov u16 o = le16_to_cpu(rec->attr_off); 2862b46acd6aSKonstantin Komarov const struct ATTRIB *attr = Add2Ptr(rec, o); 2863b46acd6aSKonstantin Komarov 2864b46acd6aSKonstantin Komarov while (o < ro) { 2865b46acd6aSKonstantin Komarov u32 asize; 2866b46acd6aSKonstantin Komarov 2867b46acd6aSKonstantin Komarov if (attr->type == ATTR_END) 2868b46acd6aSKonstantin Komarov break; 2869b46acd6aSKonstantin Komarov 2870b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr->size); 2871b46acd6aSKonstantin Komarov if (!asize) 2872b46acd6aSKonstantin Komarov break; 2873b46acd6aSKonstantin Komarov 2874b46acd6aSKonstantin Komarov o += asize; 2875b46acd6aSKonstantin Komarov attr = Add2Ptr(attr, asize); 2876b46acd6aSKonstantin Komarov } 2877b46acd6aSKonstantin Komarov 2878b46acd6aSKonstantin Komarov return o == ro && attr->type == ATTR_ROOT; 2879b46acd6aSKonstantin Komarov } 2880b46acd6aSKonstantin Komarov 2881b46acd6aSKonstantin Komarov static inline bool check_if_root_index(const struct ATTRIB *attr, 2882b46acd6aSKonstantin Komarov const struct INDEX_HDR *hdr, 2883b46acd6aSKonstantin Komarov const struct LOG_REC_HDR *lrh) 2884b46acd6aSKonstantin Komarov { 2885b46acd6aSKonstantin Komarov u16 ao = le16_to_cpu(lrh->attr_off); 2886b46acd6aSKonstantin Komarov u32 de_off = le32_to_cpu(hdr->de_off); 2887b46acd6aSKonstantin Komarov u32 o = PtrOffset(attr, hdr) + de_off; 2888b46acd6aSKonstantin Komarov const struct NTFS_DE *e = Add2Ptr(hdr, de_off); 2889b46acd6aSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 2890b46acd6aSKonstantin Komarov 2891b46acd6aSKonstantin Komarov while (o < ao) { 2892b46acd6aSKonstantin Komarov u16 esize; 2893b46acd6aSKonstantin Komarov 2894b46acd6aSKonstantin Komarov if (o >= asize) 2895b46acd6aSKonstantin Komarov break; 2896b46acd6aSKonstantin Komarov 2897b46acd6aSKonstantin Komarov esize = le16_to_cpu(e->size); 2898b46acd6aSKonstantin Komarov if (!esize) 2899b46acd6aSKonstantin Komarov break; 2900b46acd6aSKonstantin Komarov 2901b46acd6aSKonstantin Komarov o += esize; 2902b46acd6aSKonstantin Komarov e = Add2Ptr(e, esize); 2903b46acd6aSKonstantin Komarov } 2904b46acd6aSKonstantin Komarov 2905b46acd6aSKonstantin Komarov return o == ao; 2906b46acd6aSKonstantin Komarov } 2907b46acd6aSKonstantin Komarov 2908b46acd6aSKonstantin Komarov static inline bool check_if_alloc_index(const struct INDEX_HDR *hdr, 2909b46acd6aSKonstantin Komarov u32 attr_off) 2910b46acd6aSKonstantin Komarov { 2911b46acd6aSKonstantin Komarov u32 de_off = le32_to_cpu(hdr->de_off); 2912b46acd6aSKonstantin Komarov u32 o = offsetof(struct INDEX_BUFFER, ihdr) + de_off; 2913b46acd6aSKonstantin Komarov const struct NTFS_DE *e = Add2Ptr(hdr, de_off); 2914b46acd6aSKonstantin Komarov u32 used = le32_to_cpu(hdr->used); 2915b46acd6aSKonstantin Komarov 2916b46acd6aSKonstantin Komarov while (o < attr_off) { 2917b46acd6aSKonstantin Komarov u16 esize; 2918b46acd6aSKonstantin Komarov 2919b46acd6aSKonstantin Komarov if (de_off >= used) 2920b46acd6aSKonstantin Komarov break; 2921b46acd6aSKonstantin Komarov 2922b46acd6aSKonstantin Komarov esize = le16_to_cpu(e->size); 2923b46acd6aSKonstantin Komarov if (!esize) 2924b46acd6aSKonstantin Komarov break; 2925b46acd6aSKonstantin Komarov 2926b46acd6aSKonstantin Komarov o += esize; 2927b46acd6aSKonstantin Komarov de_off += esize; 2928b46acd6aSKonstantin Komarov e = Add2Ptr(e, esize); 2929b46acd6aSKonstantin Komarov } 2930b46acd6aSKonstantin Komarov 2931b46acd6aSKonstantin Komarov return o == attr_off; 2932b46acd6aSKonstantin Komarov } 2933b46acd6aSKonstantin Komarov 2934b46acd6aSKonstantin Komarov static inline void change_attr_size(struct MFT_REC *rec, struct ATTRIB *attr, 2935b46acd6aSKonstantin Komarov u32 nsize) 2936b46acd6aSKonstantin Komarov { 2937b46acd6aSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 2938b46acd6aSKonstantin Komarov int dsize = nsize - asize; 2939b46acd6aSKonstantin Komarov u8 *next = Add2Ptr(attr, asize); 2940b46acd6aSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 2941b46acd6aSKonstantin Komarov 2942b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, nsize), next, used - PtrOffset(rec, next)); 2943b46acd6aSKonstantin Komarov 2944b46acd6aSKonstantin Komarov rec->used = cpu_to_le32(used + dsize); 2945b46acd6aSKonstantin Komarov attr->size = cpu_to_le32(nsize); 2946b46acd6aSKonstantin Komarov } 2947b46acd6aSKonstantin Komarov 2948b46acd6aSKonstantin Komarov struct OpenAttr { 2949b46acd6aSKonstantin Komarov struct ATTRIB *attr; 2950b46acd6aSKonstantin Komarov struct runs_tree *run1; 2951b46acd6aSKonstantin Komarov struct runs_tree run0; 2952b46acd6aSKonstantin Komarov struct ntfs_inode *ni; 2953b46acd6aSKonstantin Komarov // CLST rno; 2954b46acd6aSKonstantin Komarov }; 2955b46acd6aSKonstantin Komarov 2956*e8b8e97fSKari Argillander /* 2957*e8b8e97fSKari Argillander * cmp_type_and_name 2958*e8b8e97fSKari Argillander * 2959*e8b8e97fSKari Argillander * Return: 0 if 'attr' has the same type and name. 2960*e8b8e97fSKari Argillander */ 2961b46acd6aSKonstantin Komarov static inline int cmp_type_and_name(const struct ATTRIB *a1, 2962b46acd6aSKonstantin Komarov const struct ATTRIB *a2) 2963b46acd6aSKonstantin Komarov { 2964b46acd6aSKonstantin Komarov return a1->type != a2->type || a1->name_len != a2->name_len || 2965b46acd6aSKonstantin Komarov (a1->name_len && memcmp(attr_name(a1), attr_name(a2), 2966b46acd6aSKonstantin Komarov a1->name_len * sizeof(short))); 2967b46acd6aSKonstantin Komarov } 2968b46acd6aSKonstantin Komarov 2969b46acd6aSKonstantin Komarov static struct OpenAttr *find_loaded_attr(struct ntfs_log *log, 2970b46acd6aSKonstantin Komarov const struct ATTRIB *attr, CLST rno) 2971b46acd6aSKonstantin Komarov { 2972b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY *oe = NULL; 2973b46acd6aSKonstantin Komarov 2974b46acd6aSKonstantin Komarov while ((oe = enum_rstbl(log->open_attr_tbl, oe))) { 2975b46acd6aSKonstantin Komarov struct OpenAttr *op_attr; 2976b46acd6aSKonstantin Komarov 2977b46acd6aSKonstantin Komarov if (ino_get(&oe->ref) != rno) 2978b46acd6aSKonstantin Komarov continue; 2979b46acd6aSKonstantin Komarov 2980b46acd6aSKonstantin Komarov op_attr = (struct OpenAttr *)oe->ptr; 2981b46acd6aSKonstantin Komarov if (!cmp_type_and_name(op_attr->attr, attr)) 2982b46acd6aSKonstantin Komarov return op_attr; 2983b46acd6aSKonstantin Komarov } 2984b46acd6aSKonstantin Komarov return NULL; 2985b46acd6aSKonstantin Komarov } 2986b46acd6aSKonstantin Komarov 2987b46acd6aSKonstantin Komarov static struct ATTRIB *attr_create_nonres_log(struct ntfs_sb_info *sbi, 2988b46acd6aSKonstantin Komarov enum ATTR_TYPE type, u64 size, 2989b46acd6aSKonstantin Komarov const u16 *name, size_t name_len, 2990b46acd6aSKonstantin Komarov __le16 flags) 2991b46acd6aSKonstantin Komarov { 2992b46acd6aSKonstantin Komarov struct ATTRIB *attr; 2993fa3cacf5SKari Argillander u32 name_size = ALIGN(name_len * sizeof(short), 8); 2994b46acd6aSKonstantin Komarov bool is_ext = flags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED); 2995b46acd6aSKonstantin Komarov u32 asize = name_size + 2996b46acd6aSKonstantin Komarov (is_ext ? SIZEOF_NONRESIDENT_EX : SIZEOF_NONRESIDENT); 2997b46acd6aSKonstantin Komarov 2998195c52bdSKari Argillander attr = kzalloc(asize, GFP_NOFS); 2999b46acd6aSKonstantin Komarov if (!attr) 3000b46acd6aSKonstantin Komarov return NULL; 3001b46acd6aSKonstantin Komarov 3002b46acd6aSKonstantin Komarov attr->type = type; 3003b46acd6aSKonstantin Komarov attr->size = cpu_to_le32(asize); 3004b46acd6aSKonstantin Komarov attr->flags = flags; 3005b46acd6aSKonstantin Komarov attr->non_res = 1; 3006b46acd6aSKonstantin Komarov attr->name_len = name_len; 3007b46acd6aSKonstantin Komarov 3008b46acd6aSKonstantin Komarov attr->nres.evcn = cpu_to_le64((u64)bytes_to_cluster(sbi, size) - 1); 3009b46acd6aSKonstantin Komarov attr->nres.alloc_size = cpu_to_le64(ntfs_up_cluster(sbi, size)); 3010b46acd6aSKonstantin Komarov attr->nres.data_size = cpu_to_le64(size); 3011b46acd6aSKonstantin Komarov attr->nres.valid_size = attr->nres.data_size; 3012b46acd6aSKonstantin Komarov if (is_ext) { 3013b46acd6aSKonstantin Komarov attr->name_off = SIZEOF_NONRESIDENT_EX_LE; 3014b46acd6aSKonstantin Komarov if (is_attr_compressed(attr)) 3015b46acd6aSKonstantin Komarov attr->nres.c_unit = COMPRESSION_UNIT; 3016b46acd6aSKonstantin Komarov 3017b46acd6aSKonstantin Komarov attr->nres.run_off = 3018b46acd6aSKonstantin Komarov cpu_to_le16(SIZEOF_NONRESIDENT_EX + name_size); 3019b46acd6aSKonstantin Komarov memcpy(Add2Ptr(attr, SIZEOF_NONRESIDENT_EX), name, 3020b46acd6aSKonstantin Komarov name_len * sizeof(short)); 3021b46acd6aSKonstantin Komarov } else { 3022b46acd6aSKonstantin Komarov attr->name_off = SIZEOF_NONRESIDENT_LE; 3023b46acd6aSKonstantin Komarov attr->nres.run_off = 3024b46acd6aSKonstantin Komarov cpu_to_le16(SIZEOF_NONRESIDENT + name_size); 3025b46acd6aSKonstantin Komarov memcpy(Add2Ptr(attr, SIZEOF_NONRESIDENT), name, 3026b46acd6aSKonstantin Komarov name_len * sizeof(short)); 3027b46acd6aSKonstantin Komarov } 3028b46acd6aSKonstantin Komarov 3029b46acd6aSKonstantin Komarov return attr; 3030b46acd6aSKonstantin Komarov } 3031b46acd6aSKonstantin Komarov 3032b46acd6aSKonstantin Komarov /* 3033*e8b8e97fSKari Argillander * do_action - Common routine for the Redo and Undo Passes. 3034*e8b8e97fSKari Argillander * @rlsn: If it is NULL then undo. 3035b46acd6aSKonstantin Komarov */ 3036b46acd6aSKonstantin Komarov static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, 3037b46acd6aSKonstantin Komarov const struct LOG_REC_HDR *lrh, u32 op, void *data, 3038b46acd6aSKonstantin Komarov u32 dlen, u32 rec_len, const u64 *rlsn) 3039b46acd6aSKonstantin Komarov { 3040b46acd6aSKonstantin Komarov int err = 0; 3041b46acd6aSKonstantin Komarov struct ntfs_sb_info *sbi = log->ni->mi.sbi; 3042b46acd6aSKonstantin Komarov struct inode *inode = NULL, *inode_parent; 3043b46acd6aSKonstantin Komarov struct mft_inode *mi = NULL, *mi2_child = NULL; 3044b46acd6aSKonstantin Komarov CLST rno = 0, rno_base = 0; 3045b46acd6aSKonstantin Komarov struct INDEX_BUFFER *ib = NULL; 3046b46acd6aSKonstantin Komarov struct MFT_REC *rec = NULL; 3047b46acd6aSKonstantin Komarov struct ATTRIB *attr = NULL, *attr2; 3048b46acd6aSKonstantin Komarov struct INDEX_HDR *hdr; 3049b46acd6aSKonstantin Komarov struct INDEX_ROOT *root; 3050b46acd6aSKonstantin Komarov struct NTFS_DE *e, *e1, *e2; 3051b46acd6aSKonstantin Komarov struct NEW_ATTRIBUTE_SIZES *new_sz; 3052b46acd6aSKonstantin Komarov struct ATTR_FILE_NAME *fname; 3053b46acd6aSKonstantin Komarov struct OpenAttr *oa, *oa2; 3054b46acd6aSKonstantin Komarov u32 nsize, t32, asize, used, esize, bmp_off, bmp_bits; 3055b46acd6aSKonstantin Komarov u16 id, id2; 3056b46acd6aSKonstantin Komarov u32 record_size = sbi->record_size; 3057b46acd6aSKonstantin Komarov u64 t64; 3058b46acd6aSKonstantin Komarov u16 roff = le16_to_cpu(lrh->record_off); 3059b46acd6aSKonstantin Komarov u16 aoff = le16_to_cpu(lrh->attr_off); 3060b46acd6aSKonstantin Komarov u64 lco = 0; 3061b46acd6aSKonstantin Komarov u64 cbo = (u64)le16_to_cpu(lrh->cluster_off) << SECTOR_SHIFT; 3062b46acd6aSKonstantin Komarov u64 tvo = le64_to_cpu(lrh->target_vcn) << sbi->cluster_bits; 3063b46acd6aSKonstantin Komarov u64 vbo = cbo + tvo; 3064b46acd6aSKonstantin Komarov void *buffer_le = NULL; 3065b46acd6aSKonstantin Komarov u32 bytes = 0; 3066b46acd6aSKonstantin Komarov bool a_dirty = false; 3067b46acd6aSKonstantin Komarov u16 data_off; 3068b46acd6aSKonstantin Komarov 3069b46acd6aSKonstantin Komarov oa = oe->ptr; 3070b46acd6aSKonstantin Komarov 3071*e8b8e97fSKari Argillander /* Big switch to prepare. */ 3072b46acd6aSKonstantin Komarov switch (op) { 3073b46acd6aSKonstantin Komarov /* ============================================================ 3074*e8b8e97fSKari Argillander * Process MFT records, as described by the current log record. 3075b46acd6aSKonstantin Komarov * ============================================================ 3076b46acd6aSKonstantin Komarov */ 3077b46acd6aSKonstantin Komarov case InitializeFileRecordSegment: 3078b46acd6aSKonstantin Komarov case DeallocateFileRecordSegment: 3079b46acd6aSKonstantin Komarov case WriteEndOfFileRecordSegment: 3080b46acd6aSKonstantin Komarov case CreateAttribute: 3081b46acd6aSKonstantin Komarov case DeleteAttribute: 3082b46acd6aSKonstantin Komarov case UpdateResidentValue: 3083b46acd6aSKonstantin Komarov case UpdateMappingPairs: 3084b46acd6aSKonstantin Komarov case SetNewAttributeSizes: 3085b46acd6aSKonstantin Komarov case AddIndexEntryRoot: 3086b46acd6aSKonstantin Komarov case DeleteIndexEntryRoot: 3087b46acd6aSKonstantin Komarov case SetIndexEntryVcnRoot: 3088b46acd6aSKonstantin Komarov case UpdateFileNameRoot: 3089b46acd6aSKonstantin Komarov case UpdateRecordDataRoot: 3090b46acd6aSKonstantin Komarov case ZeroEndOfFileRecord: 3091b46acd6aSKonstantin Komarov rno = vbo >> sbi->record_bits; 3092b46acd6aSKonstantin Komarov inode = ilookup(sbi->sb, rno); 3093b46acd6aSKonstantin Komarov if (inode) { 3094b46acd6aSKonstantin Komarov mi = &ntfs_i(inode)->mi; 3095b46acd6aSKonstantin Komarov } else if (op == InitializeFileRecordSegment) { 3096195c52bdSKari Argillander mi = kzalloc(sizeof(struct mft_inode), GFP_NOFS); 3097b46acd6aSKonstantin Komarov if (!mi) 3098b46acd6aSKonstantin Komarov return -ENOMEM; 3099b46acd6aSKonstantin Komarov err = mi_format_new(mi, sbi, rno, 0, false); 3100b46acd6aSKonstantin Komarov if (err) 3101b46acd6aSKonstantin Komarov goto out; 3102b46acd6aSKonstantin Komarov } else { 3103*e8b8e97fSKari Argillander /* Read from disk. */ 3104b46acd6aSKonstantin Komarov err = mi_get(sbi, rno, &mi); 3105b46acd6aSKonstantin Komarov if (err) 3106b46acd6aSKonstantin Komarov return err; 3107b46acd6aSKonstantin Komarov } 3108b46acd6aSKonstantin Komarov rec = mi->mrec; 3109b46acd6aSKonstantin Komarov 3110b46acd6aSKonstantin Komarov if (op == DeallocateFileRecordSegment) 3111b46acd6aSKonstantin Komarov goto skip_load_parent; 3112b46acd6aSKonstantin Komarov 3113b46acd6aSKonstantin Komarov if (InitializeFileRecordSegment != op) { 3114b46acd6aSKonstantin Komarov if (rec->rhdr.sign == NTFS_BAAD_SIGNATURE) 3115b46acd6aSKonstantin Komarov goto dirty_vol; 3116b46acd6aSKonstantin Komarov if (!check_lsn(&rec->rhdr, rlsn)) 3117b46acd6aSKonstantin Komarov goto out; 3118b46acd6aSKonstantin Komarov if (!check_file_record(rec, NULL, sbi)) 3119b46acd6aSKonstantin Komarov goto dirty_vol; 3120b46acd6aSKonstantin Komarov attr = Add2Ptr(rec, roff); 3121b46acd6aSKonstantin Komarov } 3122b46acd6aSKonstantin Komarov 3123b46acd6aSKonstantin Komarov if (is_rec_base(rec) || InitializeFileRecordSegment == op) { 3124b46acd6aSKonstantin Komarov rno_base = rno; 3125b46acd6aSKonstantin Komarov goto skip_load_parent; 3126b46acd6aSKonstantin Komarov } 3127b46acd6aSKonstantin Komarov 3128b46acd6aSKonstantin Komarov rno_base = ino_get(&rec->parent_ref); 3129b46acd6aSKonstantin Komarov inode_parent = ntfs_iget5(sbi->sb, &rec->parent_ref, NULL); 3130b46acd6aSKonstantin Komarov if (IS_ERR(inode_parent)) 3131b46acd6aSKonstantin Komarov goto skip_load_parent; 3132b46acd6aSKonstantin Komarov 3133b46acd6aSKonstantin Komarov if (is_bad_inode(inode_parent)) { 3134b46acd6aSKonstantin Komarov iput(inode_parent); 3135b46acd6aSKonstantin Komarov goto skip_load_parent; 3136b46acd6aSKonstantin Komarov } 3137b46acd6aSKonstantin Komarov 3138b46acd6aSKonstantin Komarov if (ni_load_mi_ex(ntfs_i(inode_parent), rno, &mi2_child)) { 3139b46acd6aSKonstantin Komarov iput(inode_parent); 3140b46acd6aSKonstantin Komarov } else { 3141b46acd6aSKonstantin Komarov if (mi2_child->mrec != mi->mrec) 3142b46acd6aSKonstantin Komarov memcpy(mi2_child->mrec, mi->mrec, 3143b46acd6aSKonstantin Komarov sbi->record_size); 3144b46acd6aSKonstantin Komarov 3145b46acd6aSKonstantin Komarov if (inode) 3146b46acd6aSKonstantin Komarov iput(inode); 3147b46acd6aSKonstantin Komarov else if (mi) 3148b46acd6aSKonstantin Komarov mi_put(mi); 3149b46acd6aSKonstantin Komarov 3150b46acd6aSKonstantin Komarov inode = inode_parent; 3151b46acd6aSKonstantin Komarov mi = mi2_child; 3152b46acd6aSKonstantin Komarov rec = mi2_child->mrec; 3153b46acd6aSKonstantin Komarov attr = Add2Ptr(rec, roff); 3154b46acd6aSKonstantin Komarov } 3155b46acd6aSKonstantin Komarov 3156b46acd6aSKonstantin Komarov skip_load_parent: 3157b46acd6aSKonstantin Komarov inode_parent = NULL; 3158b46acd6aSKonstantin Komarov break; 3159b46acd6aSKonstantin Komarov 3160*e8b8e97fSKari Argillander /* 3161*e8b8e97fSKari Argillander * Process attributes, as described by the current log record. 3162b46acd6aSKonstantin Komarov */ 3163b46acd6aSKonstantin Komarov case UpdateNonresidentValue: 3164b46acd6aSKonstantin Komarov case AddIndexEntryAllocation: 3165b46acd6aSKonstantin Komarov case DeleteIndexEntryAllocation: 3166b46acd6aSKonstantin Komarov case WriteEndOfIndexBuffer: 3167b46acd6aSKonstantin Komarov case SetIndexEntryVcnAllocation: 3168b46acd6aSKonstantin Komarov case UpdateFileNameAllocation: 3169b46acd6aSKonstantin Komarov case SetBitsInNonresidentBitMap: 3170b46acd6aSKonstantin Komarov case ClearBitsInNonresidentBitMap: 3171b46acd6aSKonstantin Komarov case UpdateRecordDataAllocation: 3172b46acd6aSKonstantin Komarov attr = oa->attr; 3173b46acd6aSKonstantin Komarov bytes = UpdateNonresidentValue == op ? dlen : 0; 3174b46acd6aSKonstantin Komarov lco = (u64)le16_to_cpu(lrh->lcns_follow) << sbi->cluster_bits; 3175b46acd6aSKonstantin Komarov 3176b46acd6aSKonstantin Komarov if (attr->type == ATTR_ALLOC) { 3177b46acd6aSKonstantin Komarov t32 = le32_to_cpu(oe->bytes_per_index); 3178b46acd6aSKonstantin Komarov if (bytes < t32) 3179b46acd6aSKonstantin Komarov bytes = t32; 3180b46acd6aSKonstantin Komarov } 3181b46acd6aSKonstantin Komarov 3182b46acd6aSKonstantin Komarov if (!bytes) 3183b46acd6aSKonstantin Komarov bytes = lco - cbo; 3184b46acd6aSKonstantin Komarov 3185b46acd6aSKonstantin Komarov bytes += roff; 3186b46acd6aSKonstantin Komarov if (attr->type == ATTR_ALLOC) 3187b46acd6aSKonstantin Komarov bytes = (bytes + 511) & ~511; // align 3188b46acd6aSKonstantin Komarov 3189195c52bdSKari Argillander buffer_le = kmalloc(bytes, GFP_NOFS); 3190b46acd6aSKonstantin Komarov if (!buffer_le) 3191b46acd6aSKonstantin Komarov return -ENOMEM; 3192b46acd6aSKonstantin Komarov 3193b46acd6aSKonstantin Komarov err = ntfs_read_run_nb(sbi, oa->run1, vbo, buffer_le, bytes, 3194b46acd6aSKonstantin Komarov NULL); 3195b46acd6aSKonstantin Komarov if (err) 3196b46acd6aSKonstantin Komarov goto out; 3197b46acd6aSKonstantin Komarov 3198b46acd6aSKonstantin Komarov if (attr->type == ATTR_ALLOC && *(int *)buffer_le) 3199b46acd6aSKonstantin Komarov ntfs_fix_post_read(buffer_le, bytes, false); 3200b46acd6aSKonstantin Komarov break; 3201b46acd6aSKonstantin Komarov 3202b46acd6aSKonstantin Komarov default: 3203b46acd6aSKonstantin Komarov WARN_ON(1); 3204b46acd6aSKonstantin Komarov } 3205b46acd6aSKonstantin Komarov 3206*e8b8e97fSKari Argillander /* Big switch to do operation. */ 3207b46acd6aSKonstantin Komarov switch (op) { 3208b46acd6aSKonstantin Komarov case InitializeFileRecordSegment: 3209b46acd6aSKonstantin Komarov if (roff + dlen > record_size) 3210b46acd6aSKonstantin Komarov goto dirty_vol; 3211b46acd6aSKonstantin Komarov 3212b46acd6aSKonstantin Komarov memcpy(Add2Ptr(rec, roff), data, dlen); 3213b46acd6aSKonstantin Komarov mi->dirty = true; 3214b46acd6aSKonstantin Komarov break; 3215b46acd6aSKonstantin Komarov 3216b46acd6aSKonstantin Komarov case DeallocateFileRecordSegment: 3217b46acd6aSKonstantin Komarov clear_rec_inuse(rec); 3218b46acd6aSKonstantin Komarov le16_add_cpu(&rec->seq, 1); 3219b46acd6aSKonstantin Komarov mi->dirty = true; 3220b46acd6aSKonstantin Komarov break; 3221b46acd6aSKonstantin Komarov 3222b46acd6aSKonstantin Komarov case WriteEndOfFileRecordSegment: 3223b46acd6aSKonstantin Komarov attr2 = (struct ATTRIB *)data; 3224b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh) || roff + dlen > record_size) 3225b46acd6aSKonstantin Komarov goto dirty_vol; 3226b46acd6aSKonstantin Komarov 3227b46acd6aSKonstantin Komarov memmove(attr, attr2, dlen); 3228fa3cacf5SKari Argillander rec->used = cpu_to_le32(ALIGN(roff + dlen, 8)); 3229b46acd6aSKonstantin Komarov 3230b46acd6aSKonstantin Komarov mi->dirty = true; 3231b46acd6aSKonstantin Komarov break; 3232b46acd6aSKonstantin Komarov 3233b46acd6aSKonstantin Komarov case CreateAttribute: 3234b46acd6aSKonstantin Komarov attr2 = (struct ATTRIB *)data; 3235b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr2->size); 3236b46acd6aSKonstantin Komarov used = le32_to_cpu(rec->used); 3237b46acd6aSKonstantin Komarov 3238b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh) || dlen < SIZEOF_RESIDENT || 3239fa3cacf5SKari Argillander !IS_ALIGNED(asize, 8) || 3240b46acd6aSKonstantin Komarov Add2Ptr(attr2, asize) > Add2Ptr(lrh, rec_len) || 3241b46acd6aSKonstantin Komarov dlen > record_size - used) { 3242b46acd6aSKonstantin Komarov goto dirty_vol; 3243b46acd6aSKonstantin Komarov } 3244b46acd6aSKonstantin Komarov 3245b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, asize), attr, used - roff); 3246b46acd6aSKonstantin Komarov memcpy(attr, attr2, asize); 3247b46acd6aSKonstantin Komarov 3248b46acd6aSKonstantin Komarov rec->used = cpu_to_le32(used + asize); 3249b46acd6aSKonstantin Komarov id = le16_to_cpu(rec->next_attr_id); 3250b46acd6aSKonstantin Komarov id2 = le16_to_cpu(attr2->id); 3251b46acd6aSKonstantin Komarov if (id <= id2) 3252b46acd6aSKonstantin Komarov rec->next_attr_id = cpu_to_le16(id2 + 1); 3253b46acd6aSKonstantin Komarov if (is_attr_indexed(attr)) 3254b46acd6aSKonstantin Komarov le16_add_cpu(&rec->hard_links, 1); 3255b46acd6aSKonstantin Komarov 3256b46acd6aSKonstantin Komarov oa2 = find_loaded_attr(log, attr, rno_base); 3257b46acd6aSKonstantin Komarov if (oa2) { 3258195c52bdSKari Argillander void *p2 = kmemdup(attr, le32_to_cpu(attr->size), 3259195c52bdSKari Argillander GFP_NOFS); 3260b46acd6aSKonstantin Komarov if (p2) { 3261b46acd6aSKonstantin Komarov // run_close(oa2->run1); 3262195c52bdSKari Argillander kfree(oa2->attr); 3263b46acd6aSKonstantin Komarov oa2->attr = p2; 3264b46acd6aSKonstantin Komarov } 3265b46acd6aSKonstantin Komarov } 3266b46acd6aSKonstantin Komarov 3267b46acd6aSKonstantin Komarov mi->dirty = true; 3268b46acd6aSKonstantin Komarov break; 3269b46acd6aSKonstantin Komarov 3270b46acd6aSKonstantin Komarov case DeleteAttribute: 3271b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr->size); 3272b46acd6aSKonstantin Komarov used = le32_to_cpu(rec->used); 3273b46acd6aSKonstantin Komarov 3274b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh)) 3275b46acd6aSKonstantin Komarov goto dirty_vol; 3276b46acd6aSKonstantin Komarov 3277b46acd6aSKonstantin Komarov rec->used = cpu_to_le32(used - asize); 3278b46acd6aSKonstantin Komarov if (is_attr_indexed(attr)) 3279b46acd6aSKonstantin Komarov le16_add_cpu(&rec->hard_links, -1); 3280b46acd6aSKonstantin Komarov 3281b46acd6aSKonstantin Komarov memmove(attr, Add2Ptr(attr, asize), used - asize - roff); 3282b46acd6aSKonstantin Komarov 3283b46acd6aSKonstantin Komarov mi->dirty = true; 3284b46acd6aSKonstantin Komarov break; 3285b46acd6aSKonstantin Komarov 3286b46acd6aSKonstantin Komarov case UpdateResidentValue: 3287b46acd6aSKonstantin Komarov nsize = aoff + dlen; 3288b46acd6aSKonstantin Komarov 3289b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh)) 3290b46acd6aSKonstantin Komarov goto dirty_vol; 3291b46acd6aSKonstantin Komarov 3292b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr->size); 3293b46acd6aSKonstantin Komarov used = le32_to_cpu(rec->used); 3294b46acd6aSKonstantin Komarov 3295b46acd6aSKonstantin Komarov if (lrh->redo_len == lrh->undo_len) { 3296b46acd6aSKonstantin Komarov if (nsize > asize) 3297b46acd6aSKonstantin Komarov goto dirty_vol; 3298b46acd6aSKonstantin Komarov goto move_data; 3299b46acd6aSKonstantin Komarov } 3300b46acd6aSKonstantin Komarov 3301b46acd6aSKonstantin Komarov if (nsize > asize && nsize - asize > record_size - used) 3302b46acd6aSKonstantin Komarov goto dirty_vol; 3303b46acd6aSKonstantin Komarov 3304fa3cacf5SKari Argillander nsize = ALIGN(nsize, 8); 3305b46acd6aSKonstantin Komarov data_off = le16_to_cpu(attr->res.data_off); 3306b46acd6aSKonstantin Komarov 3307b46acd6aSKonstantin Komarov if (nsize < asize) { 3308b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, aoff), data, dlen); 3309*e8b8e97fSKari Argillander data = NULL; // To skip below memmove(). 3310b46acd6aSKonstantin Komarov } 3311b46acd6aSKonstantin Komarov 3312b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, nsize), Add2Ptr(attr, asize), 3313b46acd6aSKonstantin Komarov used - le16_to_cpu(lrh->record_off) - asize); 3314b46acd6aSKonstantin Komarov 3315b46acd6aSKonstantin Komarov rec->used = cpu_to_le32(used + nsize - asize); 3316b46acd6aSKonstantin Komarov attr->size = cpu_to_le32(nsize); 3317b46acd6aSKonstantin Komarov attr->res.data_size = cpu_to_le32(aoff + dlen - data_off); 3318b46acd6aSKonstantin Komarov 3319b46acd6aSKonstantin Komarov move_data: 3320b46acd6aSKonstantin Komarov if (data) 3321b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, aoff), data, dlen); 3322b46acd6aSKonstantin Komarov 3323b46acd6aSKonstantin Komarov oa2 = find_loaded_attr(log, attr, rno_base); 3324b46acd6aSKonstantin Komarov if (oa2) { 3325195c52bdSKari Argillander void *p2 = kmemdup(attr, le32_to_cpu(attr->size), 3326195c52bdSKari Argillander GFP_NOFS); 3327b46acd6aSKonstantin Komarov if (p2) { 3328b46acd6aSKonstantin Komarov // run_close(&oa2->run0); 3329b46acd6aSKonstantin Komarov oa2->run1 = &oa2->run0; 3330195c52bdSKari Argillander kfree(oa2->attr); 3331b46acd6aSKonstantin Komarov oa2->attr = p2; 3332b46acd6aSKonstantin Komarov } 3333b46acd6aSKonstantin Komarov } 3334b46acd6aSKonstantin Komarov 3335b46acd6aSKonstantin Komarov mi->dirty = true; 3336b46acd6aSKonstantin Komarov break; 3337b46acd6aSKonstantin Komarov 3338b46acd6aSKonstantin Komarov case UpdateMappingPairs: 3339b46acd6aSKonstantin Komarov nsize = aoff + dlen; 3340b46acd6aSKonstantin Komarov asize = le32_to_cpu(attr->size); 3341b46acd6aSKonstantin Komarov used = le32_to_cpu(rec->used); 3342b46acd6aSKonstantin Komarov 3343b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh) || !attr->non_res || 3344b46acd6aSKonstantin Komarov aoff < le16_to_cpu(attr->nres.run_off) || aoff > asize || 3345b46acd6aSKonstantin Komarov (nsize > asize && nsize - asize > record_size - used)) { 3346b46acd6aSKonstantin Komarov goto dirty_vol; 3347b46acd6aSKonstantin Komarov } 3348b46acd6aSKonstantin Komarov 3349fa3cacf5SKari Argillander nsize = ALIGN(nsize, 8); 3350b46acd6aSKonstantin Komarov 3351b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, nsize), Add2Ptr(attr, asize), 3352b46acd6aSKonstantin Komarov used - le16_to_cpu(lrh->record_off) - asize); 3353b46acd6aSKonstantin Komarov rec->used = cpu_to_le32(used + nsize - asize); 3354b46acd6aSKonstantin Komarov attr->size = cpu_to_le32(nsize); 3355b46acd6aSKonstantin Komarov memmove(Add2Ptr(attr, aoff), data, dlen); 3356b46acd6aSKonstantin Komarov 3357b46acd6aSKonstantin Komarov if (run_get_highest_vcn(le64_to_cpu(attr->nres.svcn), 3358b46acd6aSKonstantin Komarov attr_run(attr), &t64)) { 3359b46acd6aSKonstantin Komarov goto dirty_vol; 3360b46acd6aSKonstantin Komarov } 3361b46acd6aSKonstantin Komarov 3362b46acd6aSKonstantin Komarov attr->nres.evcn = cpu_to_le64(t64); 3363b46acd6aSKonstantin Komarov oa2 = find_loaded_attr(log, attr, rno_base); 3364b46acd6aSKonstantin Komarov if (oa2 && oa2->attr->non_res) 3365b46acd6aSKonstantin Komarov oa2->attr->nres.evcn = attr->nres.evcn; 3366b46acd6aSKonstantin Komarov 3367b46acd6aSKonstantin Komarov mi->dirty = true; 3368b46acd6aSKonstantin Komarov break; 3369b46acd6aSKonstantin Komarov 3370b46acd6aSKonstantin Komarov case SetNewAttributeSizes: 3371b46acd6aSKonstantin Komarov new_sz = data; 3372b46acd6aSKonstantin Komarov if (!check_if_attr(rec, lrh) || !attr->non_res) 3373b46acd6aSKonstantin Komarov goto dirty_vol; 3374b46acd6aSKonstantin Komarov 3375b46acd6aSKonstantin Komarov attr->nres.alloc_size = new_sz->alloc_size; 3376b46acd6aSKonstantin Komarov attr->nres.data_size = new_sz->data_size; 3377b46acd6aSKonstantin Komarov attr->nres.valid_size = new_sz->valid_size; 3378b46acd6aSKonstantin Komarov 3379b46acd6aSKonstantin Komarov if (dlen >= sizeof(struct NEW_ATTRIBUTE_SIZES)) 3380b46acd6aSKonstantin Komarov attr->nres.total_size = new_sz->total_size; 3381b46acd6aSKonstantin Komarov 3382b46acd6aSKonstantin Komarov oa2 = find_loaded_attr(log, attr, rno_base); 3383b46acd6aSKonstantin Komarov if (oa2) { 3384195c52bdSKari Argillander void *p2 = kmemdup(attr, le32_to_cpu(attr->size), 3385195c52bdSKari Argillander GFP_NOFS); 3386b46acd6aSKonstantin Komarov if (p2) { 3387195c52bdSKari Argillander kfree(oa2->attr); 3388b46acd6aSKonstantin Komarov oa2->attr = p2; 3389b46acd6aSKonstantin Komarov } 3390b46acd6aSKonstantin Komarov } 3391b46acd6aSKonstantin Komarov mi->dirty = true; 3392b46acd6aSKonstantin Komarov break; 3393b46acd6aSKonstantin Komarov 3394b46acd6aSKonstantin Komarov case AddIndexEntryRoot: 3395b46acd6aSKonstantin Komarov e = (struct NTFS_DE *)data; 3396b46acd6aSKonstantin Komarov esize = le16_to_cpu(e->size); 3397b46acd6aSKonstantin Komarov root = resident_data(attr); 3398b46acd6aSKonstantin Komarov hdr = &root->ihdr; 3399b46acd6aSKonstantin Komarov used = le32_to_cpu(hdr->used); 3400b46acd6aSKonstantin Komarov 3401b46acd6aSKonstantin Komarov if (!check_if_index_root(rec, lrh) || 3402b46acd6aSKonstantin Komarov !check_if_root_index(attr, hdr, lrh) || 3403b46acd6aSKonstantin Komarov Add2Ptr(data, esize) > Add2Ptr(lrh, rec_len) || 3404b46acd6aSKonstantin Komarov esize > le32_to_cpu(rec->total) - le32_to_cpu(rec->used)) { 3405b46acd6aSKonstantin Komarov goto dirty_vol; 3406b46acd6aSKonstantin Komarov } 3407b46acd6aSKonstantin Komarov 3408b46acd6aSKonstantin Komarov e1 = Add2Ptr(attr, le16_to_cpu(lrh->attr_off)); 3409b46acd6aSKonstantin Komarov 3410b46acd6aSKonstantin Komarov change_attr_size(rec, attr, le32_to_cpu(attr->size) + esize); 3411b46acd6aSKonstantin Komarov 3412b46acd6aSKonstantin Komarov memmove(Add2Ptr(e1, esize), e1, 3413b46acd6aSKonstantin Komarov PtrOffset(e1, Add2Ptr(hdr, used))); 3414b46acd6aSKonstantin Komarov memmove(e1, e, esize); 3415b46acd6aSKonstantin Komarov 3416b46acd6aSKonstantin Komarov le32_add_cpu(&attr->res.data_size, esize); 3417b46acd6aSKonstantin Komarov hdr->used = cpu_to_le32(used + esize); 3418b46acd6aSKonstantin Komarov le32_add_cpu(&hdr->total, esize); 3419b46acd6aSKonstantin Komarov 3420b46acd6aSKonstantin Komarov mi->dirty = true; 3421b46acd6aSKonstantin Komarov break; 3422b46acd6aSKonstantin Komarov 3423b46acd6aSKonstantin Komarov case DeleteIndexEntryRoot: 3424b46acd6aSKonstantin Komarov root = resident_data(attr); 3425b46acd6aSKonstantin Komarov hdr = &root->ihdr; 3426b46acd6aSKonstantin Komarov used = le32_to_cpu(hdr->used); 3427b46acd6aSKonstantin Komarov 3428b46acd6aSKonstantin Komarov if (!check_if_index_root(rec, lrh) || 3429b46acd6aSKonstantin Komarov !check_if_root_index(attr, hdr, lrh)) { 3430b46acd6aSKonstantin Komarov goto dirty_vol; 3431b46acd6aSKonstantin Komarov } 3432b46acd6aSKonstantin Komarov 3433b46acd6aSKonstantin Komarov e1 = Add2Ptr(attr, le16_to_cpu(lrh->attr_off)); 3434b46acd6aSKonstantin Komarov esize = le16_to_cpu(e1->size); 3435b46acd6aSKonstantin Komarov e2 = Add2Ptr(e1, esize); 3436b46acd6aSKonstantin Komarov 3437b46acd6aSKonstantin Komarov memmove(e1, e2, PtrOffset(e2, Add2Ptr(hdr, used))); 3438b46acd6aSKonstantin Komarov 3439b46acd6aSKonstantin Komarov le32_sub_cpu(&attr->res.data_size, esize); 3440b46acd6aSKonstantin Komarov hdr->used = cpu_to_le32(used - esize); 3441b46acd6aSKonstantin Komarov le32_sub_cpu(&hdr->total, esize); 3442b46acd6aSKonstantin Komarov 3443b46acd6aSKonstantin Komarov change_attr_size(rec, attr, le32_to_cpu(attr->size) - esize); 3444b46acd6aSKonstantin Komarov 3445b46acd6aSKonstantin Komarov mi->dirty = true; 3446b46acd6aSKonstantin Komarov break; 3447b46acd6aSKonstantin Komarov 3448b46acd6aSKonstantin Komarov case SetIndexEntryVcnRoot: 3449b46acd6aSKonstantin Komarov root = resident_data(attr); 3450b46acd6aSKonstantin Komarov hdr = &root->ihdr; 3451b46acd6aSKonstantin Komarov 3452b46acd6aSKonstantin Komarov if (!check_if_index_root(rec, lrh) || 3453b46acd6aSKonstantin Komarov !check_if_root_index(attr, hdr, lrh)) { 3454b46acd6aSKonstantin Komarov goto dirty_vol; 3455b46acd6aSKonstantin Komarov } 3456b46acd6aSKonstantin Komarov 3457b46acd6aSKonstantin Komarov e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off)); 3458b46acd6aSKonstantin Komarov 3459b46acd6aSKonstantin Komarov de_set_vbn_le(e, *(__le64 *)data); 3460b46acd6aSKonstantin Komarov mi->dirty = true; 3461b46acd6aSKonstantin Komarov break; 3462b46acd6aSKonstantin Komarov 3463b46acd6aSKonstantin Komarov case UpdateFileNameRoot: 3464b46acd6aSKonstantin Komarov root = resident_data(attr); 3465b46acd6aSKonstantin Komarov hdr = &root->ihdr; 3466b46acd6aSKonstantin Komarov 3467b46acd6aSKonstantin Komarov if (!check_if_index_root(rec, lrh) || 3468b46acd6aSKonstantin Komarov !check_if_root_index(attr, hdr, lrh)) { 3469b46acd6aSKonstantin Komarov goto dirty_vol; 3470b46acd6aSKonstantin Komarov } 3471b46acd6aSKonstantin Komarov 3472b46acd6aSKonstantin Komarov e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off)); 3473b46acd6aSKonstantin Komarov fname = (struct ATTR_FILE_NAME *)(e + 1); 3474b46acd6aSKonstantin Komarov memmove(&fname->dup, data, sizeof(fname->dup)); // 3475b46acd6aSKonstantin Komarov mi->dirty = true; 3476b46acd6aSKonstantin Komarov break; 3477b46acd6aSKonstantin Komarov 3478b46acd6aSKonstantin Komarov case UpdateRecordDataRoot: 3479b46acd6aSKonstantin Komarov root = resident_data(attr); 3480b46acd6aSKonstantin Komarov hdr = &root->ihdr; 3481b46acd6aSKonstantin Komarov 3482b46acd6aSKonstantin Komarov if (!check_if_index_root(rec, lrh) || 3483b46acd6aSKonstantin Komarov !check_if_root_index(attr, hdr, lrh)) { 3484b46acd6aSKonstantin Komarov goto dirty_vol; 3485b46acd6aSKonstantin Komarov } 3486b46acd6aSKonstantin Komarov 3487b46acd6aSKonstantin Komarov e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off)); 3488b46acd6aSKonstantin Komarov 3489b46acd6aSKonstantin Komarov memmove(Add2Ptr(e, le16_to_cpu(e->view.data_off)), data, dlen); 3490b46acd6aSKonstantin Komarov 3491b46acd6aSKonstantin Komarov mi->dirty = true; 3492b46acd6aSKonstantin Komarov break; 3493b46acd6aSKonstantin Komarov 3494b46acd6aSKonstantin Komarov case ZeroEndOfFileRecord: 3495b46acd6aSKonstantin Komarov if (roff + dlen > record_size) 3496b46acd6aSKonstantin Komarov goto dirty_vol; 3497b46acd6aSKonstantin Komarov 3498b46acd6aSKonstantin Komarov memset(attr, 0, dlen); 3499b46acd6aSKonstantin Komarov mi->dirty = true; 3500b46acd6aSKonstantin Komarov break; 3501b46acd6aSKonstantin Komarov 3502b46acd6aSKonstantin Komarov case UpdateNonresidentValue: 3503b46acd6aSKonstantin Komarov if (lco < cbo + roff + dlen) 3504b46acd6aSKonstantin Komarov goto dirty_vol; 3505b46acd6aSKonstantin Komarov 3506b46acd6aSKonstantin Komarov memcpy(Add2Ptr(buffer_le, roff), data, dlen); 3507b46acd6aSKonstantin Komarov 3508b46acd6aSKonstantin Komarov a_dirty = true; 3509b46acd6aSKonstantin Komarov if (attr->type == ATTR_ALLOC) 3510b46acd6aSKonstantin Komarov ntfs_fix_pre_write(buffer_le, bytes); 3511b46acd6aSKonstantin Komarov break; 3512b46acd6aSKonstantin Komarov 3513b46acd6aSKonstantin Komarov case AddIndexEntryAllocation: 3514b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3515b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3516b46acd6aSKonstantin Komarov e = data; 3517b46acd6aSKonstantin Komarov esize = le16_to_cpu(e->size); 3518b46acd6aSKonstantin Komarov e1 = Add2Ptr(ib, aoff); 3519b46acd6aSKonstantin Komarov 3520b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3521b46acd6aSKonstantin Komarov goto dirty_vol; 3522b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3523b46acd6aSKonstantin Komarov goto out; 3524b46acd6aSKonstantin Komarov 3525b46acd6aSKonstantin Komarov used = le32_to_cpu(hdr->used); 3526b46acd6aSKonstantin Komarov 3527b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3528b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff) || 3529b46acd6aSKonstantin Komarov Add2Ptr(e, esize) > Add2Ptr(lrh, rec_len) || 3530b46acd6aSKonstantin Komarov used + esize > le32_to_cpu(hdr->total)) { 3531b46acd6aSKonstantin Komarov goto dirty_vol; 3532b46acd6aSKonstantin Komarov } 3533b46acd6aSKonstantin Komarov 3534b46acd6aSKonstantin Komarov memmove(Add2Ptr(e1, esize), e1, 3535b46acd6aSKonstantin Komarov PtrOffset(e1, Add2Ptr(hdr, used))); 3536b46acd6aSKonstantin Komarov memcpy(e1, e, esize); 3537b46acd6aSKonstantin Komarov 3538b46acd6aSKonstantin Komarov hdr->used = cpu_to_le32(used + esize); 3539b46acd6aSKonstantin Komarov 3540b46acd6aSKonstantin Komarov a_dirty = true; 3541b46acd6aSKonstantin Komarov 3542b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3543b46acd6aSKonstantin Komarov break; 3544b46acd6aSKonstantin Komarov 3545b46acd6aSKonstantin Komarov case DeleteIndexEntryAllocation: 3546b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3547b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3548b46acd6aSKonstantin Komarov e = Add2Ptr(ib, aoff); 3549b46acd6aSKonstantin Komarov esize = le16_to_cpu(e->size); 3550b46acd6aSKonstantin Komarov 3551b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3552b46acd6aSKonstantin Komarov goto dirty_vol; 3553b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3554b46acd6aSKonstantin Komarov goto out; 3555b46acd6aSKonstantin Komarov 3556b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3557b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff)) { 3558b46acd6aSKonstantin Komarov goto dirty_vol; 3559b46acd6aSKonstantin Komarov } 3560b46acd6aSKonstantin Komarov 3561b46acd6aSKonstantin Komarov e1 = Add2Ptr(e, esize); 3562b46acd6aSKonstantin Komarov nsize = esize; 3563b46acd6aSKonstantin Komarov used = le32_to_cpu(hdr->used); 3564b46acd6aSKonstantin Komarov 3565b46acd6aSKonstantin Komarov memmove(e, e1, PtrOffset(e1, Add2Ptr(hdr, used))); 3566b46acd6aSKonstantin Komarov 3567b46acd6aSKonstantin Komarov hdr->used = cpu_to_le32(used - nsize); 3568b46acd6aSKonstantin Komarov 3569b46acd6aSKonstantin Komarov a_dirty = true; 3570b46acd6aSKonstantin Komarov 3571b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3572b46acd6aSKonstantin Komarov break; 3573b46acd6aSKonstantin Komarov 3574b46acd6aSKonstantin Komarov case WriteEndOfIndexBuffer: 3575b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3576b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3577b46acd6aSKonstantin Komarov e = Add2Ptr(ib, aoff); 3578b46acd6aSKonstantin Komarov 3579b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3580b46acd6aSKonstantin Komarov goto dirty_vol; 3581b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3582b46acd6aSKonstantin Komarov goto out; 3583b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3584b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff) || 3585b46acd6aSKonstantin Komarov aoff + dlen > offsetof(struct INDEX_BUFFER, ihdr) + 3586b46acd6aSKonstantin Komarov le32_to_cpu(hdr->total)) { 3587b46acd6aSKonstantin Komarov goto dirty_vol; 3588b46acd6aSKonstantin Komarov } 3589b46acd6aSKonstantin Komarov 3590b46acd6aSKonstantin Komarov hdr->used = cpu_to_le32(dlen + PtrOffset(hdr, e)); 3591b46acd6aSKonstantin Komarov memmove(e, data, dlen); 3592b46acd6aSKonstantin Komarov 3593b46acd6aSKonstantin Komarov a_dirty = true; 3594b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3595b46acd6aSKonstantin Komarov break; 3596b46acd6aSKonstantin Komarov 3597b46acd6aSKonstantin Komarov case SetIndexEntryVcnAllocation: 3598b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3599b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3600b46acd6aSKonstantin Komarov e = Add2Ptr(ib, aoff); 3601b46acd6aSKonstantin Komarov 3602b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3603b46acd6aSKonstantin Komarov goto dirty_vol; 3604b46acd6aSKonstantin Komarov 3605b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3606b46acd6aSKonstantin Komarov goto out; 3607b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3608b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff)) { 3609b46acd6aSKonstantin Komarov goto dirty_vol; 3610b46acd6aSKonstantin Komarov } 3611b46acd6aSKonstantin Komarov 3612b46acd6aSKonstantin Komarov de_set_vbn_le(e, *(__le64 *)data); 3613b46acd6aSKonstantin Komarov 3614b46acd6aSKonstantin Komarov a_dirty = true; 3615b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3616b46acd6aSKonstantin Komarov break; 3617b46acd6aSKonstantin Komarov 3618b46acd6aSKonstantin Komarov case UpdateFileNameAllocation: 3619b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3620b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3621b46acd6aSKonstantin Komarov e = Add2Ptr(ib, aoff); 3622b46acd6aSKonstantin Komarov 3623b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3624b46acd6aSKonstantin Komarov goto dirty_vol; 3625b46acd6aSKonstantin Komarov 3626b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3627b46acd6aSKonstantin Komarov goto out; 3628b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3629b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff)) { 3630b46acd6aSKonstantin Komarov goto dirty_vol; 3631b46acd6aSKonstantin Komarov } 3632b46acd6aSKonstantin Komarov 3633b46acd6aSKonstantin Komarov fname = (struct ATTR_FILE_NAME *)(e + 1); 3634b46acd6aSKonstantin Komarov memmove(&fname->dup, data, sizeof(fname->dup)); 3635b46acd6aSKonstantin Komarov 3636b46acd6aSKonstantin Komarov a_dirty = true; 3637b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3638b46acd6aSKonstantin Komarov break; 3639b46acd6aSKonstantin Komarov 3640b46acd6aSKonstantin Komarov case SetBitsInNonresidentBitMap: 3641b46acd6aSKonstantin Komarov bmp_off = 3642b46acd6aSKonstantin Komarov le32_to_cpu(((struct BITMAP_RANGE *)data)->bitmap_off); 3643b46acd6aSKonstantin Komarov bmp_bits = le32_to_cpu(((struct BITMAP_RANGE *)data)->bits); 3644b46acd6aSKonstantin Komarov 3645b46acd6aSKonstantin Komarov if (cbo + (bmp_off + 7) / 8 > lco || 3646b46acd6aSKonstantin Komarov cbo + ((bmp_off + bmp_bits + 7) / 8) > lco) { 3647b46acd6aSKonstantin Komarov goto dirty_vol; 3648b46acd6aSKonstantin Komarov } 3649b46acd6aSKonstantin Komarov 3650b46acd6aSKonstantin Komarov __bitmap_set(Add2Ptr(buffer_le, roff), bmp_off, bmp_bits); 3651b46acd6aSKonstantin Komarov a_dirty = true; 3652b46acd6aSKonstantin Komarov break; 3653b46acd6aSKonstantin Komarov 3654b46acd6aSKonstantin Komarov case ClearBitsInNonresidentBitMap: 3655b46acd6aSKonstantin Komarov bmp_off = 3656b46acd6aSKonstantin Komarov le32_to_cpu(((struct BITMAP_RANGE *)data)->bitmap_off); 3657b46acd6aSKonstantin Komarov bmp_bits = le32_to_cpu(((struct BITMAP_RANGE *)data)->bits); 3658b46acd6aSKonstantin Komarov 3659b46acd6aSKonstantin Komarov if (cbo + (bmp_off + 7) / 8 > lco || 3660b46acd6aSKonstantin Komarov cbo + ((bmp_off + bmp_bits + 7) / 8) > lco) { 3661b46acd6aSKonstantin Komarov goto dirty_vol; 3662b46acd6aSKonstantin Komarov } 3663b46acd6aSKonstantin Komarov 3664b46acd6aSKonstantin Komarov __bitmap_clear(Add2Ptr(buffer_le, roff), bmp_off, bmp_bits); 3665b46acd6aSKonstantin Komarov a_dirty = true; 3666b46acd6aSKonstantin Komarov break; 3667b46acd6aSKonstantin Komarov 3668b46acd6aSKonstantin Komarov case UpdateRecordDataAllocation: 3669b46acd6aSKonstantin Komarov ib = Add2Ptr(buffer_le, roff); 3670b46acd6aSKonstantin Komarov hdr = &ib->ihdr; 3671b46acd6aSKonstantin Komarov e = Add2Ptr(ib, aoff); 3672b46acd6aSKonstantin Komarov 3673b46acd6aSKonstantin Komarov if (is_baad(&ib->rhdr)) 3674b46acd6aSKonstantin Komarov goto dirty_vol; 3675b46acd6aSKonstantin Komarov 3676b46acd6aSKonstantin Komarov if (!check_lsn(&ib->rhdr, rlsn)) 3677b46acd6aSKonstantin Komarov goto out; 3678b46acd6aSKonstantin Komarov if (!check_index_buffer(ib, bytes) || 3679b46acd6aSKonstantin Komarov !check_if_alloc_index(hdr, aoff)) { 3680b46acd6aSKonstantin Komarov goto dirty_vol; 3681b46acd6aSKonstantin Komarov } 3682b46acd6aSKonstantin Komarov 3683b46acd6aSKonstantin Komarov memmove(Add2Ptr(e, le16_to_cpu(e->view.data_off)), data, dlen); 3684b46acd6aSKonstantin Komarov 3685b46acd6aSKonstantin Komarov a_dirty = true; 3686b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&ib->rhdr, bytes); 3687b46acd6aSKonstantin Komarov break; 3688b46acd6aSKonstantin Komarov 3689b46acd6aSKonstantin Komarov default: 3690b46acd6aSKonstantin Komarov WARN_ON(1); 3691b46acd6aSKonstantin Komarov } 3692b46acd6aSKonstantin Komarov 3693b46acd6aSKonstantin Komarov if (rlsn) { 3694b46acd6aSKonstantin Komarov __le64 t64 = cpu_to_le64(*rlsn); 3695b46acd6aSKonstantin Komarov 3696b46acd6aSKonstantin Komarov if (rec) 3697b46acd6aSKonstantin Komarov rec->rhdr.lsn = t64; 3698b46acd6aSKonstantin Komarov if (ib) 3699b46acd6aSKonstantin Komarov ib->rhdr.lsn = t64; 3700b46acd6aSKonstantin Komarov } 3701b46acd6aSKonstantin Komarov 3702b46acd6aSKonstantin Komarov if (mi && mi->dirty) { 3703b46acd6aSKonstantin Komarov err = mi_write(mi, 0); 3704b46acd6aSKonstantin Komarov if (err) 3705b46acd6aSKonstantin Komarov goto out; 3706b46acd6aSKonstantin Komarov } 3707b46acd6aSKonstantin Komarov 3708b46acd6aSKonstantin Komarov if (a_dirty) { 3709b46acd6aSKonstantin Komarov attr = oa->attr; 3710b46acd6aSKonstantin Komarov err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes); 3711b46acd6aSKonstantin Komarov if (err) 3712b46acd6aSKonstantin Komarov goto out; 3713b46acd6aSKonstantin Komarov } 3714b46acd6aSKonstantin Komarov 3715b46acd6aSKonstantin Komarov out: 3716b46acd6aSKonstantin Komarov 3717b46acd6aSKonstantin Komarov if (inode) 3718b46acd6aSKonstantin Komarov iput(inode); 3719b46acd6aSKonstantin Komarov else if (mi != mi2_child) 3720b46acd6aSKonstantin Komarov mi_put(mi); 3721b46acd6aSKonstantin Komarov 3722195c52bdSKari Argillander kfree(buffer_le); 3723b46acd6aSKonstantin Komarov 3724b46acd6aSKonstantin Komarov return err; 3725b46acd6aSKonstantin Komarov 3726b46acd6aSKonstantin Komarov dirty_vol: 3727b46acd6aSKonstantin Komarov log->set_dirty = true; 3728b46acd6aSKonstantin Komarov goto out; 3729b46acd6aSKonstantin Komarov } 3730b46acd6aSKonstantin Komarov 3731b46acd6aSKonstantin Komarov /* 3732*e8b8e97fSKari Argillander * log_replay - Replays log and empties it. 3733b46acd6aSKonstantin Komarov * 3734*e8b8e97fSKari Argillander * This function is called during mount operation. 3735*e8b8e97fSKari Argillander * It replays log and empties it. 3736*e8b8e97fSKari Argillander * Initialized is set false if logfile contains '-1'. 3737b46acd6aSKonstantin Komarov */ 3738b46acd6aSKonstantin Komarov int log_replay(struct ntfs_inode *ni, bool *initialized) 3739b46acd6aSKonstantin Komarov { 3740b46acd6aSKonstantin Komarov int err; 3741b46acd6aSKonstantin Komarov struct ntfs_sb_info *sbi = ni->mi.sbi; 3742b46acd6aSKonstantin Komarov struct ntfs_log *log; 3743b46acd6aSKonstantin Komarov 3744b46acd6aSKonstantin Komarov struct restart_info rst_info, rst_info2; 3745b46acd6aSKonstantin Komarov u64 rec_lsn, ra_lsn, checkpt_lsn = 0, rlsn = 0; 3746b46acd6aSKonstantin Komarov struct ATTR_NAME_ENTRY *attr_names = NULL; 3747b46acd6aSKonstantin Komarov struct ATTR_NAME_ENTRY *ane; 3748b46acd6aSKonstantin Komarov struct RESTART_TABLE *dptbl = NULL; 3749b46acd6aSKonstantin Komarov struct RESTART_TABLE *trtbl = NULL; 3750b46acd6aSKonstantin Komarov const struct RESTART_TABLE *rt; 3751b46acd6aSKonstantin Komarov struct RESTART_TABLE *oatbl = NULL; 3752b46acd6aSKonstantin Komarov struct inode *inode; 3753b46acd6aSKonstantin Komarov struct OpenAttr *oa; 3754b46acd6aSKonstantin Komarov struct ntfs_inode *ni_oe; 3755b46acd6aSKonstantin Komarov struct ATTRIB *attr = NULL; 3756b46acd6aSKonstantin Komarov u64 size, vcn, undo_next_lsn; 3757b46acd6aSKonstantin Komarov CLST rno, lcn, lcn0, len0, clen; 3758b46acd6aSKonstantin Komarov void *data; 3759b46acd6aSKonstantin Komarov struct NTFS_RESTART *rst = NULL; 3760b46acd6aSKonstantin Komarov struct lcb *lcb = NULL; 3761b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY *oe; 3762b46acd6aSKonstantin Komarov struct TRANSACTION_ENTRY *tr; 3763b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY *dp; 3764b46acd6aSKonstantin Komarov u32 i, bytes_per_attr_entry; 3765b46acd6aSKonstantin Komarov u32 l_size = ni->vfs_inode.i_size; 3766b46acd6aSKonstantin Komarov u32 orig_file_size = l_size; 3767b46acd6aSKonstantin Komarov u32 page_size, vbo, tail, off, dlen; 3768b46acd6aSKonstantin Komarov u32 saved_len, rec_len, transact_id; 3769b46acd6aSKonstantin Komarov bool use_second_page; 3770b46acd6aSKonstantin Komarov struct RESTART_AREA *ra2, *ra = NULL; 3771b46acd6aSKonstantin Komarov struct CLIENT_REC *ca, *cr; 3772b46acd6aSKonstantin Komarov __le16 client; 3773b46acd6aSKonstantin Komarov struct RESTART_HDR *rh; 3774b46acd6aSKonstantin Komarov const struct LFS_RECORD_HDR *frh; 3775b46acd6aSKonstantin Komarov const struct LOG_REC_HDR *lrh; 3776b46acd6aSKonstantin Komarov bool is_mapped; 3777b46acd6aSKonstantin Komarov bool is_ro = sb_rdonly(sbi->sb); 3778b46acd6aSKonstantin Komarov u64 t64; 3779b46acd6aSKonstantin Komarov u16 t16; 3780b46acd6aSKonstantin Komarov u32 t32; 3781b46acd6aSKonstantin Komarov 3782*e8b8e97fSKari Argillander /* Get the size of page. NOTE: To replay we can use default page. */ 3783b46acd6aSKonstantin Komarov #if PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <= DefaultLogPageSize * 2 3784b46acd6aSKonstantin Komarov page_size = norm_file_page(PAGE_SIZE, &l_size, true); 3785b46acd6aSKonstantin Komarov #else 3786b46acd6aSKonstantin Komarov page_size = norm_file_page(PAGE_SIZE, &l_size, false); 3787b46acd6aSKonstantin Komarov #endif 3788b46acd6aSKonstantin Komarov if (!page_size) 3789b46acd6aSKonstantin Komarov return -EINVAL; 3790b46acd6aSKonstantin Komarov 3791195c52bdSKari Argillander log = kzalloc(sizeof(struct ntfs_log), GFP_NOFS); 3792b46acd6aSKonstantin Komarov if (!log) 3793b46acd6aSKonstantin Komarov return -ENOMEM; 3794b46acd6aSKonstantin Komarov 3795b46acd6aSKonstantin Komarov log->ni = ni; 3796b46acd6aSKonstantin Komarov log->l_size = l_size; 3797195c52bdSKari Argillander log->one_page_buf = kmalloc(page_size, GFP_NOFS); 3798b46acd6aSKonstantin Komarov 3799b46acd6aSKonstantin Komarov if (!log->one_page_buf) { 3800b46acd6aSKonstantin Komarov err = -ENOMEM; 3801b46acd6aSKonstantin Komarov goto out; 3802b46acd6aSKonstantin Komarov } 3803b46acd6aSKonstantin Komarov 3804b46acd6aSKonstantin Komarov log->page_size = page_size; 3805b46acd6aSKonstantin Komarov log->page_mask = page_size - 1; 3806b46acd6aSKonstantin Komarov log->page_bits = blksize_bits(page_size); 3807b46acd6aSKonstantin Komarov 3808*e8b8e97fSKari Argillander /* Look for a restart area on the disk. */ 3809b46acd6aSKonstantin Komarov err = log_read_rst(log, l_size, true, &rst_info); 3810b46acd6aSKonstantin Komarov if (err) 3811b46acd6aSKonstantin Komarov goto out; 3812b46acd6aSKonstantin Komarov 3813b46acd6aSKonstantin Komarov /* remember 'initialized' */ 3814b46acd6aSKonstantin Komarov *initialized = rst_info.initialized; 3815b46acd6aSKonstantin Komarov 3816b46acd6aSKonstantin Komarov if (!rst_info.restart) { 3817b46acd6aSKonstantin Komarov if (rst_info.initialized) { 3818*e8b8e97fSKari Argillander /* No restart area but the file is not initialized. */ 3819b46acd6aSKonstantin Komarov err = -EINVAL; 3820b46acd6aSKonstantin Komarov goto out; 3821b46acd6aSKonstantin Komarov } 3822b46acd6aSKonstantin Komarov 3823b46acd6aSKonstantin Komarov log_init_pg_hdr(log, page_size, page_size, 1, 1); 3824b46acd6aSKonstantin Komarov log_create(log, l_size, 0, get_random_int(), false, false); 3825b46acd6aSKonstantin Komarov 3826b46acd6aSKonstantin Komarov log->ra = ra; 3827b46acd6aSKonstantin Komarov 3828b46acd6aSKonstantin Komarov ra = log_create_ra(log); 3829b46acd6aSKonstantin Komarov if (!ra) { 3830b46acd6aSKonstantin Komarov err = -ENOMEM; 3831b46acd6aSKonstantin Komarov goto out; 3832b46acd6aSKonstantin Komarov } 3833b46acd6aSKonstantin Komarov log->ra = ra; 3834b46acd6aSKonstantin Komarov log->init_ra = true; 3835b46acd6aSKonstantin Komarov 3836b46acd6aSKonstantin Komarov goto process_log; 3837b46acd6aSKonstantin Komarov } 3838b46acd6aSKonstantin Komarov 3839b46acd6aSKonstantin Komarov /* 3840b46acd6aSKonstantin Komarov * If the restart offset above wasn't zero then we won't 3841*e8b8e97fSKari Argillander * look for a second restart. 3842b46acd6aSKonstantin Komarov */ 3843b46acd6aSKonstantin Komarov if (rst_info.vbo) 3844b46acd6aSKonstantin Komarov goto check_restart_area; 3845b46acd6aSKonstantin Komarov 3846b46acd6aSKonstantin Komarov err = log_read_rst(log, l_size, false, &rst_info2); 3847b46acd6aSKonstantin Komarov 3848*e8b8e97fSKari Argillander /* Determine which restart area to use. */ 3849b46acd6aSKonstantin Komarov if (!rst_info2.restart || rst_info2.last_lsn <= rst_info.last_lsn) 3850b46acd6aSKonstantin Komarov goto use_first_page; 3851b46acd6aSKonstantin Komarov 3852b46acd6aSKonstantin Komarov use_second_page = true; 3853b46acd6aSKonstantin Komarov 3854b46acd6aSKonstantin Komarov if (rst_info.chkdsk_was_run && page_size != rst_info.vbo) { 3855b46acd6aSKonstantin Komarov struct RECORD_PAGE_HDR *sp = NULL; 3856b46acd6aSKonstantin Komarov bool usa_error; 3857b46acd6aSKonstantin Komarov 3858b46acd6aSKonstantin Komarov if (!read_log_page(log, page_size, &sp, &usa_error) && 3859b46acd6aSKonstantin Komarov sp->rhdr.sign == NTFS_CHKD_SIGNATURE) { 3860b46acd6aSKonstantin Komarov use_second_page = false; 3861b46acd6aSKonstantin Komarov } 3862195c52bdSKari Argillander kfree(sp); 3863b46acd6aSKonstantin Komarov } 3864b46acd6aSKonstantin Komarov 3865b46acd6aSKonstantin Komarov if (use_second_page) { 3866195c52bdSKari Argillander kfree(rst_info.r_page); 3867b46acd6aSKonstantin Komarov memcpy(&rst_info, &rst_info2, sizeof(struct restart_info)); 3868b46acd6aSKonstantin Komarov rst_info2.r_page = NULL; 3869b46acd6aSKonstantin Komarov } 3870b46acd6aSKonstantin Komarov 3871b46acd6aSKonstantin Komarov use_first_page: 3872195c52bdSKari Argillander kfree(rst_info2.r_page); 3873b46acd6aSKonstantin Komarov 3874b46acd6aSKonstantin Komarov check_restart_area: 3875*e8b8e97fSKari Argillander /* 3876*e8b8e97fSKari Argillander * If the restart area is at offset 0, we want 3877*e8b8e97fSKari Argillander * to write the second restart area first. 3878*e8b8e97fSKari Argillander */ 3879b46acd6aSKonstantin Komarov log->init_ra = !!rst_info.vbo; 3880b46acd6aSKonstantin Komarov 3881*e8b8e97fSKari Argillander /* If we have a valid page then grab a pointer to the restart area. */ 3882b46acd6aSKonstantin Komarov ra2 = rst_info.valid_page 3883b46acd6aSKonstantin Komarov ? Add2Ptr(rst_info.r_page, 3884b46acd6aSKonstantin Komarov le16_to_cpu(rst_info.r_page->ra_off)) 3885b46acd6aSKonstantin Komarov : NULL; 3886b46acd6aSKonstantin Komarov 3887b46acd6aSKonstantin Komarov if (rst_info.chkdsk_was_run || 3888b46acd6aSKonstantin Komarov (ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) { 3889b46acd6aSKonstantin Komarov bool wrapped = false; 3890b46acd6aSKonstantin Komarov bool use_multi_page = false; 3891b46acd6aSKonstantin Komarov u32 open_log_count; 3892b46acd6aSKonstantin Komarov 3893*e8b8e97fSKari Argillander /* Do some checks based on whether we have a valid log page. */ 3894b46acd6aSKonstantin Komarov if (!rst_info.valid_page) { 3895b46acd6aSKonstantin Komarov open_log_count = get_random_int(); 3896b46acd6aSKonstantin Komarov goto init_log_instance; 3897b46acd6aSKonstantin Komarov } 3898b46acd6aSKonstantin Komarov open_log_count = le32_to_cpu(ra2->open_log_count); 3899b46acd6aSKonstantin Komarov 3900b46acd6aSKonstantin Komarov /* 3901b46acd6aSKonstantin Komarov * If the restart page size isn't changing then we want to 3902*e8b8e97fSKari Argillander * check how much work we need to do. 3903b46acd6aSKonstantin Komarov */ 3904b46acd6aSKonstantin Komarov if (page_size != le32_to_cpu(rst_info.r_page->sys_page_size)) 3905b46acd6aSKonstantin Komarov goto init_log_instance; 3906b46acd6aSKonstantin Komarov 3907b46acd6aSKonstantin Komarov init_log_instance: 3908b46acd6aSKonstantin Komarov log_init_pg_hdr(log, page_size, page_size, 1, 1); 3909b46acd6aSKonstantin Komarov 3910b46acd6aSKonstantin Komarov log_create(log, l_size, rst_info.last_lsn, open_log_count, 3911b46acd6aSKonstantin Komarov wrapped, use_multi_page); 3912b46acd6aSKonstantin Komarov 3913b46acd6aSKonstantin Komarov ra = log_create_ra(log); 3914b46acd6aSKonstantin Komarov if (!ra) { 3915b46acd6aSKonstantin Komarov err = -ENOMEM; 3916b46acd6aSKonstantin Komarov goto out; 3917b46acd6aSKonstantin Komarov } 3918b46acd6aSKonstantin Komarov log->ra = ra; 3919b46acd6aSKonstantin Komarov 3920*e8b8e97fSKari Argillander /* Put the restart areas and initialize 3921*e8b8e97fSKari Argillander * the log file as required. 3922*e8b8e97fSKari Argillander */ 3923b46acd6aSKonstantin Komarov goto process_log; 3924b46acd6aSKonstantin Komarov } 3925b46acd6aSKonstantin Komarov 3926b46acd6aSKonstantin Komarov if (!ra2) { 3927b46acd6aSKonstantin Komarov err = -EINVAL; 3928b46acd6aSKonstantin Komarov goto out; 3929b46acd6aSKonstantin Komarov } 3930b46acd6aSKonstantin Komarov 3931b46acd6aSKonstantin Komarov /* 3932*e8b8e97fSKari Argillander * If the log page or the system page sizes have changed, we can't 3933*e8b8e97fSKari Argillander * use the log file. We must use the system page size instead of the 3934*e8b8e97fSKari Argillander * default size if there is not a clean shutdown. 3935b46acd6aSKonstantin Komarov */ 3936b46acd6aSKonstantin Komarov t32 = le32_to_cpu(rst_info.r_page->sys_page_size); 3937b46acd6aSKonstantin Komarov if (page_size != t32) { 3938b46acd6aSKonstantin Komarov l_size = orig_file_size; 3939b46acd6aSKonstantin Komarov page_size = 3940b46acd6aSKonstantin Komarov norm_file_page(t32, &l_size, t32 == DefaultLogPageSize); 3941b46acd6aSKonstantin Komarov } 3942b46acd6aSKonstantin Komarov 3943b46acd6aSKonstantin Komarov if (page_size != t32 || 3944b46acd6aSKonstantin Komarov page_size != le32_to_cpu(rst_info.r_page->page_size)) { 3945b46acd6aSKonstantin Komarov err = -EINVAL; 3946b46acd6aSKonstantin Komarov goto out; 3947b46acd6aSKonstantin Komarov } 3948b46acd6aSKonstantin Komarov 3949*e8b8e97fSKari Argillander /* If the file size has shrunk then we won't mount it. */ 3950b46acd6aSKonstantin Komarov if (l_size < le64_to_cpu(ra2->l_size)) { 3951b46acd6aSKonstantin Komarov err = -EINVAL; 3952b46acd6aSKonstantin Komarov goto out; 3953b46acd6aSKonstantin Komarov } 3954b46acd6aSKonstantin Komarov 3955b46acd6aSKonstantin Komarov log_init_pg_hdr(log, page_size, page_size, 3956b46acd6aSKonstantin Komarov le16_to_cpu(rst_info.r_page->major_ver), 3957b46acd6aSKonstantin Komarov le16_to_cpu(rst_info.r_page->minor_ver)); 3958b46acd6aSKonstantin Komarov 3959b46acd6aSKonstantin Komarov log->l_size = le64_to_cpu(ra2->l_size); 3960b46acd6aSKonstantin Komarov log->seq_num_bits = le32_to_cpu(ra2->seq_num_bits); 3961b46acd6aSKonstantin Komarov log->file_data_bits = sizeof(u64) * 8 - log->seq_num_bits; 3962b46acd6aSKonstantin Komarov log->seq_num_mask = (8 << log->file_data_bits) - 1; 3963b46acd6aSKonstantin Komarov log->last_lsn = le64_to_cpu(ra2->current_lsn); 3964b46acd6aSKonstantin Komarov log->seq_num = log->last_lsn >> log->file_data_bits; 3965b46acd6aSKonstantin Komarov log->ra_off = le16_to_cpu(rst_info.r_page->ra_off); 3966b46acd6aSKonstantin Komarov log->restart_size = log->sys_page_size - log->ra_off; 3967b46acd6aSKonstantin Komarov log->record_header_len = le16_to_cpu(ra2->rec_hdr_len); 3968b46acd6aSKonstantin Komarov log->ra_size = le16_to_cpu(ra2->ra_len); 3969b46acd6aSKonstantin Komarov log->data_off = le16_to_cpu(ra2->data_off); 3970b46acd6aSKonstantin Komarov log->data_size = log->page_size - log->data_off; 3971b46acd6aSKonstantin Komarov log->reserved = log->data_size - log->record_header_len; 3972b46acd6aSKonstantin Komarov 3973b46acd6aSKonstantin Komarov vbo = lsn_to_vbo(log, log->last_lsn); 3974b46acd6aSKonstantin Komarov 3975b46acd6aSKonstantin Komarov if (vbo < log->first_page) { 3976*e8b8e97fSKari Argillander /* This is a pseudo lsn. */ 3977b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_NO_LAST_LSN; 3978b46acd6aSKonstantin Komarov log->next_page = log->first_page; 3979b46acd6aSKonstantin Komarov goto find_oldest; 3980b46acd6aSKonstantin Komarov } 3981b46acd6aSKonstantin Komarov 3982*e8b8e97fSKari Argillander /* Find the end of this log record. */ 3983b46acd6aSKonstantin Komarov off = final_log_off(log, log->last_lsn, 3984b46acd6aSKonstantin Komarov le32_to_cpu(ra2->last_lsn_data_len)); 3985b46acd6aSKonstantin Komarov 3986*e8b8e97fSKari Argillander /* If we wrapped the file then increment the sequence number. */ 3987b46acd6aSKonstantin Komarov if (off <= vbo) { 3988b46acd6aSKonstantin Komarov log->seq_num += 1; 3989b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED; 3990b46acd6aSKonstantin Komarov } 3991b46acd6aSKonstantin Komarov 3992*e8b8e97fSKari Argillander /* Now compute the next log page to use. */ 3993b46acd6aSKonstantin Komarov vbo &= ~log->sys_page_mask; 3994b46acd6aSKonstantin Komarov tail = log->page_size - (off & log->page_mask) - 1; 3995b46acd6aSKonstantin Komarov 3996*e8b8e97fSKari Argillander /* 3997*e8b8e97fSKari Argillander *If we can fit another log record on the page, 3998*e8b8e97fSKari Argillander * move back a page the log file. 3999*e8b8e97fSKari Argillander */ 4000b46acd6aSKonstantin Komarov if (tail >= log->record_header_len) { 4001b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_REUSE_TAIL; 4002b46acd6aSKonstantin Komarov log->next_page = vbo; 4003b46acd6aSKonstantin Komarov } else { 4004b46acd6aSKonstantin Komarov log->next_page = next_page_off(log, vbo); 4005b46acd6aSKonstantin Komarov } 4006b46acd6aSKonstantin Komarov 4007b46acd6aSKonstantin Komarov find_oldest: 4008*e8b8e97fSKari Argillander /* 4009*e8b8e97fSKari Argillander * Find the oldest client lsn. Use the last 4010*e8b8e97fSKari Argillander * flushed lsn as a starting point. 4011*e8b8e97fSKari Argillander */ 4012b46acd6aSKonstantin Komarov log->oldest_lsn = log->last_lsn; 4013b46acd6aSKonstantin Komarov oldest_client_lsn(Add2Ptr(ra2, le16_to_cpu(ra2->client_off)), 4014b46acd6aSKonstantin Komarov ra2->client_idx[1], &log->oldest_lsn); 4015b46acd6aSKonstantin Komarov log->oldest_lsn_off = lsn_to_vbo(log, log->oldest_lsn); 4016b46acd6aSKonstantin Komarov 4017b46acd6aSKonstantin Komarov if (log->oldest_lsn_off < log->first_page) 4018b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_NO_OLDEST_LSN; 4019b46acd6aSKonstantin Komarov 4020b46acd6aSKonstantin Komarov if (!(ra2->flags & RESTART_SINGLE_PAGE_IO)) 4021b46acd6aSKonstantin Komarov log->l_flags |= NTFSLOG_WRAPPED | NTFSLOG_MULTIPLE_PAGE_IO; 4022b46acd6aSKonstantin Komarov 4023b46acd6aSKonstantin Komarov log->current_openlog_count = le32_to_cpu(ra2->open_log_count); 4024b46acd6aSKonstantin Komarov log->total_avail_pages = log->l_size - log->first_page; 4025b46acd6aSKonstantin Komarov log->total_avail = log->total_avail_pages >> log->page_bits; 4026b46acd6aSKonstantin Komarov log->max_current_avail = log->total_avail * log->reserved; 4027b46acd6aSKonstantin Komarov log->total_avail = log->total_avail * log->data_size; 4028b46acd6aSKonstantin Komarov 4029b46acd6aSKonstantin Komarov log->current_avail = current_log_avail(log); 4030b46acd6aSKonstantin Komarov 4031195c52bdSKari Argillander ra = kzalloc(log->restart_size, GFP_NOFS); 4032b46acd6aSKonstantin Komarov if (!ra) { 4033b46acd6aSKonstantin Komarov err = -ENOMEM; 4034b46acd6aSKonstantin Komarov goto out; 4035b46acd6aSKonstantin Komarov } 4036b46acd6aSKonstantin Komarov log->ra = ra; 4037b46acd6aSKonstantin Komarov 4038b46acd6aSKonstantin Komarov t16 = le16_to_cpu(ra2->client_off); 4039b46acd6aSKonstantin Komarov if (t16 == offsetof(struct RESTART_AREA, clients)) { 4040b46acd6aSKonstantin Komarov memcpy(ra, ra2, log->ra_size); 4041b46acd6aSKonstantin Komarov } else { 4042b46acd6aSKonstantin Komarov memcpy(ra, ra2, offsetof(struct RESTART_AREA, clients)); 4043b46acd6aSKonstantin Komarov memcpy(ra->clients, Add2Ptr(ra2, t16), 4044b46acd6aSKonstantin Komarov le16_to_cpu(ra2->ra_len) - t16); 4045b46acd6aSKonstantin Komarov 4046b46acd6aSKonstantin Komarov log->current_openlog_count = get_random_int(); 4047b46acd6aSKonstantin Komarov ra->open_log_count = cpu_to_le32(log->current_openlog_count); 4048b46acd6aSKonstantin Komarov log->ra_size = offsetof(struct RESTART_AREA, clients) + 4049b46acd6aSKonstantin Komarov sizeof(struct CLIENT_REC); 4050b46acd6aSKonstantin Komarov ra->client_off = 4051b46acd6aSKonstantin Komarov cpu_to_le16(offsetof(struct RESTART_AREA, clients)); 4052b46acd6aSKonstantin Komarov ra->ra_len = cpu_to_le16(log->ra_size); 4053b46acd6aSKonstantin Komarov } 4054b46acd6aSKonstantin Komarov 4055b46acd6aSKonstantin Komarov le32_add_cpu(&ra->open_log_count, 1); 4056b46acd6aSKonstantin Komarov 4057*e8b8e97fSKari Argillander /* Now we need to walk through looking for the last lsn. */ 4058b46acd6aSKonstantin Komarov err = last_log_lsn(log); 4059b46acd6aSKonstantin Komarov if (err) 4060b46acd6aSKonstantin Komarov goto out; 4061b46acd6aSKonstantin Komarov 4062b46acd6aSKonstantin Komarov log->current_avail = current_log_avail(log); 4063b46acd6aSKonstantin Komarov 4064*e8b8e97fSKari Argillander /* Remember which restart area to write first. */ 4065b46acd6aSKonstantin Komarov log->init_ra = rst_info.vbo; 4066b46acd6aSKonstantin Komarov 4067b46acd6aSKonstantin Komarov process_log: 4068*e8b8e97fSKari Argillander /* 1.0, 1.1, 2.0 log->major_ver/minor_ver - short values. */ 4069b46acd6aSKonstantin Komarov switch ((log->major_ver << 16) + log->minor_ver) { 4070b46acd6aSKonstantin Komarov case 0x10000: 4071b46acd6aSKonstantin Komarov case 0x10001: 4072b46acd6aSKonstantin Komarov case 0x20000: 4073b46acd6aSKonstantin Komarov break; 4074b46acd6aSKonstantin Komarov default: 4075b46acd6aSKonstantin Komarov ntfs_warn(sbi->sb, "\x24LogFile version %d.%d is not supported", 4076b46acd6aSKonstantin Komarov log->major_ver, log->minor_ver); 4077b46acd6aSKonstantin Komarov err = -EOPNOTSUPP; 4078b46acd6aSKonstantin Komarov log->set_dirty = true; 4079b46acd6aSKonstantin Komarov goto out; 4080b46acd6aSKonstantin Komarov } 4081b46acd6aSKonstantin Komarov 4082*e8b8e97fSKari Argillander /* One client "NTFS" per logfile. */ 4083b46acd6aSKonstantin Komarov ca = Add2Ptr(ra, le16_to_cpu(ra->client_off)); 4084b46acd6aSKonstantin Komarov 4085b46acd6aSKonstantin Komarov for (client = ra->client_idx[1];; client = cr->next_client) { 4086b46acd6aSKonstantin Komarov if (client == LFS_NO_CLIENT_LE) { 4087*e8b8e97fSKari Argillander /* Insert "NTFS" client LogFile. */ 4088b46acd6aSKonstantin Komarov client = ra->client_idx[0]; 4089b46acd6aSKonstantin Komarov if (client == LFS_NO_CLIENT_LE) 4090b46acd6aSKonstantin Komarov return -EINVAL; 4091b46acd6aSKonstantin Komarov 4092b46acd6aSKonstantin Komarov t16 = le16_to_cpu(client); 4093b46acd6aSKonstantin Komarov cr = ca + t16; 4094b46acd6aSKonstantin Komarov 4095b46acd6aSKonstantin Komarov remove_client(ca, cr, &ra->client_idx[0]); 4096b46acd6aSKonstantin Komarov 4097b46acd6aSKonstantin Komarov cr->restart_lsn = 0; 4098b46acd6aSKonstantin Komarov cr->oldest_lsn = cpu_to_le64(log->oldest_lsn); 4099b46acd6aSKonstantin Komarov cr->name_bytes = cpu_to_le32(8); 4100b46acd6aSKonstantin Komarov cr->name[0] = cpu_to_le16('N'); 4101b46acd6aSKonstantin Komarov cr->name[1] = cpu_to_le16('T'); 4102b46acd6aSKonstantin Komarov cr->name[2] = cpu_to_le16('F'); 4103b46acd6aSKonstantin Komarov cr->name[3] = cpu_to_le16('S'); 4104b46acd6aSKonstantin Komarov 4105b46acd6aSKonstantin Komarov add_client(ca, t16, &ra->client_idx[1]); 4106b46acd6aSKonstantin Komarov break; 4107b46acd6aSKonstantin Komarov } 4108b46acd6aSKonstantin Komarov 4109b46acd6aSKonstantin Komarov cr = ca + le16_to_cpu(client); 4110b46acd6aSKonstantin Komarov 4111b46acd6aSKonstantin Komarov if (cpu_to_le32(8) == cr->name_bytes && 4112b46acd6aSKonstantin Komarov cpu_to_le16('N') == cr->name[0] && 4113b46acd6aSKonstantin Komarov cpu_to_le16('T') == cr->name[1] && 4114b46acd6aSKonstantin Komarov cpu_to_le16('F') == cr->name[2] && 4115b46acd6aSKonstantin Komarov cpu_to_le16('S') == cr->name[3]) 4116b46acd6aSKonstantin Komarov break; 4117b46acd6aSKonstantin Komarov } 4118b46acd6aSKonstantin Komarov 4119*e8b8e97fSKari Argillander /* Update the client handle with the client block information. */ 4120b46acd6aSKonstantin Komarov log->client_id.seq_num = cr->seq_num; 4121b46acd6aSKonstantin Komarov log->client_id.client_idx = client; 4122b46acd6aSKonstantin Komarov 4123b46acd6aSKonstantin Komarov err = read_rst_area(log, &rst, &ra_lsn); 4124b46acd6aSKonstantin Komarov if (err) 4125b46acd6aSKonstantin Komarov goto out; 4126b46acd6aSKonstantin Komarov 4127b46acd6aSKonstantin Komarov if (!rst) 4128b46acd6aSKonstantin Komarov goto out; 4129b46acd6aSKonstantin Komarov 4130b46acd6aSKonstantin Komarov bytes_per_attr_entry = !rst->major_ver ? 0x2C : 0x28; 4131b46acd6aSKonstantin Komarov 4132b46acd6aSKonstantin Komarov checkpt_lsn = le64_to_cpu(rst->check_point_start); 4133b46acd6aSKonstantin Komarov if (!checkpt_lsn) 4134b46acd6aSKonstantin Komarov checkpt_lsn = ra_lsn; 4135b46acd6aSKonstantin Komarov 4136*e8b8e97fSKari Argillander /* Allocate and Read the Transaction Table. */ 4137b46acd6aSKonstantin Komarov if (!rst->transact_table_len) 4138b46acd6aSKonstantin Komarov goto check_dirty_page_table; 4139b46acd6aSKonstantin Komarov 4140b46acd6aSKonstantin Komarov t64 = le64_to_cpu(rst->transact_table_lsn); 4141b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, t64, lcb_ctx_prev, &lcb); 4142b46acd6aSKonstantin Komarov if (err) 4143b46acd6aSKonstantin Komarov goto out; 4144b46acd6aSKonstantin Komarov 4145b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4146b46acd6aSKonstantin Komarov frh = lcb->lrh; 4147b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4148b46acd6aSKonstantin Komarov 4149b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, le32_to_cpu(frh->transact_id), 4150b46acd6aSKonstantin Komarov bytes_per_attr_entry)) { 4151b46acd6aSKonstantin Komarov err = -EINVAL; 4152b46acd6aSKonstantin Komarov goto out; 4153b46acd6aSKonstantin Komarov } 4154b46acd6aSKonstantin Komarov 4155b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->redo_off); 4156b46acd6aSKonstantin Komarov 4157b46acd6aSKonstantin Komarov rt = Add2Ptr(lrh, t16); 4158b46acd6aSKonstantin Komarov t32 = rec_len - t16; 4159b46acd6aSKonstantin Komarov 4160*e8b8e97fSKari Argillander /* Now check that this is a valid restart table. */ 4161b46acd6aSKonstantin Komarov if (!check_rstbl(rt, t32)) { 4162b46acd6aSKonstantin Komarov err = -EINVAL; 4163b46acd6aSKonstantin Komarov goto out; 4164b46acd6aSKonstantin Komarov } 4165b46acd6aSKonstantin Komarov 4166195c52bdSKari Argillander trtbl = kmemdup(rt, t32, GFP_NOFS); 4167b46acd6aSKonstantin Komarov if (!trtbl) { 4168b46acd6aSKonstantin Komarov err = -ENOMEM; 4169b46acd6aSKonstantin Komarov goto out; 4170b46acd6aSKonstantin Komarov } 4171b46acd6aSKonstantin Komarov 4172b46acd6aSKonstantin Komarov lcb_put(lcb); 4173b46acd6aSKonstantin Komarov lcb = NULL; 4174b46acd6aSKonstantin Komarov 4175b46acd6aSKonstantin Komarov check_dirty_page_table: 4176*e8b8e97fSKari Argillander /* The next record back should be the Dirty Pages Table. */ 4177b46acd6aSKonstantin Komarov if (!rst->dirty_pages_len) 4178b46acd6aSKonstantin Komarov goto check_attribute_names; 4179b46acd6aSKonstantin Komarov 4180b46acd6aSKonstantin Komarov t64 = le64_to_cpu(rst->dirty_pages_table_lsn); 4181b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, t64, lcb_ctx_prev, &lcb); 4182b46acd6aSKonstantin Komarov if (err) 4183b46acd6aSKonstantin Komarov goto out; 4184b46acd6aSKonstantin Komarov 4185b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4186b46acd6aSKonstantin Komarov frh = lcb->lrh; 4187b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4188b46acd6aSKonstantin Komarov 4189b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, le32_to_cpu(frh->transact_id), 4190b46acd6aSKonstantin Komarov bytes_per_attr_entry)) { 4191b46acd6aSKonstantin Komarov err = -EINVAL; 4192b46acd6aSKonstantin Komarov goto out; 4193b46acd6aSKonstantin Komarov } 4194b46acd6aSKonstantin Komarov 4195b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->redo_off); 4196b46acd6aSKonstantin Komarov 4197b46acd6aSKonstantin Komarov rt = Add2Ptr(lrh, t16); 4198b46acd6aSKonstantin Komarov t32 = rec_len - t16; 4199b46acd6aSKonstantin Komarov 4200*e8b8e97fSKari Argillander /* Now check that this is a valid restart table. */ 4201b46acd6aSKonstantin Komarov if (!check_rstbl(rt, t32)) { 4202b46acd6aSKonstantin Komarov err = -EINVAL; 4203b46acd6aSKonstantin Komarov goto out; 4204b46acd6aSKonstantin Komarov } 4205b46acd6aSKonstantin Komarov 4206195c52bdSKari Argillander dptbl = kmemdup(rt, t32, GFP_NOFS); 4207b46acd6aSKonstantin Komarov if (!dptbl) { 4208b46acd6aSKonstantin Komarov err = -ENOMEM; 4209b46acd6aSKonstantin Komarov goto out; 4210b46acd6aSKonstantin Komarov } 4211b46acd6aSKonstantin Komarov 4212*e8b8e97fSKari Argillander /* Convert Ra version '0' into version '1'. */ 4213b46acd6aSKonstantin Komarov if (rst->major_ver) 4214b46acd6aSKonstantin Komarov goto end_conv_1; 4215b46acd6aSKonstantin Komarov 4216b46acd6aSKonstantin Komarov dp = NULL; 4217b46acd6aSKonstantin Komarov while ((dp = enum_rstbl(dptbl, dp))) { 4218b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY_32 *dp0 = (struct DIR_PAGE_ENTRY_32 *)dp; 4219*e8b8e97fSKari Argillander // NOTE: Danger. Check for of boundary. 4220b46acd6aSKonstantin Komarov memmove(&dp->vcn, &dp0->vcn_low, 4221b46acd6aSKonstantin Komarov 2 * sizeof(u64) + 4222b46acd6aSKonstantin Komarov le32_to_cpu(dp->lcns_follow) * sizeof(u64)); 4223b46acd6aSKonstantin Komarov } 4224b46acd6aSKonstantin Komarov 4225b46acd6aSKonstantin Komarov end_conv_1: 4226b46acd6aSKonstantin Komarov lcb_put(lcb); 4227b46acd6aSKonstantin Komarov lcb = NULL; 4228b46acd6aSKonstantin Komarov 4229*e8b8e97fSKari Argillander /* 4230*e8b8e97fSKari Argillander * Go through the table and remove the duplicates, 4231*e8b8e97fSKari Argillander * remembering the oldest lsn values. 4232*e8b8e97fSKari Argillander */ 4233b46acd6aSKonstantin Komarov if (sbi->cluster_size <= log->page_size) 4234b46acd6aSKonstantin Komarov goto trace_dp_table; 4235b46acd6aSKonstantin Komarov 4236b46acd6aSKonstantin Komarov dp = NULL; 4237b46acd6aSKonstantin Komarov while ((dp = enum_rstbl(dptbl, dp))) { 4238b46acd6aSKonstantin Komarov struct DIR_PAGE_ENTRY *next = dp; 4239b46acd6aSKonstantin Komarov 4240b46acd6aSKonstantin Komarov while ((next = enum_rstbl(dptbl, next))) { 4241b46acd6aSKonstantin Komarov if (next->target_attr == dp->target_attr && 4242b46acd6aSKonstantin Komarov next->vcn == dp->vcn) { 4243b46acd6aSKonstantin Komarov if (le64_to_cpu(next->oldest_lsn) < 4244b46acd6aSKonstantin Komarov le64_to_cpu(dp->oldest_lsn)) { 4245b46acd6aSKonstantin Komarov dp->oldest_lsn = next->oldest_lsn; 4246b46acd6aSKonstantin Komarov } 4247b46acd6aSKonstantin Komarov 4248b46acd6aSKonstantin Komarov free_rsttbl_idx(dptbl, PtrOffset(dptbl, next)); 4249b46acd6aSKonstantin Komarov } 4250b46acd6aSKonstantin Komarov } 4251b46acd6aSKonstantin Komarov } 4252b46acd6aSKonstantin Komarov trace_dp_table: 4253b46acd6aSKonstantin Komarov check_attribute_names: 4254*e8b8e97fSKari Argillander /* The next record should be the Attribute Names. */ 4255b46acd6aSKonstantin Komarov if (!rst->attr_names_len) 4256b46acd6aSKonstantin Komarov goto check_attr_table; 4257b46acd6aSKonstantin Komarov 4258b46acd6aSKonstantin Komarov t64 = le64_to_cpu(rst->attr_names_lsn); 4259b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, t64, lcb_ctx_prev, &lcb); 4260b46acd6aSKonstantin Komarov if (err) 4261b46acd6aSKonstantin Komarov goto out; 4262b46acd6aSKonstantin Komarov 4263b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4264b46acd6aSKonstantin Komarov frh = lcb->lrh; 4265b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4266b46acd6aSKonstantin Komarov 4267b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, le32_to_cpu(frh->transact_id), 4268b46acd6aSKonstantin Komarov bytes_per_attr_entry)) { 4269b46acd6aSKonstantin Komarov err = -EINVAL; 4270b46acd6aSKonstantin Komarov goto out; 4271b46acd6aSKonstantin Komarov } 4272b46acd6aSKonstantin Komarov 4273b46acd6aSKonstantin Komarov t32 = lrh_length(lrh); 4274b46acd6aSKonstantin Komarov rec_len -= t32; 4275b46acd6aSKonstantin Komarov 4276195c52bdSKari Argillander attr_names = kmemdup(Add2Ptr(lrh, t32), rec_len, GFP_NOFS); 4277b46acd6aSKonstantin Komarov 4278b46acd6aSKonstantin Komarov lcb_put(lcb); 4279b46acd6aSKonstantin Komarov lcb = NULL; 4280b46acd6aSKonstantin Komarov 4281b46acd6aSKonstantin Komarov check_attr_table: 4282*e8b8e97fSKari Argillander /* The next record should be the attribute Table. */ 4283b46acd6aSKonstantin Komarov if (!rst->open_attr_len) 4284b46acd6aSKonstantin Komarov goto check_attribute_names2; 4285b46acd6aSKonstantin Komarov 4286b46acd6aSKonstantin Komarov t64 = le64_to_cpu(rst->open_attr_table_lsn); 4287b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, t64, lcb_ctx_prev, &lcb); 4288b46acd6aSKonstantin Komarov if (err) 4289b46acd6aSKonstantin Komarov goto out; 4290b46acd6aSKonstantin Komarov 4291b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4292b46acd6aSKonstantin Komarov frh = lcb->lrh; 4293b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4294b46acd6aSKonstantin Komarov 4295b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, le32_to_cpu(frh->transact_id), 4296b46acd6aSKonstantin Komarov bytes_per_attr_entry)) { 4297b46acd6aSKonstantin Komarov err = -EINVAL; 4298b46acd6aSKonstantin Komarov goto out; 4299b46acd6aSKonstantin Komarov } 4300b46acd6aSKonstantin Komarov 4301b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->redo_off); 4302b46acd6aSKonstantin Komarov 4303b46acd6aSKonstantin Komarov rt = Add2Ptr(lrh, t16); 4304b46acd6aSKonstantin Komarov t32 = rec_len - t16; 4305b46acd6aSKonstantin Komarov 4306b46acd6aSKonstantin Komarov if (!check_rstbl(rt, t32)) { 4307b46acd6aSKonstantin Komarov err = -EINVAL; 4308b46acd6aSKonstantin Komarov goto out; 4309b46acd6aSKonstantin Komarov } 4310b46acd6aSKonstantin Komarov 4311195c52bdSKari Argillander oatbl = kmemdup(rt, t32, GFP_NOFS); 4312b46acd6aSKonstantin Komarov if (!oatbl) { 4313b46acd6aSKonstantin Komarov err = -ENOMEM; 4314b46acd6aSKonstantin Komarov goto out; 4315b46acd6aSKonstantin Komarov } 4316b46acd6aSKonstantin Komarov 4317b46acd6aSKonstantin Komarov log->open_attr_tbl = oatbl; 4318b46acd6aSKonstantin Komarov 4319*e8b8e97fSKari Argillander /* Clear all of the Attr pointers. */ 4320b46acd6aSKonstantin Komarov oe = NULL; 4321b46acd6aSKonstantin Komarov while ((oe = enum_rstbl(oatbl, oe))) { 4322b46acd6aSKonstantin Komarov if (!rst->major_ver) { 4323b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY_32 oe0; 4324b46acd6aSKonstantin Komarov 4325*e8b8e97fSKari Argillander /* Really 'oe' points to OPEN_ATTR_ENRTY_32. */ 4326b46acd6aSKonstantin Komarov memcpy(&oe0, oe, SIZEOF_OPENATTRIBUTEENTRY0); 4327b46acd6aSKonstantin Komarov 4328b46acd6aSKonstantin Komarov oe->bytes_per_index = oe0.bytes_per_index; 4329b46acd6aSKonstantin Komarov oe->type = oe0.type; 4330b46acd6aSKonstantin Komarov oe->is_dirty_pages = oe0.is_dirty_pages; 4331b46acd6aSKonstantin Komarov oe->name_len = 0; 4332b46acd6aSKonstantin Komarov oe->ref = oe0.ref; 4333b46acd6aSKonstantin Komarov oe->open_record_lsn = oe0.open_record_lsn; 4334b46acd6aSKonstantin Komarov } 4335b46acd6aSKonstantin Komarov 4336b46acd6aSKonstantin Komarov oe->is_attr_name = 0; 4337b46acd6aSKonstantin Komarov oe->ptr = NULL; 4338b46acd6aSKonstantin Komarov } 4339b46acd6aSKonstantin Komarov 4340b46acd6aSKonstantin Komarov lcb_put(lcb); 4341b46acd6aSKonstantin Komarov lcb = NULL; 4342b46acd6aSKonstantin Komarov 4343b46acd6aSKonstantin Komarov check_attribute_names2: 4344b46acd6aSKonstantin Komarov if (!rst->attr_names_len) 4345b46acd6aSKonstantin Komarov goto trace_attribute_table; 4346b46acd6aSKonstantin Komarov 4347b46acd6aSKonstantin Komarov ane = attr_names; 4348b46acd6aSKonstantin Komarov if (!oatbl) 4349b46acd6aSKonstantin Komarov goto trace_attribute_table; 4350b46acd6aSKonstantin Komarov while (ane->off) { 4351b46acd6aSKonstantin Komarov /* TODO: Clear table on exit! */ 4352b46acd6aSKonstantin Komarov oe = Add2Ptr(oatbl, le16_to_cpu(ane->off)); 4353b46acd6aSKonstantin Komarov t16 = le16_to_cpu(ane->name_bytes); 4354b46acd6aSKonstantin Komarov oe->name_len = t16 / sizeof(short); 4355b46acd6aSKonstantin Komarov oe->ptr = ane->name; 4356b46acd6aSKonstantin Komarov oe->is_attr_name = 2; 4357b46acd6aSKonstantin Komarov ane = Add2Ptr(ane, sizeof(struct ATTR_NAME_ENTRY) + t16); 4358b46acd6aSKonstantin Komarov } 4359b46acd6aSKonstantin Komarov 4360b46acd6aSKonstantin Komarov trace_attribute_table: 4361b46acd6aSKonstantin Komarov /* 4362b46acd6aSKonstantin Komarov * If the checkpt_lsn is zero, then this is a freshly 4363*e8b8e97fSKari Argillander * formatted disk and we have no work to do. 4364b46acd6aSKonstantin Komarov */ 4365b46acd6aSKonstantin Komarov if (!checkpt_lsn) { 4366b46acd6aSKonstantin Komarov err = 0; 4367b46acd6aSKonstantin Komarov goto out; 4368b46acd6aSKonstantin Komarov } 4369b46acd6aSKonstantin Komarov 4370b46acd6aSKonstantin Komarov if (!oatbl) { 4371b46acd6aSKonstantin Komarov oatbl = init_rsttbl(bytes_per_attr_entry, 8); 4372b46acd6aSKonstantin Komarov if (!oatbl) { 4373b46acd6aSKonstantin Komarov err = -ENOMEM; 4374b46acd6aSKonstantin Komarov goto out; 4375b46acd6aSKonstantin Komarov } 4376b46acd6aSKonstantin Komarov } 4377b46acd6aSKonstantin Komarov 4378b46acd6aSKonstantin Komarov log->open_attr_tbl = oatbl; 4379b46acd6aSKonstantin Komarov 4380b46acd6aSKonstantin Komarov /* Start the analysis pass from the Checkpoint lsn. */ 4381b46acd6aSKonstantin Komarov rec_lsn = checkpt_lsn; 4382b46acd6aSKonstantin Komarov 4383*e8b8e97fSKari Argillander /* Read the first lsn. */ 4384b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, checkpt_lsn, lcb_ctx_next, &lcb); 4385b46acd6aSKonstantin Komarov if (err) 4386b46acd6aSKonstantin Komarov goto out; 4387b46acd6aSKonstantin Komarov 4388*e8b8e97fSKari Argillander /* Loop to read all subsequent records to the end of the log file. */ 4389b46acd6aSKonstantin Komarov next_log_record_analyze: 4390b46acd6aSKonstantin Komarov err = read_next_log_rec(log, lcb, &rec_lsn); 4391b46acd6aSKonstantin Komarov if (err) 4392b46acd6aSKonstantin Komarov goto out; 4393b46acd6aSKonstantin Komarov 4394b46acd6aSKonstantin Komarov if (!rec_lsn) 4395b46acd6aSKonstantin Komarov goto end_log_records_enumerate; 4396b46acd6aSKonstantin Komarov 4397b46acd6aSKonstantin Komarov frh = lcb->lrh; 4398b46acd6aSKonstantin Komarov transact_id = le32_to_cpu(frh->transact_id); 4399b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4400b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4401b46acd6aSKonstantin Komarov 4402b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, transact_id, bytes_per_attr_entry)) { 4403b46acd6aSKonstantin Komarov err = -EINVAL; 4404b46acd6aSKonstantin Komarov goto out; 4405b46acd6aSKonstantin Komarov } 4406b46acd6aSKonstantin Komarov 4407b46acd6aSKonstantin Komarov /* 4408b46acd6aSKonstantin Komarov * The first lsn after the previous lsn remembered 4409*e8b8e97fSKari Argillander * the checkpoint is the first candidate for the rlsn. 4410b46acd6aSKonstantin Komarov */ 4411b46acd6aSKonstantin Komarov if (!rlsn) 4412b46acd6aSKonstantin Komarov rlsn = rec_lsn; 4413b46acd6aSKonstantin Komarov 4414b46acd6aSKonstantin Komarov if (LfsClientRecord != frh->record_type) 4415b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4416b46acd6aSKonstantin Komarov 4417b46acd6aSKonstantin Komarov /* 4418*e8b8e97fSKari Argillander * Now update the Transaction Table for this transaction. If there 4419*e8b8e97fSKari Argillander * is no entry present or it is unallocated we allocate the entry. 4420b46acd6aSKonstantin Komarov */ 4421b46acd6aSKonstantin Komarov if (!trtbl) { 4422b46acd6aSKonstantin Komarov trtbl = init_rsttbl(sizeof(struct TRANSACTION_ENTRY), 4423b46acd6aSKonstantin Komarov INITIAL_NUMBER_TRANSACTIONS); 4424b46acd6aSKonstantin Komarov if (!trtbl) { 4425b46acd6aSKonstantin Komarov err = -ENOMEM; 4426b46acd6aSKonstantin Komarov goto out; 4427b46acd6aSKonstantin Komarov } 4428b46acd6aSKonstantin Komarov } 4429b46acd6aSKonstantin Komarov 4430b46acd6aSKonstantin Komarov tr = Add2Ptr(trtbl, transact_id); 4431b46acd6aSKonstantin Komarov 4432b46acd6aSKonstantin Komarov if (transact_id >= bytes_per_rt(trtbl) || 4433b46acd6aSKonstantin Komarov tr->next != RESTART_ENTRY_ALLOCATED_LE) { 4434b46acd6aSKonstantin Komarov tr = alloc_rsttbl_from_idx(&trtbl, transact_id); 4435b46acd6aSKonstantin Komarov if (!tr) { 4436b46acd6aSKonstantin Komarov err = -ENOMEM; 4437b46acd6aSKonstantin Komarov goto out; 4438b46acd6aSKonstantin Komarov } 4439b46acd6aSKonstantin Komarov tr->transact_state = TransactionActive; 4440b46acd6aSKonstantin Komarov tr->first_lsn = cpu_to_le64(rec_lsn); 4441b46acd6aSKonstantin Komarov } 4442b46acd6aSKonstantin Komarov 4443b46acd6aSKonstantin Komarov tr->prev_lsn = tr->undo_next_lsn = cpu_to_le64(rec_lsn); 4444b46acd6aSKonstantin Komarov 4445b46acd6aSKonstantin Komarov /* 4446b46acd6aSKonstantin Komarov * If this is a compensation log record, then change 4447*e8b8e97fSKari Argillander * the undo_next_lsn to be the undo_next_lsn of this record. 4448b46acd6aSKonstantin Komarov */ 4449b46acd6aSKonstantin Komarov if (lrh->undo_op == cpu_to_le16(CompensationLogRecord)) 4450b46acd6aSKonstantin Komarov tr->undo_next_lsn = frh->client_undo_next_lsn; 4451b46acd6aSKonstantin Komarov 4452*e8b8e97fSKari Argillander /* Dispatch to handle log record depending on type. */ 4453b46acd6aSKonstantin Komarov switch (le16_to_cpu(lrh->redo_op)) { 4454b46acd6aSKonstantin Komarov case InitializeFileRecordSegment: 4455b46acd6aSKonstantin Komarov case DeallocateFileRecordSegment: 4456b46acd6aSKonstantin Komarov case WriteEndOfFileRecordSegment: 4457b46acd6aSKonstantin Komarov case CreateAttribute: 4458b46acd6aSKonstantin Komarov case DeleteAttribute: 4459b46acd6aSKonstantin Komarov case UpdateResidentValue: 4460b46acd6aSKonstantin Komarov case UpdateNonresidentValue: 4461b46acd6aSKonstantin Komarov case UpdateMappingPairs: 4462b46acd6aSKonstantin Komarov case SetNewAttributeSizes: 4463b46acd6aSKonstantin Komarov case AddIndexEntryRoot: 4464b46acd6aSKonstantin Komarov case DeleteIndexEntryRoot: 4465b46acd6aSKonstantin Komarov case AddIndexEntryAllocation: 4466b46acd6aSKonstantin Komarov case DeleteIndexEntryAllocation: 4467b46acd6aSKonstantin Komarov case WriteEndOfIndexBuffer: 4468b46acd6aSKonstantin Komarov case SetIndexEntryVcnRoot: 4469b46acd6aSKonstantin Komarov case SetIndexEntryVcnAllocation: 4470b46acd6aSKonstantin Komarov case UpdateFileNameRoot: 4471b46acd6aSKonstantin Komarov case UpdateFileNameAllocation: 4472b46acd6aSKonstantin Komarov case SetBitsInNonresidentBitMap: 4473b46acd6aSKonstantin Komarov case ClearBitsInNonresidentBitMap: 4474b46acd6aSKonstantin Komarov case UpdateRecordDataRoot: 4475b46acd6aSKonstantin Komarov case UpdateRecordDataAllocation: 4476b46acd6aSKonstantin Komarov case ZeroEndOfFileRecord: 4477b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->target_attr); 4478b46acd6aSKonstantin Komarov t64 = le64_to_cpu(lrh->target_vcn); 4479b46acd6aSKonstantin Komarov dp = find_dp(dptbl, t16, t64); 4480b46acd6aSKonstantin Komarov 4481b46acd6aSKonstantin Komarov if (dp) 4482b46acd6aSKonstantin Komarov goto copy_lcns; 4483b46acd6aSKonstantin Komarov 4484b46acd6aSKonstantin Komarov /* 4485b46acd6aSKonstantin Komarov * Calculate the number of clusters per page the system 4486*e8b8e97fSKari Argillander * which wrote the checkpoint, possibly creating the table. 4487b46acd6aSKonstantin Komarov */ 4488b46acd6aSKonstantin Komarov if (dptbl) { 4489b46acd6aSKonstantin Komarov t32 = (le16_to_cpu(dptbl->size) - 4490b46acd6aSKonstantin Komarov sizeof(struct DIR_PAGE_ENTRY)) / 4491b46acd6aSKonstantin Komarov sizeof(u64); 4492b46acd6aSKonstantin Komarov } else { 4493b46acd6aSKonstantin Komarov t32 = log->clst_per_page; 4494195c52bdSKari Argillander kfree(dptbl); 4495b46acd6aSKonstantin Komarov dptbl = init_rsttbl(struct_size(dp, page_lcns, t32), 4496b46acd6aSKonstantin Komarov 32); 4497b46acd6aSKonstantin Komarov if (!dptbl) { 4498b46acd6aSKonstantin Komarov err = -ENOMEM; 4499b46acd6aSKonstantin Komarov goto out; 4500b46acd6aSKonstantin Komarov } 4501b46acd6aSKonstantin Komarov } 4502b46acd6aSKonstantin Komarov 4503b46acd6aSKonstantin Komarov dp = alloc_rsttbl_idx(&dptbl); 4504a1b04d38SDan Carpenter if (!dp) { 4505a1b04d38SDan Carpenter err = -ENOMEM; 4506a1b04d38SDan Carpenter goto out; 4507a1b04d38SDan Carpenter } 4508b46acd6aSKonstantin Komarov dp->target_attr = cpu_to_le32(t16); 4509b46acd6aSKonstantin Komarov dp->transfer_len = cpu_to_le32(t32 << sbi->cluster_bits); 4510b46acd6aSKonstantin Komarov dp->lcns_follow = cpu_to_le32(t32); 4511b46acd6aSKonstantin Komarov dp->vcn = cpu_to_le64(t64 & ~((u64)t32 - 1)); 4512b46acd6aSKonstantin Komarov dp->oldest_lsn = cpu_to_le64(rec_lsn); 4513b46acd6aSKonstantin Komarov 4514b46acd6aSKonstantin Komarov copy_lcns: 4515b46acd6aSKonstantin Komarov /* 4516*e8b8e97fSKari Argillander * Copy the Lcns from the log record into the Dirty Page Entry. 4517*e8b8e97fSKari Argillander * TODO: For different page size support, must somehow make 4518*e8b8e97fSKari Argillander * whole routine a loop, case Lcns do not fit below. 4519b46acd6aSKonstantin Komarov */ 4520b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->lcns_follow); 4521b46acd6aSKonstantin Komarov for (i = 0; i < t16; i++) { 4522b46acd6aSKonstantin Komarov size_t j = (size_t)(le64_to_cpu(lrh->target_vcn) - 4523b46acd6aSKonstantin Komarov le64_to_cpu(dp->vcn)); 4524b46acd6aSKonstantin Komarov dp->page_lcns[j + i] = lrh->page_lcns[i]; 4525b46acd6aSKonstantin Komarov } 4526b46acd6aSKonstantin Komarov 4527b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4528b46acd6aSKonstantin Komarov 4529b46acd6aSKonstantin Komarov case DeleteDirtyClusters: { 4530b46acd6aSKonstantin Komarov u32 range_count = 4531b46acd6aSKonstantin Komarov le16_to_cpu(lrh->redo_len) / sizeof(struct LCN_RANGE); 4532b46acd6aSKonstantin Komarov const struct LCN_RANGE *r = 4533b46acd6aSKonstantin Komarov Add2Ptr(lrh, le16_to_cpu(lrh->redo_off)); 4534b46acd6aSKonstantin Komarov 4535*e8b8e97fSKari Argillander /* Loop through all of the Lcn ranges this log record. */ 4536b46acd6aSKonstantin Komarov for (i = 0; i < range_count; i++, r++) { 4537b46acd6aSKonstantin Komarov u64 lcn0 = le64_to_cpu(r->lcn); 4538b46acd6aSKonstantin Komarov u64 lcn_e = lcn0 + le64_to_cpu(r->len) - 1; 4539b46acd6aSKonstantin Komarov 4540b46acd6aSKonstantin Komarov dp = NULL; 4541b46acd6aSKonstantin Komarov while ((dp = enum_rstbl(dptbl, dp))) { 4542b46acd6aSKonstantin Komarov u32 j; 4543b46acd6aSKonstantin Komarov 4544b46acd6aSKonstantin Komarov t32 = le32_to_cpu(dp->lcns_follow); 4545b46acd6aSKonstantin Komarov for (j = 0; j < t32; j++) { 4546b46acd6aSKonstantin Komarov t64 = le64_to_cpu(dp->page_lcns[j]); 4547b46acd6aSKonstantin Komarov if (t64 >= lcn0 && t64 <= lcn_e) 4548b46acd6aSKonstantin Komarov dp->page_lcns[j] = 0; 4549b46acd6aSKonstantin Komarov } 4550b46acd6aSKonstantin Komarov } 4551b46acd6aSKonstantin Komarov } 4552b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4553b46acd6aSKonstantin Komarov ; 4554b46acd6aSKonstantin Komarov } 4555b46acd6aSKonstantin Komarov 4556b46acd6aSKonstantin Komarov case OpenNonresidentAttribute: 4557b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->target_attr); 4558b46acd6aSKonstantin Komarov if (t16 >= bytes_per_rt(oatbl)) { 4559b46acd6aSKonstantin Komarov /* 4560b46acd6aSKonstantin Komarov * Compute how big the table needs to be. 4561*e8b8e97fSKari Argillander * Add 10 extra entries for some cushion. 4562b46acd6aSKonstantin Komarov */ 4563b46acd6aSKonstantin Komarov u32 new_e = t16 / le16_to_cpu(oatbl->size); 4564b46acd6aSKonstantin Komarov 4565b46acd6aSKonstantin Komarov new_e += 10 - le16_to_cpu(oatbl->used); 4566b46acd6aSKonstantin Komarov 4567b46acd6aSKonstantin Komarov oatbl = extend_rsttbl(oatbl, new_e, ~0u); 4568b46acd6aSKonstantin Komarov log->open_attr_tbl = oatbl; 4569b46acd6aSKonstantin Komarov if (!oatbl) { 4570b46acd6aSKonstantin Komarov err = -ENOMEM; 4571b46acd6aSKonstantin Komarov goto out; 4572b46acd6aSKonstantin Komarov } 4573b46acd6aSKonstantin Komarov } 4574b46acd6aSKonstantin Komarov 4575*e8b8e97fSKari Argillander /* Point to the entry being opened. */ 4576b46acd6aSKonstantin Komarov oe = alloc_rsttbl_from_idx(&oatbl, t16); 4577b46acd6aSKonstantin Komarov log->open_attr_tbl = oatbl; 4578b46acd6aSKonstantin Komarov if (!oe) { 4579b46acd6aSKonstantin Komarov err = -ENOMEM; 4580b46acd6aSKonstantin Komarov goto out; 4581b46acd6aSKonstantin Komarov } 4582b46acd6aSKonstantin Komarov 4583*e8b8e97fSKari Argillander /* Initialize this entry from the log record. */ 4584b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->redo_off); 4585b46acd6aSKonstantin Komarov if (!rst->major_ver) { 4586*e8b8e97fSKari Argillander /* Convert version '0' into version '1'. */ 4587b46acd6aSKonstantin Komarov struct OPEN_ATTR_ENRTY_32 *oe0 = Add2Ptr(lrh, t16); 4588b46acd6aSKonstantin Komarov 4589b46acd6aSKonstantin Komarov oe->bytes_per_index = oe0->bytes_per_index; 4590b46acd6aSKonstantin Komarov oe->type = oe0->type; 4591b46acd6aSKonstantin Komarov oe->is_dirty_pages = oe0->is_dirty_pages; 4592b46acd6aSKonstantin Komarov oe->name_len = 0; //oe0.name_len; 4593b46acd6aSKonstantin Komarov oe->ref = oe0->ref; 4594b46acd6aSKonstantin Komarov oe->open_record_lsn = oe0->open_record_lsn; 4595b46acd6aSKonstantin Komarov } else { 4596b46acd6aSKonstantin Komarov memcpy(oe, Add2Ptr(lrh, t16), bytes_per_attr_entry); 4597b46acd6aSKonstantin Komarov } 4598b46acd6aSKonstantin Komarov 4599b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->undo_len); 4600b46acd6aSKonstantin Komarov if (t16) { 4601195c52bdSKari Argillander oe->ptr = kmalloc(t16, GFP_NOFS); 4602b46acd6aSKonstantin Komarov if (!oe->ptr) { 4603b46acd6aSKonstantin Komarov err = -ENOMEM; 4604b46acd6aSKonstantin Komarov goto out; 4605b46acd6aSKonstantin Komarov } 4606b46acd6aSKonstantin Komarov oe->name_len = t16 / sizeof(short); 4607b46acd6aSKonstantin Komarov memcpy(oe->ptr, 4608b46acd6aSKonstantin Komarov Add2Ptr(lrh, le16_to_cpu(lrh->undo_off)), t16); 4609b46acd6aSKonstantin Komarov oe->is_attr_name = 1; 4610b46acd6aSKonstantin Komarov } else { 4611b46acd6aSKonstantin Komarov oe->ptr = NULL; 4612b46acd6aSKonstantin Komarov oe->is_attr_name = 0; 4613b46acd6aSKonstantin Komarov } 4614b46acd6aSKonstantin Komarov 4615b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4616b46acd6aSKonstantin Komarov 4617b46acd6aSKonstantin Komarov case HotFix: 4618b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->target_attr); 4619b46acd6aSKonstantin Komarov t64 = le64_to_cpu(lrh->target_vcn); 4620b46acd6aSKonstantin Komarov dp = find_dp(dptbl, t16, t64); 4621b46acd6aSKonstantin Komarov if (dp) { 4622b46acd6aSKonstantin Komarov size_t j = le64_to_cpu(lrh->target_vcn) - 4623b46acd6aSKonstantin Komarov le64_to_cpu(dp->vcn); 4624b46acd6aSKonstantin Komarov if (dp->page_lcns[j]) 4625b46acd6aSKonstantin Komarov dp->page_lcns[j] = lrh->page_lcns[0]; 4626b46acd6aSKonstantin Komarov } 4627b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4628b46acd6aSKonstantin Komarov 4629b46acd6aSKonstantin Komarov case EndTopLevelAction: 4630b46acd6aSKonstantin Komarov tr = Add2Ptr(trtbl, transact_id); 4631b46acd6aSKonstantin Komarov tr->prev_lsn = cpu_to_le64(rec_lsn); 4632b46acd6aSKonstantin Komarov tr->undo_next_lsn = frh->client_undo_next_lsn; 4633b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4634b46acd6aSKonstantin Komarov 4635b46acd6aSKonstantin Komarov case PrepareTransaction: 4636b46acd6aSKonstantin Komarov tr = Add2Ptr(trtbl, transact_id); 4637b46acd6aSKonstantin Komarov tr->transact_state = TransactionPrepared; 4638b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4639b46acd6aSKonstantin Komarov 4640b46acd6aSKonstantin Komarov case CommitTransaction: 4641b46acd6aSKonstantin Komarov tr = Add2Ptr(trtbl, transact_id); 4642b46acd6aSKonstantin Komarov tr->transact_state = TransactionCommitted; 4643b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4644b46acd6aSKonstantin Komarov 4645b46acd6aSKonstantin Komarov case ForgetTransaction: 4646b46acd6aSKonstantin Komarov free_rsttbl_idx(trtbl, transact_id); 4647b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4648b46acd6aSKonstantin Komarov 4649b46acd6aSKonstantin Komarov case Noop: 4650b46acd6aSKonstantin Komarov case OpenAttributeTableDump: 4651b46acd6aSKonstantin Komarov case AttributeNamesDump: 4652b46acd6aSKonstantin Komarov case DirtyPageTableDump: 4653b46acd6aSKonstantin Komarov case TransactionTableDump: 4654*e8b8e97fSKari Argillander /* The following cases require no action the Analysis Pass. */ 4655b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4656b46acd6aSKonstantin Komarov 4657b46acd6aSKonstantin Komarov default: 4658b46acd6aSKonstantin Komarov /* 4659b46acd6aSKonstantin Komarov * All codes will be explicitly handled. 4660*e8b8e97fSKari Argillander * If we see a code we do not expect, then we are trouble. 4661b46acd6aSKonstantin Komarov */ 4662b46acd6aSKonstantin Komarov goto next_log_record_analyze; 4663b46acd6aSKonstantin Komarov } 4664b46acd6aSKonstantin Komarov 4665b46acd6aSKonstantin Komarov end_log_records_enumerate: 4666b46acd6aSKonstantin Komarov lcb_put(lcb); 4667b46acd6aSKonstantin Komarov lcb = NULL; 4668b46acd6aSKonstantin Komarov 4669b46acd6aSKonstantin Komarov /* 4670b46acd6aSKonstantin Komarov * Scan the Dirty Page Table and Transaction Table for 4671*e8b8e97fSKari Argillander * the lowest lsn, and return it as the Redo lsn. 4672b46acd6aSKonstantin Komarov */ 4673b46acd6aSKonstantin Komarov dp = NULL; 4674b46acd6aSKonstantin Komarov while ((dp = enum_rstbl(dptbl, dp))) { 4675b46acd6aSKonstantin Komarov t64 = le64_to_cpu(dp->oldest_lsn); 4676b46acd6aSKonstantin Komarov if (t64 && t64 < rlsn) 4677b46acd6aSKonstantin Komarov rlsn = t64; 4678b46acd6aSKonstantin Komarov } 4679b46acd6aSKonstantin Komarov 4680b46acd6aSKonstantin Komarov tr = NULL; 4681b46acd6aSKonstantin Komarov while ((tr = enum_rstbl(trtbl, tr))) { 4682b46acd6aSKonstantin Komarov t64 = le64_to_cpu(tr->first_lsn); 4683b46acd6aSKonstantin Komarov if (t64 && t64 < rlsn) 4684b46acd6aSKonstantin Komarov rlsn = t64; 4685b46acd6aSKonstantin Komarov } 4686b46acd6aSKonstantin Komarov 4687*e8b8e97fSKari Argillander /* 4688*e8b8e97fSKari Argillander * Only proceed if the Dirty Page Table or Transaction 4689*e8b8e97fSKari Argillander * table are not empty. 4690*e8b8e97fSKari Argillander */ 4691b46acd6aSKonstantin Komarov if ((!dptbl || !dptbl->total) && (!trtbl || !trtbl->total)) 4692b46acd6aSKonstantin Komarov goto end_reply; 4693b46acd6aSKonstantin Komarov 4694b46acd6aSKonstantin Komarov sbi->flags |= NTFS_FLAGS_NEED_REPLAY; 4695b46acd6aSKonstantin Komarov if (is_ro) 4696b46acd6aSKonstantin Komarov goto out; 4697b46acd6aSKonstantin Komarov 4698*e8b8e97fSKari Argillander /* Reopen all of the attributes with dirty pages. */ 4699b46acd6aSKonstantin Komarov oe = NULL; 4700b46acd6aSKonstantin Komarov next_open_attribute: 4701b46acd6aSKonstantin Komarov 4702b46acd6aSKonstantin Komarov oe = enum_rstbl(oatbl, oe); 4703b46acd6aSKonstantin Komarov if (!oe) { 4704b46acd6aSKonstantin Komarov err = 0; 4705b46acd6aSKonstantin Komarov dp = NULL; 4706b46acd6aSKonstantin Komarov goto next_dirty_page; 4707b46acd6aSKonstantin Komarov } 4708b46acd6aSKonstantin Komarov 4709195c52bdSKari Argillander oa = kzalloc(sizeof(struct OpenAttr), GFP_NOFS); 4710b46acd6aSKonstantin Komarov if (!oa) { 4711b46acd6aSKonstantin Komarov err = -ENOMEM; 4712b46acd6aSKonstantin Komarov goto out; 4713b46acd6aSKonstantin Komarov } 4714b46acd6aSKonstantin Komarov 4715b46acd6aSKonstantin Komarov inode = ntfs_iget5(sbi->sb, &oe->ref, NULL); 4716b46acd6aSKonstantin Komarov if (IS_ERR(inode)) 4717b46acd6aSKonstantin Komarov goto fake_attr; 4718b46acd6aSKonstantin Komarov 4719b46acd6aSKonstantin Komarov if (is_bad_inode(inode)) { 4720b46acd6aSKonstantin Komarov iput(inode); 4721b46acd6aSKonstantin Komarov fake_attr: 4722b46acd6aSKonstantin Komarov if (oa->ni) { 4723b46acd6aSKonstantin Komarov iput(&oa->ni->vfs_inode); 4724b46acd6aSKonstantin Komarov oa->ni = NULL; 4725b46acd6aSKonstantin Komarov } 4726b46acd6aSKonstantin Komarov 4727b46acd6aSKonstantin Komarov attr = attr_create_nonres_log(sbi, oe->type, 0, oe->ptr, 4728b46acd6aSKonstantin Komarov oe->name_len, 0); 4729b46acd6aSKonstantin Komarov if (!attr) { 4730195c52bdSKari Argillander kfree(oa); 4731b46acd6aSKonstantin Komarov err = -ENOMEM; 4732b46acd6aSKonstantin Komarov goto out; 4733b46acd6aSKonstantin Komarov } 4734b46acd6aSKonstantin Komarov oa->attr = attr; 4735b46acd6aSKonstantin Komarov oa->run1 = &oa->run0; 4736b46acd6aSKonstantin Komarov goto final_oe; 4737b46acd6aSKonstantin Komarov } 4738b46acd6aSKonstantin Komarov 4739b46acd6aSKonstantin Komarov ni_oe = ntfs_i(inode); 4740b46acd6aSKonstantin Komarov oa->ni = ni_oe; 4741b46acd6aSKonstantin Komarov 4742b46acd6aSKonstantin Komarov attr = ni_find_attr(ni_oe, NULL, NULL, oe->type, oe->ptr, oe->name_len, 4743b46acd6aSKonstantin Komarov NULL, NULL); 4744b46acd6aSKonstantin Komarov 4745b46acd6aSKonstantin Komarov if (!attr) 4746b46acd6aSKonstantin Komarov goto fake_attr; 4747b46acd6aSKonstantin Komarov 4748b46acd6aSKonstantin Komarov t32 = le32_to_cpu(attr->size); 4749195c52bdSKari Argillander oa->attr = kmemdup(attr, t32, GFP_NOFS); 4750b46acd6aSKonstantin Komarov if (!oa->attr) 4751b46acd6aSKonstantin Komarov goto fake_attr; 4752b46acd6aSKonstantin Komarov 4753b46acd6aSKonstantin Komarov if (!S_ISDIR(inode->i_mode)) { 4754b46acd6aSKonstantin Komarov if (attr->type == ATTR_DATA && !attr->name_len) { 4755b46acd6aSKonstantin Komarov oa->run1 = &ni_oe->file.run; 4756b46acd6aSKonstantin Komarov goto final_oe; 4757b46acd6aSKonstantin Komarov } 4758b46acd6aSKonstantin Komarov } else { 4759b46acd6aSKonstantin Komarov if (attr->type == ATTR_ALLOC && 4760b46acd6aSKonstantin Komarov attr->name_len == ARRAY_SIZE(I30_NAME) && 4761b46acd6aSKonstantin Komarov !memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME))) { 4762b46acd6aSKonstantin Komarov oa->run1 = &ni_oe->dir.alloc_run; 4763b46acd6aSKonstantin Komarov goto final_oe; 4764b46acd6aSKonstantin Komarov } 4765b46acd6aSKonstantin Komarov } 4766b46acd6aSKonstantin Komarov 4767b46acd6aSKonstantin Komarov if (attr->non_res) { 4768b46acd6aSKonstantin Komarov u16 roff = le16_to_cpu(attr->nres.run_off); 4769b46acd6aSKonstantin Komarov CLST svcn = le64_to_cpu(attr->nres.svcn); 4770b46acd6aSKonstantin Komarov 4771b46acd6aSKonstantin Komarov err = run_unpack(&oa->run0, sbi, inode->i_ino, svcn, 4772b46acd6aSKonstantin Komarov le64_to_cpu(attr->nres.evcn), svcn, 4773b46acd6aSKonstantin Komarov Add2Ptr(attr, roff), t32 - roff); 4774b46acd6aSKonstantin Komarov if (err < 0) { 4775195c52bdSKari Argillander kfree(oa->attr); 4776b46acd6aSKonstantin Komarov oa->attr = NULL; 4777b46acd6aSKonstantin Komarov goto fake_attr; 4778b46acd6aSKonstantin Komarov } 4779b46acd6aSKonstantin Komarov err = 0; 4780b46acd6aSKonstantin Komarov } 4781b46acd6aSKonstantin Komarov oa->run1 = &oa->run0; 4782b46acd6aSKonstantin Komarov attr = oa->attr; 4783b46acd6aSKonstantin Komarov 4784b46acd6aSKonstantin Komarov final_oe: 4785b46acd6aSKonstantin Komarov if (oe->is_attr_name == 1) 4786195c52bdSKari Argillander kfree(oe->ptr); 4787b46acd6aSKonstantin Komarov oe->is_attr_name = 0; 4788b46acd6aSKonstantin Komarov oe->ptr = oa; 4789b46acd6aSKonstantin Komarov oe->name_len = attr->name_len; 4790b46acd6aSKonstantin Komarov 4791b46acd6aSKonstantin Komarov goto next_open_attribute; 4792b46acd6aSKonstantin Komarov 4793b46acd6aSKonstantin Komarov /* 4794*e8b8e97fSKari Argillander * Now loop through the dirty page table to extract all of the Vcn/Lcn. 4795*e8b8e97fSKari Argillander * Mapping that we have, and insert it into the appropriate run. 4796b46acd6aSKonstantin Komarov */ 4797b46acd6aSKonstantin Komarov next_dirty_page: 4798b46acd6aSKonstantin Komarov dp = enum_rstbl(dptbl, dp); 4799b46acd6aSKonstantin Komarov if (!dp) 4800b46acd6aSKonstantin Komarov goto do_redo_1; 4801b46acd6aSKonstantin Komarov 4802b46acd6aSKonstantin Komarov oe = Add2Ptr(oatbl, le32_to_cpu(dp->target_attr)); 4803b46acd6aSKonstantin Komarov 4804b46acd6aSKonstantin Komarov if (oe->next != RESTART_ENTRY_ALLOCATED_LE) 4805b46acd6aSKonstantin Komarov goto next_dirty_page; 4806b46acd6aSKonstantin Komarov 4807b46acd6aSKonstantin Komarov oa = oe->ptr; 4808b46acd6aSKonstantin Komarov if (!oa) 4809b46acd6aSKonstantin Komarov goto next_dirty_page; 4810b46acd6aSKonstantin Komarov 4811b46acd6aSKonstantin Komarov i = -1; 4812b46acd6aSKonstantin Komarov next_dirty_page_vcn: 4813b46acd6aSKonstantin Komarov i += 1; 4814b46acd6aSKonstantin Komarov if (i >= le32_to_cpu(dp->lcns_follow)) 4815b46acd6aSKonstantin Komarov goto next_dirty_page; 4816b46acd6aSKonstantin Komarov 4817b46acd6aSKonstantin Komarov vcn = le64_to_cpu(dp->vcn) + i; 4818b46acd6aSKonstantin Komarov size = (vcn + 1) << sbi->cluster_bits; 4819b46acd6aSKonstantin Komarov 4820b46acd6aSKonstantin Komarov if (!dp->page_lcns[i]) 4821b46acd6aSKonstantin Komarov goto next_dirty_page_vcn; 4822b46acd6aSKonstantin Komarov 4823b46acd6aSKonstantin Komarov rno = ino_get(&oe->ref); 4824b46acd6aSKonstantin Komarov if (rno <= MFT_REC_MIRR && 4825b46acd6aSKonstantin Komarov size < (MFT_REC_VOL + 1) * sbi->record_size && 4826b46acd6aSKonstantin Komarov oe->type == ATTR_DATA) { 4827b46acd6aSKonstantin Komarov goto next_dirty_page_vcn; 4828b46acd6aSKonstantin Komarov } 4829b46acd6aSKonstantin Komarov 4830b46acd6aSKonstantin Komarov lcn = le64_to_cpu(dp->page_lcns[i]); 4831b46acd6aSKonstantin Komarov 4832b46acd6aSKonstantin Komarov if ((!run_lookup_entry(oa->run1, vcn, &lcn0, &len0, NULL) || 4833b46acd6aSKonstantin Komarov lcn0 != lcn) && 4834b46acd6aSKonstantin Komarov !run_add_entry(oa->run1, vcn, lcn, 1, false)) { 4835b46acd6aSKonstantin Komarov err = -ENOMEM; 4836b46acd6aSKonstantin Komarov goto out; 4837b46acd6aSKonstantin Komarov } 4838b46acd6aSKonstantin Komarov attr = oa->attr; 4839b46acd6aSKonstantin Komarov t64 = le64_to_cpu(attr->nres.alloc_size); 4840b46acd6aSKonstantin Komarov if (size > t64) { 4841b46acd6aSKonstantin Komarov attr->nres.valid_size = attr->nres.data_size = 4842b46acd6aSKonstantin Komarov attr->nres.alloc_size = cpu_to_le64(size); 4843b46acd6aSKonstantin Komarov } 4844b46acd6aSKonstantin Komarov goto next_dirty_page_vcn; 4845b46acd6aSKonstantin Komarov 4846b46acd6aSKonstantin Komarov do_redo_1: 4847b46acd6aSKonstantin Komarov /* 4848b46acd6aSKonstantin Komarov * Perform the Redo Pass, to restore all of the dirty pages to the same 4849*e8b8e97fSKari Argillander * contents that they had immediately before the crash. If the dirty 4850*e8b8e97fSKari Argillander * page table is empty, then we can skip the entire Redo Pass. 4851b46acd6aSKonstantin Komarov */ 4852b46acd6aSKonstantin Komarov if (!dptbl || !dptbl->total) 4853b46acd6aSKonstantin Komarov goto do_undo_action; 4854b46acd6aSKonstantin Komarov 4855b46acd6aSKonstantin Komarov rec_lsn = rlsn; 4856b46acd6aSKonstantin Komarov 4857b46acd6aSKonstantin Komarov /* 4858b46acd6aSKonstantin Komarov * Read the record at the Redo lsn, before falling 4859*e8b8e97fSKari Argillander * into common code to handle each record. 4860b46acd6aSKonstantin Komarov */ 4861b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, rlsn, lcb_ctx_next, &lcb); 4862b46acd6aSKonstantin Komarov if (err) 4863b46acd6aSKonstantin Komarov goto out; 4864b46acd6aSKonstantin Komarov 4865b46acd6aSKonstantin Komarov /* 4866*e8b8e97fSKari Argillander * Now loop to read all of our log records forwards, until 4867*e8b8e97fSKari Argillander * we hit the end of the file, cleaning up at the end. 4868b46acd6aSKonstantin Komarov */ 4869b46acd6aSKonstantin Komarov do_action_next: 4870b46acd6aSKonstantin Komarov frh = lcb->lrh; 4871b46acd6aSKonstantin Komarov 4872b46acd6aSKonstantin Komarov if (LfsClientRecord != frh->record_type) 4873b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4874b46acd6aSKonstantin Komarov 4875b46acd6aSKonstantin Komarov transact_id = le32_to_cpu(frh->transact_id); 4876b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 4877b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 4878b46acd6aSKonstantin Komarov 4879b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, transact_id, bytes_per_attr_entry)) { 4880b46acd6aSKonstantin Komarov err = -EINVAL; 4881b46acd6aSKonstantin Komarov goto out; 4882b46acd6aSKonstantin Komarov } 4883b46acd6aSKonstantin Komarov 4884*e8b8e97fSKari Argillander /* Ignore log records that do not update pages. */ 4885b46acd6aSKonstantin Komarov if (lrh->lcns_follow) 4886b46acd6aSKonstantin Komarov goto find_dirty_page; 4887b46acd6aSKonstantin Komarov 4888b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4889b46acd6aSKonstantin Komarov 4890b46acd6aSKonstantin Komarov find_dirty_page: 4891b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->target_attr); 4892b46acd6aSKonstantin Komarov t64 = le64_to_cpu(lrh->target_vcn); 4893b46acd6aSKonstantin Komarov dp = find_dp(dptbl, t16, t64); 4894b46acd6aSKonstantin Komarov 4895b46acd6aSKonstantin Komarov if (!dp) 4896b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4897b46acd6aSKonstantin Komarov 4898b46acd6aSKonstantin Komarov if (rec_lsn < le64_to_cpu(dp->oldest_lsn)) 4899b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4900b46acd6aSKonstantin Komarov 4901b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->target_attr); 4902b46acd6aSKonstantin Komarov if (t16 >= bytes_per_rt(oatbl)) { 4903b46acd6aSKonstantin Komarov err = -EINVAL; 4904b46acd6aSKonstantin Komarov goto out; 4905b46acd6aSKonstantin Komarov } 4906b46acd6aSKonstantin Komarov 4907b46acd6aSKonstantin Komarov oe = Add2Ptr(oatbl, t16); 4908b46acd6aSKonstantin Komarov 4909b46acd6aSKonstantin Komarov if (oe->next != RESTART_ENTRY_ALLOCATED_LE) { 4910b46acd6aSKonstantin Komarov err = -EINVAL; 4911b46acd6aSKonstantin Komarov goto out; 4912b46acd6aSKonstantin Komarov } 4913b46acd6aSKonstantin Komarov 4914b46acd6aSKonstantin Komarov oa = oe->ptr; 4915b46acd6aSKonstantin Komarov 4916b46acd6aSKonstantin Komarov if (!oa) { 4917b46acd6aSKonstantin Komarov err = -EINVAL; 4918b46acd6aSKonstantin Komarov goto out; 4919b46acd6aSKonstantin Komarov } 4920b46acd6aSKonstantin Komarov attr = oa->attr; 4921b46acd6aSKonstantin Komarov 4922b46acd6aSKonstantin Komarov vcn = le64_to_cpu(lrh->target_vcn); 4923b46acd6aSKonstantin Komarov 4924b46acd6aSKonstantin Komarov if (!run_lookup_entry(oa->run1, vcn, &lcn, NULL, NULL) || 4925b46acd6aSKonstantin Komarov lcn == SPARSE_LCN) { 4926b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4927b46acd6aSKonstantin Komarov } 4928b46acd6aSKonstantin Komarov 4929*e8b8e97fSKari Argillander /* Point to the Redo data and get its length. */ 4930b46acd6aSKonstantin Komarov data = Add2Ptr(lrh, le16_to_cpu(lrh->redo_off)); 4931b46acd6aSKonstantin Komarov dlen = le16_to_cpu(lrh->redo_len); 4932b46acd6aSKonstantin Komarov 4933*e8b8e97fSKari Argillander /* Shorten length by any Lcns which were deleted. */ 4934b46acd6aSKonstantin Komarov saved_len = dlen; 4935b46acd6aSKonstantin Komarov 4936b46acd6aSKonstantin Komarov for (i = le16_to_cpu(lrh->lcns_follow); i; i--) { 4937b46acd6aSKonstantin Komarov size_t j; 4938b46acd6aSKonstantin Komarov u32 alen, voff; 4939b46acd6aSKonstantin Komarov 4940b46acd6aSKonstantin Komarov voff = le16_to_cpu(lrh->record_off) + 4941b46acd6aSKonstantin Komarov le16_to_cpu(lrh->attr_off); 4942b46acd6aSKonstantin Komarov voff += le16_to_cpu(lrh->cluster_off) << SECTOR_SHIFT; 4943b46acd6aSKonstantin Komarov 4944b46acd6aSKonstantin Komarov /* If the Vcn question is allocated, we can just get out. */ 4945b46acd6aSKonstantin Komarov j = le64_to_cpu(lrh->target_vcn) - le64_to_cpu(dp->vcn); 4946b46acd6aSKonstantin Komarov if (dp->page_lcns[j + i - 1]) 4947b46acd6aSKonstantin Komarov break; 4948b46acd6aSKonstantin Komarov 4949b46acd6aSKonstantin Komarov if (!saved_len) 4950b46acd6aSKonstantin Komarov saved_len = 1; 4951b46acd6aSKonstantin Komarov 4952b46acd6aSKonstantin Komarov /* 4953b46acd6aSKonstantin Komarov * Calculate the allocated space left relative to the 4954*e8b8e97fSKari Argillander * log record Vcn, after removing this unallocated Vcn. 4955b46acd6aSKonstantin Komarov */ 4956b46acd6aSKonstantin Komarov alen = (i - 1) << sbi->cluster_bits; 4957b46acd6aSKonstantin Komarov 4958b46acd6aSKonstantin Komarov /* 4959b46acd6aSKonstantin Komarov * If the update described this log record goes beyond 4960*e8b8e97fSKari Argillander * the allocated space, then we will have to reduce the length. 4961b46acd6aSKonstantin Komarov */ 4962b46acd6aSKonstantin Komarov if (voff >= alen) 4963b46acd6aSKonstantin Komarov dlen = 0; 4964b46acd6aSKonstantin Komarov else if (voff + dlen > alen) 4965b46acd6aSKonstantin Komarov dlen = alen - voff; 4966b46acd6aSKonstantin Komarov } 4967b46acd6aSKonstantin Komarov 4968*e8b8e97fSKari Argillander /* 4969*e8b8e97fSKari Argillander * If the resulting dlen from above is now zero, 4970*e8b8e97fSKari Argillander * we can skip this log record. 4971*e8b8e97fSKari Argillander */ 4972b46acd6aSKonstantin Komarov if (!dlen && saved_len) 4973b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4974b46acd6aSKonstantin Komarov 4975b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->redo_op); 4976b46acd6aSKonstantin Komarov if (can_skip_action(t16)) 4977b46acd6aSKonstantin Komarov goto read_next_log_do_action; 4978b46acd6aSKonstantin Komarov 4979*e8b8e97fSKari Argillander /* Apply the Redo operation a common routine. */ 4980b46acd6aSKonstantin Komarov err = do_action(log, oe, lrh, t16, data, dlen, rec_len, &rec_lsn); 4981b46acd6aSKonstantin Komarov if (err) 4982b46acd6aSKonstantin Komarov goto out; 4983b46acd6aSKonstantin Komarov 4984*e8b8e97fSKari Argillander /* Keep reading and looping back until end of file. */ 4985b46acd6aSKonstantin Komarov read_next_log_do_action: 4986b46acd6aSKonstantin Komarov err = read_next_log_rec(log, lcb, &rec_lsn); 4987b46acd6aSKonstantin Komarov if (!err && rec_lsn) 4988b46acd6aSKonstantin Komarov goto do_action_next; 4989b46acd6aSKonstantin Komarov 4990b46acd6aSKonstantin Komarov lcb_put(lcb); 4991b46acd6aSKonstantin Komarov lcb = NULL; 4992b46acd6aSKonstantin Komarov 4993b46acd6aSKonstantin Komarov do_undo_action: 4994*e8b8e97fSKari Argillander /* Scan Transaction Table. */ 4995b46acd6aSKonstantin Komarov tr = NULL; 4996b46acd6aSKonstantin Komarov transaction_table_next: 4997b46acd6aSKonstantin Komarov tr = enum_rstbl(trtbl, tr); 4998b46acd6aSKonstantin Komarov if (!tr) 4999b46acd6aSKonstantin Komarov goto undo_action_done; 5000b46acd6aSKonstantin Komarov 5001b46acd6aSKonstantin Komarov if (TransactionActive != tr->transact_state || !tr->undo_next_lsn) { 5002b46acd6aSKonstantin Komarov free_rsttbl_idx(trtbl, PtrOffset(trtbl, tr)); 5003b46acd6aSKonstantin Komarov goto transaction_table_next; 5004b46acd6aSKonstantin Komarov } 5005b46acd6aSKonstantin Komarov 5006b46acd6aSKonstantin Komarov log->transaction_id = PtrOffset(trtbl, tr); 5007b46acd6aSKonstantin Komarov undo_next_lsn = le64_to_cpu(tr->undo_next_lsn); 5008b46acd6aSKonstantin Komarov 5009b46acd6aSKonstantin Komarov /* 5010b46acd6aSKonstantin Komarov * We only have to do anything if the transaction has 5011*e8b8e97fSKari Argillander * something its undo_next_lsn field. 5012b46acd6aSKonstantin Komarov */ 5013b46acd6aSKonstantin Komarov if (!undo_next_lsn) 5014b46acd6aSKonstantin Komarov goto commit_undo; 5015b46acd6aSKonstantin Komarov 5016*e8b8e97fSKari Argillander /* Read the first record to be undone by this transaction. */ 5017b46acd6aSKonstantin Komarov err = read_log_rec_lcb(log, undo_next_lsn, lcb_ctx_undo_next, &lcb); 5018b46acd6aSKonstantin Komarov if (err) 5019b46acd6aSKonstantin Komarov goto out; 5020b46acd6aSKonstantin Komarov 5021b46acd6aSKonstantin Komarov /* 5022b46acd6aSKonstantin Komarov * Now loop to read all of our log records forwards, 5023*e8b8e97fSKari Argillander * until we hit the end of the file, cleaning up at the end. 5024b46acd6aSKonstantin Komarov */ 5025b46acd6aSKonstantin Komarov undo_action_next: 5026b46acd6aSKonstantin Komarov 5027b46acd6aSKonstantin Komarov lrh = lcb->log_rec; 5028b46acd6aSKonstantin Komarov frh = lcb->lrh; 5029b46acd6aSKonstantin Komarov transact_id = le32_to_cpu(frh->transact_id); 5030b46acd6aSKonstantin Komarov rec_len = le32_to_cpu(frh->client_data_len); 5031b46acd6aSKonstantin Komarov 5032b46acd6aSKonstantin Komarov if (!check_log_rec(lrh, rec_len, transact_id, bytes_per_attr_entry)) { 5033b46acd6aSKonstantin Komarov err = -EINVAL; 5034b46acd6aSKonstantin Komarov goto out; 5035b46acd6aSKonstantin Komarov } 5036b46acd6aSKonstantin Komarov 5037b46acd6aSKonstantin Komarov if (lrh->undo_op == cpu_to_le16(Noop)) 5038b46acd6aSKonstantin Komarov goto read_next_log_undo_action; 5039b46acd6aSKonstantin Komarov 5040b46acd6aSKonstantin Komarov oe = Add2Ptr(oatbl, le16_to_cpu(lrh->target_attr)); 5041b46acd6aSKonstantin Komarov oa = oe->ptr; 5042b46acd6aSKonstantin Komarov 5043b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->lcns_follow); 5044b46acd6aSKonstantin Komarov if (!t16) 5045b46acd6aSKonstantin Komarov goto add_allocated_vcns; 5046b46acd6aSKonstantin Komarov 5047b46acd6aSKonstantin Komarov is_mapped = run_lookup_entry(oa->run1, le64_to_cpu(lrh->target_vcn), 5048b46acd6aSKonstantin Komarov &lcn, &clen, NULL); 5049b46acd6aSKonstantin Komarov 5050b46acd6aSKonstantin Komarov /* 5051b46acd6aSKonstantin Komarov * If the mapping isn't already the table or the mapping 5052b46acd6aSKonstantin Komarov * corresponds to a hole the mapping, we need to make sure 5053*e8b8e97fSKari Argillander * there is no partial page already memory. 5054b46acd6aSKonstantin Komarov */ 5055b46acd6aSKonstantin Komarov if (is_mapped && lcn != SPARSE_LCN && clen >= t16) 5056b46acd6aSKonstantin Komarov goto add_allocated_vcns; 5057b46acd6aSKonstantin Komarov 5058b46acd6aSKonstantin Komarov vcn = le64_to_cpu(lrh->target_vcn); 5059b46acd6aSKonstantin Komarov vcn &= ~(log->clst_per_page - 1); 5060b46acd6aSKonstantin Komarov 5061b46acd6aSKonstantin Komarov add_allocated_vcns: 5062b46acd6aSKonstantin Komarov for (i = 0, vcn = le64_to_cpu(lrh->target_vcn), 5063b46acd6aSKonstantin Komarov size = (vcn + 1) << sbi->cluster_bits; 5064b46acd6aSKonstantin Komarov i < t16; i++, vcn += 1, size += sbi->cluster_size) { 5065b46acd6aSKonstantin Komarov attr = oa->attr; 5066b46acd6aSKonstantin Komarov if (!attr->non_res) { 5067b46acd6aSKonstantin Komarov if (size > le32_to_cpu(attr->res.data_size)) 5068b46acd6aSKonstantin Komarov attr->res.data_size = cpu_to_le32(size); 5069b46acd6aSKonstantin Komarov } else { 5070b46acd6aSKonstantin Komarov if (size > le64_to_cpu(attr->nres.data_size)) 5071b46acd6aSKonstantin Komarov attr->nres.valid_size = attr->nres.data_size = 5072b46acd6aSKonstantin Komarov attr->nres.alloc_size = 5073b46acd6aSKonstantin Komarov cpu_to_le64(size); 5074b46acd6aSKonstantin Komarov } 5075b46acd6aSKonstantin Komarov } 5076b46acd6aSKonstantin Komarov 5077b46acd6aSKonstantin Komarov t16 = le16_to_cpu(lrh->undo_op); 5078b46acd6aSKonstantin Komarov if (can_skip_action(t16)) 5079b46acd6aSKonstantin Komarov goto read_next_log_undo_action; 5080b46acd6aSKonstantin Komarov 5081*e8b8e97fSKari Argillander /* Point to the Redo data and get its length. */ 5082b46acd6aSKonstantin Komarov data = Add2Ptr(lrh, le16_to_cpu(lrh->undo_off)); 5083b46acd6aSKonstantin Komarov dlen = le16_to_cpu(lrh->undo_len); 5084b46acd6aSKonstantin Komarov 5085*e8b8e97fSKari Argillander /* It is time to apply the undo action. */ 5086b46acd6aSKonstantin Komarov err = do_action(log, oe, lrh, t16, data, dlen, rec_len, NULL); 5087b46acd6aSKonstantin Komarov 5088b46acd6aSKonstantin Komarov read_next_log_undo_action: 5089b46acd6aSKonstantin Komarov /* 5090b46acd6aSKonstantin Komarov * Keep reading and looping back until we have read the 5091*e8b8e97fSKari Argillander * last record for this transaction. 5092b46acd6aSKonstantin Komarov */ 5093b46acd6aSKonstantin Komarov err = read_next_log_rec(log, lcb, &rec_lsn); 5094b46acd6aSKonstantin Komarov if (err) 5095b46acd6aSKonstantin Komarov goto out; 5096b46acd6aSKonstantin Komarov 5097b46acd6aSKonstantin Komarov if (rec_lsn) 5098b46acd6aSKonstantin Komarov goto undo_action_next; 5099b46acd6aSKonstantin Komarov 5100b46acd6aSKonstantin Komarov lcb_put(lcb); 5101b46acd6aSKonstantin Komarov lcb = NULL; 5102b46acd6aSKonstantin Komarov 5103b46acd6aSKonstantin Komarov commit_undo: 5104b46acd6aSKonstantin Komarov free_rsttbl_idx(trtbl, log->transaction_id); 5105b46acd6aSKonstantin Komarov 5106b46acd6aSKonstantin Komarov log->transaction_id = 0; 5107b46acd6aSKonstantin Komarov 5108b46acd6aSKonstantin Komarov goto transaction_table_next; 5109b46acd6aSKonstantin Komarov 5110b46acd6aSKonstantin Komarov undo_action_done: 5111b46acd6aSKonstantin Komarov 5112b46acd6aSKonstantin Komarov ntfs_update_mftmirr(sbi, 0); 5113b46acd6aSKonstantin Komarov 5114b46acd6aSKonstantin Komarov sbi->flags &= ~NTFS_FLAGS_NEED_REPLAY; 5115b46acd6aSKonstantin Komarov 5116b46acd6aSKonstantin Komarov end_reply: 5117b46acd6aSKonstantin Komarov 5118b46acd6aSKonstantin Komarov err = 0; 5119b46acd6aSKonstantin Komarov if (is_ro) 5120b46acd6aSKonstantin Komarov goto out; 5121b46acd6aSKonstantin Komarov 5122195c52bdSKari Argillander rh = kzalloc(log->page_size, GFP_NOFS); 5123b46acd6aSKonstantin Komarov if (!rh) { 5124b46acd6aSKonstantin Komarov err = -ENOMEM; 5125b46acd6aSKonstantin Komarov goto out; 5126b46acd6aSKonstantin Komarov } 5127b46acd6aSKonstantin Komarov 5128b46acd6aSKonstantin Komarov rh->rhdr.sign = NTFS_RSTR_SIGNATURE; 5129b46acd6aSKonstantin Komarov rh->rhdr.fix_off = cpu_to_le16(offsetof(struct RESTART_HDR, fixups)); 5130b46acd6aSKonstantin Komarov t16 = (log->page_size >> SECTOR_SHIFT) + 1; 5131b46acd6aSKonstantin Komarov rh->rhdr.fix_num = cpu_to_le16(t16); 5132b46acd6aSKonstantin Komarov rh->sys_page_size = cpu_to_le32(log->page_size); 5133b46acd6aSKonstantin Komarov rh->page_size = cpu_to_le32(log->page_size); 5134b46acd6aSKonstantin Komarov 5135fa3cacf5SKari Argillander t16 = ALIGN(offsetof(struct RESTART_HDR, fixups) + 5136fa3cacf5SKari Argillander sizeof(short) * t16, 8); 5137b46acd6aSKonstantin Komarov rh->ra_off = cpu_to_le16(t16); 5138b46acd6aSKonstantin Komarov rh->minor_ver = cpu_to_le16(1); // 0x1A: 5139b46acd6aSKonstantin Komarov rh->major_ver = cpu_to_le16(1); // 0x1C: 5140b46acd6aSKonstantin Komarov 5141b46acd6aSKonstantin Komarov ra2 = Add2Ptr(rh, t16); 5142b46acd6aSKonstantin Komarov memcpy(ra2, ra, sizeof(struct RESTART_AREA)); 5143b46acd6aSKonstantin Komarov 5144b46acd6aSKonstantin Komarov ra2->client_idx[0] = 0; 5145b46acd6aSKonstantin Komarov ra2->client_idx[1] = LFS_NO_CLIENT_LE; 5146b46acd6aSKonstantin Komarov ra2->flags = cpu_to_le16(2); 5147b46acd6aSKonstantin Komarov 5148b46acd6aSKonstantin Komarov le32_add_cpu(&ra2->open_log_count, 1); 5149b46acd6aSKonstantin Komarov 5150b46acd6aSKonstantin Komarov ntfs_fix_pre_write(&rh->rhdr, log->page_size); 5151b46acd6aSKonstantin Komarov 5152b46acd6aSKonstantin Komarov err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size); 5153b46acd6aSKonstantin Komarov if (!err) 5154b46acd6aSKonstantin Komarov err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size, 5155b46acd6aSKonstantin Komarov rh, log->page_size); 5156b46acd6aSKonstantin Komarov 5157195c52bdSKari Argillander kfree(rh); 5158b46acd6aSKonstantin Komarov if (err) 5159b46acd6aSKonstantin Komarov goto out; 5160b46acd6aSKonstantin Komarov 5161b46acd6aSKonstantin Komarov out: 5162195c52bdSKari Argillander kfree(rst); 5163b46acd6aSKonstantin Komarov if (lcb) 5164b46acd6aSKonstantin Komarov lcb_put(lcb); 5165b46acd6aSKonstantin Komarov 5166*e8b8e97fSKari Argillander /* 5167*e8b8e97fSKari Argillander * Scan the Open Attribute Table to close all of 5168*e8b8e97fSKari Argillander * the open attributes. 5169*e8b8e97fSKari Argillander */ 5170b46acd6aSKonstantin Komarov oe = NULL; 5171b46acd6aSKonstantin Komarov while ((oe = enum_rstbl(oatbl, oe))) { 5172b46acd6aSKonstantin Komarov rno = ino_get(&oe->ref); 5173b46acd6aSKonstantin Komarov 5174b46acd6aSKonstantin Komarov if (oe->is_attr_name == 1) { 5175195c52bdSKari Argillander kfree(oe->ptr); 5176b46acd6aSKonstantin Komarov oe->ptr = NULL; 5177b46acd6aSKonstantin Komarov continue; 5178b46acd6aSKonstantin Komarov } 5179b46acd6aSKonstantin Komarov 5180b46acd6aSKonstantin Komarov if (oe->is_attr_name) 5181b46acd6aSKonstantin Komarov continue; 5182b46acd6aSKonstantin Komarov 5183b46acd6aSKonstantin Komarov oa = oe->ptr; 5184b46acd6aSKonstantin Komarov if (!oa) 5185b46acd6aSKonstantin Komarov continue; 5186b46acd6aSKonstantin Komarov 5187b46acd6aSKonstantin Komarov run_close(&oa->run0); 5188195c52bdSKari Argillander kfree(oa->attr); 5189b46acd6aSKonstantin Komarov if (oa->ni) 5190b46acd6aSKonstantin Komarov iput(&oa->ni->vfs_inode); 5191195c52bdSKari Argillander kfree(oa); 5192b46acd6aSKonstantin Komarov } 5193b46acd6aSKonstantin Komarov 5194195c52bdSKari Argillander kfree(trtbl); 5195195c52bdSKari Argillander kfree(oatbl); 5196195c52bdSKari Argillander kfree(dptbl); 5197195c52bdSKari Argillander kfree(attr_names); 5198195c52bdSKari Argillander kfree(rst_info.r_page); 5199b46acd6aSKonstantin Komarov 5200195c52bdSKari Argillander kfree(ra); 5201195c52bdSKari Argillander kfree(log->one_page_buf); 5202b46acd6aSKonstantin Komarov 5203b46acd6aSKonstantin Komarov if (err) 5204b46acd6aSKonstantin Komarov sbi->flags |= NTFS_FLAGS_NEED_REPLAY; 5205b46acd6aSKonstantin Komarov 5206b46acd6aSKonstantin Komarov if (err == -EROFS) 5207b46acd6aSKonstantin Komarov err = 0; 5208b46acd6aSKonstantin Komarov else if (log->set_dirty) 5209b46acd6aSKonstantin Komarov ntfs_set_state(sbi, NTFS_DIRTY_ERROR); 5210b46acd6aSKonstantin Komarov 5211195c52bdSKari Argillander kfree(log); 5212b46acd6aSKonstantin Komarov 5213b46acd6aSKonstantin Komarov return err; 5214b46acd6aSKonstantin Komarov } 5215