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>
This commit is contained in:
parent
846b730e99
commit
5f55dbc0c5
|
@ -4,7 +4,7 @@
|
|||
|
||||
obj-$(CONFIG_SQUASHFS) += squashfs.o
|
||||
squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
|
||||
squashfs-y += namei.o super.o symlink.o decompressor.o
|
||||
squashfs-y += namei.o super.o symlink.o decompressor.o file_cache.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o
|
||||
|
|
|
@ -370,77 +370,15 @@ static int read_blocklist(struct inode *inode, int index, u64 *block)
|
|||
return le32_to_cpu(size);
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_readpage(struct file *file, struct page *page)
|
||||
/* Copy data into page cache */
|
||||
void squashfs_copy_cache(struct page *page, struct squashfs_cache_entry *buffer,
|
||||
int bytes, int offset)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int bytes, i, offset = 0, sparse = 0;
|
||||
struct squashfs_cache_entry *buffer = NULL;
|
||||
void *pageaddr;
|
||||
|
||||
int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1;
|
||||
int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
|
||||
int start_index = page->index & ~mask;
|
||||
int end_index = start_index | mask;
|
||||
int file_end = i_size_read(inode) >> msblk->block_log;
|
||||
|
||||
TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
|
||||
page->index, squashfs_i(inode)->start);
|
||||
|
||||
if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT))
|
||||
goto out;
|
||||
|
||||
if (index < file_end || squashfs_i(inode)->fragment_block ==
|
||||
SQUASHFS_INVALID_BLK) {
|
||||
/*
|
||||
* Reading a datablock from disk. Need to read block list
|
||||
* to get location and block size.
|
||||
*/
|
||||
u64 block = 0;
|
||||
int bsize = read_blocklist(inode, index, &block);
|
||||
if (bsize < 0)
|
||||
goto error_out;
|
||||
|
||||
if (bsize == 0) { /* hole */
|
||||
bytes = index == file_end ?
|
||||
(i_size_read(inode) & (msblk->block_size - 1)) :
|
||||
msblk->block_size;
|
||||
sparse = 1;
|
||||
} else {
|
||||
/*
|
||||
* Read and decompress datablock.
|
||||
*/
|
||||
buffer = squashfs_get_datablock(inode->i_sb,
|
||||
block, bsize);
|
||||
if (buffer->error) {
|
||||
ERROR("Unable to read page, block %llx, size %x"
|
||||
"\n", block, bsize);
|
||||
squashfs_cache_put(buffer);
|
||||
goto error_out;
|
||||
}
|
||||
bytes = buffer->length;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Datablock is stored inside a fragment (tail-end packed
|
||||
* block).
|
||||
*/
|
||||
buffer = squashfs_get_fragment(inode->i_sb,
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
|
||||
if (buffer->error) {
|
||||
ERROR("Unable to read page, block %llx, size %x\n",
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
squashfs_cache_put(buffer);
|
||||
goto error_out;
|
||||
}
|
||||
bytes = i_size_read(inode) & (msblk->block_size - 1);
|
||||
offset = squashfs_i(inode)->fragment_offset;
|
||||
}
|
||||
int i, mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1;
|
||||
int start_index = page->index & ~mask, end_index = start_index | mask;
|
||||
|
||||
/*
|
||||
* Loop copying datablock into pages. As the datablock likely covers
|
||||
|
@ -451,7 +389,7 @@ static int squashfs_readpage(struct file *file, struct page *page)
|
|||
for (i = start_index; i <= end_index && bytes > 0; i++,
|
||||
bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) {
|
||||
struct page *push_page;
|
||||
int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE);
|
||||
int avail = buffer ? min_t(int, bytes, PAGE_CACHE_SIZE) : 0;
|
||||
|
||||
TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
|
||||
|
||||
|
@ -475,11 +413,75 @@ static int squashfs_readpage(struct file *file, struct page *page)
|
|||
if (i != page->index)
|
||||
page_cache_release(push_page);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sparse)
|
||||
squashfs_cache_put(buffer);
|
||||
/* Read datablock stored packed inside a fragment (tail-end packed block) */
|
||||
static int squashfs_readpage_fragment(struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
int res = buffer->error;
|
||||
|
||||
if (res)
|
||||
ERROR("Unable to read page, block %llx, size %x\n",
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
else
|
||||
squashfs_copy_cache(page, buffer, i_size_read(inode) &
|
||||
(msblk->block_size - 1),
|
||||
squashfs_i(inode)->fragment_offset);
|
||||
|
||||
squashfs_cache_put(buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int squashfs_readpage_sparse(struct page *page, int index, int file_end)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int bytes = index == file_end ?
|
||||
(i_size_read(inode) & (msblk->block_size - 1)) :
|
||||
msblk->block_size;
|
||||
|
||||
squashfs_copy_cache(page, NULL, bytes, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int squashfs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
|
||||
int file_end = i_size_read(inode) >> msblk->block_log;
|
||||
int res;
|
||||
void *pageaddr;
|
||||
|
||||
TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
|
||||
page->index, squashfs_i(inode)->start);
|
||||
|
||||
if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT))
|
||||
goto out;
|
||||
|
||||
if (index < file_end || squashfs_i(inode)->fragment_block ==
|
||||
SQUASHFS_INVALID_BLK) {
|
||||
u64 block = 0;
|
||||
int bsize = read_blocklist(inode, index, &block);
|
||||
if (bsize < 0)
|
||||
goto error_out;
|
||||
|
||||
if (bsize == 0)
|
||||
res = squashfs_readpage_sparse(page, index, file_end);
|
||||
else
|
||||
res = squashfs_readpage_block(page, block, bsize);
|
||||
} else
|
||||
res = squashfs_readpage_fragment(page);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
SetPageError(page);
|
||||
|
|
38
fs/squashfs/file_cache.c
Normal file
38
fs/squashfs/file_cache.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/* Read separately compressed datablock and memcopy into page cache */
|
||||
int squashfs_readpage_block(struct page *page, u64 block, int bsize)
|
||||
{
|
||||
struct inode *i = page->mapping->host;
|
||||
struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
|
||||
block, bsize);
|
||||
int res = buffer->error;
|
||||
|
||||
if (res)
|
||||
ERROR("Unable to read page, block %llx, size %x\n", block,
|
||||
bsize);
|
||||
else
|
||||
squashfs_copy_cache(page, buffer, buffer->length, 0);
|
||||
|
||||
squashfs_cache_put(buffer);
|
||||
return res;
|
||||
}
|
|
@ -66,6 +66,13 @@ extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *);
|
|||
extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
|
||||
u64, u64, unsigned int);
|
||||
|
||||
/* file.c */
|
||||
void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int,
|
||||
int);
|
||||
|
||||
/* file_xxx.c */
|
||||
extern int squashfs_readpage_block(struct page *, u64, int);
|
||||
|
||||
/* id.c */
|
||||
extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
|
||||
extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64,
|
||||
|
|
Loading…
Reference in New Issue
Block a user