1 // SPDX-License-Identifier: GPL-2.0-or-later << 2 /* 1 /* 3 * Squashfs - a compressed read only filesyste 2 * Squashfs - a compressed read only filesystem for Linux 4 * 3 * 5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6 * Phillip Lougher <phillip@squashfs.org.uk> !! 5 * Phillip Lougher <phillip@lougher.demon.co.uk> >> 6 * >> 7 * This program is free software; you can redistribute it and/or >> 8 * modify it under the terms of the GNU General Public License >> 9 * as published by the Free Software Foundation; either version 2, >> 10 * or (at your option) any later version. >> 11 * >> 12 * This program is distributed in the hope that it will be useful, >> 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of >> 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 15 * GNU General Public License for more details. >> 16 * >> 17 * You should have received a copy of the GNU General Public License >> 18 * along with this program; if not, write to the Free Software >> 19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 7 * 20 * 8 * block.c 21 * block.c 9 */ 22 */ 10 23 11 /* 24 /* 12 * This file implements the low-level routines 25 * This file implements the low-level routines to read and decompress 13 * datablocks and metadata blocks. 26 * datablocks and metadata blocks. 14 */ 27 */ 15 28 16 #include <linux/blkdev.h> << 17 #include <linux/fs.h> 29 #include <linux/fs.h> 18 #include <linux/vfs.h> 30 #include <linux/vfs.h> 19 #include <linux/slab.h> 31 #include <linux/slab.h> 20 #include <linux/pagemap.h> !! 32 #include <linux/mutex.h> 21 #include <linux/string.h> 33 #include <linux/string.h> 22 #include <linux/bio.h> !! 34 #include <linux/buffer_head.h> >> 35 #include <linux/zlib.h> 23 36 24 #include "squashfs_fs.h" 37 #include "squashfs_fs.h" 25 #include "squashfs_fs_sb.h" 38 #include "squashfs_fs_sb.h" >> 39 #include "squashfs_fs_i.h" 26 #include "squashfs.h" 40 #include "squashfs.h" 27 #include "decompressor.h" << 28 #include "page_actor.h" << 29 41 30 /* 42 /* 31 * Returns the amount of bytes copied to the p !! 43 * Read the metadata block length, this is stored in the first two >> 44 * bytes of the metadata block. 32 */ 45 */ 33 static int copy_bio_to_actor(struct bio *bio, !! 46 static struct buffer_head *get_block_length(struct super_block *sb, 34 struct squashfs_p !! 47 u64 *cur_index, int *offset, int *length) 35 int offset, int r << 36 { << 37 void *actor_addr; << 38 struct bvec_iter_all iter_all = {}; << 39 struct bio_vec *bvec = bvec_init_iter_ << 40 int copied_bytes = 0; << 41 int actor_offset = 0; << 42 << 43 squashfs_actor_nobuff(actor); << 44 actor_addr = squashfs_first_page(actor << 45 << 46 if (WARN_ON_ONCE(!bio_next_segment(bio << 47 return 0; << 48 << 49 while (copied_bytes < req_length) { << 50 int bytes_to_copy = min_t(int, << 51 PAGE << 52 << 53 bytes_to_copy = min_t(int, byt << 54 req_leng << 55 if (!IS_ERR(actor_addr)) << 56 memcpy(actor_addr + ac << 57 offset << 58 << 59 actor_offset += bytes_to_copy; << 60 copied_bytes += bytes_to_copy; << 61 offset += bytes_to_copy; << 62 << 63 if (actor_offset >= PAGE_SIZE) << 64 actor_addr = squashfs_ << 65 if (!actor_addr) << 66 break; << 67 actor_offset = 0; << 68 } << 69 if (offset >= bvec->bv_len) { << 70 if (!bio_next_segment( << 71 break; << 72 offset = 0; << 73 } << 74 } << 75 squashfs_finish_page(actor); << 76 return copied_bytes; << 77 } << 78 << 79 static int squashfs_bio_read_cached(struct bio << 80 struct address_space *cache_ma << 81 u64 read_start, u64 read_end, << 82 { 48 { 83 struct page *head_to_cache = NULL, *ta !! 49 struct squashfs_sb_info *msblk = sb->s_fs_info; 84 struct block_device *bdev = fullbio->b !! 50 struct buffer_head *bh; 85 int start_idx = 0, end_idx = 0; << 86 struct bvec_iter_all iter_all; << 87 struct bio *bio = NULL; << 88 struct bio_vec *bv; << 89 int idx = 0; << 90 int err = 0; << 91 << 92 bio_for_each_segment_all(bv, fullbio, << 93 struct page *page = bv->bv_pag << 94 << 95 if (page->mapping == cache_map << 96 idx++; << 97 continue; << 98 } << 99 << 100 /* << 101 * We only use this when the d << 102 * the page size, so read_star << 103 * << 104 * Compare these to the origin << 105 * only cache pages which were << 106 * are the ones which are like << 107 * adjacent blocks. << 108 */ << 109 if (idx == 0 && index != read_ << 110 head_to_cache = page; << 111 else if (idx == page_count - 1 << 112 tail_to_cache = page; << 113 << 114 if (!bio || idx != end_idx) { << 115 struct bio *new = bio_ << 116 << 117 << 118 if (bio) { << 119 bio_trim(bio, << 120 (end_ << 121 bio_chain(bio, << 122 submit_bio(bio << 123 } << 124 << 125 bio = new; << 126 start_idx = idx; << 127 } << 128 << 129 idx++; << 130 end_idx = idx; << 131 } << 132 << 133 if (bio) { << 134 bio_trim(bio, start_idx * PAGE << 135 (end_idx - start_idx) << 136 err = submit_bio_wait(bio); << 137 bio_put(bio); << 138 } << 139 << 140 if (err) << 141 return err; << 142 << 143 if (head_to_cache) { << 144 int ret = add_to_page_cache_lr << 145 << 146 << 147 << 148 if (!ret) { << 149 SetPageUptodate(head_t << 150 unlock_page(head_to_ca << 151 } << 152 << 153 } << 154 << 155 if (tail_to_cache) { << 156 int ret = add_to_page_cache_lr << 157 << 158 << 159 << 160 if (!ret) { << 161 SetPageUptodate(tail_t << 162 unlock_page(tail_to_ca << 163 } << 164 } << 165 << 166 return 0; << 167 } << 168 << 169 static struct page *squashfs_get_cache_page(st << 170 pg << 171 { << 172 struct page *page; << 173 << 174 if (!mapping) << 175 return NULL; << 176 51 177 page = find_get_page(mapping, index); !! 52 bh = sb_bread(sb, *cur_index); 178 if (!page) !! 53 if (bh == NULL) 179 return NULL; 54 return NULL; 180 55 181 if (!PageUptodate(page)) { !! 56 if (msblk->devblksize - *offset == 1) { 182 put_page(page); !! 57 *length = (unsigned char) bh->b_data[*offset]; 183 return NULL; !! 58 put_bh(bh); >> 59 bh = sb_bread(sb, ++(*cur_index)); >> 60 if (bh == NULL) >> 61 return NULL; >> 62 *length |= (unsigned char) bh->b_data[0] << 8; >> 63 *offset = 1; >> 64 } else { >> 65 *length = (unsigned char) bh->b_data[*offset] | >> 66 (unsigned char) bh->b_data[*offset + 1] << 8; >> 67 *offset += 2; 184 } 68 } 185 69 186 return page; !! 70 return bh; 187 } 71 } 188 72 189 static int squashfs_bio_read(struct super_bloc << 190 struct bio **biop << 191 { << 192 struct squashfs_sb_info *msblk = sb->s << 193 struct address_space *cache_mapping = << 194 const u64 read_start = round_down(inde << 195 const sector_t block = read_start >> m << 196 const u64 read_end = round_up(index + << 197 const sector_t block_end = read_end >> << 198 int offset = read_start - round_down(i << 199 int total_len = (block_end - block) << << 200 const int page_count = DIV_ROUND_UP(to << 201 int error, i; << 202 struct bio *bio; << 203 << 204 bio = bio_kmalloc(page_count, GFP_NOIO << 205 if (!bio) << 206 return -ENOMEM; << 207 bio_init(bio, sb->s_bdev, bio->bi_inli << 208 bio->bi_iter.bi_sector = block * (msbl << 209 << 210 for (i = 0; i < page_count; ++i) { << 211 unsigned int len = << 212 min_t(unsigned int, PA << 213 pgoff_t index = (read_start >> << 214 struct page *page; << 215 << 216 page = squashfs_get_cache_page << 217 if (!page) << 218 page = alloc_page(GFP_ << 219 << 220 if (!page) { << 221 error = -ENOMEM; << 222 goto out_free_bio; << 223 } << 224 << 225 /* << 226 * Use the __ version to avoid << 227 * to be separate when we chec << 228 */ << 229 __bio_add_page(bio, page, len, << 230 offset = 0; << 231 total_len -= len; << 232 } << 233 << 234 if (cache_mapping) << 235 error = squashfs_bio_read_cach << 236 << 237 << 238 else << 239 error = submit_bio_wait(bio); << 240 if (error) << 241 goto out_free_bio; << 242 << 243 *biop = bio; << 244 *block_offset = index & ((1 << msblk-> << 245 return 0; << 246 << 247 out_free_bio: << 248 bio_free_pages(bio); << 249 bio_uninit(bio); << 250 kfree(bio); << 251 return error; << 252 } << 253 73 254 /* 74 /* 255 * Read and decompress a metadata block or dat 75 * Read and decompress a metadata block or datablock. Length is non-zero 256 * if a datablock is being read (the size is s 76 * if a datablock is being read (the size is stored elsewhere in the 257 * filesystem), otherwise the length is obtain 77 * filesystem), otherwise the length is obtained from the first two bytes of 258 * the metadata block. A bit in the length fi 78 * the metadata block. A bit in the length field indicates if the block 259 * is stored uncompressed in the filesystem (u 79 * is stored uncompressed in the filesystem (usually because compression 260 * generated a larger block - this does occasi !! 80 * generated a larger block - this does occasionally happen with zlib). 261 * algorithms). << 262 */ 81 */ 263 int squashfs_read_data(struct super_block *sb, !! 82 int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, 264 u64 *next_index, struct !! 83 int length, u64 *next_index, int srclength, int pages) 265 { 84 { 266 struct squashfs_sb_info *msblk = sb->s 85 struct squashfs_sb_info *msblk = sb->s_fs_info; 267 struct bio *bio = NULL; !! 86 struct buffer_head **bh; 268 int compressed; !! 87 int offset = index & ((1 << msblk->devblksize_log2) - 1); 269 int res; !! 88 u64 cur_index = index >> msblk->devblksize_log2; 270 int offset; !! 89 int bytes, compressed, b = 0, k = 0, page = 0, avail; >> 90 >> 91 >> 92 bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1, >> 93 sizeof(*bh), GFP_KERNEL); >> 94 if (bh == NULL) >> 95 return -ENOMEM; 271 96 272 if (length) { 97 if (length) { 273 /* 98 /* 274 * Datablock. 99 * Datablock. 275 */ 100 */ >> 101 bytes = -offset; 276 compressed = SQUASHFS_COMPRESS 102 compressed = SQUASHFS_COMPRESSED_BLOCK(length); 277 length = SQUASHFS_COMPRESSED_S 103 length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); >> 104 if (next_index) >> 105 *next_index = index + length; >> 106 278 TRACE("Block @ 0x%llx, %scompr 107 TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", 279 index, compressed ? "" !! 108 index, compressed ? "" : "un", length, srclength); >> 109 >> 110 if (length < 0 || length > srclength || >> 111 (index + length) > msblk->bytes_used) >> 112 goto read_failure; >> 113 >> 114 for (b = 0; bytes < length; b++, cur_index++) { >> 115 bh[b] = sb_getblk(sb, cur_index); >> 116 if (bh[b] == NULL) >> 117 goto block_release; >> 118 bytes += msblk->devblksize; >> 119 } >> 120 ll_rw_block(READ, b, bh); 280 } else { 121 } else { 281 /* 122 /* 282 * Metadata block. 123 * Metadata block. 283 */ 124 */ 284 const u8 *data; !! 125 if ((index + 2) > msblk->bytes_used) 285 struct bvec_iter_all iter_all !! 126 goto read_failure; 286 struct bio_vec *bvec = bvec_in !! 127 287 !! 128 bh[0] = get_block_length(sb, &cur_index, &offset, &length); 288 if (index + 2 > msblk->bytes_u !! 129 if (bh[0] == NULL) 289 res = -EIO; !! 130 goto read_failure; 290 goto out; !! 131 b = 1; 291 } << 292 res = squashfs_bio_read(sb, in << 293 if (res) << 294 goto out; << 295 << 296 if (WARN_ON_ONCE(!bio_next_seg << 297 res = -EIO; << 298 goto out_free_bio; << 299 } << 300 /* Extract the length of the m << 301 data = bvec_virt(bvec); << 302 length = data[offset]; << 303 if (offset < bvec->bv_len - 1) << 304 length |= data[offset << 305 } else { << 306 if (WARN_ON_ONCE(!bio_ << 307 res = -EIO; << 308 goto out_free_ << 309 } << 310 data = bvec_virt(bvec) << 311 length |= data[0] << 8 << 312 } << 313 bio_free_pages(bio); << 314 bio_uninit(bio); << 315 kfree(bio); << 316 132 >> 133 bytes = msblk->devblksize - offset; 317 compressed = SQUASHFS_COMPRESS 134 compressed = SQUASHFS_COMPRESSED(length); 318 length = SQUASHFS_COMPRESSED_S 135 length = SQUASHFS_COMPRESSED_SIZE(length); 319 index += 2; !! 136 if (next_index) >> 137 *next_index = index + length + 2; 320 138 321 TRACE("Block @ 0x%llx, %scompr !! 139 TRACE("Block @ 0x%llx, %scompressed size %d\n", index, 322 compressed ? "" : "un", !! 140 compressed ? "" : "un", length); 323 } !! 141 324 if (length <= 0 || length > output->le !! 142 if (length < 0 || length > srclength || 325 (index + length) > msb !! 143 (index + length) > msblk->bytes_used) 326 res = -EIO; !! 144 goto block_release; 327 goto out; !! 145 >> 146 for (; bytes < length; b++) { >> 147 bh[b] = sb_getblk(sb, ++cur_index); >> 148 if (bh[b] == NULL) >> 149 goto block_release; >> 150 bytes += msblk->devblksize; >> 151 } >> 152 ll_rw_block(READ, b - 1, bh + 1); 328 } 153 } 329 154 330 if (next_index) !! 155 if (compressed) { 331 *next_index = index + length; !! 156 int zlib_err = 0, zlib_init = 0; >> 157 >> 158 /* >> 159 * Uncompress block. >> 160 */ >> 161 >> 162 mutex_lock(&msblk->read_data_mutex); 332 163 333 res = squashfs_bio_read(sb, index, len !! 164 msblk->stream.avail_out = 0; 334 if (res) !! 165 msblk->stream.avail_in = 0; 335 goto out; << 336 166 337 if (compressed) { !! 167 bytes = length; 338 if (!msblk->stream) { !! 168 do { 339 res = -EIO; !! 169 if (msblk->stream.avail_in == 0 && k < b) { 340 goto out_free_bio; !! 170 avail = min(bytes, msblk->devblksize - offset); >> 171 bytes -= avail; >> 172 wait_on_buffer(bh[k]); >> 173 if (!buffer_uptodate(bh[k])) >> 174 goto release_mutex; >> 175 >> 176 if (avail == 0) { >> 177 offset = 0; >> 178 put_bh(bh[k++]); >> 179 continue; >> 180 } >> 181 >> 182 msblk->stream.next_in = bh[k]->b_data + offset; >> 183 msblk->stream.avail_in = avail; >> 184 offset = 0; >> 185 } >> 186 >> 187 if (msblk->stream.avail_out == 0 && page < pages) { >> 188 msblk->stream.next_out = buffer[page++]; >> 189 msblk->stream.avail_out = PAGE_CACHE_SIZE; >> 190 } >> 191 >> 192 if (!zlib_init) { >> 193 zlib_err = zlib_inflateInit(&msblk->stream); >> 194 if (zlib_err != Z_OK) { >> 195 ERROR("zlib_inflateInit returned" >> 196 " unexpected result 0x%x," >> 197 " srclength %d\n", zlib_err, >> 198 srclength); >> 199 goto release_mutex; >> 200 } >> 201 zlib_init = 1; >> 202 } >> 203 >> 204 zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH); >> 205 >> 206 if (msblk->stream.avail_in == 0 && k < b) >> 207 put_bh(bh[k++]); >> 208 } while (zlib_err == Z_OK); >> 209 >> 210 if (zlib_err != Z_STREAM_END) { >> 211 ERROR("zlib_inflate error, data probably corrupt\n"); >> 212 goto release_mutex; 341 } 213 } 342 res = msblk->thread_ops->decom !! 214 >> 215 zlib_err = zlib_inflateEnd(&msblk->stream); >> 216 if (zlib_err != Z_OK) { >> 217 ERROR("zlib_inflate error, data probably corrupt\n"); >> 218 goto release_mutex; >> 219 } >> 220 length = msblk->stream.total_out; >> 221 mutex_unlock(&msblk->read_data_mutex); 343 } else { 222 } else { 344 res = copy_bio_to_actor(bio, o !! 223 /* 345 } !! 224 * Block is uncompressed. >> 225 */ >> 226 int i, in, pg_offset = 0; 346 227 347 out_free_bio: !! 228 for (i = 0; i < b; i++) { 348 bio_free_pages(bio); !! 229 wait_on_buffer(bh[i]); 349 bio_uninit(bio); !! 230 if (!buffer_uptodate(bh[i])) 350 kfree(bio); !! 231 goto block_release; 351 out: !! 232 } 352 if (res < 0) { !! 233 353 ERROR("Failed to read block 0x !! 234 for (bytes = length; k < b; k++) { 354 if (msblk->panic_on_errors) !! 235 in = min(bytes, msblk->devblksize - offset); 355 panic("squashfs read f !! 236 bytes -= in; >> 237 while (in) { >> 238 if (pg_offset == PAGE_CACHE_SIZE) { >> 239 page++; >> 240 pg_offset = 0; >> 241 } >> 242 avail = min_t(int, in, PAGE_CACHE_SIZE - >> 243 pg_offset); >> 244 memcpy(buffer[page] + pg_offset, >> 245 bh[k]->b_data + offset, avail); >> 246 in -= avail; >> 247 pg_offset += avail; >> 248 offset += avail; >> 249 } >> 250 offset = 0; >> 251 put_bh(bh[k]); >> 252 } 356 } 253 } 357 254 358 return res; !! 255 kfree(bh); >> 256 return length; >> 257 >> 258 release_mutex: >> 259 mutex_unlock(&msblk->read_data_mutex); >> 260 >> 261 block_release: >> 262 for (; k < b; k++) >> 263 put_bh(bh[k]); >> 264 >> 265 read_failure: >> 266 ERROR("squashfs_read_data failed to read block 0x%llx\n", >> 267 (unsigned long long) index); >> 268 kfree(bh); >> 269 return -EIO; 359 } 270 } 360 271
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.