aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhillip Lougher <phillip@squashfs.org.uk>2013-10-31 15:24:27 -0400
committerPhillip Lougher <phillip@squashfs.org.uk>2013-11-19 22:59:07 -0500
commit5f55dbc0c5c466a9cdfa4da7ac1bfe351c7fc52a (patch)
treedccfe66c090bfd05c75f5d6a1cc31bf138bd76b1
parent846b730e99518a1c9945afcb2afbe4d08a02ed80 (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/Makefile2
-rw-r--r--fs/squashfs/file.c142
-rw-r--r--fs/squashfs/file_cache.c38
-rw-r--r--fs/squashfs/squashfs.h7
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
5obj-$(CONFIG_SQUASHFS) += squashfs.o 5obj-$(CONFIG_SQUASHFS) += squashfs.o
6squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 6squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
7squashfs-y += namei.o super.o symlink.o decompressor.o 7squashfs-y += namei.o super.o symlink.o decompressor.o file_cache.o
8squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o 8squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o
9squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o 9squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o
10squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o 10squashfs-$(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 */
374static int squashfs_readpage(struct file *file, struct page *page) 374void 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) */
419static 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) 441static 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
453static 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
484error_out: 486error_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 */
23int 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 *);
66extern __le64 *squashfs_read_fragment_index_table(struct super_block *, 66extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
67 u64, u64, unsigned int); 67 u64, u64, unsigned int);
68 68
69/* file.c */
70void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int,
71 int);
72
73/* file_xxx.c */
74extern int squashfs_readpage_block(struct page *, u64, int);
75
69/* id.c */ 76/* id.c */
70extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); 77extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
71extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, 78extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64,