Skip to content

Commit b62e71b

Browse files
chaseyuJaegeuk Kim
authored and
Jaegeuk Kim
committed
f2fs: support errors=remount-ro|continue|panic mountoption
This patch supports errors=remount-ro|continue|panic mount option for f2fs. f2fs behaves as below in three different modes: mode continue remount-ro panic access ops normal noraml N/A syscall errors -EIO -EROFS N/A mount option rw ro N/A pending dir write keep keep N/A pending non-dir write drop keep N/A pending node write drop keep N/A pending meta write keep keep N/A By default it uses "continue" mode. [Yangtao helps to clean up function's name] Signed-off-by: Yangtao Li <[email protected]> Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent ac9a786 commit b62e71b

File tree

8 files changed

+167
-24
lines changed

8 files changed

+167
-24
lines changed

Documentation/filesystems/f2fs.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,22 @@ age_extent_cache Enable an age extent cache based on rb-tree. It records
351351
data block update frequency of the extent per inode, in
352352
order to provide better temperature hints for data block
353353
allocation.
354+
errors=%s Specify f2fs behavior on critical errors. This supports modes:
355+
"panic", "continue" and "remount-ro", respectively, trigger
356+
panic immediately, continue without doing anything, and remount
357+
the partition in read-only mode. By default it uses "continue"
358+
mode.
359+
====================== =============== =============== ========
360+
mode continue remount-ro panic
361+
====================== =============== =============== ========
362+
access ops normal noraml N/A
363+
syscall errors -EIO -EROFS N/A
364+
mount option rw ro N/A
365+
pending dir write keep keep N/A
366+
pending non-dir write drop keep N/A
367+
pending node write drop keep N/A
368+
pending meta write keep keep N/A
369+
====================== =============== =============== ========
354370
======================== ============================================================
355371

356372
Debugfs Entries

fs/f2fs/checkpoint.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io,
3030
unsigned char reason)
3131
{
3232
f2fs_build_fault_attr(sbi, 0, 0);
33-
set_ckpt_flags(sbi, CP_ERROR_FLAG);
34-
if (!end_io) {
33+
if (!end_io)
3534
f2fs_flush_merged_writes(sbi);
36-
37-
f2fs_handle_stop(sbi, reason);
38-
}
35+
f2fs_handle_critical_error(sbi, reason, end_io);
3936
}
4037

4138
/*

fs/f2fs/data.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,10 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
28072807
if (S_ISDIR(inode->i_mode) &&
28082808
!is_sbi_flag_set(sbi, SBI_IS_CLOSE))
28092809
goto redirty_out;
2810+
2811+
/* keep data pages in remount-ro mode */
2812+
if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY)
2813+
goto redirty_out;
28102814
goto out;
28112815
}
28122816

fs/f2fs/f2fs.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ struct f2fs_mount_info {
162162
int fs_mode; /* fs mode: LFS or ADAPTIVE */
163163
int bggc_mode; /* bggc mode: off, on or sync */
164164
int memory_mode; /* memory mode */
165+
int errors; /* errors parameter */
165166
int discard_unit; /*
166167
* discard command's offset/size should
167168
* be aligned to this unit: block,
@@ -1370,6 +1371,12 @@ enum {
13701371
MEMORY_MODE_LOW, /* memory mode for low memry devices */
13711372
};
13721373

