Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Squashfs: Restructure squashfs_readpage()

Restructure squashfs_readpage() splitting it into separate
functions for datablocks, fragments and sparse blocks.

Move the memcpying (from squashfs cache entry) implementation of
squashfs_readpage_block into file_cache.c

This allows different implementations to be supported.

Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
Reviewed-by: Minchan Kim <minchan@kernel.org>

+118 -71
+1 -1
fs/squashfs/Makefile
··· 4 4 5 5 obj-$(CONFIG_SQUASHFS) += squashfs.o 6 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 7 - squashfs-y += namei.o super.o symlink.o decompressor.o 7 + squashfs-y += namei.o super.o symlink.o decompressor.o file_cache.o 8 8 squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o 9 9 squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o 10 10 squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o
+72 -70
fs/squashfs/file.c
··· 370 370 return le32_to_cpu(size); 371 371 } 372 372 373 - 374 - static int squashfs_readpage(struct file *file, struct page *page) 373 + /* Copy data into page cache */ 374 + void squashfs_copy_cache(struct page *page, struct squashfs_cache_entry *buffer, 375 + int bytes, int offset) 375 376 { 376 377 struct inode *inode = page->mapping->host; 377 378 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 378 - int bytes, i, offset = 0, sparse = 0; 379 - struct squashfs_cache_entry *buffer = NULL; 380 379 void *pageaddr; 381 - 382 - int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; 383 - int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); 384 - int start_index = page->index & ~mask; 385 - int end_index = start_index | mask; 386 - int file_end = i_size_read(inode) >> msblk->block_log; 387 - 388 - TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", 389 - page->index, squashfs_i(inode)->start); 390 - 391 - if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> 392 - PAGE_CACHE_SHIFT)) 393 - goto out; 394 - 395 - if (index < file_end || squashfs_i(inode)->fragment_block == 396 - SQUASHFS_INVALID_BLK) { 397 - /* 398 - * Reading a datablock from disk. Need to read block list 399 - * to get location and block size. 400 - */ 401 - u64 block = 0; 402 - int bsize = read_blocklist(inode, index, &block); 403 - if (bsize < 0) 404 - goto error_out; 405 - 406 - if (bsize == 0) { /* hole */ 407 - bytes = index == file_end ? 408 - (i_size_read(inode) & (msblk->block_size - 1)) : 409 - msblk->block_size; 410 - sparse = 1; 411 - } else { 412 - /* 413 - * Read and decompress datablock. 414 - */ 415 - buffer = squashfs_get_datablock(inode->i_sb, 416 - block, bsize); 417 - if (buffer->error) { 418 - ERROR("Unable to read page, block %llx, size %x" 419 - "\n", block, bsize); 420 - squashfs_cache_put(buffer); 421 - goto error_out; 422 - } 423 - bytes = buffer->length; 424 - } 425 - } else { 426 - /* 427 - * Datablock is stored inside a fragment (tail-end packed 428 - * block). 429 - */ 430 - buffer = squashfs_get_fragment(inode->i_sb, 431 - squashfs_i(inode)->fragment_block, 432 - squashfs_i(inode)->fragment_size); 433 - 434 - if (buffer->error) { 435 - ERROR("Unable to read page, block %llx, size %x\n", 436 - squashfs_i(inode)->fragment_block, 437 - squashfs_i(inode)->fragment_size); 438 - squashfs_cache_put(buffer); 439 - goto error_out; 440 - } 441 - bytes = i_size_read(inode) & (msblk->block_size - 1); 442 - offset = squashfs_i(inode)->fragment_offset; 443 - } 380 + int i, mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; 381 + int start_index = page->index & ~mask, end_index = start_index | mask; 444 382 445 383 /* 446 384 * Loop copying datablock into pages. As the datablock likely covers ··· 389 451 for (i = start_index; i <= end_index && bytes > 0; i++, 390 452 bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { 391 453 struct page *push_page; 392 - int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE); 454 + int avail = buffer ? min_t(int, bytes, PAGE_CACHE_SIZE) : 0; 393 455 394 456 TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); 395 457 ··· 413 475 if (i != page->index) 414 476 page_cache_release(push_page); 415 477 } 478 + } 416 479 417 - if (!sparse) 418 - squashfs_cache_put(buffer); 480 + /* Read datablock stored packed inside a fragment (tail-end packed block) */ 481 + static int squashfs_readpage_fragment(struct page *page) 482 + { 483 + struct inode *inode = page->mapping->host; 484 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 485 + struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb, 486 + squashfs_i(inode)->fragment_block, 487 + squashfs_i(inode)->fragment_size); 488 + int res = buffer->error; 419 489 490 + if (res) 491 + ERROR("Unable to read page, block %llx, size %x\n", 492 + squashfs_i(inode)->fragment_block, 493 + squashfs_i(inode)->fragment_size); 494 + else 495 + squashfs_copy_cache(page, buffer, i_size_read(inode) & 496 + (msblk->block_size - 1), 497 + squashfs_i(inode)->fragment_offset); 498 + 499 + squashfs_cache_put(buffer); 500 + return res; 501 + } 502 + 503 + static int squashfs_readpage_sparse(struct page *page, int index, int file_end) 504 + { 505 + struct inode *inode = page->mapping->host; 506 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 507 + int bytes = index == file_end ? 508 + (i_size_read(inode) & (msblk->block_size - 1)) : 509 + msblk->block_size; 510 + 511 + squashfs_copy_cache(page, NULL, bytes, 0); 420 512 return 0; 513 + } 514 + 515 + static int squashfs_readpage(struct file *file, struct page *page) 516 + { 517 + struct inode *inode = page->mapping->host; 518 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 519 + int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); 520 + int file_end = i_size_read(inode) >> msblk->block_log; 521 + int res; 522 + void *pageaddr; 523 + 524 + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", 525 + page->index, squashfs_i(inode)->start); 526 + 527 + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> 528 + PAGE_CACHE_SHIFT)) 529 + goto out; 530 + 531 + if (index < file_end || squashfs_i(inode)->fragment_block == 532 + SQUASHFS_INVALID_BLK) { 533 + u64 block = 0; 534 + int bsize = read_blocklist(inode, index, &block); 535 + if (bsize < 0) 536 + goto error_out; 537 + 538 + if (bsize == 0) 539 + res = squashfs_readpage_sparse(page, index, file_end); 540 + else 541 + res = squashfs_readpage_block(page, block, bsize); 542 + } else 543 + res = squashfs_readpage_fragment(page); 544 + 545 + if (!res) 546 + return 0; 421 547 422 548 error_out: 423 549 SetPageError(page);
+38
fs/squashfs/file_cache.c
··· 1 + /* 2 + * Copyright (c) 2013 3 + * Phillip Lougher <phillip@squashfs.org.uk> 4 + * 5 + * This work is licensed under the terms of the GNU GPL, version 2. See 6 + * the COPYING file in the top-level directory. 7 + */ 8 + 9 + #include <linux/fs.h> 10 + #include <linux/vfs.h> 11 + #include <linux/kernel.h> 12 + #include <linux/slab.h> 13 + #include <linux/string.h> 14 + #include <linux/pagemap.h> 15 + #include <linux/mutex.h> 16 + 17 + #include "squashfs_fs.h" 18 + #include "squashfs_fs_sb.h" 19 + #include "squashfs_fs_i.h" 20 + #include "squashfs.h" 21 + 22 + /* Read separately compressed datablock and memcopy into page cache */ 23 + int squashfs_readpage_block(struct page *page, u64 block, int bsize) 24 + { 25 + struct inode *i = page->mapping->host; 26 + struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb, 27 + block, bsize); 28 + int res = buffer->error; 29 + 30 + if (res) 31 + ERROR("Unable to read page, block %llx, size %x\n", block, 32 + bsize); 33 + else 34 + squashfs_copy_cache(page, buffer, buffer->length, 0); 35 + 36 + squashfs_cache_put(buffer); 37 + return res; 38 + }
+7
fs/squashfs/squashfs.h
··· 66 66 extern __le64 *squashfs_read_fragment_index_table(struct super_block *, 67 67 u64, u64, unsigned int); 68 68 69 + /* file.c */ 70 + void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int, 71 + int); 72 + 73 + /* file_xxx.c */ 74 + extern int squashfs_readpage_block(struct page *, u64, int); 75 + 69 76 /* id.c */ 70 77 extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); 71 78 extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64,