1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * Squashfs - a compressed read only filesyste 3 * Squashfs - a compressed read only filesystem for Linux 4 * 4 * 5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6 * Phillip Lougher <phillip@squashfs.org.uk> 6 * Phillip Lougher <phillip@squashfs.org.uk> 7 * 7 * 8 * block.c 8 * block.c 9 */ 9 */ 10 10 11 /* 11 /* 12 * This file implements the low-level routines 12 * This file implements the low-level routines to read and decompress 13 * datablocks and metadata blocks. 13 * datablocks and metadata blocks. 14 */ 14 */ 15 15 16 #include <linux/blkdev.h> 16 #include <linux/blkdev.h> 17 #include <linux/fs.h> 17 #include <linux/fs.h> 18 #include <linux/vfs.h> 18 #include <linux/vfs.h> 19 #include <linux/slab.h> 19 #include <linux/slab.h> 20 #include <linux/pagemap.h> << 21 #include <linux/string.h> 20 #include <linux/string.h> >> 21 #include <linux/buffer_head.h> 22 #include <linux/bio.h> 22 #include <linux/bio.h> 23 23 24 #include "squashfs_fs.h" 24 #include "squashfs_fs.h" 25 #include "squashfs_fs_sb.h" 25 #include "squashfs_fs_sb.h" 26 #include "squashfs.h" 26 #include "squashfs.h" 27 #include "decompressor.h" 27 #include "decompressor.h" 28 #include "page_actor.h" 28 #include "page_actor.h" 29 29 30 /* 30 /* 31 * Returns the amount of bytes copied to the p 31 * Returns the amount of bytes copied to the page actor. 32 */ 32 */ 33 static int copy_bio_to_actor(struct bio *bio, 33 static int copy_bio_to_actor(struct bio *bio, 34 struct squashfs_p 34 struct squashfs_page_actor *actor, 35 int offset, int r 35 int offset, int req_length) 36 { 36 { 37 void *actor_addr; !! 37 void *actor_addr = squashfs_first_page(actor); 38 struct bvec_iter_all iter_all = {}; 38 struct bvec_iter_all iter_all = {}; 39 struct bio_vec *bvec = bvec_init_iter_ 39 struct bio_vec *bvec = bvec_init_iter_all(&iter_all); 40 int copied_bytes = 0; 40 int copied_bytes = 0; 41 int actor_offset = 0; 41 int actor_offset = 0; 42 42 43 squashfs_actor_nobuff(actor); << 44 actor_addr = squashfs_first_page(actor << 45 << 46 if (WARN_ON_ONCE(!bio_next_segment(bio 43 if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) 47 return 0; 44 return 0; 48 45 49 while (copied_bytes < req_length) { 46 while (copied_bytes < req_length) { 50 int bytes_to_copy = min_t(int, 47 int bytes_to_copy = min_t(int, bvec->bv_len - offset, 51 PAGE 48 PAGE_SIZE - actor_offset); 52 49 53 bytes_to_copy = min_t(int, byt 50 bytes_to_copy = min_t(int, bytes_to_copy, 54 req_leng 51 req_length - copied_bytes); 55 if (!IS_ERR(actor_addr)) !! 52 memcpy(actor_addr + actor_offset, bvec_virt(bvec) + offset, 56 memcpy(actor_addr + ac !! 53 bytes_to_copy); 57 offset << 58 54 59 actor_offset += bytes_to_copy; 55 actor_offset += bytes_to_copy; 60 copied_bytes += bytes_to_copy; 56 copied_bytes += bytes_to_copy; 61 offset += bytes_to_copy; 57 offset += bytes_to_copy; 62 58 63 if (actor_offset >= PAGE_SIZE) 59 if (actor_offset >= PAGE_SIZE) { 64 actor_addr = squashfs_ 60 actor_addr = squashfs_next_page(actor); 65 if (!actor_addr) 61 if (!actor_addr) 66 break; 62 break; 67 actor_offset = 0; 63 actor_offset = 0; 68 } 64 } 69 if (offset >= bvec->bv_len) { 65 if (offset >= bvec->bv_len) { 70 if (!bio_next_segment( 66 if (!bio_next_segment(bio, &iter_all)) 71 break; 67 break; 72 offset = 0; 68 offset = 0; 73 } 69 } 74 } 70 } 75 squashfs_finish_page(actor); 71 squashfs_finish_page(actor); 76 return copied_bytes; 72 return copied_bytes; 77 } 73 } 78 74 79 static int squashfs_bio_read_cached(struct bio << 80 struct address_space *cache_ma << 81 u64 read_start, u64 read_end, << 82 { << 83 struct page *head_to_cache = NULL, *ta << 84 struct block_device *bdev = fullbio->b << 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 << 177 page = find_get_page(mapping, index); << 178 if (!page) << 179 return NULL; << 180 << 181 if (!PageUptodate(page)) { << 182 put_page(page); << 183 return NULL; << 184 } << 185 << 186 return page; << 187 } << 188 << 189 static int squashfs_bio_read(struct super_bloc 75 static int squashfs_bio_read(struct super_block *sb, u64 index, int length, 190 struct bio **biop 76 struct bio **biop, int *block_offset) 191 { 77 { 192 struct squashfs_sb_info *msblk = sb->s 78 struct squashfs_sb_info *msblk = sb->s_fs_info; 193 struct address_space *cache_mapping = << 194 const u64 read_start = round_down(inde 79 const u64 read_start = round_down(index, msblk->devblksize); 195 const sector_t block = read_start >> m 80 const sector_t block = read_start >> msblk->devblksize_log2; 196 const u64 read_end = round_up(index + 81 const u64 read_end = round_up(index + length, msblk->devblksize); 197 const sector_t block_end = read_end >> 82 const sector_t block_end = read_end >> msblk->devblksize_log2; 198 int offset = read_start - round_down(i 83 int offset = read_start - round_down(index, PAGE_SIZE); 199 int total_len = (block_end - block) << 84 int total_len = (block_end - block) << msblk->devblksize_log2; 200 const int page_count = DIV_ROUND_UP(to 85 const int page_count = DIV_ROUND_UP(total_len + offset, PAGE_SIZE); 201 int error, i; 86 int error, i; 202 struct bio *bio; 87 struct bio *bio; 203 88 204 bio = bio_kmalloc(page_count, GFP_NOIO !! 89 if (page_count <= BIO_MAX_VECS) >> 90 bio = bio_alloc(GFP_NOIO, page_count); >> 91 else >> 92 bio = bio_kmalloc(GFP_NOIO, page_count); >> 93 205 if (!bio) 94 if (!bio) 206 return -ENOMEM; 95 return -ENOMEM; 207 bio_init(bio, sb->s_bdev, bio->bi_inli !! 96 >> 97 bio_set_dev(bio, sb->s_bdev); >> 98 bio->bi_opf = READ; 208 bio->bi_iter.bi_sector = block * (msbl 99 bio->bi_iter.bi_sector = block * (msblk->devblksize >> SECTOR_SHIFT); 209 100 210 for (i = 0; i < page_count; ++i) { 101 for (i = 0; i < page_count; ++i) { 211 unsigned int len = 102 unsigned int len = 212 min_t(unsigned int, PA 103 min_t(unsigned int, PAGE_SIZE - offset, total_len); 213 pgoff_t index = (read_start >> !! 104 struct page *page = alloc_page(GFP_NOIO); 214 struct page *page; << 215 << 216 page = squashfs_get_cache_page << 217 if (!page) << 218 page = alloc_page(GFP_ << 219 105 220 if (!page) { 106 if (!page) { 221 error = -ENOMEM; 107 error = -ENOMEM; 222 goto out_free_bio; 108 goto out_free_bio; 223 } 109 } 224 !! 110 if (!bio_add_page(bio, page, len, offset)) { 225 /* !! 111 error = -EIO; 226 * Use the __ version to avoid !! 112 goto out_free_bio; 227 * to be separate when we chec !! 113 } 228 */ << 229 __bio_add_page(bio, page, len, << 230 offset = 0; 114 offset = 0; 231 total_len -= len; 115 total_len -= len; 232 } 116 } 233 117 234 if (cache_mapping) !! 118 error = submit_bio_wait(bio); 235 error = squashfs_bio_read_cach << 236 << 237 << 238 else << 239 error = submit_bio_wait(bio); << 240 if (error) 119 if (error) 241 goto out_free_bio; 120 goto out_free_bio; 242 121 243 *biop = bio; 122 *biop = bio; 244 *block_offset = index & ((1 << msblk-> 123 *block_offset = index & ((1 << msblk->devblksize_log2) - 1); 245 return 0; 124 return 0; 246 125 247 out_free_bio: 126 out_free_bio: 248 bio_free_pages(bio); 127 bio_free_pages(bio); 249 bio_uninit(bio); !! 128 bio_put(bio); 250 kfree(bio); << 251 return error; 129 return error; 252 } 130 } 253 131 254 /* 132 /* 255 * Read and decompress a metadata block or dat 133 * Read and decompress a metadata block or datablock. Length is non-zero 256 * if a datablock is being read (the size is s 134 * if a datablock is being read (the size is stored elsewhere in the 257 * filesystem), otherwise the length is obtain 135 * filesystem), otherwise the length is obtained from the first two bytes of 258 * the metadata block. A bit in the length fi 136 * the metadata block. A bit in the length field indicates if the block 259 * is stored uncompressed in the filesystem (u 137 * is stored uncompressed in the filesystem (usually because compression 260 * generated a larger block - this does occasi 138 * generated a larger block - this does occasionally happen with compression 261 * algorithms). 139 * algorithms). 262 */ 140 */ 263 int squashfs_read_data(struct super_block *sb, 141 int squashfs_read_data(struct super_block *sb, u64 index, int length, 264 u64 *next_index, struct 142 u64 *next_index, struct squashfs_page_actor *output) 265 { 143 { 266 struct squashfs_sb_info *msblk = sb->s 144 struct squashfs_sb_info *msblk = sb->s_fs_info; 267 struct bio *bio = NULL; 145 struct bio *bio = NULL; 268 int compressed; 146 int compressed; 269 int res; 147 int res; 270 int offset; 148 int offset; 271 149 272 if (length) { 150 if (length) { 273 /* 151 /* 274 * Datablock. 152 * Datablock. 275 */ 153 */ 276 compressed = SQUASHFS_COMPRESS 154 compressed = SQUASHFS_COMPRESSED_BLOCK(length); 277 length = SQUASHFS_COMPRESSED_S 155 length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); 278 TRACE("Block @ 0x%llx, %scompr 156 TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", 279 index, compressed ? "" 157 index, compressed ? "" : "un", length, output->length); 280 } else { 158 } else { 281 /* 159 /* 282 * Metadata block. 160 * Metadata block. 283 */ 161 */ 284 const u8 *data; 162 const u8 *data; 285 struct bvec_iter_all iter_all 163 struct bvec_iter_all iter_all = {}; 286 struct bio_vec *bvec = bvec_in 164 struct bio_vec *bvec = bvec_init_iter_all(&iter_all); 287 165 288 if (index + 2 > msblk->bytes_u 166 if (index + 2 > msblk->bytes_used) { 289 res = -EIO; 167 res = -EIO; 290 goto out; 168 goto out; 291 } 169 } 292 res = squashfs_bio_read(sb, in 170 res = squashfs_bio_read(sb, index, 2, &bio, &offset); 293 if (res) 171 if (res) 294 goto out; 172 goto out; 295 173 296 if (WARN_ON_ONCE(!bio_next_seg 174 if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) { 297 res = -EIO; 175 res = -EIO; 298 goto out_free_bio; 176 goto out_free_bio; 299 } 177 } 300 /* Extract the length of the m 178 /* Extract the length of the metadata block */ 301 data = bvec_virt(bvec); 179 data = bvec_virt(bvec); 302 length = data[offset]; 180 length = data[offset]; 303 if (offset < bvec->bv_len - 1) 181 if (offset < bvec->bv_len - 1) { 304 length |= data[offset 182 length |= data[offset + 1] << 8; 305 } else { 183 } else { 306 if (WARN_ON_ONCE(!bio_ 184 if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) { 307 res = -EIO; 185 res = -EIO; 308 goto out_free_ 186 goto out_free_bio; 309 } 187 } 310 data = bvec_virt(bvec) 188 data = bvec_virt(bvec); 311 length |= data[0] << 8 189 length |= data[0] << 8; 312 } 190 } 313 bio_free_pages(bio); 191 bio_free_pages(bio); 314 bio_uninit(bio); !! 192 bio_put(bio); 315 kfree(bio); << 316 193 317 compressed = SQUASHFS_COMPRESS 194 compressed = SQUASHFS_COMPRESSED(length); 318 length = SQUASHFS_COMPRESSED_S 195 length = SQUASHFS_COMPRESSED_SIZE(length); 319 index += 2; 196 index += 2; 320 197 321 TRACE("Block @ 0x%llx, %scompr 198 TRACE("Block @ 0x%llx, %scompressed size %d\n", index - 2, 322 compressed ? "" : "un", 199 compressed ? "" : "un", length); 323 } 200 } 324 if (length <= 0 || length > output->le !! 201 if (length < 0 || length > output->length || 325 (index + length) > msb 202 (index + length) > msblk->bytes_used) { 326 res = -EIO; 203 res = -EIO; 327 goto out; 204 goto out; 328 } 205 } 329 206 330 if (next_index) 207 if (next_index) 331 *next_index = index + length; 208 *next_index = index + length; 332 209 333 res = squashfs_bio_read(sb, index, len 210 res = squashfs_bio_read(sb, index, length, &bio, &offset); 334 if (res) 211 if (res) 335 goto out; 212 goto out; 336 213 337 if (compressed) { 214 if (compressed) { 338 if (!msblk->stream) { 215 if (!msblk->stream) { 339 res = -EIO; 216 res = -EIO; 340 goto out_free_bio; 217 goto out_free_bio; 341 } 218 } 342 res = msblk->thread_ops->decom !! 219 res = squashfs_decompress(msblk, bio, offset, length, output); 343 } else { 220 } else { 344 res = copy_bio_to_actor(bio, o 221 res = copy_bio_to_actor(bio, output, offset, length); 345 } 222 } 346 223 347 out_free_bio: 224 out_free_bio: 348 bio_free_pages(bio); 225 bio_free_pages(bio); 349 bio_uninit(bio); !! 226 bio_put(bio); 350 kfree(bio); << 351 out: 227 out: 352 if (res < 0) { 228 if (res < 0) { 353 ERROR("Failed to read block 0x 229 ERROR("Failed to read block 0x%llx: %d\n", index, res); 354 if (msblk->panic_on_errors) 230 if (msblk->panic_on_errors) 355 panic("squashfs read f 231 panic("squashfs read failed"); 356 } 232 } 357 233 358 return res; 234 return res; 359 } 235 } 360 236
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.