1374+
enum errors_option {
1375+
MOUNT_ERRORS_READONLY, /* remount fs ro on errors */
1376+
MOUNT_ERRORS_CONTINUE, /* continue on errors */
1377+
MOUNT_ERRORS_PANIC, /* panic on errors */
1378+
};
1379+
13731380
static inline int f2fs_test_bit(unsigned int nr, char *addr);
13741381
static inline void f2fs_set_bit(unsigned int nr, char *addr);
13751382
static inline void f2fs_clear_bit(unsigned int nr, char *addr);
@@ -1721,8 +1728,14 @@ struct f2fs_sb_info {
17211728

17221729
struct workqueue_struct *post_read_wq; /* post read workqueue */
17231730

1724-
unsigned char errors[MAX_F2FS_ERRORS]; /* error flags */
1725-
spinlock_t error_lock; /* protect errors array */
1731+
/*
1732+
* If we are in irq context, let's update error information into
1733+
* on-disk superblock in the work.
1734+
*/
1735+
struct work_struct s_error_work;
1736+
unsigned char errors[MAX_F2FS_ERRORS]; /* error flags */
1737+
unsigned char stop_reason[MAX_STOP_REASON]; /* stop reason */
1738+
spinlock_t error_lock; /* protect errors/stop_reason array */
17261739
bool error_dirty; /* errors of sb is dirty */
17271740

17281741
struct kmem_cache *inline_xattr_slab; /* inline xattr entry */
@@ -3541,8 +3554,9 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
35413554
int f2fs_quota_sync(struct super_block *sb, int type);
35423555
loff_t max_file_blocks(struct inode *inode);
35433556
void f2fs_quota_off_umount(struct super_block *sb);
3544-
void f2fs_handle_stop(struct f2fs_sb_info *sbi, unsigned char reason);
35453557
void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag);
3558+
void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason,
3559+
bool irq_context);
35463560
void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error);
35473561
int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
35483562
int f2fs_sync_fs(struct super_block *sb, int sync);

fs/f2fs/file.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,7 +2225,6 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
22252225
ret = 0;
22262226
f2fs_stop_checkpoint(sbi, false,
22272227
STOP_CP_REASON_SHUTDOWN);
2228-
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22292228
trace_f2fs_shutdown(sbi, in, ret);
22302229
}
22312230
return ret;
@@ -2238,7 +2237,6 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
22382237
if (ret)
22392238
goto out;
22402239
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2241-
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22422240
thaw_bdev(sb->s_bdev);
22432241
break;
22442242
case F2FS_GOING_DOWN_METASYNC:
@@ -2247,16 +2245,13 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
22472245
if (ret)
22482246
goto out;
22492247
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2250-
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22512248
break;
22522249
case F2FS_GOING_DOWN_NOSYNC:
22532250
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2254-
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22552251
break;
22562252
case F2FS_GOING_DOWN_METAFLUSH:
22572253
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
22582254
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2259-
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22602255
break;
22612256
case F2FS_GOING_DOWN_NEED_FSCK:
22622257
set_sbi_flag(sbi, SBI_NEED_FSCK);

fs/f2fs/gc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int gc_thread_func(void *data)
5959
if (gc_th->gc_wake)
6060
gc_th->gc_wake = false;
6161

62-
if (try_to_freeze()) {
62+
if (try_to_freeze() || f2fs_readonly(sbi->sb)) {
6363
stat_other_skip_bggc_count(sbi);
6464
continue;
6565
}

fs/f2fs/node.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,9 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
15961596
trace_f2fs_writepage(page, NODE);
15971597

15981598
if (unlikely(f2fs_cp_error(sbi))) {
1599+
/* keep node pages in remount-ro mode */
1600+
if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY)
1601+
goto redirty_out;
15991602
ClearPageUptodate(page);
16001603
dec_page_count(sbi, F2FS_DIRTY_NODES);
16011604
unlock_page(page);

fs/f2fs/super.c

Lines changed: 124 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ enum {
164164
Opt_discard_unit,
165165
Opt_memory_mode,
166166
Opt_age_extent_cache,
167+
Opt_errors,
167168
Opt_err,
168169
};
169170

@@ -243,6 +244,7 @@ static match_table_t f2fs_tokens = {
243244
{Opt_discard_unit, "discard_unit=%s"},
244245
{Opt_memory_mode, "memory=%s"},
245246
{Opt_age_extent_cache, "age_extent_cache"},
247+
{Opt_errors, "errors=%s"},
246248
{Opt_err, NULL},
247249
};
248250

@@ -1268,6 +1270,25 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
12681270
case Opt_age_extent_cache:
12691271
set_opt(sbi, AGE_EXTENT_CACHE);
12701272
break;
1273+
case Opt_errors:
1274+
name = match_strdup(&args[0]);
1275+
if (!name)
1276+
return -ENOMEM;
1277+
if (!strcmp(name, "remount-ro")) {
1278+
F2FS_OPTION(sbi).errors =
1279+
MOUNT_ERRORS_READONLY;
1280+
} else if (!strcmp(name, "continue")) {
1281+
F2FS_OPTION(sbi).errors =
1282+
MOUNT_ERRORS_CONTINUE;
1283+
} else if (!strcmp(name, "panic")) {
1284+
F2FS_OPTION(sbi).errors =
1285+
MOUNT_ERRORS_PANIC;
1286+
} else {
1287+
kfree(name);
1288+
return -EINVAL;
1289+
}
1290+
kfree(name);
1291+
break;
12711292
default:
12721293
f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
12731294
p);
@@ -1622,6 +1643,9 @@ static void f2fs_put_super(struct super_block *sb)
16221643
f2fs_destroy_node_manager(sbi);
16231644
f2fs_destroy_segment_manager(sbi);
16241645

