[lvc-project] [PATCH] f2fs: Add a flush_work() call before destroying raw_super

Fedor Pchelkin pchelkin at ispras.ru
Tue May 5 17:41:24 MSK 2026


On Tue, 05. May 17:19, aitsygunka at yandex.ru wrote:
> Ага, конкретно сюда:
> 	/* get an inode for meta space */
> 	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
> 	if (IS_ERR(sbi->meta_inode)) {
> 		f2fs_err(sbi, "Failed to read F2FS meta data inode");
> 		err = PTR_ERR(sbi->meta_inode);
> 		// <-- вот сюда, т.к. именно отсюда мы переходим
> 		goto free_page_array_cache;
> 	}

Такое точно не годится, т.к. подавляет только конкретный репродьюсер с
конкретной трассой, а сама проблема может например возникнуть при
обработке ошибки следующей функции

	err = f2fs_get_valid_checkpoint(sbi);
	if (err) {
		f2fs_err(sbi, "Failed to get valid F2FS checkpoint");
		goto free_meta_inode;
	}

и т.д.

>  
> > Ну, я имел ввиду перенос уже имеющегося внутри f2fs_fill_super() вызова
> > flush_work() на пути обработки ошибки. Верно ли он поставлен? Может
> > быть, его лучше переместить в другое место, ниже по коду?
> 
> Да, я понял, оно логично, но у меня нет четкого понимания, что при переходе на метки
> выше мы также не получим состояние гонки.

По-хорошему порядок вызова функций на пути обработки ошибки в
f2fs_fill_super() должен соответствовать таковому в f2fs_put_super().
Но тут похоже порядок в f2fs_fill_super перемудрён.  Можно попробовать
начать с дублирования вызова flush_work(), но главное - отразить в
описании патча мотивы его _дополнительной_ постановки.  Должно быть ясно,
что вы проанализировали этот момент с дублированием и всё-таки решили
остановиться на нём, а не на перемещении вызова flush_work, вследствие
таких-то причин.

На мой взгляд перемещение вызова flush_work

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index ccf806b676f5..75215dc78262 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -5418,7 +5418,6 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 stop_ckpt_thread:
	f2fs_stop_ckpt_thread(sbi);
	/* flush s_error_work before sbi destroy */
-	flush_work(&sbi->s_error_work);
	f2fs_destroy_post_read_wq(sbi);
 free_devices:
	destroy_device_list(sbi);
@@ -5449,6 +5448,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
	/* no need to free dummy_enc_policy, we just keep it in ctx when failed */
	swap(F2FS_CTX_INFO(ctx).dummy_enc_policy, F2FS_OPTION(sbi).dummy_enc_policy);
 free_sb_buf:
+	flush_work(&sbi->s_error_work);
	kfree(raw_super);
 free_sbi:
 #ifdef CONFIG_DEBUG_LOCK_ALLOC

вполне может годиться.  Не вижу, чтобы воркер-обработчик s_error_work
касался полей, освобождаемых до метки free_sb_buf, т.е use-after-free быть
не должно.  Но здесь уже мэйнтенеры смогут более точно соориентировать.



More information about the lvc-project mailing list