Skip to content

Commit ccaa66c

Browse files
committed
Revert "btrfs: compression: drop kmap/kunmap from lzo"
This reverts commit 8c945d3. The kmaps in compression code are still needed and cause crashes on 32bit machines (ARM, x86). Reproducible eg. by running fstest btrfs/004 with enabled LZO or ZSTD compression. The revert does not apply cleanly due to changes in a6e66e6 ("btrfs: rework lzo_decompress_bio() to make it subpage compatible") that reworked the page iteration so the revert is done to be equivalent to the original code. Link: https://lore.kernel.org/all/CAJCQCtT+OuemovPO7GZk8Y8=qtOObr0XTDp8jh4OHD6y84AFxw@mail.gmail.com/ Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=214839 Tested-by: Qu Wenruo <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 55276e1 commit ccaa66c

File tree

1 file changed

+25
-11
lines changed

1 file changed

+25
-11
lines changed

fs/btrfs/lzo.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
141141
*total_in = 0;
142142

143143
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
144-
data_in = page_address(in_page);
144+
data_in = kmap(in_page);
145145

146146
/*
147147
* store the size of all chunks of compressed data in
@@ -152,7 +152,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
152152
ret = -ENOMEM;
153153
goto out;
154154
}
155-
cpage_out = page_address(out_page);
155+
cpage_out = kmap(out_page);
156156
out_offset = LZO_LEN;
157157
tot_out = LZO_LEN;
158158
pages[0] = out_page;
@@ -210,6 +210,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
210210
if (out_len == 0 && tot_in >= len)
211211
break;
212212

213+
kunmap(out_page);
213214
if (nr_pages == nr_dest_pages) {
214215
out_page = NULL;
215216
ret = -E2BIG;
@@ -221,7 +222,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
221222
ret = -ENOMEM;
222223
goto out;
223224
}
224-
cpage_out = page_address(out_page);
225+
cpage_out = kmap(out_page);
225226
pages[nr_pages++] = out_page;
226227

227228
pg_bytes_left = PAGE_SIZE;
@@ -243,11 +244,12 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
243244
break;
244245

245246
bytes_left = len - tot_in;
247+
kunmap(in_page);
246248
put_page(in_page);
247249

248250
start += PAGE_SIZE;
249251
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
250-
data_in = page_address(in_page);
252+
data_in = kmap(in_page);
251253
in_len = min(bytes_left, PAGE_SIZE);
252254
}
253255

@@ -257,17 +259,22 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
257259
}
258260

259261
/* store the size of all chunks of compressed data */
260-
sizes_ptr = page_address(pages[0]);
262+
sizes_ptr = kmap_local_page(pages[0]);
261263
write_compress_length(sizes_ptr, tot_out);
264+
kunmap_local(sizes_ptr);
262265

263266
ret = 0;
264267
*total_out = tot_out;
265268
*total_in = tot_in;
266269
out:
267270
*out_pages = nr_pages;
271+
if (out_page)
272+
kunmap(out_page);
268273

269-
if (in_page)
274+
if (in_page) {
275+
kunmap(in_page);
270276
put_page(in_page);
277+
}
271278

272279
return ret;
273280
}
@@ -283,16 +290,19 @@ static void copy_compressed_segment(struct compressed_bio *cb,
283290
u32 orig_in = *cur_in;
284291

285292
while (*cur_in < orig_in + len) {
293+
char *kaddr;
286294
struct page *cur_page;
287295
u32 copy_len = min_t(u32, PAGE_SIZE - offset_in_page(*cur_in),
288296
orig_in + len - *cur_in);
289297

290298
ASSERT(copy_len);
291299
cur_page = cb->compressed_pages[*cur_in / PAGE_SIZE];
292300

301+
kaddr = kmap(cur_page);
293302
memcpy(dest + *cur_in - orig_in,
294-
page_address(cur_page) + offset_in_page(*cur_in),
303+
kaddr + offset_in_page(*cur_in),
295304
copy_len);
305+
kunmap(cur_page);
296306

297307
*cur_in += copy_len;
298308
}
@@ -303,6 +313,7 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
303313
struct workspace *workspace = list_entry(ws, struct workspace, list);
304314
const struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
305315
const u32 sectorsize = fs_info->sectorsize;
316+
char *kaddr;
306317
int ret;
307318
/* Compressed data length, can be unaligned */
308319
u32 len_in;
@@ -311,7 +322,9 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
311322
/* Bytes decompressed so far */
312323
u32 cur_out = 0;
313324

314-
len_in = read_compress_length(page_address(cb->compressed_pages[0]));
325+
kaddr = kmap(cb->compressed_pages[0]);
326+
len_in = read_compress_length(kaddr);
327+
kunmap(cb->compressed_pages[0]);
315328
cur_in += LZO_LEN;
316329

317330
/*
@@ -344,9 +357,9 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
344357
ASSERT(cur_in / sectorsize ==
345358
(cur_in + LZO_LEN - 1) / sectorsize);
346359
cur_page = cb->compressed_pages[cur_in / PAGE_SIZE];
360+
kaddr = kmap(cur_page);
347361
ASSERT(cur_page);
348-
seg_len = read_compress_length(page_address(cur_page) +
349-
offset_in_page(cur_in));
362+
seg_len = read_compress_length(kaddr + offset_in_page(cur_in));
350363
cur_in += LZO_LEN;
351364

352365
/* Copy the compressed segment payload into workspace */
@@ -431,7 +444,7 @@ int lzo_decompress(struct list_head *ws, unsigned char *data_in,
431444
destlen = min_t(unsigned long, destlen, PAGE_SIZE);
432445
bytes = min_t(unsigned long, destlen, out_len - start_byte);
433446

434-
kaddr = page_address(dest_page);
447+
kaddr = kmap_local_page(dest_page);
435448
memcpy(kaddr, workspace->buf + start_byte, bytes);
436449

437450
/*
@@ -441,6 +454,7 @@ int lzo_decompress(struct list_head *ws, unsigned char *data_in,
441454
*/
442455
if (bytes < destlen)
443456
memset(kaddr+bytes, 0, destlen-bytes);
457+
kunmap_local(kaddr);
444458
out:
445459
return ret;
446460
}

0 commit comments

Comments
 (0)