126 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 20134 * Phillip Lougher <phillip@squashfs.org.uk>5 */6 7#include <linux/fs.h>8#include <linux/vfs.h>9#include <linux/kernel.h>10#include <linux/slab.h>11#include <linux/string.h>12#include <linux/pagemap.h>13#include <linux/mutex.h>14 15#include "squashfs_fs.h"16#include "squashfs_fs_sb.h"17#include "squashfs_fs_i.h"18#include "squashfs.h"19#include "page_actor.h"20 21/* Read separately compressed datablock directly into page cache */22int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,23 int expected)24 25{26 struct folio *folio = page_folio(target_page);27 struct inode *inode = target_page->mapping->host;28 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;29 loff_t file_end = (i_size_read(inode) - 1) >> PAGE_SHIFT;30 int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;31 loff_t start_index = folio->index & ~mask;32 loff_t end_index = start_index | mask;33 loff_t index;34 int i, pages, bytes, res = -ENOMEM;35 struct page **page, *last_page;36 struct squashfs_page_actor *actor;37 void *pageaddr;38 39 if (end_index > file_end)40 end_index = file_end;41 42 pages = end_index - start_index + 1;43 44 page = kmalloc_array(pages, sizeof(void *), GFP_KERNEL);45 if (page == NULL)46 return res;47 48 /* Try to grab all the pages covered by the Squashfs block */49 for (i = 0, index = start_index; index <= end_index; index++) {50 page[i] = (index == folio->index) ? target_page :51 grab_cache_page_nowait(target_page->mapping, index);52 53 if (page[i] == NULL)54 continue;55 56 if (PageUptodate(page[i])) {57 unlock_page(page[i]);58 put_page(page[i]);59 continue;60 }61 62 i++;63 }64 65 pages = i;66 67 /*68 * Create a "page actor" which will kmap and kunmap the69 * page cache pages appropriately within the decompressor70 */71 actor = squashfs_page_actor_init_special(msblk, page, pages, expected,72 start_index << PAGE_SHIFT);73 if (actor == NULL)74 goto out;75 76 /* Decompress directly into the page cache buffers */77 res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);78 79 last_page = squashfs_page_actor_free(actor);80 81 if (res < 0)82 goto mark_errored;83 84 if (res != expected || IS_ERR(last_page)) {85 res = -EIO;86 goto mark_errored;87 }88 89 /* Last page (if present) may have trailing bytes not filled */90 bytes = res % PAGE_SIZE;91 if (end_index == file_end && last_page && bytes) {92 pageaddr = kmap_local_page(last_page);93 memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);94 kunmap_local(pageaddr);95 }96 97 /* Mark pages as uptodate, unlock and release */98 for (i = 0; i < pages; i++) {99 flush_dcache_page(page[i]);100 SetPageUptodate(page[i]);101 unlock_page(page[i]);102 if (page[i] != target_page)103 put_page(page[i]);104 }105 106 kfree(page);107 108 return 0;109 110mark_errored:111 /* Decompression failed. Target_page is112 * dealt with by the caller113 */114 for (i = 0; i < pages; i++) {115 if (page[i] == NULL || page[i] == target_page)116 continue;117 flush_dcache_page(page[i]);118 unlock_page(page[i]);119 put_page(page[i]);120 }121 122out:123 kfree(page);124 return res;125}126