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