1646+
/* flush s_error_work before sbi destroy */
1647+
flush_work(&sbi->s_error_work);
1648+
16251649
f2fs_destroy_post_read_wq(sbi);
16261650

16271651
kvfree(sbi->ckpt);
@@ -2052,6 +2076,13 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
20522076
else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW)
20532077
seq_printf(seq, ",memory=%s", "low");
20542078

2079+
if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY)
2080+
seq_printf(seq, ",errors=%s", "remount-ro");
2081+
else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE)
2082+
seq_printf(seq, ",errors=%s", "continue");
2083+
else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC)
2084+
seq_printf(seq, ",errors=%s", "panic");
2085+
20552086
return 0;
20562087
}
20572088

@@ -2080,6 +2111,7 @@ static void default_options(struct f2fs_sb_info *sbi)
20802111
}
20812112
F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
20822113
F2FS_OPTION(sbi).memory_mode = MEMORY_MODE_NORMAL;
2114+
F2FS_OPTION(sbi).errors = MOUNT_ERRORS_CONTINUE;
20832115

20842116
sbi->sb->s_flags &= ~SB_INLINECRYPT;
20852117

@@ -2281,6 +2313,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
22812313
if (err)
22822314
goto restore_opts;
22832315

2316+
/* flush outstanding errors before changing fs state */
2317+
flush_work(&sbi->s_error_work);
2318+
22842319
/*
22852320
* Previous and new state of filesystem is RO,
22862321
* so skip checking GC and FLUSH_MERGE conditions.
@@ -3926,45 +3961,60 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
39263961
return err;
39273962
}
39283963

3929-
void f2fs_handle_stop(struct f2fs_sb_info *sbi, unsigned char reason)
3964+
static void save_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason)
3965+
{
3966+
unsigned long flags;
3967+
3968+
spin_lock_irqsave(&sbi->error_lock, flags);
3969+
if (sbi->stop_reason[reason] < GENMASK(BITS_PER_BYTE - 1, 0))
3970+
sbi->stop_reason[reason]++;
3971+
spin_unlock_irqrestore(&sbi->error_lock, flags);
3972+
}
3973+
3974+
static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi)
39303975
{
39313976
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
3977+
unsigned long flags;
39323978
int err;
39333979

39343980
f2fs_down_write(&sbi->sb_lock);
39353981

3936-
if (raw_super->s_stop_reason[reason] < GENMASK(BITS_PER_BYTE - 1, 0))
3937-
raw_super->s_stop_reason[reason]++;
3982+
spin_lock_irqsave(&sbi->error_lock, flags);
3983+
memcpy(raw_super->s_stop_reason, sbi->stop_reason, MAX_STOP_REASON);
3984+
spin_unlock_irqrestore(&sbi->error_lock, flags);
39383985

39393986
err = f2fs_commit_super(sbi, false);
3940-
if (err)
3941-
f2fs_err(sbi, "f2fs_commit_super fails to record reason:%u err:%d",
3942-
reason, err);
3987+
39433988
f2fs_up_write(&sbi->sb_lock);
3989+
if (err)
3990+
f2fs_err(sbi, "f2fs_commit_super fails to record err:%d", err);
39443991
}
39453992

39463993
void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag)
39473994
{
3948-
spin_lock(&sbi->error_lock);
3995+
unsigned long flags;
3996+
3997+
spin_lock_irqsave(&sbi->error_lock, flags);
39493998
if (!test_bit(flag, (unsigned long *)sbi->errors)) {
39503999
set_bit(flag, (unsigned long *)sbi->errors);
39514000
sbi->error_dirty = true;
39524001
}
3953-
spin_unlock(&sbi->error_lock);
4002+
spin_unlock_irqrestore(&sbi->error_lock, flags);
39544003
}
39554004

39564005
static bool f2fs_update_errors(struct f2fs_sb_info *sbi)
39574006
{
4007+
unsigned long flags;
39584008
bool need_update = false;
39594009

3960-
spin_lock(&sbi->error_lock);
4010+
spin_lock_irqsave(&sbi->error_lock, flags);
39614011
if (sbi->error_dirty) {
39624012
memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors,
39634013
MAX_F2FS_ERRORS);
39644014
sbi->error_dirty = false;
39654015
need_update = true;
39664016
}
3967-
spin_unlock(&sbi->error_lock);
4017+
spin_unlock_irqrestore(&sbi->error_lock, flags);
39684018

39694019
return need_update;
39704020
}
@@ -3988,6 +4038,66 @@ void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error)
39884038
f2fs_up_write(&sbi->sb_lock);
39894039
}
39904040

4041+
static bool system_going_down(void)
4042+
{
4043+
return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF
4044+
|| system_state == SYSTEM_RESTART;
4045+
}
4046+
4047+
void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason,
4048+
bool irq_context)
4049+
{
4050+
struct super_block *sb = sbi->sb;
4051+
bool shutdown = reason == STOP_CP_REASON_SHUTDOWN;
4052+
bool continue_fs = !shutdown &&
4053+
F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE;
4054+
4055+
set_ckpt_flags(sbi, CP_ERROR_FLAG);
4056+
4057+
if (!f2fs_hw_is_readonly(sbi)) {
4058+
save_stop_reason(sbi, reason);
4059+
4060+
if (irq_context && !shutdown)
4061+
schedule_work(&sbi->s_error_work);
4062+
else
4063+
f2fs_record_stop_reason(sbi);
4064+
}
4065+
4066+
/*
4067+
* We force ERRORS_RO behavior when system is rebooting. Otherwise we
4068+
* could panic during 'reboot -f' as the underlying device got already
4069+
* disabled.
4070+
*/
4071+
if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC &&
4072+
!shutdown && !system_going_down() &&
4073+
!is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN))
4074+
panic("F2FS-fs (device %s): panic forced after error\n",
4075+
sb->s_id);
4076+
4077+
if (shutdown)
4078+
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
4079+
4080+
/* continue filesystem operators if errors=continue */
4081+
if (continue_fs || f2fs_readonly(sb))
4082+
return;
4083+
4084+
f2fs_warn(sbi, "Remounting filesystem read-only");
4085+
/*
4086+
* Make sure updated value of ->s_mount_flags will be visible before
4087+
* ->s_flags update
4088+
*/
4089+
smp_wmb();
4090+
sb->s_flags |= SB_RDONLY;
4091+
}
4092+
4093+
static void f2fs_record_error_work(struct work_struct *work)
4094+
{
4095+
struct f2fs_sb_info *sbi = container_of(work,
4096+
struct f2fs_sb_info, s_error_work);
4097+
4098+
f2fs_record_stop_reason(sbi);
4099+
}
4100+
39914101
static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
39924102
{
39934103
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
@@ -4218,7 +4328,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
42184328
sb->s_fs_info = sbi;
42194329
sbi->raw_super = raw_super;
42204330

4331+
INIT_WORK(&sbi->s_error_work, f2fs_record_error_work);
42214332
memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS);
4333+
memcpy(sbi->stop_reason, raw_super->s_stop_reason, MAX_STOP_REASON);
42224334

42234335
/* precompute checksum seed for metadata */
42244336
if (f2fs_sb_has_inode_chksum(sbi))
@@ -4615,6 +4727,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
46154727
f2fs_destroy_segment_manager(sbi);
46164728
stop_ckpt_thread:
46174729
f2fs_stop_ckpt_thread(sbi);
4730+
/* flush s_error_work before sbi destroy */
4731+
flush_work(&sbi->s_error_work);
46184732
f2fs_destroy_post_read_wq(sbi);
46194733
free_devices:
46204734
destroy_device_list(sbi);

0 commit comments

Comments
 (0)