Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa0010c8 authored by Chao Yu's avatar Chao Yu Committed by Daniel Rosenberg
Browse files

BACKPORT: f2fs: fix to handle segment allocation failure correctly



If CONFIG_F2FS_CHECK_FS is off, and for very rare corner case that
we run out of free segment, we should not panic kernel, instead,
let's handle such error correctly in its caller.

Signed-off-by: default avatarChao Yu <chao@kernel.org>
Tested-by: default avatarZhiguo Niu <zhiguo.niu@unisoc.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>

(cherry picked from commit 7d009e048d7cfcc21d400f2aba4c8bacbdebbd47)
[drosen: Resolved many conflicts in segment.c ]
Change-Id: Ic3db543ed6012d4083c7d899bc3c83f310f78437
Signed-off-by: default avatarDaniel Rosenberg <drosen@google.com>
Bug: 358293777
parent 862cf9f2
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -1451,8 +1451,11 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
alloc:
	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
	old_blkaddr = dn->data_blkaddr;
	f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
					&sum, seg_type, NULL, false);
	err = f2fs_allocate_data_block(sbi, NULL, old_blkaddr,
				&dn->data_blkaddr, &sum, seg_type, NULL, false);
	if (err)
		return err;

	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
		invalidate_mapping_pages(META_MAPPING(sbi),
					old_blkaddr, old_blkaddr);
+1 −1
Original line number Diff line number Diff line
@@ -3356,7 +3356,7 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
			block_t old_addr, block_t new_addr,
			unsigned char version, bool recover_curseg,
			bool recover_newaddr);
void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
			block_t old_blkaddr, block_t *new_blkaddr,
			struct f2fs_summary *sum, int type,
			struct f2fs_io_info *fio, bool add_list);
+6 −1
Original line number Diff line number Diff line
@@ -2276,8 +2276,11 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
	case F2FS_GOING_DOWN_METASYNC:
		/* do checkpoint only */
		ret = f2fs_sync_fs(sb, 1);
		if (ret)
		if (ret) {
			if (ret == -EIO)
				ret = 0;
			goto out;
		}
		f2fs_stop_checkpoint(sbi, false);
		set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
		break;
@@ -2296,6 +2299,8 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
		set_sbi_flag(sbi, SBI_IS_DIRTY);
		/* do checkpoint only */
		ret = f2fs_sync_fs(sb, 1);
		if (ret == -EIO)
			ret = 0;
		goto out;
	default:
		ret = -EINVAL;
+8 −2
Original line number Diff line number Diff line
@@ -863,8 +863,14 @@ static int move_data_block(struct inode *inode, block_t bidx,
		}
	}

	f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
	/* allocate block address */
	err = f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
				&sum, CURSEG_COLD_DATA, NULL, false);
	if (err) {
		f2fs_put_page(mpage, 1);
		/* filesystem should shutdown, no need to recovery block */
		goto up_out;
	}

	fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
				newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
+44 −7
Original line number Diff line number Diff line
@@ -492,6 +492,9 @@ int f2fs_commit_inmem_pages(struct inode *inode)
 */
void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
{
	if (f2fs_cp_error(sbi))
		return;

	if (time_to_inject(sbi, FAULT_CHECKPOINT)) {
		f2fs_show_injection_info(sbi, FAULT_CHECKPOINT);
		f2fs_stop_checkpoint(sbi, false);
@@ -2382,7 +2385,7 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi, int type)
 * Find a new segment from the free segments bitmap to right order
 * This function should be returned with success, otherwise BUG
 */
static void get_new_segment(struct f2fs_sb_info *sbi,
static int get_new_segment(struct f2fs_sb_info *sbi,
			unsigned int *newseg, bool new_sec, int dir)
{
	struct free_segmap_info *free_i = FREE_I(sbi);
@@ -2480,6 +2483,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
		f2fs_stop_checkpoint(sbi, false);
		f2fs_bug_on(sbi, 1);
	}
	return ret;
}

static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
@@ -2487,6 +2491,10 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
	struct curseg_info *curseg = CURSEG_I(sbi, type);
	struct summary_footer *sum_footer;

	/* only happen when get_new_segment() fails */
	if (curseg->next_segno == NULL_SEGNO)
		return;

	curseg->segno = curseg->next_segno;
	curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
	curseg->next_blkoff = 0;
@@ -2543,7 +2551,11 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
		dir = ALLOC_RIGHT;

	segno = __get_next_segno(sbi, type);
	get_new_segment(sbi, &segno, new_sec, dir);
	if (get_new_segment(sbi, &segno, new_sec, dir)) {
		curseg->segno = NULL_SEGNO;
		return;
	}

	curseg->next_segno = segno;
	reset_curseg(sbi, type, 1);
	curseg->alloc_type = LFS;
@@ -3103,7 +3115,7 @@ static int __get_segment_type(struct f2fs_io_info *fio)
	return type;
}

void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
		block_t old_blkaddr, block_t *new_blkaddr,
		struct f2fs_summary *sum, int type,
		struct f2fs_io_info *fio, bool add_list)
@@ -3137,6 +3149,9 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
	mutex_lock(&curseg->curseg_mutex);
	down_write(&sit_i->sentry_lock);

	if (curseg->segno == NULL_SEGNO)
		goto out_err;

	*new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);

	f2fs_wait_discard_bio(sbi, *new_blkaddr);
@@ -3193,7 +3208,6 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
	}

	mutex_unlock(&curseg->curseg_mutex);

	up_read(&SM_I(sbi)->curseg_lock);

	if (IS_DATASEG(type))
@@ -3201,6 +3215,19 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,

	if (put_pin_sem)
		up_read(&sbi->pin_sem);
	return 0;
out_err:
	*new_blkaddr = NULL_ADDR;

	up_write(&sit_i->sentry_lock);
	mutex_unlock(&curseg->curseg_mutex);
	up_read(&SM_I(sbi)->curseg_lock);
	if (IS_DATASEG(type))
		up_write(&sbi->node_write);

	if (put_pin_sem)
		up_read(&sbi->pin_sem);
	return -ENOSPC;
}

static void update_device_state(struct f2fs_io_info *fio)
@@ -3231,9 +3258,19 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)

	if (keep_order)
		down_read(&fio->sbi->io_order_lock);

reallocate:
	f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
			&fio->new_blkaddr, sum, type, fio, true);
	if (f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
			&fio->new_blkaddr, sum, type, fio, true)) {
		if (fscrypt_inode_uses_fs_layer_crypto(fio->page->mapping->host))
			fscrypt_finalize_bounce_page(&fio->encrypted_page);
		if (PageWriteback(fio->page))
			end_page_writeback(fio->page);
		if (f2fs_in_warm_node_list(fio->sbi, fio->page))
			f2fs_del_fsync_node_entry(fio->sbi, fio->page);
		goto out;
	}

	if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
		invalidate_mapping_pages(META_MAPPING(fio->sbi),
					fio->old_blkaddr, fio->old_blkaddr);
@@ -3246,7 +3283,7 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
	}

	update_device_state(fio);

out:
	if (keep_order)
		up_read(&fio->sbi->io_order_lock);
}