File Index
Files and directories
Sign in
FILE

file_direct.c

File preview with syntax highlighting.

linux-6.19.14/fs/squashfs/file_direct.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2013
  4 * 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 folio *folio, u64 block, int bsize,
 23		int expected)
 24{
 25	struct page *target_page = &folio->page;
 26	struct inode *inode = folio->mapping->host;
 27	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
 28	loff_t file_end = (i_size_read(inode) - 1) >> PAGE_SHIFT;
 29	int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
 30	loff_t start_index = folio->index & ~mask;
 31	loff_t end_index = start_index | mask;
 32	loff_t index;
 33	int i, pages, bytes, res = -ENOMEM;
 34	struct page **page, *last_page;
 35	struct squashfs_page_actor *actor;
 36	void *pageaddr;
 37
 38	if (end_index > file_end)
 39		end_index = file_end;
 40
 41	pages = end_index - start_index + 1;
 42
 43	page = kmalloc_array(pages, sizeof(void *), GFP_KERNEL);
 44	if (page == NULL)
 45		return res;
 46
 47	/* Try to grab all the pages covered by the Squashfs block */
 48	for (i = 0, index = start_index; index <= end_index; index++) {
 49		page[i] = (index == folio->index) ? target_page :
 50			grab_cache_page_nowait(folio->mapping, index);
 51
 52		if (page[i] == NULL)
 53			continue;
 54
 55		if (PageUptodate(page[i])) {
 56			unlock_page(page[i]);
 57			put_page(page[i]);
 58			continue;
 59		}
 60
 61		i++;
 62	}
 63
 64	pages = i;
 65
 66	/*
 67	 * Create a "page actor" which will kmap and kunmap the
 68	 * page cache pages appropriately within the decompressor
 69	 */
 70	actor = squashfs_page_actor_init_special(msblk, page, pages, expected,
 71						start_index << PAGE_SHIFT);
 72	if (actor == NULL)
 73		goto out;
 74
 75	/* Decompress directly into the page cache buffers */
 76	res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
 77
 78	last_page = squashfs_page_actor_free(actor);
 79
 80	if (res < 0)
 81		goto mark_errored;
 82
 83	if (res != expected || IS_ERR(last_page)) {
 84		res = -EIO;
 85		goto mark_errored;
 86	}
 87
 88	/* Last page (if present) may have trailing bytes not filled */
 89	bytes = res % PAGE_SIZE;
 90	if (end_index == file_end && last_page && bytes) {
 91		pageaddr = kmap_local_page(last_page);
 92		memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);
 93		kunmap_local(pageaddr);
 94	}
 95
 96	/* Mark pages as uptodate, unlock and release */
 97	for (i = 0; i < pages; i++) {
 98		flush_dcache_page(page[i]);
 99		SetPageUptodate(page[i]);
100		unlock_page(page[i]);
101		if (page[i] != target_page)
102			put_page(page[i]);
103	}
104
105	kfree(page);
106
107	return 0;
108
109mark_errored:
110	/* Decompression failed.  Target_page is
111	 * dealt with by the caller
112	 */
113	for (i = 0; i < pages; i++) {
114		if (page[i] == NULL || page[i] == target_page)
115			continue;
116		flush_dcache_page(page[i]);
117		unlock_page(page[i]);
118		put_page(page[i]);
119	}
120
121out:
122	kfree(page);
123	return res;
124}
~/ Read-only file preview.