Skip to content

Commit

Permalink
Merge tag 'for-5.15-rc7-tag' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "Last minute fixes for crash on 32bit architectures when compression is
  in use. It's a regression introduced in 5.15-rc and I'd really like
  not let this into the final release, fixes via stable trees would add
  unnecessary delay.

  The problem is on 32bit architectures with highmem enabled, the pages
  for compression may need to be kmapped, while the patches removed that
  as we don't use GFP_HIGHMEM allocations anymore. The pages that don't
  come from local allocation still may be from highmem. Despite being on
  32bit there's enough such ARM machines in use so it's not a marginal
  issue.

  I did full reverts of the patches one by one instead of a huge one.
  There's one exception for the "lzo" revert as there was an
  intermediate patch touching the same code to make it compatible with
  subpage. I can't revert that one too, so the revert in lzo.c is
  manual. Qu Wenruo has worked on that with me and verified the changes"

* tag 'for-5.15-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  Revert "btrfs: compression: drop kmap/kunmap from lzo"
  Revert "btrfs: compression: drop kmap/kunmap from zlib"
  Revert "btrfs: compression: drop kmap/kunmap from zstd"
  Revert "btrfs: compression: drop kmap/kunmap from generic helpers"
  • Loading branch information
torvalds committed Oct 29, 2021
2 parents 6f11521 + ccaa66c commit fd919bb
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 33 deletions.
3 changes: 2 additions & 1 deletion fs/btrfs/compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,10 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
/* Hash through the page sector by sector */
for (pg_offset = 0; pg_offset < bytes_left;
pg_offset += sectorsize) {
kaddr = page_address(page);
kaddr = kmap_atomic(page);
crypto_shash_digest(shash, kaddr + pg_offset,
sectorsize, csum);
kunmap_atomic(kaddr);

if (memcmp(&csum, cb_sum, csum_size) != 0) {
btrfs_print_data_csum_error(inode, disk_start,
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,9 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
cur_size = min_t(unsigned long, compressed_size,
PAGE_SIZE);

kaddr = page_address(cpage);
kaddr = kmap_atomic(cpage);
write_extent_buffer(leaf, kaddr, ptr, cur_size);
kunmap_atomic(kaddr);

i++;
ptr += cur_size;
Expand Down
36 changes: 25 additions & 11 deletions fs/btrfs/lzo.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
*total_in = 0;

in_page = find_get_page(mapping, start >> PAGE_SHIFT);
data_in = page_address(in_page);
data_in = kmap(in_page);

/*
* store the size of all chunks of compressed data in
Expand All @@ -152,7 +152,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
ret = -ENOMEM;
goto out;
}
cpage_out = page_address(out_page);
cpage_out = kmap(out_page);
out_offset = LZO_LEN;
tot_out = LZO_LEN;
pages[0] = out_page;
Expand Down Expand Up @@ -210,6 +210,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
if (out_len == 0 && tot_in >= len)
break;

kunmap(out_page);
if (nr_pages == nr_dest_pages) {
out_page = NULL;
ret = -E2BIG;
Expand All @@ -221,7 +222,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
ret = -ENOMEM;
goto out;
}
cpage_out = page_address(out_page);
cpage_out = kmap(out_page);
pages[nr_pages++] = out_page;

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

bytes_left = len - tot_in;
kunmap(in_page);
put_page(in_page);

start += PAGE_SIZE;
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
data_in = page_address(in_page);
data_in = kmap(in_page);
in_len = min(bytes_left, PAGE_SIZE);
}

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

/* store the size of all chunks of compressed data */
sizes_ptr = page_address(pages[0]);
sizes_ptr = kmap_local_page(pages[0]);
write_compress_length(sizes_ptr, tot_out);
kunmap_local(sizes_ptr);

ret = 0;
*total_out = tot_out;
*total_in = tot_in;
out:
*out_pages = nr_pages;
if (out_page)
kunmap(out_page);

if (in_page)
if (in_page) {
kunmap(in_page);
put_page(in_page);
}

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

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

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

kaddr = kmap(cur_page);
memcpy(dest + *cur_in - orig_in,
page_address(cur_page) + offset_in_page(*cur_in),
kaddr + offset_in_page(*cur_in),
copy_len);
kunmap(cur_page);

*cur_in += copy_len;
}
Expand All @@ -303,6 +313,7 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
struct workspace *workspace = list_entry(ws, struct workspace, list);
const struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
const u32 sectorsize = fs_info->sectorsize;
char *kaddr;
int ret;
/* Compressed data length, can be unaligned */
u32 len_in;
Expand All @@ -311,7 +322,9 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
/* Bytes decompressed so far */
u32 cur_out = 0;

len_in = read_compress_length(page_address(cb->compressed_pages[0]));
kaddr = kmap(cb->compressed_pages[0]);
len_in = read_compress_length(kaddr);
kunmap(cb->compressed_pages[0]);
cur_in += LZO_LEN;

/*
Expand Down Expand Up @@ -344,9 +357,9 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
ASSERT(cur_in / sectorsize ==
(cur_in + LZO_LEN - 1) / sectorsize);
cur_page = cb->compressed_pages[cur_in / PAGE_SIZE];
kaddr = kmap(cur_page);
ASSERT(cur_page);
seg_len = read_compress_length(page_address(cur_page) +
offset_in_page(cur_in));
seg_len = read_compress_length(kaddr + offset_in_page(cur_in));
cur_in += LZO_LEN;

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

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

/*
Expand All @@ -441,6 +454,7 @@ int lzo_decompress(struct list_head *ws, unsigned char *data_in,
*/
if (bytes < destlen)
memset(kaddr+bytes, 0, destlen-bytes);
kunmap_local(kaddr);
out:
return ret;
}
Expand Down
36 changes: 25 additions & 11 deletions fs/btrfs/zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
ret = -ENOMEM;
goto out;
}
cpage_out = page_address(out_page);
cpage_out = kmap(out_page);
pages[0] = out_page;
nr_pages = 1;

