mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 22:09:30 +02:00
Merge tag 'erofs-for-7.3-rc3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang:
"The most impactful fix here is to disable LZ4 rolling decompression
for now.
AWS folks recently found their systems could get corrupted data with
some rare, specific LZ4 datasets, and after a deeper analysis, I found
the root cause is that there could be uncontrolled backward memory
copies in the current LZ4 implementation and it breaks the assumption
of the rolling decompression optimization, since the kernel LZ4
codebase is out of our control and it needs more time to plan how to
do next, so disable LZ4 rolling decompression for now to ensure data
correctness for real production on these rare cases first. The
technical details also see the corresponding commit.
Other changes are random minor fixes.
Summary:
- Disable LZ4 rolling decompression for now due to the uncontrolled
LZ4 implementation
- Fix missing sysfs feature entry for xattr prefixes
- Fix invalid LZMA decoders on resize failure
- Rearrange the inode_share cache key to avoid potential collisions
- Fix erofs_bread() when fsoffset is used on sub-page-block EROFS
filesystems"
* tag 'erofs-for-7.3-rc3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
erofs: add missing buf->off in erofs_bread()
erofs: delimit inode_share cache key components
erofs: disable LZ4 rolling decompression for now
erofs: preserve LZMA decoders on resize failure
erofs: add sysfs feature entry for xattr prefixes
This commit is contained in:
@@ -5,7 +5,7 @@ Description: Shows all enabled kernel features.
|
||||
Supported features:
|
||||
compr_cfgs, big_pcluster, chunked_file, device_table,
|
||||
compr_head2, sb_chksum, ztailpacking, dedupe, fragments,
|
||||
48bit, metabox.
|
||||
xattr_prefixes, 48bit, metabox.
|
||||
|
||||
What: /sys/fs/erofs/<disk>/sync_decompress
|
||||
Date: November 2021
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
|
||||
return NULL;
|
||||
if (!buf->base)
|
||||
buf->base = kmap_local_page(buf->page);
|
||||
return buf->base + (offset & ~PAGE_MASK);
|
||||
return buf->base + ((buf->off + offset) & ~PAGE_MASK);
|
||||
}
|
||||
|
||||
int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
||||
|
||||
+12
-43
@@ -7,8 +7,6 @@
|
||||
#include "compress.h"
|
||||
#include <linux/lz4.h>
|
||||
|
||||
#define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
|
||||
|
||||
static int z_erofs_load_lz4_config(struct super_block *sb,
|
||||
struct erofs_super_block *dsb, void *data, int size)
|
||||
{
|
||||
@@ -21,8 +19,6 @@ static int z_erofs_load_lz4_config(struct super_block *sb,
|
||||
erofs_err(sb, "invalid lz4 cfgs, size=%u", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
distance = le16_to_cpu(lz4->max_distance);
|
||||
|
||||
sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks);
|
||||
if (!sbi->lz4.max_pclusterblks) {
|
||||
sbi->lz4.max_pclusterblks = 1; /* reserved case */
|
||||
@@ -39,45 +35,25 @@ static int z_erofs_load_lz4_config(struct super_block *sb,
|
||||
sbi->lz4.max_pclusterblks = 1;
|
||||
sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
|
||||
}
|
||||
|
||||
sbi->lz4.max_distance_pages = distance ?
|
||||
DIV_ROUND_UP(distance, PAGE_SIZE) + 1 :
|
||||
LZ4_MAX_DISTANCE_PAGES;
|
||||
return z_erofs_gbuf_growsize(sbi->lz4.max_pclusterblks);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill all gaps with bounce pages if it's a sparse page list. Also check if
|
||||
* all physical pages are consecutive, which can be seen for moderate CR.
|
||||
* Fill all gaps with bounce pages if it's a sparse page list (for example some
|
||||
* folios are already uptodate and thus can be mapped into userspace). Also
|
||||
* check if pages are physically consecutive, which can be seen for moderate CR.
|
||||
*/
|
||||
static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
|
||||
struct page **pagepool)
|
||||
static int z_erofs_oneshot_prepare_dstpages(struct z_erofs_decompress_req *rq,
|
||||
struct page **pagepool)
|
||||
{
|
||||
struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
|
||||
unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
|
||||
BITS_PER_LONG)] = { 0 };
|
||||
unsigned int lz4_max_distance_pages =
|
||||
EROFS_SB(rq->sb)->lz4.max_distance_pages;
|
||||
void *kaddr = NULL;
|
||||
unsigned int i, j, top;
|
||||
unsigned int i;
|
||||
|
||||
top = 0;
|
||||
for (i = j = 0; i < rq->outpages; ++i, ++j) {
|
||||
struct page *const page = rq->out[i];
|
||||
struct page *victim;
|
||||
|
||||
if (j >= lz4_max_distance_pages)
|
||||
j = 0;
|
||||
|
||||
/* 'valid' bounced can only be tested after a complete round */
|
||||
if (!rq->fillgaps && test_bit(j, bounced)) {
|
||||
DBG_BUGON(i < lz4_max_distance_pages);
|
||||
DBG_BUGON(top >= lz4_max_distance_pages);
|
||||
availables[top++] = rq->out[i - lz4_max_distance_pages];
|
||||
}
|
||||
for (i = 0; i < rq->outpages; ++i) {
|
||||
struct page *page, *victim;
|
||||
|
||||
page = rq->out[i];
|
||||
if (page) {
|
||||
__clear_bit(j, bounced);
|
||||
if (!PageHighMem(page)) {
|
||||
if (!i) {
|
||||
kaddr = page_address(page);
|
||||
@@ -89,21 +65,14 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
kaddr = NULL;
|
||||
continue;
|
||||
}
|
||||
kaddr = NULL;
|
||||
__set_bit(j, bounced);
|
||||
|
||||
if (top) {
|
||||
victim = availables[--top];
|
||||
} else {
|
||||
victim = __erofs_allocpage(pagepool, rq->gfp, true);
|
||||
if (!victim)
|
||||
return -ENOMEM;
|
||||
set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
|
||||
rq->out[i] = victim;
|
||||
}
|
||||
rq->out[i] = victim;
|
||||
kaddr = NULL;
|
||||
}
|
||||
return kaddr ? 1 : 0;
|
||||
}
|
||||
@@ -266,7 +235,7 @@ static const char *z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
|
||||
dst_maptype = 0;
|
||||
} else {
|
||||
/* general decoding path which can be used for all cases */
|
||||
ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
|
||||
ret = z_erofs_oneshot_prepare_dstpages(rq, pagepool);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
if (ret > 0) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
struct z_erofs_lzma {
|
||||
struct z_erofs_lzma *next;
|
||||
struct xz_dec_microlzma *state;
|
||||
unsigned int dict_size;
|
||||
u8 bounce[PAGE_SIZE];
|
||||
};
|
||||
|
||||
@@ -128,11 +129,19 @@ again:
|
||||
err = 0;
|
||||
/* 2. walk each isolated stream and grow max dict_size if needed */
|
||||
for (strm = head; strm; strm = strm->next) {
|
||||
struct xz_dec_microlzma *state;
|
||||
|
||||
if (strm->dict_size >= dict_size)
|
||||
continue;
|
||||
state = xz_dec_microlzma_alloc(XZ_PREALLOC, dict_size);
|
||||
if (!state) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if (strm->state)
|
||||
xz_dec_microlzma_end(strm->state);
|
||||
strm->state = xz_dec_microlzma_alloc(XZ_PREALLOC, dict_size);
|
||||
if (!strm->state)
|
||||
err = -ENOMEM;
|
||||
strm->state = state;
|
||||
strm->dict_size = dict_size;
|
||||
}
|
||||
|
||||
/* 3. push back all to the global list and update max dict_size */
|
||||
@@ -142,7 +151,8 @@ again:
|
||||
spin_unlock(&z_erofs_lzma_lock);
|
||||
wake_up_all(&z_erofs_lzma_wq);
|
||||
|
||||
z_erofs_lzma_max_dictsize = dict_size;
|
||||
if (!err)
|
||||
z_erofs_lzma_max_dictsize = dict_size;
|
||||
mutex_unlock(&lzma_resize_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
+1
-5
@@ -71,12 +71,8 @@ struct erofs_dev_context {
|
||||
bool flatdev;
|
||||
};
|
||||
|
||||
/* all filesystem-wide lz4 configurations */
|
||||
struct erofs_sb_lz4_info {
|
||||
/* # of pages needed for EROFS lz4 rolling decompression */
|
||||
u16 max_distance_pages;
|
||||
/* maximum possible blocks for pclusters in the filesystem */
|
||||
u16 max_pclusterblks;
|
||||
u16 max_pclusterblks; /* maximum physical blocks for LZ4 pclusters */
|
||||
};
|
||||
|
||||
struct erofs_xattr_prefix_item {
|
||||
|
||||
@@ -95,6 +95,7 @@ EROFS_ATTR_FEATURE(sb_chksum);
|
||||
EROFS_ATTR_FEATURE(ztailpacking);
|
||||
EROFS_ATTR_FEATURE(fragments);
|
||||
EROFS_ATTR_FEATURE(dedupe);
|
||||
EROFS_ATTR_FEATURE(xattr_prefixes);
|
||||
EROFS_ATTR_FEATURE(48bit);
|
||||
EROFS_ATTR_FEATURE(metabox);
|
||||
|
||||
@@ -108,6 +109,7 @@ static struct attribute *erofs_feat_attrs[] = {
|
||||
ATTR_LIST(ztailpacking),
|
||||
ATTR_LIST(fragments),
|
||||
ATTR_LIST(dedupe),
|
||||
ATTR_LIST(xattr_prefixes),
|
||||
ATTR_LIST(48bit),
|
||||
ATTR_LIST(metabox),
|
||||
NULL,
|
||||
|
||||
+5
-4
@@ -620,8 +620,8 @@ int erofs_xattr_fill_inode_fingerprint(struct erofs_inode_fingerprint *fp,
|
||||
{
|
||||
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
|
||||
struct erofs_xattr_prefix_item *prefix;
|
||||
int domainlen, valuelen, base_index;
|
||||
const char *infix;
|
||||
int valuelen, base_index;
|
||||
|
||||
if (!test_opt(&sbi->opt, INODE_SHARE))
|
||||
return -EOPNOTSUPP;
|
||||
@@ -633,17 +633,18 @@ int erofs_xattr_fill_inode_fingerprint(struct erofs_inode_fingerprint *fp,
|
||||
valuelen = erofs_getxattr(inode, base_index, infix, NULL, 0);
|
||||
if (valuelen <= 0 || valuelen > (1 << sbi->blkszbits))
|
||||
return -EFSCORRUPTED;
|
||||
fp->size = valuelen + (domain_id ? strlen(domain_id) : 0);
|
||||
domainlen = strlen(domain_id);
|
||||
fp->size = domainlen + 1 + valuelen;
|
||||
fp->opaque = kmalloc(fp->size, GFP_KERNEL);
|
||||
if (!fp->opaque)
|
||||
return -ENOMEM;
|
||||
memcpy(fp->opaque, domain_id, domainlen + 1);
|
||||
if (valuelen != erofs_getxattr(inode, base_index, infix,
|
||||
fp->opaque, valuelen)) {
|
||||
fp->opaque + domainlen + 1, valuelen)) {
|
||||
kfree(fp->opaque);
|
||||
fp->opaque = NULL;
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
memcpy(fp->opaque + valuelen, domain_id, fp->size - valuelen);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-15
@@ -1259,7 +1259,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
|
||||
const struct z_erofs_decompressor *alg =
|
||||
z_erofs_decomp[pcl->algorithmformat];
|
||||
bool try_free = true;
|
||||
int i, j, jtop, err2, err = eio ? -EIO : 0;
|
||||
int i, err2, err = eio ? -EIO : 0;
|
||||
struct page *page;
|
||||
bool overlapped;
|
||||
const char *reason;
|
||||
@@ -1348,7 +1348,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
|
||||
be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES)
|
||||
kvfree(be->compressed_pages);
|
||||
|
||||
jtop = 0;
|
||||
z_erofs_fill_other_copies(be, err);
|
||||
for (i = 0; i < be->nr_pages; ++i) {
|
||||
page = be->decompressed_pages[i];
|
||||
@@ -1356,22 +1355,11 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
|
||||
continue;
|
||||
|
||||
DBG_BUGON(z_erofs_page_is_invalidated(page));
|
||||
if (!z_erofs_is_shortlived_page(page)) {
|
||||
if (!z_erofs_is_shortlived_page(page))
|
||||
erofs_onlinefolio_end(page_folio(page), err, true);
|
||||
continue;
|
||||
}
|
||||
if (pcl->algorithmformat != Z_EROFS_COMPRESSION_LZ4) {
|
||||
else
|
||||
erofs_pagepool_add(be->pagepool, page);
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < jtop && be->decompressed_pages[j] != page; ++j)
|
||||
;
|
||||
if (j >= jtop) /* this bounce page is newly detected */
|
||||
be->decompressed_pages[jtop++] = page;
|
||||
}
|
||||
while (jtop)
|
||||
erofs_pagepool_add(be->pagepool,
|
||||
be->decompressed_pages[--jtop]);
|
||||
if (be->decompressed_pages != be->onstack_pages)
|
||||
kvfree(be->decompressed_pages);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user