diff options
author | Phillip Lougher <phillip@squashfs.org.uk> | 2013-10-31 15:24:27 -0400 |
---|---|---|
committer | Phillip Lougher <phillip@squashfs.org.uk> | 2013-11-19 22:59:07 -0500 |
commit | 5f55dbc0c5c466a9cdfa4da7ac1bfe351c7fc52a (patch) | |
tree | dccfe66c090bfd05c75f5d6a1cc31bf138bd76b1 | |
parent | 846b730e99518a1c9945afcb2afbe4d08a02ed80 (diff) |
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>
-rw-r--r-- | fs/squashfs/Makefile | 2 | ||||
-rw-r--r-- | fs/squashfs/file.c | 142 | ||||
-rw-r--r-- | fs/squashfs/file_cache.c | 38 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 7 |
4 files changed, 118 insertions, 71 deletions
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 5833b96ee69c..e01ba1126c89 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_SQUASHFS) += squashfs.o | 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o |
6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | 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 | squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o | 8 | squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o |
9 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o | 9 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o |
10 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o | 10 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o |
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index 8ca62c28fe12..e5c9689062ba 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c | |||
@@ -370,77 +370,15 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) | |||
370 | return le32_to_cpu(size); | 370 | return le32_to_cpu(size); |
371 | } | 371 | } |
372 | 372 | ||
373 | 373 | /* Copy data into page cache */ | |
374 | static int squashfs_readpage(struct file *file, struct page *page) | 374 | void squashfs_copy_cache(struct page *page, struct squashfs_cache_entry *buffer, |
375 | int bytes, int offset) | ||
375 | { | 376 | { |
376 | struct inode *inode = page->mapping->host; | 377 | struct inode *inode = page->mapping->host; |
377 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | 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 | void *pageaddr; | 379 | void *pageaddr; |
381 | 380 | int i, mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | |
382 | int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | 381 | int start_index = page->index & ~mask, end_index = start_index | mask; |
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 | } | ||
444 | 382 | ||
445 | /* | 383 | /* |
446 | * Loop copying datablock into pages. As the datablock likely covers | 384 | * Loop copying datablock into pages. As the datablock likely covers |
@@ -451,7 +389,7 @@ static int squashfs_readpage(struct file *file, struct page *page) | |||
451 | for (i = start_index; i <= end_index && bytes > 0; i++, | 389 | for (i = start_index; i <= end_index && bytes > 0; i++, |
452 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { | 390 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { |
453 | struct page *push_page; | 391 | struct page *push_page; |
454 | int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE); | 392 | int avail = buffer ? min_t(int, bytes, PAGE_CACHE_SIZE) : 0; |
455 | 393 | ||
456 | TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); | 394 | TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); |
457 | 395 | ||
@@ -475,11 +413,75 @@ skip_page: | |||
475 | if (i != page->index) | 413 | if (i != page->index) |
476 | page_cache_release(push_page); | 414 | page_cache_release(push_page); |
477 | } | 415 | } |
416 | } | ||
417 | |||
418 | /* Read datablock stored packed inside a fragment (tail-end packed block) */ | ||
419 | static int squashfs_readpage_fragment(struct page *page) | ||
420 | { | ||
421 | struct inode *inode = page->mapping->host; | ||
422 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
423 | struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb, | ||
424 | squashfs_i(inode)->fragment_block, | ||
425 | squashfs_i(inode)->fragment_size); | ||
426 | int res = buffer->error; | ||
427 | |||
428 | if (res) | ||
429 | ERROR("Unable to read page, block %llx, size %x\n", | ||
430 | squashfs_i(inode)->fragment_block, | ||
431 | squashfs_i(inode)->fragment_size); | ||
432 | else | ||
433 | squashfs_copy_cache(page, buffer, i_size_read(inode) & | ||
434 | (msblk->block_size - 1), | ||
435 | squashfs_i(inode)->fragment_offset); | ||
436 | |||
437 | squashfs_cache_put(buffer); | ||
438 | return res; | ||
439 | } | ||
478 | 440 | ||
479 | if (!sparse) | 441 | static int squashfs_readpage_sparse(struct page *page, int index, int file_end) |
480 | squashfs_cache_put(buffer); | 442 | { |
443 | struct inode *inode = page->mapping->host; | ||
444 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
445 | int bytes = index == file_end ? | ||
446 | (i_size_read(inode) & (msblk->block_size - 1)) : | ||
447 | msblk->block_size; | ||
481 | 448 | ||
449 | squashfs_copy_cache(page, NULL, bytes, 0); | ||
482 | return 0; | 450 | return 0; |
451 | } | ||
452 | |||
453 | static int squashfs_readpage(struct file *file, struct page *page) | ||
454 | { | ||
455 | struct inode *inode = page->mapping->host; | ||
456 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
457 | int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); | ||
458 | int file_end = i_size_read(inode) >> msblk->block_log; | ||
459 | int res; | ||
460 | void *pageaddr; | ||
461 | |||
462 | TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", | ||
463 | page->index, squashfs_i(inode)->start); | ||
464 | |||
465 | if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
466 | PAGE_CACHE_SHIFT)) | ||
467 | goto out; | ||
468 | |||
469 | if (index < file_end || squashfs_i(inode)->fragment_block == | ||
470 | SQUASHFS_INVALID_BLK) { | ||
471 | u64 block = 0; | ||
472 | int bsize = read_blocklist(inode, index, &block); | ||
473 | if (bsize < 0) | ||
474 | goto error_out; | ||
475 | |||
476 | if (bsize == 0) | ||
477 | res = squashfs_readpage_sparse(page, index, file_end); | ||
478 | else | ||
479 | res = squashfs_readpage_block(page, block, bsize); | ||
480 | } else | ||
481 | res = squashfs_readpage_fragment(page); | ||
482 | |||
483 | if (!res) | ||
484 | return 0; | ||
483 | 485 | ||
484 | error_out: | 486 | error_out: |
485 | SetPageError(page); | 487 | SetPageError(page); |
diff --git a/fs/squashfs/file_cache.c b/fs/squashfs/file_cache.c new file mode 100644 index 000000000000..f2310d2a2019 --- /dev/null +++ b/fs/squashfs/file_cache.c | |||
@@ -0,0 +1,38 @@ | |||
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 | } | ||
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 6a97e63ca173..9e1bb79f7e6f 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
@@ -66,6 +66,13 @@ extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); | |||
66 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, | 66 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, |
67 | u64, u64, unsigned int); | 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 | /* id.c */ | 76 | /* id.c */ |
70 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | 77 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); |
71 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, | 78 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, |