Expand All @@ -148,22 +148,26 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
int i;

for (i = 0; i < in_buf_pages; i++) {
if (in_page)
if (in_page) {
kunmap(in_page);
put_page(in_page);
}
in_page = find_get_page(mapping,
start >> PAGE_SHIFT);
data_in = page_address(in_page);
data_in = kmap(in_page);
memcpy(workspace->buf + i * PAGE_SIZE,
data_in, PAGE_SIZE);
start += PAGE_SIZE;
}
workspace->strm.next_in = workspace->buf;
} else {
if (in_page)
if (in_page) {
kunmap(in_page);
put_page(in_page);
}
in_page = find_get_page(mapping,
start >> PAGE_SHIFT);
data_in = page_address(in_page);
data_in = kmap(in_page);
start += PAGE_SIZE;
workspace->strm.next_in = data_in;
}
Expand Down Expand Up @@ -192,6 +196,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
* the stream end if required
*/
if (workspace->strm.avail_out == 0) {
kunmap(out_page);
if (nr_pages == nr_dest_pages) {
out_page = NULL;
ret = -E2BIG;
Expand All @@ -202,7 +207,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
ret = -ENOMEM;
goto out;
}
cpage_out = page_address(out_page);
cpage_out = kmap(out_page);
pages[nr_pages] = out_page;
nr_pages++;
workspace->strm.avail_out = PAGE_SIZE;
Expand All @@ -229,6 +234,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
goto out;
} else if (workspace->strm.avail_out == 0) {
/* get another page for the stream end */
kunmap(out_page);
if (nr_pages == nr_dest_pages) {
out_page = NULL;
ret = -E2BIG;
Expand All @@ -239,7 +245,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
ret = -ENOMEM;
goto out;
}
cpage_out = page_address(out_page);
cpage_out = kmap(out_page);
pages[nr_pages] = out_page;
nr_pages++;
workspace->strm.avail_out = PAGE_SIZE;
Expand All @@ -258,8 +264,13 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
*total_in = workspace->strm.total_in;
out:
*out_pages = nr_pages;
if (in_page)
if (out_page)
kunmap(out_page);

if (in_page) {
kunmap(in_page);
put_page(in_page);
}
return ret;
}

Expand All @@ -276,7 +287,7 @@ int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
unsigned long buf_start;
struct page **pages_in = cb->compressed_pages;

data_in = page_address(pages_in[page_in_index]);
data_in = kmap(pages_in[page_in_index]);
workspace->strm.next_in = data_in;
workspace->strm.avail_in = min_t(size_t, srclen, PAGE_SIZE);
workspace->strm.total_in = 0;
Expand All @@ -298,6 +309,7 @@ int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)

if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
pr_warn("BTRFS: inflateInit failed\n");
kunmap(pages_in[page_in_index]);
return -EIO;
}
while (workspace->strm.total_in < srclen) {
Expand All @@ -324,13 +336,13 @@ int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)

if (workspace->strm.avail_in == 0) {
unsigned long tmp;

kunmap(pages_in[page_in_index]);
page_in_index++;
if (page_in_index >= total_pages_in) {
data_in = NULL;
break;
}
data_in = page_address(pages_in[page_in_index]);
data_in = kmap(pages_in[page_in_index]);
workspace->strm.next_in = data_in;
tmp = srclen - workspace->strm.total_in;
workspace->strm.avail_in = min(tmp, PAGE_SIZE);
Expand All @@ -342,6 +354,8 @@ int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
ret = 0;
done:
zlib_inflateEnd(&workspace->strm);
if (data_in)
kunmap(pages_in[page_in_index]);
if (!ret)
zero_fill_bio(cb->orig_bio);
return ret;
Expand Down
Loading

0 comments on commit fd919bb

Please sign in to comment.