Blame view
fs/squashfs/block.c
4.94 KB
68252eb5f treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
e2780ab15 Squashfs: block o... |
2 3 4 5 |
/* * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
d7f2ff671 Squashfs: update ... |
6 |
* Phillip Lougher <phillip@squashfs.org.uk> |
e2780ab15 Squashfs: block o... |
7 |
* |
e2780ab15 Squashfs: block o... |
8 9 10 11 12 13 14 15 16 17 18 |
* block.c */ /* * This file implements the low-level routines to read and decompress * datablocks and metadata blocks. */ #include <linux/fs.h> #include <linux/vfs.h> #include <linux/slab.h> |
e2780ab15 Squashfs: block o... |
19 20 |
#include <linux/string.h> #include <linux/buffer_head.h> |
2f8b54447 block,fs: untangl... |
21 |
#include <linux/bio.h> |
e2780ab15 Squashfs: block o... |
22 23 24 |
#include "squashfs_fs.h" #include "squashfs_fs_sb.h" |
e2780ab15 Squashfs: block o... |
25 |
#include "squashfs.h" |
4c0f0bb23 Squashfs: add a d... |
26 |
#include "decompressor.h" |
846b730e9 Squashfs: General... |
27 |
#include "page_actor.h" |
e2780ab15 Squashfs: block o... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
/* * Read the metadata block length, this is stored in the first two * bytes of the metadata block. */ static struct buffer_head *get_block_length(struct super_block *sb, u64 *cur_index, int *offset, int *length) { struct squashfs_sb_info *msblk = sb->s_fs_info; struct buffer_head *bh; bh = sb_bread(sb, *cur_index); if (bh == NULL) return NULL; if (msblk->devblksize - *offset == 1) { *length = (unsigned char) bh->b_data[*offset]; put_bh(bh); bh = sb_bread(sb, ++(*cur_index)); if (bh == NULL) return NULL; *length |= (unsigned char) bh->b_data[0] << 8; *offset = 1; } else { *length = (unsigned char) bh->b_data[*offset] | (unsigned char) bh->b_data[*offset + 1] << 8; *offset += 2; |
3689456b4 squashfs: fix use... |
55 56 57 58 59 60 61 62 |
if (*offset == msblk->devblksize) { put_bh(bh); bh = sb_bread(sb, ++(*cur_index)); if (bh == NULL) return NULL; *offset = 0; } |
e2780ab15 Squashfs: block o... |
63 64 65 66 67 68 69 70 71 72 73 74 |
} return bh; } /* * Read and decompress a metadata block or datablock. Length is non-zero * if a datablock is being read (the size is stored elsewhere in the * filesystem), otherwise the length is obtained from the first two bytes of * the metadata block. A bit in the length field indicates if the block * is stored uncompressed in the filesystem (usually because compression |
ec9267b61 Squashfs: update ... |
75 76 |
* generated a larger block - this does occasionally happen with compression * algorithms). |
e2780ab15 Squashfs: block o... |
77 |
*/ |
846b730e9 Squashfs: General... |
78 79 |
int squashfs_read_data(struct super_block *sb, u64 index, int length, u64 *next_index, struct squashfs_page_actor *output) |
e2780ab15 Squashfs: block o... |
80 81 82 83 84 |
{ struct squashfs_sb_info *msblk = sb->s_fs_info; struct buffer_head **bh; int offset = index & ((1 << msblk->devblksize_log2) - 1); u64 cur_index = index >> msblk->devblksize_log2; |
846b730e9 Squashfs: General... |
85 |
int bytes, compressed, b = 0, k = 0, avail, i; |
e2780ab15 Squashfs: block o... |
86 |
|
846b730e9 Squashfs: General... |
87 |
bh = kcalloc(((output->length + msblk->devblksize - 1) |
e0d1f7001 squashfs: fix pot... |
88 |
>> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); |
e2780ab15 Squashfs: block o... |
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
if (bh == NULL) return -ENOMEM; if (length) { /* * Datablock. */ bytes = -offset; compressed = SQUASHFS_COMPRESSED_BLOCK(length); length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); if (next_index) *next_index = index + length; TRACE("Block @ 0x%llx, %scompressed size %d, src size %d ", |
846b730e9 Squashfs: General... |
104 |
index, compressed ? "" : "un", length, output->length); |
e2780ab15 Squashfs: block o... |
105 |
|
846b730e9 Squashfs: General... |
106 |
if (length < 0 || length > output->length || |
e2780ab15 Squashfs: block o... |
107 108 109 110 111 112 113 114 115 |
(index + length) > msblk->bytes_used) goto read_failure; for (b = 0; bytes < length; b++, cur_index++) { bh[b] = sb_getblk(sb, cur_index); if (bh[b] == NULL) goto block_release; bytes += msblk->devblksize; } |
dfec8a14f fs: have ll_rw_bl... |
116 |
ll_rw_block(REQ_OP_READ, 0, b, bh); |
e2780ab15 Squashfs: block o... |
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
} else { /* * Metadata block. */ if ((index + 2) > msblk->bytes_used) goto read_failure; bh[0] = get_block_length(sb, &cur_index, &offset, &length); if (bh[0] == NULL) goto read_failure; b = 1; bytes = msblk->devblksize - offset; compressed = SQUASHFS_COMPRESSED(length); length = SQUASHFS_COMPRESSED_SIZE(length); if (next_index) *next_index = index + length + 2; TRACE("Block @ 0x%llx, %scompressed size %d ", index, compressed ? "" : "un", length); |
846b730e9 Squashfs: General... |
138 |
if (length < 0 || length > output->length || |
e2780ab15 Squashfs: block o... |
139 140 141 142 143 144 145 146 147 |
(index + length) > msblk->bytes_used) goto block_release; for (; bytes < length; b++) { bh[b] = sb_getblk(sb, ++cur_index); if (bh[b] == NULL) goto block_release; bytes += msblk->devblksize; } |
dfec8a14f fs: have ll_rw_bl... |
148 |
ll_rw_block(REQ_OP_READ, 0, b - 1, bh + 1); |
e2780ab15 Squashfs: block o... |
149 |
} |
9508c6b90 Squashfs: Refacto... |
150 151 152 153 154 |
for (i = 0; i < b; i++) { wait_on_buffer(bh[i]); if (!buffer_uptodate(bh[i])) goto block_release; } |
e2780ab15 Squashfs: block o... |
155 |
if (compressed) { |
d51258478 squashfs: more me... |
156 157 |
if (!msblk->stream) goto read_failure; |
846b730e9 Squashfs: General... |
158 159 |
length = squashfs_decompress(msblk, bh, b, offset, length, output); |
e6a6d3795 Squashfs: move zl... |
160 161 |
if (length < 0) goto read_failure; |
e2780ab15 Squashfs: block o... |
162 163 164 165 |
} else { /* * Block is uncompressed. */ |
e0125262a Squashfs: Optimiz... |
166 |
int in, pg_offset = 0; |
846b730e9 Squashfs: General... |
167 |
void *data = squashfs_first_page(output); |
e2780ab15 Squashfs: block o... |
168 169 170 171 172 |
for (bytes = length; k < b; k++) { in = min(bytes, msblk->devblksize - offset); bytes -= in; while (in) { |
09cbfeaf1 mm, fs: get rid o... |
173 |
if (pg_offset == PAGE_SIZE) { |
846b730e9 Squashfs: General... |
174 |
data = squashfs_next_page(output); |
e2780ab15 Squashfs: block o... |
175 176 |
pg_offset = 0; } |
09cbfeaf1 mm, fs: get rid o... |
177 |
avail = min_t(int, in, PAGE_SIZE - |
e2780ab15 Squashfs: block o... |
178 |
pg_offset); |
846b730e9 Squashfs: General... |
179 180 |
memcpy(data + pg_offset, bh[k]->b_data + offset, avail); |
e2780ab15 Squashfs: block o... |
181 182 183 184 185 186 187 |
in -= avail; pg_offset += avail; offset += avail; } offset = 0; put_bh(bh[k]); } |
846b730e9 Squashfs: General... |
188 |
squashfs_finish_page(output); |
e2780ab15 Squashfs: block o... |
189 190 191 192 |
} kfree(bh); return length; |
e2780ab15 Squashfs: block o... |
193 194 195 196 197 |
block_release: for (; k < b; k++) put_bh(bh[k]); read_failure: |
118e1ef6f Squashfs: Fix oop... |
198 199 200 |
ERROR("squashfs_read_data failed to read block 0x%llx ", (unsigned long long) index); |
e2780ab15 Squashfs: block o... |
201 202 203 |
kfree(bh); return -EIO; } |