f2fs-5.13-rc1-fix
This series of patches fix some critical bugs such as memory leak in compression flows, kernel panic when handling errors, and swapon failure due to newly added condition check. -----BEGIN PGP SIGNATURE----- iQIyBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmCeTNcACgkQQBSofoJI UNKc0Q/3X9Tngns5DpnzQw9kbWochucG/7Vf1HjdvV2gE7IxruDPofGtBdhPdSYV uR+nP9dxhXLQQNfWS2KICzdj0yceKCKq8xpnnNdq9SGjVJmUjCD39ByGJV3GMOGM fY6dizcywltH7iBQboMZ0Eh3ivPh6ugl5klDo20WzYsH6F/UF7CPSuSJ3K5ezGuY T6R3NkqG8v1cS6+5u+teDpmdCCHOCBEeizBFQ6XskNDBavbw7KEA0liwKOv6eghB PdoeqYemg1VfOHAKqP6F3o+eSlsT5Ljs0Zmc5x8h8qRS76JK/hb9REFngrcERaIw GPDnMPCHniCHMd61z90oqGtMf4PFqLUVnBTdxhxLK5G4+u874dlZLciKWGDIGTLv eNU2W+8c9s+KdJAZFJbYN5zVoyJUR5SW7RcYTuvZWt8wX38Ch+FZEGqOC8FxWyWU i1WHXZiGeifIlIeqUOPJP5sbslL2hfK5OqMYJotAeIW/E2RyJWnc+Yo2UwvmvXVU xPOKFOn9nAAQz2GGgSpvGaWAVfMNqhoLw7/gzwdkabP0EASIzHuW2PCJhp59c1NO Fb9eUi7yhgd94vDbYftXRBgAhrUmCd0u+/gySyou4vujWtfWcO+AvOEreV7VRFfL Su0bGkBJ03ThFEFAZnY14RenydGSwpk5Fd9wkRy4Qk7mBv9sRg== =NeKH -----END PGP SIGNATURE----- Merge tag 'f2fs-5.13-rc1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs Pull f2fs fixes from Jaegeuk Kim: "This fixes some critical bugs such as memory leak in compression flows, kernel panic when handling errors, and swapon failure due to newly added condition check" * tag 'f2fs-5.13-rc1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: f2fs: return EINVAL for hole cases in swap file f2fs: avoid swapon failure by giving a warning first f2fs: compress: fix to assign cc.cluster_idx correctly f2fs: compress: fix race condition of overwrite vs truncate f2fs: compress: fix to free compress page correctly f2fs: support iflag change given the mask f2fs: avoid null pointer access when handling IPU error
This commit is contained in:
Коммит
ac524ece21
|
@ -117,19 +117,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)
|
||||||
f2fs_drop_rpages(cc, len, true);
|
f2fs_drop_rpages(cc, len, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void f2fs_put_rpages_mapping(struct address_space *mapping,
|
|
||||||
pgoff_t start, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
struct page *page = find_get_page(mapping, start + i);
|
|
||||||
|
|
||||||
put_page(page);
|
|
||||||
put_page(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
|
static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
|
||||||
struct writeback_control *wbc, bool redirty, int unlock)
|
struct writeback_control *wbc, bool redirty, int unlock)
|
||||||
{
|
{
|
||||||
|
@ -158,13 +145,14 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc)
|
||||||
return cc->rpages ? 0 : -ENOMEM;
|
return cc->rpages ? 0 : -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc)
|
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse)
|
||||||
{
|
{
|
||||||
page_array_free(cc->inode, cc->rpages, cc->cluster_size);
|
page_array_free(cc->inode, cc->rpages, cc->cluster_size);
|
||||||
cc->rpages = NULL;
|
cc->rpages = NULL;
|
||||||
cc->nr_rpages = 0;
|
cc->nr_rpages = 0;
|
||||||
cc->nr_cpages = 0;
|
cc->nr_cpages = 0;
|
||||||
cc->cluster_idx = NULL_CLUSTER;
|
if (!reuse)
|
||||||
|
cc->cluster_idx = NULL_CLUSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page)
|
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page)
|
||||||
|
@ -1036,7 +1024,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageUptodate(page))
|
if (PageUptodate(page))
|
||||||
unlock_page(page);
|
f2fs_put_page(page, 1);
|
||||||
else
|
else
|
||||||
f2fs_compress_ctx_add_page(cc, page);
|
f2fs_compress_ctx_add_page(cc, page);
|
||||||
}
|
}
|
||||||
|
@ -1046,33 +1034,35 @@ retry:
|
||||||
|
|
||||||
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
|
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
|
||||||
&last_block_in_bio, false, true);
|
&last_block_in_bio, false, true);
|
||||||
f2fs_destroy_compress_ctx(cc);
|
f2fs_put_rpages(cc);
|
||||||
|
f2fs_destroy_compress_ctx(cc, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto release_pages;
|
goto out;
|
||||||
if (bio)
|
if (bio)
|
||||||
f2fs_submit_bio(sbi, bio, DATA);
|
f2fs_submit_bio(sbi, bio, DATA);
|
||||||
|
|
||||||
ret = f2fs_init_compress_ctx(cc);
|
ret = f2fs_init_compress_ctx(cc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto release_pages;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < cc->cluster_size; i++) {
|
for (i = 0; i < cc->cluster_size; i++) {
|
||||||
f2fs_bug_on(sbi, cc->rpages[i]);
|
f2fs_bug_on(sbi, cc->rpages[i]);
|
||||||
|
|
||||||
page = find_lock_page(mapping, start_idx + i);
|
page = find_lock_page(mapping, start_idx + i);
|
||||||
f2fs_bug_on(sbi, !page);
|
if (!page) {
|
||||||
|
/* page can be truncated */
|
||||||
|
goto release_and_retry;
|
||||||
|
}
|
||||||
|
|
||||||
f2fs_wait_on_page_writeback(page, DATA, true, true);
|
f2fs_wait_on_page_writeback(page, DATA, true, true);
|
||||||
|
|
||||||
f2fs_compress_ctx_add_page(cc, page);
|
f2fs_compress_ctx_add_page(cc, page);
|
||||||
f2fs_put_page(page, 0);
|
|
||||||
|
|
||||||
if (!PageUptodate(page)) {
|
if (!PageUptodate(page)) {
|
||||||
|
release_and_retry:
|
||||||
|
f2fs_put_rpages(cc);
|
||||||
f2fs_unlock_rpages(cc, i + 1);
|
f2fs_unlock_rpages(cc, i + 1);
|
||||||
f2fs_put_rpages_mapping(mapping, start_idx,
|
f2fs_destroy_compress_ctx(cc, true);
|
||||||
cc->cluster_size);
|
|
||||||
f2fs_destroy_compress_ctx(cc);
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1103,10 +1093,10 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_pages:
|
unlock_pages:
|
||||||
|
f2fs_put_rpages(cc);
|
||||||
f2fs_unlock_rpages(cc, i);
|
f2fs_unlock_rpages(cc, i);
|
||||||
release_pages:
|
f2fs_destroy_compress_ctx(cc, true);
|
||||||
f2fs_put_rpages_mapping(mapping, start_idx, i);
|
out:
|
||||||
f2fs_destroy_compress_ctx(cc);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1141,7 +1131,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
|
||||||
set_cluster_dirty(&cc);
|
set_cluster_dirty(&cc);
|
||||||
|
|
||||||
f2fs_put_rpages_wbc(&cc, NULL, false, 1);
|
f2fs_put_rpages_wbc(&cc, NULL, false, 1);
|
||||||
f2fs_destroy_compress_ctx(&cc);
|
f2fs_destroy_compress_ctx(&cc, false);
|
||||||
|
|
||||||
return first_index;
|
return first_index;
|
||||||
}
|
}
|
||||||
|
@ -1361,7 +1351,7 @@ unlock_continue:
|
||||||
f2fs_put_rpages(cc);
|
f2fs_put_rpages(cc);
|
||||||
page_array_free(cc->inode, cc->cpages, cc->nr_cpages);
|
page_array_free(cc->inode, cc->cpages, cc->nr_cpages);
|
||||||
cc->cpages = NULL;
|
cc->cpages = NULL;
|
||||||
f2fs_destroy_compress_ctx(cc);
|
f2fs_destroy_compress_ctx(cc, false);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_destroy_crypt:
|
out_destroy_crypt:
|
||||||
|
@ -1372,7 +1362,8 @@ out_destroy_crypt:
|
||||||
for (i = 0; i < cc->nr_cpages; i++) {
|
for (i = 0; i < cc->nr_cpages; i++) {
|
||||||
if (!cc->cpages[i])
|
if (!cc->cpages[i])
|
||||||
continue;
|
continue;
|
||||||
f2fs_put_page(cc->cpages[i], 1);
|
f2fs_compress_free_page(cc->cpages[i]);
|
||||||
|
cc->cpages[i] = NULL;
|
||||||
}
|
}
|
||||||
out_put_cic:
|
out_put_cic:
|
||||||
kmem_cache_free(cic_entry_slab, cic);
|
kmem_cache_free(cic_entry_slab, cic);
|
||||||
|
@ -1522,7 +1513,7 @@ write:
|
||||||
err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
|
err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
|
||||||
f2fs_put_rpages_wbc(cc, wbc, false, 0);
|
f2fs_put_rpages_wbc(cc, wbc, false, 0);
|
||||||
destroy_out:
|
destroy_out:
|
||||||
f2fs_destroy_compress_ctx(cc);
|
f2fs_destroy_compress_ctx(cc, false);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2287,7 +2287,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
|
||||||
max_nr_pages,
|
max_nr_pages,
|
||||||
&last_block_in_bio,
|
&last_block_in_bio,
|
||||||
rac != NULL, false);
|
rac != NULL, false);
|
||||||
f2fs_destroy_compress_ctx(&cc);
|
f2fs_destroy_compress_ctx(&cc, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto set_error_page;
|
goto set_error_page;
|
||||||
}
|
}
|
||||||
|
@ -2332,7 +2332,7 @@ next_page:
|
||||||
max_nr_pages,
|
max_nr_pages,
|
||||||
&last_block_in_bio,
|
&last_block_in_bio,
|
||||||
rac != NULL, false);
|
rac != NULL, false);
|
||||||
f2fs_destroy_compress_ctx(&cc);
|
f2fs_destroy_compress_ctx(&cc, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3033,7 +3033,7 @@ next:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (f2fs_compressed_file(inode))
|
if (f2fs_compressed_file(inode))
|
||||||
f2fs_destroy_compress_ctx(&cc);
|
f2fs_destroy_compress_ctx(&cc, false);
|
||||||
#endif
|
#endif
|
||||||
if (retry) {
|
if (retry) {
|
||||||
index = 0;
|
index = 0;
|
||||||
|
@ -3801,6 +3801,7 @@ static int f2fs_is_file_aligned(struct inode *inode)
|
||||||
block_t pblock;
|
block_t pblock;
|
||||||
unsigned long nr_pblocks;
|
unsigned long nr_pblocks;
|
||||||
unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
|
unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
|
||||||
|
unsigned int not_aligned = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
cur_lblock = 0;
|
cur_lblock = 0;
|
||||||
|
@ -3833,13 +3834,20 @@ static int f2fs_is_file_aligned(struct inode *inode)
|
||||||
|
|
||||||
if ((pblock - main_blkaddr) & (blocks_per_sec - 1) ||
|
if ((pblock - main_blkaddr) & (blocks_per_sec - 1) ||
|
||||||
nr_pblocks & (blocks_per_sec - 1)) {
|
nr_pblocks & (blocks_per_sec - 1)) {
|
||||||
f2fs_err(sbi, "Swapfile does not align to section");
|
if (f2fs_is_pinned_file(inode)) {
|
||||||
ret = -EINVAL;
|
f2fs_err(sbi, "Swapfile does not align to section");
|
||||||
goto out;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
not_aligned++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_lblock += nr_pblocks;
|
cur_lblock += nr_pblocks;
|
||||||
}
|
}
|
||||||
|
if (not_aligned)
|
||||||
|
f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n"
|
||||||
|
"\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()",
|
||||||
|
not_aligned);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3858,6 +3866,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
|
||||||
int nr_extents = 0;
|
int nr_extents = 0;
|
||||||
unsigned long nr_pblocks;
|
unsigned long nr_pblocks;
|
||||||
unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
|
unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
|
||||||
|
unsigned int not_aligned = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3887,7 +3896,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
|
||||||
/* hole */
|
/* hole */
|
||||||
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
|
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
|
||||||
f2fs_err(sbi, "Swapfile has holes\n");
|
f2fs_err(sbi, "Swapfile has holes\n");
|
||||||
ret = -ENOENT;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3896,9 +3905,12 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
|
||||||
|
|
||||||
if ((pblock - SM_I(sbi)->main_blkaddr) & (blocks_per_sec - 1) ||
|
if ((pblock - SM_I(sbi)->main_blkaddr) & (blocks_per_sec - 1) ||
|
||||||
nr_pblocks & (blocks_per_sec - 1)) {
|
nr_pblocks & (blocks_per_sec - 1)) {
|
||||||
f2fs_err(sbi, "Swapfile does not align to section");
|
if (f2fs_is_pinned_file(inode)) {
|
||||||
ret = -EINVAL;
|
f2fs_err(sbi, "Swapfile does not align to section");
|
||||||
goto out;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
not_aligned++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_lblock + nr_pblocks >= sis->max)
|
if (cur_lblock + nr_pblocks >= sis->max)
|
||||||
|
@ -3927,6 +3939,11 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
|
||||||
sis->max = cur_lblock;
|
sis->max = cur_lblock;
|
||||||
sis->pages = cur_lblock - 1;
|
sis->pages = cur_lblock - 1;
|
||||||
sis->highest_bit = cur_lblock - 1;
|
sis->highest_bit = cur_lblock - 1;
|
||||||
|
|
||||||
|
if (not_aligned)
|
||||||
|
f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n"
|
||||||
|
"\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()",
|
||||||
|
not_aligned);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -4035,7 +4052,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
bad_bmap:
|
bad_bmap:
|
||||||
f2fs_err(sbi, "Swapfile has holes\n");
|
f2fs_err(sbi, "Swapfile has holes\n");
|
||||||
return -ENOENT;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
||||||
|
|
|
@ -3956,7 +3956,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
|
||||||
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed);
|
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed);
|
||||||
void f2fs_put_page_dic(struct page *page);
|
void f2fs_put_page_dic(struct page *page);
|
||||||
int f2fs_init_compress_ctx(struct compress_ctx *cc);
|
int f2fs_init_compress_ctx(struct compress_ctx *cc);
|
||||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc);
|
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse);
|
||||||
void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
|
void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
|
||||||
int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi);
|
int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi);
|
||||||
void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);
|
void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);
|
||||||
|
|
|
@ -1817,7 +1817,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
||||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||||
u32 masked_flags = fi->i_flags & mask;
|
u32 masked_flags = fi->i_flags & mask;
|
||||||
|
|
||||||
f2fs_bug_on(F2FS_I_SB(inode), (iflags & ~mask));
|
/* mask can be shrunk by flags_valid selector */
|
||||||
|
iflags &= mask;
|
||||||
|
|
||||||
/* Is it quota file? Do not allow user to mess with it */
|
/* Is it quota file? Do not allow user to mess with it */
|
||||||
if (IS_NOQUOTA(inode))
|
if (IS_NOQUOTA(inode))
|
||||||
|
|
|
@ -3574,12 +3574,12 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
drop_bio:
|
drop_bio:
|
||||||
if (fio->bio) {
|
if (fio->bio && *(fio->bio)) {
|
||||||
struct bio *bio = *(fio->bio);
|
struct bio *bio = *(fio->bio);
|
||||||
|
|
||||||
bio->bi_status = BLK_STS_IOERR;
|
bio->bi_status = BLK_STS_IOERR;
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
fio->bio = NULL;
|
*(fio->bio) = NULL;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче