11701aecbSPhillip Lougher /* 21701aecbSPhillip Lougher * Squashfs - a compressed read only filesystem for Linux 31701aecbSPhillip Lougher * 41701aecbSPhillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 5d7f2ff67SPhillip Lougher * Phillip Lougher <phillip@squashfs.org.uk> 61701aecbSPhillip Lougher * 71701aecbSPhillip Lougher * This program is free software; you can redistribute it and/or 81701aecbSPhillip Lougher * modify it under the terms of the GNU General Public License 91701aecbSPhillip Lougher * as published by the Free Software Foundation; either version 2, 101701aecbSPhillip Lougher * or (at your option) any later version. 111701aecbSPhillip Lougher * 121701aecbSPhillip Lougher * This program is distributed in the hope that it will be useful, 131701aecbSPhillip Lougher * but WITHOUT ANY WARRANTY; without even the implied warranty of 141701aecbSPhillip Lougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151701aecbSPhillip Lougher * GNU General Public License for more details. 161701aecbSPhillip Lougher * 171701aecbSPhillip Lougher * You should have received a copy of the GNU General Public License 181701aecbSPhillip Lougher * along with this program; if not, write to the Free Software 191701aecbSPhillip Lougher * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 201701aecbSPhillip Lougher * 211701aecbSPhillip Lougher * file.c 221701aecbSPhillip Lougher */ 231701aecbSPhillip Lougher 241701aecbSPhillip Lougher /* 251701aecbSPhillip Lougher * This file contains code for handling regular files. A regular file 261701aecbSPhillip Lougher * consists of a sequence of contiguous compressed blocks, and/or a 271701aecbSPhillip Lougher * compressed fragment block (tail-end packed block). The compressed size 281701aecbSPhillip Lougher * of each datablock is stored in a block list contained within the 291701aecbSPhillip Lougher * file inode (itself stored in one or more compressed metadata blocks). 301701aecbSPhillip Lougher * 311701aecbSPhillip Lougher * To speed up access to datablocks when reading 'large' files (256 Mbytes or 321701aecbSPhillip Lougher * larger), the code implements an index cache that caches the mapping from 331701aecbSPhillip Lougher * block index to datablock location on disk. 341701aecbSPhillip Lougher * 351701aecbSPhillip Lougher * The index cache allows Squashfs to handle large files (up to 1.75 TiB) while 361701aecbSPhillip Lougher * retaining a simple and space-efficient block list on disk. The cache 371701aecbSPhillip Lougher * is split into slots, caching up to eight 224 GiB files (128 KiB blocks). 381701aecbSPhillip Lougher * Larger files use multiple slots, with 1.75 TiB files using all 8 slots. 391701aecbSPhillip Lougher * The index cache is designed to be memory efficient, and by default uses 401701aecbSPhillip Lougher * 16 KiB. 411701aecbSPhillip Lougher */ 421701aecbSPhillip Lougher 431701aecbSPhillip Lougher #include <linux/fs.h> 441701aecbSPhillip Lougher #include <linux/vfs.h> 451701aecbSPhillip Lougher #include <linux/kernel.h> 461701aecbSPhillip Lougher #include <linux/slab.h> 471701aecbSPhillip Lougher #include <linux/string.h> 481701aecbSPhillip Lougher #include <linux/pagemap.h> 491701aecbSPhillip Lougher #include <linux/mutex.h> 501701aecbSPhillip Lougher 511701aecbSPhillip Lougher #include "squashfs_fs.h" 521701aecbSPhillip Lougher #include "squashfs_fs_sb.h" 531701aecbSPhillip Lougher #include "squashfs_fs_i.h" 541701aecbSPhillip Lougher #include "squashfs.h" 551701aecbSPhillip Lougher 561701aecbSPhillip Lougher /* 571701aecbSPhillip Lougher * Locate cache slot in range [offset, index] for specified inode. If 581701aecbSPhillip Lougher * there's more than one return the slot closest to index. 591701aecbSPhillip Lougher */ 601701aecbSPhillip Lougher static struct meta_index *locate_meta_index(struct inode *inode, int offset, 611701aecbSPhillip Lougher int index) 621701aecbSPhillip Lougher { 631701aecbSPhillip Lougher struct meta_index *meta = NULL; 641701aecbSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 651701aecbSPhillip Lougher int i; 661701aecbSPhillip Lougher 671701aecbSPhillip Lougher mutex_lock(&msblk->meta_index_mutex); 681701aecbSPhillip Lougher 691701aecbSPhillip Lougher TRACE("locate_meta_index: index %d, offset %d\n", index, offset); 701701aecbSPhillip Lougher 711701aecbSPhillip Lougher if (msblk->meta_index == NULL) 721701aecbSPhillip Lougher goto not_allocated; 731701aecbSPhillip Lougher 741701aecbSPhillip Lougher for (i = 0; i < SQUASHFS_META_SLOTS; i++) { 751701aecbSPhillip Lougher if (msblk->meta_index[i].inode_number == inode->i_ino && 761701aecbSPhillip Lougher msblk->meta_index[i].offset >= offset && 771701aecbSPhillip Lougher msblk->meta_index[i].offset <= index && 781701aecbSPhillip Lougher msblk->meta_index[i].locked == 0) { 791701aecbSPhillip Lougher TRACE("locate_meta_index: entry %d, offset %d\n", i, 801701aecbSPhillip Lougher msblk->meta_index[i].offset); 811701aecbSPhillip Lougher meta = &msblk->meta_index[i]; 821701aecbSPhillip Lougher offset = meta->offset; 831701aecbSPhillip Lougher } 841701aecbSPhillip Lougher } 851701aecbSPhillip Lougher 861701aecbSPhillip Lougher if (meta) 871701aecbSPhillip Lougher meta->locked = 1; 881701aecbSPhillip Lougher 891701aecbSPhillip Lougher not_allocated: 901701aecbSPhillip Lougher mutex_unlock(&msblk->meta_index_mutex); 911701aecbSPhillip Lougher 921701aecbSPhillip Lougher return meta; 931701aecbSPhillip Lougher } 941701aecbSPhillip Lougher 951701aecbSPhillip Lougher 961701aecbSPhillip Lougher /* 971701aecbSPhillip Lougher * Find and initialise an empty cache slot for index offset. 981701aecbSPhillip Lougher */ 991701aecbSPhillip Lougher static struct meta_index *empty_meta_index(struct inode *inode, int offset, 1001701aecbSPhillip Lougher int skip) 1011701aecbSPhillip Lougher { 1021701aecbSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 1031701aecbSPhillip Lougher struct meta_index *meta = NULL; 1041701aecbSPhillip Lougher int i; 1051701aecbSPhillip Lougher 1061701aecbSPhillip Lougher mutex_lock(&msblk->meta_index_mutex); 1071701aecbSPhillip Lougher 1081701aecbSPhillip Lougher TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); 1091701aecbSPhillip Lougher 1101701aecbSPhillip Lougher if (msblk->meta_index == NULL) { 1111701aecbSPhillip Lougher /* 1121701aecbSPhillip Lougher * First time cache index has been used, allocate and 1131701aecbSPhillip Lougher * initialise. The cache index could be allocated at 1141701aecbSPhillip Lougher * mount time but doing it here means it is allocated only 1151701aecbSPhillip Lougher * if a 'large' file is read. 1161701aecbSPhillip Lougher */ 1171701aecbSPhillip Lougher msblk->meta_index = kcalloc(SQUASHFS_META_SLOTS, 1181701aecbSPhillip Lougher sizeof(*(msblk->meta_index)), GFP_KERNEL); 1191701aecbSPhillip Lougher if (msblk->meta_index == NULL) { 1201701aecbSPhillip Lougher ERROR("Failed to allocate meta_index\n"); 1211701aecbSPhillip Lougher goto failed; 1221701aecbSPhillip Lougher } 1231701aecbSPhillip Lougher for (i = 0; i < SQUASHFS_META_SLOTS; i++) { 1241701aecbSPhillip Lougher msblk->meta_index[i].inode_number = 0; 1251701aecbSPhillip Lougher msblk->meta_index[i].locked = 0; 1261701aecbSPhillip Lougher } 1271701aecbSPhillip Lougher msblk->next_meta_index = 0; 1281701aecbSPhillip Lougher } 1291701aecbSPhillip Lougher 1301701aecbSPhillip Lougher for (i = SQUASHFS_META_SLOTS; i && 1311701aecbSPhillip Lougher msblk->meta_index[msblk->next_meta_index].locked; i--) 1321701aecbSPhillip Lougher msblk->next_meta_index = (msblk->next_meta_index + 1) % 1331701aecbSPhillip Lougher SQUASHFS_META_SLOTS; 1341701aecbSPhillip Lougher 1351701aecbSPhillip Lougher if (i == 0) { 1361701aecbSPhillip Lougher TRACE("empty_meta_index: failed!\n"); 1371701aecbSPhillip Lougher goto failed; 1381701aecbSPhillip Lougher } 1391701aecbSPhillip Lougher 1401701aecbSPhillip Lougher TRACE("empty_meta_index: returned meta entry %d, %p\n", 1411701aecbSPhillip Lougher msblk->next_meta_index, 1421701aecbSPhillip Lougher &msblk->meta_index[msblk->next_meta_index]); 1431701aecbSPhillip Lougher 1441701aecbSPhillip Lougher meta = &msblk->meta_index[msblk->next_meta_index]; 1451701aecbSPhillip Lougher msblk->next_meta_index = (msblk->next_meta_index + 1) % 1461701aecbSPhillip Lougher SQUASHFS_META_SLOTS; 1471701aecbSPhillip Lougher 1481701aecbSPhillip Lougher meta->inode_number = inode->i_ino; 1491701aecbSPhillip Lougher meta->offset = offset; 1501701aecbSPhillip Lougher meta->skip = skip; 1511701aecbSPhillip Lougher meta->entries = 0; 1521701aecbSPhillip Lougher meta->locked = 1; 1531701aecbSPhillip Lougher 1541701aecbSPhillip Lougher failed: 1551701aecbSPhillip Lougher mutex_unlock(&msblk->meta_index_mutex); 1561701aecbSPhillip Lougher return meta; 1571701aecbSPhillip Lougher } 1581701aecbSPhillip Lougher 1591701aecbSPhillip Lougher 1601701aecbSPhillip Lougher static void release_meta_index(struct inode *inode, struct meta_index *meta) 1611701aecbSPhillip Lougher { 1621701aecbSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 1631701aecbSPhillip Lougher mutex_lock(&msblk->meta_index_mutex); 1641701aecbSPhillip Lougher meta->locked = 0; 1651701aecbSPhillip Lougher mutex_unlock(&msblk->meta_index_mutex); 1661701aecbSPhillip Lougher } 1671701aecbSPhillip Lougher 1681701aecbSPhillip Lougher 1691701aecbSPhillip Lougher /* 1701701aecbSPhillip Lougher * Read the next n blocks from the block list, starting from 1711701aecbSPhillip Lougher * metadata block <start_block, offset>. 1721701aecbSPhillip Lougher */ 1731701aecbSPhillip Lougher static long long read_indexes(struct super_block *sb, int n, 1741701aecbSPhillip Lougher u64 *start_block, int *offset) 1751701aecbSPhillip Lougher { 1761701aecbSPhillip Lougher int err, i; 1771701aecbSPhillip Lougher long long block = 0; 1781701aecbSPhillip Lougher __le32 *blist = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); 1791701aecbSPhillip Lougher 1801701aecbSPhillip Lougher if (blist == NULL) { 1811701aecbSPhillip Lougher ERROR("read_indexes: Failed to allocate block_list\n"); 1821701aecbSPhillip Lougher return -ENOMEM; 1831701aecbSPhillip Lougher } 1841701aecbSPhillip Lougher 1851701aecbSPhillip Lougher while (n) { 1861701aecbSPhillip Lougher int blocks = min_t(int, n, PAGE_CACHE_SIZE >> 2); 1871701aecbSPhillip Lougher 1881701aecbSPhillip Lougher err = squashfs_read_metadata(sb, blist, start_block, 1891701aecbSPhillip Lougher offset, blocks << 2); 1901701aecbSPhillip Lougher if (err < 0) { 1911701aecbSPhillip Lougher ERROR("read_indexes: reading block [%llx:%x]\n", 1921701aecbSPhillip Lougher *start_block, *offset); 1931701aecbSPhillip Lougher goto failure; 1941701aecbSPhillip Lougher } 1951701aecbSPhillip Lougher 1961701aecbSPhillip Lougher for (i = 0; i < blocks; i++) { 1971701aecbSPhillip Lougher int size = le32_to_cpu(blist[i]); 1981701aecbSPhillip Lougher block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size); 1991701aecbSPhillip Lougher } 2001701aecbSPhillip Lougher n -= blocks; 2011701aecbSPhillip Lougher } 2021701aecbSPhillip Lougher 2031701aecbSPhillip Lougher kfree(blist); 2041701aecbSPhillip Lougher return block; 2051701aecbSPhillip Lougher 2061701aecbSPhillip Lougher failure: 2071701aecbSPhillip Lougher kfree(blist); 2081701aecbSPhillip Lougher return err; 2091701aecbSPhillip Lougher } 2101701aecbSPhillip Lougher 2111701aecbSPhillip Lougher 2121701aecbSPhillip Lougher /* 2131701aecbSPhillip Lougher * Each cache index slot has SQUASHFS_META_ENTRIES, each of which 2141701aecbSPhillip Lougher * can cache one index -> datablock/blocklist-block mapping. We wish 2151701aecbSPhillip Lougher * to distribute these over the length of the file, entry[0] maps index x, 2161701aecbSPhillip Lougher * entry[1] maps index x + skip, entry[2] maps index x + 2 * skip, and so on. 2171701aecbSPhillip Lougher * The larger the file, the greater the skip factor. The skip factor is 2181701aecbSPhillip Lougher * limited to the size of the metadata cache (SQUASHFS_CACHED_BLKS) to ensure 2191701aecbSPhillip Lougher * the number of metadata blocks that need to be read fits into the cache. 2201701aecbSPhillip Lougher * If the skip factor is limited in this way then the file will use multiple 2211701aecbSPhillip Lougher * slots. 2221701aecbSPhillip Lougher */ 2231701aecbSPhillip Lougher static inline int calculate_skip(int blocks) 2241701aecbSPhillip Lougher { 2251701aecbSPhillip Lougher int skip = blocks / ((SQUASHFS_META_ENTRIES + 1) 2261701aecbSPhillip Lougher * SQUASHFS_META_INDEXES); 2271701aecbSPhillip Lougher return min(SQUASHFS_CACHED_BLKS - 1, skip + 1); 2281701aecbSPhillip Lougher } 2291701aecbSPhillip Lougher 2301701aecbSPhillip Lougher 2311701aecbSPhillip Lougher /* 2321701aecbSPhillip Lougher * Search and grow the index cache for the specified inode, returning the 2331701aecbSPhillip Lougher * on-disk locations of the datablock and block list metadata block 2341701aecbSPhillip Lougher * <index_block, index_offset> for index (scaled to nearest cache index). 2351701aecbSPhillip Lougher */ 2361701aecbSPhillip Lougher static int fill_meta_index(struct inode *inode, int index, 2371701aecbSPhillip Lougher u64 *index_block, int *index_offset, u64 *data_block) 2381701aecbSPhillip Lougher { 2391701aecbSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 2401701aecbSPhillip Lougher int skip = calculate_skip(i_size_read(inode) >> msblk->block_log); 2411701aecbSPhillip Lougher int offset = 0; 2421701aecbSPhillip Lougher struct meta_index *meta; 2431701aecbSPhillip Lougher struct meta_entry *meta_entry; 2441701aecbSPhillip Lougher u64 cur_index_block = squashfs_i(inode)->block_list_start; 2451701aecbSPhillip Lougher int cur_offset = squashfs_i(inode)->offset; 2461701aecbSPhillip Lougher u64 cur_data_block = squashfs_i(inode)->start; 2471701aecbSPhillip Lougher int err, i; 2481701aecbSPhillip Lougher 2491701aecbSPhillip Lougher /* 2501701aecbSPhillip Lougher * Scale index to cache index (cache slot entry) 2511701aecbSPhillip Lougher */ 2521701aecbSPhillip Lougher index /= SQUASHFS_META_INDEXES * skip; 2531701aecbSPhillip Lougher 2541701aecbSPhillip Lougher while (offset < index) { 2551701aecbSPhillip Lougher meta = locate_meta_index(inode, offset + 1, index); 2561701aecbSPhillip Lougher 2571701aecbSPhillip Lougher if (meta == NULL) { 2581701aecbSPhillip Lougher meta = empty_meta_index(inode, offset + 1, skip); 2591701aecbSPhillip Lougher if (meta == NULL) 2601701aecbSPhillip Lougher goto all_done; 2611701aecbSPhillip Lougher } else { 2621701aecbSPhillip Lougher offset = index < meta->offset + meta->entries ? index : 2631701aecbSPhillip Lougher meta->offset + meta->entries - 1; 2641701aecbSPhillip Lougher meta_entry = &meta->meta_entry[offset - meta->offset]; 2651701aecbSPhillip Lougher cur_index_block = meta_entry->index_block + 2661701aecbSPhillip Lougher msblk->inode_table; 2671701aecbSPhillip Lougher cur_offset = meta_entry->offset; 2681701aecbSPhillip Lougher cur_data_block = meta_entry->data_block; 2691701aecbSPhillip Lougher TRACE("get_meta_index: offset %d, meta->offset %d, " 2701701aecbSPhillip Lougher "meta->entries %d\n", offset, meta->offset, 2711701aecbSPhillip Lougher meta->entries); 2721701aecbSPhillip Lougher TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" 2731701aecbSPhillip Lougher " data_block 0x%llx\n", cur_index_block, 2741701aecbSPhillip Lougher cur_offset, cur_data_block); 2751701aecbSPhillip Lougher } 2761701aecbSPhillip Lougher 2771701aecbSPhillip Lougher /* 2781701aecbSPhillip Lougher * If necessary grow cache slot by reading block list. Cache 2791701aecbSPhillip Lougher * slot is extended up to index or to the end of the slot, in 2801701aecbSPhillip Lougher * which case further slots will be used. 2811701aecbSPhillip Lougher */ 2821701aecbSPhillip Lougher for (i = meta->offset + meta->entries; i <= index && 2831701aecbSPhillip Lougher i < meta->offset + SQUASHFS_META_ENTRIES; i++) { 2841701aecbSPhillip Lougher int blocks = skip * SQUASHFS_META_INDEXES; 2851701aecbSPhillip Lougher long long res = read_indexes(inode->i_sb, blocks, 2861701aecbSPhillip Lougher &cur_index_block, &cur_offset); 2871701aecbSPhillip Lougher 2881701aecbSPhillip Lougher if (res < 0) { 2891701aecbSPhillip Lougher if (meta->entries == 0) 2901701aecbSPhillip Lougher /* 2911701aecbSPhillip Lougher * Don't leave an empty slot on read 2921701aecbSPhillip Lougher * error allocated to this inode... 2931701aecbSPhillip Lougher */ 2941701aecbSPhillip Lougher meta->inode_number = 0; 2951701aecbSPhillip Lougher err = res; 2961701aecbSPhillip Lougher goto failed; 2971701aecbSPhillip Lougher } 2981701aecbSPhillip Lougher 2991701aecbSPhillip Lougher cur_data_block += res; 3001701aecbSPhillip Lougher meta_entry = &meta->meta_entry[i - meta->offset]; 3011701aecbSPhillip Lougher meta_entry->index_block = cur_index_block - 3021701aecbSPhillip Lougher msblk->inode_table; 3031701aecbSPhillip Lougher meta_entry->offset = cur_offset; 3041701aecbSPhillip Lougher meta_entry->data_block = cur_data_block; 3051701aecbSPhillip Lougher meta->entries++; 3061701aecbSPhillip Lougher offset++; 3071701aecbSPhillip Lougher } 3081701aecbSPhillip Lougher 3091701aecbSPhillip Lougher TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", 3101701aecbSPhillip Lougher meta->offset, meta->entries); 3111701aecbSPhillip Lougher 3121701aecbSPhillip Lougher release_meta_index(inode, meta); 3131701aecbSPhillip Lougher } 3141701aecbSPhillip Lougher 3151701aecbSPhillip Lougher all_done: 3161701aecbSPhillip Lougher *index_block = cur_index_block; 3171701aecbSPhillip Lougher *index_offset = cur_offset; 3181701aecbSPhillip Lougher *data_block = cur_data_block; 3191701aecbSPhillip Lougher 3201701aecbSPhillip Lougher /* 3211701aecbSPhillip Lougher * Scale cache index (cache slot entry) to index 3221701aecbSPhillip Lougher */ 3231701aecbSPhillip Lougher return offset * SQUASHFS_META_INDEXES * skip; 3241701aecbSPhillip Lougher 3251701aecbSPhillip Lougher failed: 3261701aecbSPhillip Lougher release_meta_index(inode, meta); 3271701aecbSPhillip Lougher return err; 3281701aecbSPhillip Lougher } 3291701aecbSPhillip Lougher 3301701aecbSPhillip Lougher 3311701aecbSPhillip Lougher /* 3321701aecbSPhillip Lougher * Get the on-disk location and compressed size of the datablock 3331701aecbSPhillip Lougher * specified by index. Fill_meta_index() does most of the work. 3341701aecbSPhillip Lougher */ 3351701aecbSPhillip Lougher static int read_blocklist(struct inode *inode, int index, u64 *block) 3361701aecbSPhillip Lougher { 3371701aecbSPhillip Lougher u64 start; 3381701aecbSPhillip Lougher long long blks; 3391701aecbSPhillip Lougher int offset; 3401701aecbSPhillip Lougher __le32 size; 3411701aecbSPhillip Lougher int res = fill_meta_index(inode, index, &start, &offset, block); 3421701aecbSPhillip Lougher 3431701aecbSPhillip Lougher TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset" 3441701aecbSPhillip Lougher " 0x%x, block 0x%llx\n", res, index, start, offset, 3451701aecbSPhillip Lougher *block); 3461701aecbSPhillip Lougher 3471701aecbSPhillip Lougher if (res < 0) 3481701aecbSPhillip Lougher return res; 3491701aecbSPhillip Lougher 3501701aecbSPhillip Lougher /* 3511701aecbSPhillip Lougher * res contains the index of the mapping returned by fill_meta_index(), 3521701aecbSPhillip Lougher * this will likely be less than the desired index (because the 3531701aecbSPhillip Lougher * meta_index cache works at a higher granularity). Read any 3541701aecbSPhillip Lougher * extra block indexes needed. 3551701aecbSPhillip Lougher */ 3561701aecbSPhillip Lougher if (res < index) { 3571701aecbSPhillip Lougher blks = read_indexes(inode->i_sb, index - res, &start, &offset); 3581701aecbSPhillip Lougher if (blks < 0) 3591701aecbSPhillip Lougher return (int) blks; 3601701aecbSPhillip Lougher *block += blks; 3611701aecbSPhillip Lougher } 3621701aecbSPhillip Lougher 3631701aecbSPhillip Lougher /* 3641701aecbSPhillip Lougher * Read length of block specified by index. 3651701aecbSPhillip Lougher */ 3661701aecbSPhillip Lougher res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset, 3671701aecbSPhillip Lougher sizeof(size)); 3681701aecbSPhillip Lougher if (res < 0) 3691701aecbSPhillip Lougher return res; 3701701aecbSPhillip Lougher return le32_to_cpu(size); 3711701aecbSPhillip Lougher } 3721701aecbSPhillip Lougher 3731701aecbSPhillip Lougher 3741701aecbSPhillip Lougher static int squashfs_readpage(struct file *file, struct page *page) 3751701aecbSPhillip Lougher { 3761701aecbSPhillip Lougher struct inode *inode = page->mapping->host; 3771701aecbSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 3781701aecbSPhillip Lougher int bytes, i, offset = 0, sparse = 0; 3791701aecbSPhillip Lougher struct squashfs_cache_entry *buffer = NULL; 3801701aecbSPhillip Lougher void *pageaddr; 3811701aecbSPhillip Lougher 3821701aecbSPhillip Lougher int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; 3831701aecbSPhillip Lougher int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); 3841701aecbSPhillip Lougher int start_index = page->index & ~mask; 3851701aecbSPhillip Lougher int end_index = start_index | mask; 3861701aecbSPhillip Lougher int file_end = i_size_read(inode) >> msblk->block_log; 3871701aecbSPhillip Lougher 3881701aecbSPhillip Lougher TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", 3891701aecbSPhillip Lougher page->index, squashfs_i(inode)->start); 3901701aecbSPhillip Lougher 3911701aecbSPhillip Lougher if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> 3921701aecbSPhillip Lougher PAGE_CACHE_SHIFT)) 3931701aecbSPhillip Lougher goto out; 3941701aecbSPhillip Lougher 3951701aecbSPhillip Lougher if (index < file_end || squashfs_i(inode)->fragment_block == 3961701aecbSPhillip Lougher SQUASHFS_INVALID_BLK) { 3971701aecbSPhillip Lougher /* 3981701aecbSPhillip Lougher * Reading a datablock from disk. Need to read block list 3991701aecbSPhillip Lougher * to get location and block size. 4001701aecbSPhillip Lougher */ 4011701aecbSPhillip Lougher u64 block = 0; 4021701aecbSPhillip Lougher int bsize = read_blocklist(inode, index, &block); 4031701aecbSPhillip Lougher if (bsize < 0) 4041701aecbSPhillip Lougher goto error_out; 4051701aecbSPhillip Lougher 4061701aecbSPhillip Lougher if (bsize == 0) { /* hole */ 4071701aecbSPhillip Lougher bytes = index == file_end ? 4081701aecbSPhillip Lougher (i_size_read(inode) & (msblk->block_size - 1)) : 4091701aecbSPhillip Lougher msblk->block_size; 4101701aecbSPhillip Lougher sparse = 1; 4111701aecbSPhillip Lougher } else { 4121701aecbSPhillip Lougher /* 4131701aecbSPhillip Lougher * Read and decompress datablock. 4141701aecbSPhillip Lougher */ 4151701aecbSPhillip Lougher buffer = squashfs_get_datablock(inode->i_sb, 4161701aecbSPhillip Lougher block, bsize); 4171701aecbSPhillip Lougher if (buffer->error) { 4181701aecbSPhillip Lougher ERROR("Unable to read page, block %llx, size %x" 4191701aecbSPhillip Lougher "\n", block, bsize); 4201701aecbSPhillip Lougher squashfs_cache_put(buffer); 4211701aecbSPhillip Lougher goto error_out; 4221701aecbSPhillip Lougher } 4231701aecbSPhillip Lougher bytes = buffer->length; 4241701aecbSPhillip Lougher } 4251701aecbSPhillip Lougher } else { 4261701aecbSPhillip Lougher /* 4271701aecbSPhillip Lougher * Datablock is stored inside a fragment (tail-end packed 4281701aecbSPhillip Lougher * block). 4291701aecbSPhillip Lougher */ 4301701aecbSPhillip Lougher buffer = squashfs_get_fragment(inode->i_sb, 4311701aecbSPhillip Lougher squashfs_i(inode)->fragment_block, 4321701aecbSPhillip Lougher squashfs_i(inode)->fragment_size); 4331701aecbSPhillip Lougher 4341701aecbSPhillip Lougher if (buffer->error) { 4351701aecbSPhillip Lougher ERROR("Unable to read page, block %llx, size %x\n", 4361701aecbSPhillip Lougher squashfs_i(inode)->fragment_block, 4371701aecbSPhillip Lougher squashfs_i(inode)->fragment_size); 4381701aecbSPhillip Lougher squashfs_cache_put(buffer); 4391701aecbSPhillip Lougher goto error_out; 4401701aecbSPhillip Lougher } 4411701aecbSPhillip Lougher bytes = i_size_read(inode) & (msblk->block_size - 1); 4421701aecbSPhillip Lougher offset = squashfs_i(inode)->fragment_offset; 4431701aecbSPhillip Lougher } 4441701aecbSPhillip Lougher 4451701aecbSPhillip Lougher /* 4461701aecbSPhillip Lougher * Loop copying datablock into pages. As the datablock likely covers 4471701aecbSPhillip Lougher * many PAGE_CACHE_SIZE pages (default block size is 128 KiB) explicitly 4481701aecbSPhillip Lougher * grab the pages from the page cache, except for the page that we've 4491701aecbSPhillip Lougher * been called to fill. 4501701aecbSPhillip Lougher */ 4511701aecbSPhillip Lougher for (i = start_index; i <= end_index && bytes > 0; i++, 4521701aecbSPhillip Lougher bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { 4531701aecbSPhillip Lougher struct page *push_page; 4541701aecbSPhillip Lougher int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE); 4551701aecbSPhillip Lougher 4561701aecbSPhillip Lougher TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); 4571701aecbSPhillip Lougher 4581701aecbSPhillip Lougher push_page = (i == page->index) ? page : 4591701aecbSPhillip Lougher grab_cache_page_nowait(page->mapping, i); 4601701aecbSPhillip Lougher 4611701aecbSPhillip Lougher if (!push_page) 4621701aecbSPhillip Lougher continue; 4631701aecbSPhillip Lougher 4641701aecbSPhillip Lougher if (PageUptodate(push_page)) 4651701aecbSPhillip Lougher goto skip_page; 4661701aecbSPhillip Lougher 46753b55e55SCong Wang pageaddr = kmap_atomic(push_page); 4681701aecbSPhillip Lougher squashfs_copy_data(pageaddr, buffer, offset, avail); 4691701aecbSPhillip Lougher memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); 47053b55e55SCong Wang kunmap_atomic(pageaddr); 4711701aecbSPhillip Lougher flush_dcache_page(push_page); 4721701aecbSPhillip Lougher SetPageUptodate(push_page); 4731701aecbSPhillip Lougher skip_page: 4741701aecbSPhillip Lougher unlock_page(push_page); 4751701aecbSPhillip Lougher if (i != page->index) 4761701aecbSPhillip Lougher page_cache_release(push_page); 4771701aecbSPhillip Lougher } 4781701aecbSPhillip Lougher 4791701aecbSPhillip Lougher if (!sparse) 4801701aecbSPhillip Lougher squashfs_cache_put(buffer); 4811701aecbSPhillip Lougher 4821701aecbSPhillip Lougher return 0; 4831701aecbSPhillip Lougher 4841701aecbSPhillip Lougher error_out: 4851701aecbSPhillip Lougher SetPageError(page); 4861701aecbSPhillip Lougher out: 48753b55e55SCong Wang pageaddr = kmap_atomic(page); 4881701aecbSPhillip Lougher memset(pageaddr, 0, PAGE_CACHE_SIZE); 48953b55e55SCong Wang kunmap_atomic(pageaddr); 4901701aecbSPhillip Lougher flush_dcache_page(page); 4911701aecbSPhillip Lougher if (!PageError(page)) 4921701aecbSPhillip Lougher SetPageUptodate(page); 4931701aecbSPhillip Lougher unlock_page(page); 4941701aecbSPhillip Lougher 4951701aecbSPhillip Lougher return 0; 4961701aecbSPhillip Lougher } 4971701aecbSPhillip Lougher 4981701aecbSPhillip Lougher 4991701aecbSPhillip Lougher const struct address_space_operations squashfs_aops = { 5001701aecbSPhillip Lougher .readpage = squashfs_readpage 5011701aecbSPhillip Lougher }; 502