hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/fs/squashfs/block.c
....@@ -1,22 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Squashfs - a compressed read only filesystem for Linux
34 *
45 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
56 * Phillip Lougher <phillip@squashfs.org.uk>
6
- *
7
- * This program is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU General Public License
9
- * as published by the Free Software Foundation; either version 2,
10
- * or (at your option) any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License
18
- * along with this program; if not, write to the Free Software
19
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
207 *
218 * block.c
229 */
....@@ -26,6 +13,7 @@
2613 * datablocks and metadata blocks.
2714 */
2815
16
+#include <linux/blkdev.h>
2917 #include <linux/fs.h>
3018 #include <linux/vfs.h>
3119 #include <linux/slab.h>
....@@ -40,44 +28,107 @@
4028 #include "page_actor.h"
4129
4230 /*
43
- * Read the metadata block length, this is stored in the first two
44
- * bytes of the metadata block.
31
+ * Returns the amount of bytes copied to the page actor.
4532 */
46
-static struct buffer_head *get_block_length(struct super_block *sb,
47
- u64 *cur_index, int *offset, int *length)
33
+static int copy_bio_to_actor(struct bio *bio,
34
+ struct squashfs_page_actor *actor,
35
+ int offset, int req_length)
4836 {
49
- struct squashfs_sb_info *msblk = sb->s_fs_info;
50
- struct buffer_head *bh;
37
+ void *actor_addr = squashfs_first_page(actor);
38
+ struct bvec_iter_all iter_all = {};
39
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
40
+ int copied_bytes = 0;
41
+ int actor_offset = 0;
5142
52
- bh = sb_bread(sb, *cur_index);
53
- if (bh == NULL)
54
- return NULL;
43
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all)))
44
+ return 0;
5545
56
- if (msblk->devblksize - *offset == 1) {
57
- *length = (unsigned char) bh->b_data[*offset];
58
- put_bh(bh);
59
- bh = sb_bread(sb, ++(*cur_index));
60
- if (bh == NULL)
61
- return NULL;
62
- *length |= (unsigned char) bh->b_data[0] << 8;
63
- *offset = 1;
64
- } else {
65
- *length = (unsigned char) bh->b_data[*offset] |
66
- (unsigned char) bh->b_data[*offset + 1] << 8;
67
- *offset += 2;
46
+ while (copied_bytes < req_length) {
47
+ int bytes_to_copy = min_t(int, bvec->bv_len - offset,
48
+ PAGE_SIZE - actor_offset);
6849
69
- if (*offset == msblk->devblksize) {
70
- put_bh(bh);
71
- bh = sb_bread(sb, ++(*cur_index));
72
- if (bh == NULL)
73
- return NULL;
74
- *offset = 0;
50
+ bytes_to_copy = min_t(int, bytes_to_copy,
51
+ req_length - copied_bytes);
52
+ memcpy(actor_addr + actor_offset,
53
+ page_address(bvec->bv_page) + bvec->bv_offset + offset,
54
+ bytes_to_copy);
55
+
56
+ actor_offset += bytes_to_copy;
57
+ copied_bytes += bytes_to_copy;
58
+ offset += bytes_to_copy;
59
+
60
+ if (actor_offset >= PAGE_SIZE) {
61
+ actor_addr = squashfs_next_page(actor);
62
+ if (!actor_addr)
63
+ break;
64
+ actor_offset = 0;
65
+ }
66
+ if (offset >= bvec->bv_len) {
67
+ if (!bio_next_segment(bio, &iter_all))
68
+ break;
69
+ offset = 0;
7570 }
7671 }
77
-
78
- return bh;
72
+ squashfs_finish_page(actor);
73
+ return copied_bytes;
7974 }
8075
76
+static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
77
+ struct bio **biop, int *block_offset)
78
+{
79
+ struct squashfs_sb_info *msblk = sb->s_fs_info;
80
+ const u64 read_start = round_down(index, msblk->devblksize);
81
+ const sector_t block = read_start >> msblk->devblksize_log2;
82
+ const u64 read_end = round_up(index + length, msblk->devblksize);
83
+ const sector_t block_end = read_end >> msblk->devblksize_log2;
84
+ int offset = read_start - round_down(index, PAGE_SIZE);
85
+ int total_len = (block_end - block) << msblk->devblksize_log2;
86
+ const int page_count = DIV_ROUND_UP(total_len + offset, PAGE_SIZE);
87
+ int error, i;
88
+ struct bio *bio;
89
+
90
+ if (page_count <= BIO_MAX_PAGES)
91
+ bio = bio_alloc(GFP_NOIO, page_count);
92
+ else
93
+ bio = bio_kmalloc(GFP_NOIO, page_count);
94
+
95
+ if (!bio)
96
+ return -ENOMEM;
97
+
98
+ bio_set_dev(bio, sb->s_bdev);
99
+ bio->bi_opf = READ;
100
+ bio->bi_iter.bi_sector = block * (msblk->devblksize >> SECTOR_SHIFT);
101
+
102
+ for (i = 0; i < page_count; ++i) {
103
+ unsigned int len =
104
+ min_t(unsigned int, PAGE_SIZE - offset, total_len);
105
+ struct page *page = alloc_page(GFP_NOIO);
106
+
107
+ if (!page) {
108
+ error = -ENOMEM;
109
+ goto out_free_bio;
110
+ }
111
+ if (!bio_add_page(bio, page, len, offset)) {
112
+ error = -EIO;
113
+ goto out_free_bio;
114
+ }
115
+ offset = 0;
116
+ total_len -= len;
117
+ }
118
+
119
+ error = submit_bio_wait(bio);
120
+ if (error)
121
+ goto out_free_bio;
122
+
123
+ *biop = bio;
124
+ *block_offset = index & ((1 << msblk->devblksize_log2) - 1);
125
+ return 0;
126
+
127
+out_free_bio:
128
+ bio_free_pages(bio);
129
+ bio_put(bio);
130
+ return error;
131
+}
81132
82133 /*
83134 * Read and decompress a metadata block or datablock. Length is non-zero
....@@ -89,129 +140,94 @@
89140 * algorithms).
90141 */
91142 int squashfs_read_data(struct super_block *sb, u64 index, int length,
92
- u64 *next_index, struct squashfs_page_actor *output)
143
+ u64 *next_index, struct squashfs_page_actor *output)
93144 {
94145 struct squashfs_sb_info *msblk = sb->s_fs_info;
95
- struct buffer_head **bh;
96
- int offset = index & ((1 << msblk->devblksize_log2) - 1);
97
- u64 cur_index = index >> msblk->devblksize_log2;
98
- int bytes, compressed, b = 0, k = 0, avail, i;
99
-
100
- bh = kcalloc(((output->length + msblk->devblksize - 1)
101
- >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
102
- if (bh == NULL)
103
- return -ENOMEM;
146
+ struct bio *bio = NULL;
147
+ int compressed;
148
+ int res;
149
+ int offset;
104150
105151 if (length) {
106152 /*
107153 * Datablock.
108154 */
109
- bytes = -offset;
110155 compressed = SQUASHFS_COMPRESSED_BLOCK(length);
111156 length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
112
- if (next_index)
113
- *next_index = index + length;
114
-
115157 TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
116158 index, compressed ? "" : "un", length, output->length);
117
-
118
- if (length < 0 || length > output->length ||
119
- (index + length) > msblk->bytes_used)
120
- goto read_failure;
121
-
122
- for (b = 0; bytes < length; b++, cur_index++) {
123
- bh[b] = sb_getblk(sb, cur_index);
124
- if (bh[b] == NULL)
125
- goto block_release;
126
- bytes += msblk->devblksize;
127
- }
128
- ll_rw_block(REQ_OP_READ, 0, b, bh);
129159 } else {
130160 /*
131161 * Metadata block.
132162 */
133
- if ((index + 2) > msblk->bytes_used)
134
- goto read_failure;
163
+ const u8 *data;
164
+ struct bvec_iter_all iter_all = {};
165
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
135166
136
- bh[0] = get_block_length(sb, &cur_index, &offset, &length);
137
- if (bh[0] == NULL)
138
- goto read_failure;
139
- b = 1;
167
+ if (index + 2 > msblk->bytes_used) {
168
+ res = -EIO;
169
+ goto out;
170
+ }
171
+ res = squashfs_bio_read(sb, index, 2, &bio, &offset);
172
+ if (res)
173
+ goto out;
140174
141
- bytes = msblk->devblksize - offset;
175
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
176
+ res = -EIO;
177
+ goto out_free_bio;
178
+ }
179
+ /* Extract the length of the metadata block */
180
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
181
+ length = data[offset];
182
+ if (offset < bvec->bv_len - 1) {
183
+ length |= data[offset + 1] << 8;
184
+ } else {
185
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
186
+ res = -EIO;
187
+ goto out_free_bio;
188
+ }
189
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
190
+ length |= data[0] << 8;
191
+ }
192
+ bio_free_pages(bio);
193
+ bio_put(bio);
194
+
142195 compressed = SQUASHFS_COMPRESSED(length);
143196 length = SQUASHFS_COMPRESSED_SIZE(length);
144
- if (next_index)
145
- *next_index = index + length + 2;
197
+ index += 2;
146198
147
- TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
148
- compressed ? "" : "un", length);
149
-
150
- if (length < 0 || length > output->length ||
151
- (index + length) > msblk->bytes_used)
152
- goto block_release;
153
-
154
- for (; bytes < length; b++) {
155
- bh[b] = sb_getblk(sb, ++cur_index);
156
- if (bh[b] == NULL)
157
- goto block_release;
158
- bytes += msblk->devblksize;
159
- }
160
- ll_rw_block(REQ_OP_READ, 0, b - 1, bh + 1);
199
+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index - 2,
200
+ compressed ? "" : "un", length);
201
+ }
202
+ if (length < 0 || length > output->length ||
203
+ (index + length) > msblk->bytes_used) {
204
+ res = -EIO;
205
+ goto out;
161206 }
162207
163
- for (i = 0; i < b; i++) {
164
- wait_on_buffer(bh[i]);
165
- if (!buffer_uptodate(bh[i]))
166
- goto block_release;
167
- }
208
+ if (next_index)
209
+ *next_index = index + length;
210
+
211
+ res = squashfs_bio_read(sb, index, length, &bio, &offset);
212
+ if (res)
213
+ goto out;
168214
169215 if (compressed) {
170
- if (!msblk->stream)
171
- goto read_failure;
172
- length = squashfs_decompress(msblk, bh, b, offset, length,
173
- output);
174
- if (length < 0)
175
- goto read_failure;
176
- } else {
177
- /*
178
- * Block is uncompressed.
179
- */
180
- int in, pg_offset = 0;
181
- void *data = squashfs_first_page(output);
182
-
183
- for (bytes = length; k < b; k++) {
184
- in = min(bytes, msblk->devblksize - offset);
185
- bytes -= in;
186
- while (in) {
187
- if (pg_offset == PAGE_SIZE) {
188
- data = squashfs_next_page(output);
189
- pg_offset = 0;
190
- }
191
- avail = min_t(int, in, PAGE_SIZE -
192
- pg_offset);
193
- memcpy(data + pg_offset, bh[k]->b_data + offset,
194
- avail);
195
- in -= avail;
196
- pg_offset += avail;
197
- offset += avail;
198
- }
199
- offset = 0;
200
- put_bh(bh[k]);
216
+ if (!msblk->stream) {
217
+ res = -EIO;
218
+ goto out_free_bio;
201219 }
202
- squashfs_finish_page(output);
220
+ res = squashfs_decompress(msblk, bio, offset, length, output);
221
+ } else {
222
+ res = copy_bio_to_actor(bio, output, offset, length);
203223 }
204224
205
- kfree(bh);
206
- return length;
225
+out_free_bio:
226
+ bio_free_pages(bio);
227
+ bio_put(bio);
228
+out:
229
+ if (res < 0)
230
+ ERROR("Failed to read block 0x%llx: %d\n", index, res);
207231
208
-block_release:
209
- for (; k < b; k++)
210
- put_bh(bh[k]);
211
-
212
-read_failure:
213
- ERROR("squashfs_read_data failed to read block 0x%llx\n",
214
- (unsigned long long) index);
215
- kfree(bh);
216
- return -EIO;
232
+ return res;
217233 }