/** * map_mft_record_page - map the page in which a specific mft record resides * @ni: ntfs inode whose mft record page to map * * This maps the page in which the mft record of the ntfs inode @ni is situated * and returns a pointer to the mft record within the mapped page. * * Return value needs to be checked with IS_ERR() and if that is true PTR_ERR() * contains the negative error code returned. */ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) { ntfs_volume *vol = ni->vol; struct inode *mft_vi = vol->mft_ino; struct page *page; unsigned long index, ofs, end_index; BUG_ON(ni->page); /* * The index into the page cache and the offset within the page cache * page of the wanted mft record. FIXME: We need to check for * overflowing the unsigned long, but I don't think we would ever get * here if the volume was that big... */ index = ni->mft_no << vol->mft_record_size_bits >> PAGE_CACHE_SHIFT; ofs = (ni->mft_no << vol->mft_record_size_bits) & ~PAGE_CACHE_MASK; /* The maximum valid index into the page cache for $MFT's data. */ end_index = mft_vi->i_size >> PAGE_CACHE_SHIFT; /* If the wanted index is out of bounds the mft record doesn't exist. */ if (unlikely(index >= end_index)) { if (index > end_index || (mft_vi->i_size & ~PAGE_CACHE_MASK) < ofs + vol->mft_record_size) { page = ERR_PTR(-ENOENT); goto err_out; } } /* Read, map, and pin the page. */ page = ntfs_map_page(mft_vi->i_mapping, index); if (likely(!IS_ERR(page))) { ni->page = page; ni->page_ofs = ofs; return page_address(page) + ofs; } err_out: ni->page = NULL; ni->page_ofs = 0; ntfs_error(vol->sb, "Failed with error code %lu.", -PTR_ERR(page)); return (void*)page; }
/** * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume * @vol: ntfs volume on which to stamp the transaction log * * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return * 'true' on success and 'false' on error. * * This function assumes that the transaction log has already been loaded and * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl(). */ bool ntfs_stamp_usnjrnl(ntfs_volume *vol) { ntfs_debug("Entering."); if (likely(!NVolUsnJrnlStamped(vol))) { sle64 stamp; struct page *page; USN_HEADER *uh; page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0); if (IS_ERR(page)) { ntfs_error(vol->sb, "Failed to read from " "$UsnJrnl/$DATA/$Max attribute."); return false; } uh = (USN_HEADER*)page_address(page); stamp = get_current_ntfs_time(); ntfs_debug("Stamping transaction log ($UsnJrnl): old " "journal_id 0x%llx, old lowest_valid_usn " "0x%llx, new journal_id 0x%llx, new " "lowest_valid_usn 0x%llx.", (long long)sle64_to_cpu(uh->journal_id), (long long)sle64_to_cpu(uh->lowest_valid_usn), (long long)sle64_to_cpu(stamp), i_size_read(vol->usnjrnl_j_ino)); uh->lowest_valid_usn = cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino)); uh->journal_id = stamp; flush_dcache_page(page); set_page_dirty(page); ntfs_unmap_page(page); /* Set the flag so we do not have to do it again on remount. */ NVolSetUsnJrnlStamped(vol); } ntfs_debug("Done."); return true; }