Commit ac524ece authored by Linus Torvalds's avatar Linus Torvalds

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
parents b5304a4f f395183f
...@@ -117,19 +117,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len) ...@@ -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) ...@@ -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 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, ...@@ -1036,7 +1024,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
} }
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 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, ...@@ -1046,33 +1034,35 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
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 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, ...@@ -1103,10 +1093,10 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
} }
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, ...@@ -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 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, ...@@ -1361,7 +1351,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
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 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, ...@@ -1372,7 +1362,8 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
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 @@ int f2fs_write_multi_pages(struct compress_ctx *cc, ...@@ -1522,7 +1513,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
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, ...@@ -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 @@ static int f2fs_mpage_readpages(struct inode *inode, ...@@ -2332,7 +2332,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);
} }
} }
#endif #endif
...@@ -3033,7 +3033,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping, ...@@ -3033,7 +3033,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
} }
} }
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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ static int check_swap_activate(struct swap_info_struct *sis, ...@@ -4035,7 +4052,7 @@ static int check_swap_activate(struct swap_info_struct *sis,
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); ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment