0001
0002
0003
0004
0005
0006
0007 #include <linux/fs.h>
0008 #include <linux/vfs.h>
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011 #include <linux/string.h>
0012 #include <linux/pagemap.h>
0013 #include <linux/mutex.h>
0014
0015 #include "squashfs_fs.h"
0016 #include "squashfs_fs_sb.h"
0017 #include "squashfs_fs_i.h"
0018 #include "squashfs.h"
0019 #include "page_actor.h"
0020
0021
0022 int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
0023 int expected)
0024
0025 {
0026 struct inode *inode = target_page->mapping->host;
0027 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
0028
0029 int file_end = (i_size_read(inode) - 1) >> PAGE_SHIFT;
0030 int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
0031 int start_index = target_page->index & ~mask;
0032 int end_index = start_index | mask;
0033 int i, n, pages, bytes, res = -ENOMEM;
0034 struct page **page;
0035 struct squashfs_page_actor *actor;
0036 void *pageaddr;
0037
0038 if (end_index > file_end)
0039 end_index = file_end;
0040
0041 pages = end_index - start_index + 1;
0042
0043 page = kmalloc_array(pages, sizeof(void *), GFP_KERNEL);
0044 if (page == NULL)
0045 return res;
0046
0047
0048 for (i = 0, n = start_index; n <= end_index; n++) {
0049 page[i] = (n == target_page->index) ? target_page :
0050 grab_cache_page_nowait(target_page->mapping, n);
0051
0052 if (page[i] == NULL)
0053 continue;
0054
0055 if (PageUptodate(page[i])) {
0056 unlock_page(page[i]);
0057 put_page(page[i]);
0058 continue;
0059 }
0060
0061 i++;
0062 }
0063
0064 pages = i;
0065
0066
0067
0068
0069
0070 actor = squashfs_page_actor_init_special(msblk, page, pages, expected);
0071 if (actor == NULL)
0072 goto out;
0073
0074
0075 res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
0076
0077 squashfs_page_actor_free(actor);
0078
0079 if (res < 0)
0080 goto mark_errored;
0081
0082 if (res != expected) {
0083 res = -EIO;
0084 goto mark_errored;
0085 }
0086
0087
0088 bytes = res % PAGE_SIZE;
0089 if (page[pages - 1]->index == end_index && bytes) {
0090 pageaddr = kmap_local_page(page[pages - 1]);
0091 memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);
0092 kunmap_local(pageaddr);
0093 }
0094
0095
0096 for (i = 0; i < pages; i++) {
0097 flush_dcache_page(page[i]);
0098 SetPageUptodate(page[i]);
0099 unlock_page(page[i]);
0100 if (page[i] != target_page)
0101 put_page(page[i]);
0102 }
0103
0104 kfree(page);
0105
0106 return 0;
0107
0108 mark_errored:
0109
0110
0111
0112 for (i = 0; i < pages; i++) {
0113 if (page[i] == NULL || page[i] == target_page)
0114 continue;
0115 flush_dcache_page(page[i]);
0116 SetPageError(page[i]);
0117 unlock_page(page[i]);
0118 put_page(page[i]);
0119 }
0120
0121 out:
0122 kfree(page);
0123 return res;
0124 }