f2fs: turn off atomic writes when deteting abnormal behaviors
Jaegeuk Kim
maintainerPATCH 1/3 f2fs: turn off atomic writes when deteting abnormal behaviors
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
- write_begin() gives EINVAL to avoid stale data writes, and SQLite will call F2FS_IOC_ABORT_VOLATILE_WRITE to notify aborting the transaction,
- F2FS_IOC_START_ATOMIC_WRITE gives EINVAL for SQLite to fall back normal journal_mode,
- F2FS_IOC_COMMIT_ATOMIC_WRITE gives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
--- fs/f2fs/data.c | 7 ++++--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/file.c | 6 +++++- fs/f2fs/gc.c | 4 +--- fs/f2fs/segment.c | 21 +++++++++++---------- 5 files changed, 23 insertions(+), 19 deletions(-)
fs/f2fs/data.c +4 -3
@@ -2247,8 +2247,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { - err = -ENOMEM ; + (is_sbi_flag_set (sbi,SBI_DISABLE_ATOMIC_WRITE ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { + err = -EINVAL ; drop_atomic = true; goto fail; }
@@ -2331,7 +2332,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,f2fs_put_page (page,1 );f2fs_write_failed (mapping, pos + len);if (drop_atomic) -f2fs_drop_inmem_pages_all (sbi, false); +f2fs_disable_atomic_write (sbi);return err; }
fs/f2fs/f2fs.h +2 -2
@@ -621,7 +621,6 @@ enum {enum {GC_FAILURE_PIN , -GC_FAILURE_ATOMIC ,MAX_GC_FAILURE };
@@ -1066,6 +1065,7 @@ enum {SBI_POR_DOING ,/* recovery is doing or not */ SBI_NEED_SB_WRITE ,/* need to recover superblock */ SBI_NEED_CP ,/* need to checkpoint */ + SBI_DISABLE_ATOMIC_WRITE, /* turn off atomic write */ }; enum {
@@ -2833,7 +2833,7 @@ void f2fs_destroy_node_manager_caches(void);*/ bool f2fs_need_SSR (struct f2fs_sb_info *sbi);void f2fs_register_inmem_page (struct inode *inode,struct page *page); -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure); +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi);void f2fs_drop_inmem_pages (struct inode *inode);void f2fs_drop_inmem_page (struct inode *inode,struct page *page);int f2fs_commit_inmem_pages (struct inode *inode);
fs/f2fs/file.c +5 -1
@@ -1682,6 +1682,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)if (!S_ISREG (inode->i_mode))return -EINVAL ; +if (is_sbi_flag_set (F2FS_I_SB (inode),SBI_DISABLE_ATOMIC_WRITE )) +return -EINVAL ; + ret =mnt_want_write_file (filp);if (ret)return ret;
@@ -1750,7 +1753,6 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true);if (!ret) {clear_inode_flag (inode,FI_ATOMIC_FILE ); -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); } }else {
@@ -1853,6 +1855,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);
fs/f2fs/gc.c +1 -3
@@ -629,7 +629,6 @@ static void move_data_block(struct inode *inode, block_t bidx, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }
@@ -745,7 +744,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }
@@ -1100,7 +1098,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,if (has_not_enough_free_secs (sbi, sec_freed,0 )) {if (skipped_round >MAX_SKIP_ATOMIC_COUNT && skipped_round *2 >= round) -f2fs_drop_inmem_pages_all (sbi, true); +f2fs_disable_atomic_write (sbi); segno =NULL_SEGNO ; goto gc_more; }
fs/f2fs/segment.c +11 -10
@@ -274,11 +274,14 @@ static int __revoke_inmem_pages(struct inode *inode,return err; } -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure) +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi) {struct list_head *head = &sbi->inode_list[ATOMIC_FILE ];struct inode *inode;struct f2fs_inode_info *fi; + +/* just turn it off */ +set_sbi_flag (sbi,SBI_DISABLE_ATOMIC_WRITE ); next:spin_lock (&sbi->inode_lock[ATOMIC_FILE ]);if (list_empty (head)) {
@@ -290,17 +293,16 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)spin_unlock (&sbi->inode_lock[ATOMIC_FILE ]);if (inode) { -if (gc_failure) { -if (fi->i_gc_failures[GC_FAILURE_ATOMIC ]) - goto drop; - goto skip; +inode_lock (inode); +/* need to check whether it was already revoked */ +if (f2fs_is_atomic_file (inode)) { +f2fs_drop_inmem_pages (inode); +set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); } -drop: -set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); -f2fs_drop_inmem_pages (inode); +inode_unlock (inode);iput (inode); } -skip: +congestion_wait (BLK_RW_ASYNC ,HZ /50 );cond_resched (); goto next;
@@ -320,7 +322,6 @@ void f2fs_drop_inmem_pages(struct inode *inode)mutex_unlock (&fi->inmem_lock);clear_inode_flag (inode,FI_ATOMIC_FILE ); - fi->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Jaegeuk Kim
maintainerPATCH 2/3 f2fs: keep meta pages in cp_error state
It turns out losing meta pages in shutdown period makes f2fs very unstable so that I could see many unexpected error conditions.
Let's keep meta pages for fault injection and sudden power-off tests.
--- fs/f2fs/checkpoint.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-)
fs/f2fs/checkpoint.c +13 -15
@@ -242,11 +242,8 @@ static int __f2fs_write_meta_page(struct page *page,trace_f2fs_writepage (page,META ); -if (unlikely (f2fs_cp_error (sbi))) { -dec_page_count (sbi,F2FS_DIRTY_META ); -unlock_page (page); -return 0 ; - } +if (unlikely (f2fs_cp_error (sbi))) + goto redirty_out;if (unlikely (is_sbi_flag_set (sbi,SBI_POR_DOING ))) goto redirty_out;if (wbc->for_reclaim && page->index <GET_SUM_BLOCK (sbi,0 ))
@@ -1129,6 +1126,9 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)if (!get_pages (sbi,F2FS_WB_CP_DATA ))break ; +if (unlikely (f2fs_cp_error (sbi))) +break ; +io_schedule_timeout (5 *HZ ); }finish_wait (&sbi->cp_wait, &wait);
@@ -1202,8 +1202,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,/* writeout cp pack 2 page */ err =__f2fs_write_meta_page (page, &wbc,FS_CP_META_IO ); -f2fs_bug_on (sbi, err); +if (unlikely (err &&f2fs_cp_error (sbi))) { +f2fs_put_page (page,1 ); +return ; + } +f2fs_bug_on (sbi, err);f2fs_put_page (page,0 );/* submit checkpoint (with barrier if NOBARRIER is not set) */
@@ -1229,7 +1233,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)while (get_pages (sbi,F2FS_DIRTY_META )) {f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; }/*
@@ -1309,7 +1313,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; } }
@@ -1350,9 +1354,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)/* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback (sbi); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -/* flush all device cache */ err =f2fs_flush_device_cache (sbi);if (err)
@@ -1364,9 +1365,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_release_ino_entry (sbi, false); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -clear_sbi_flag (sbi,SBI_IS_DIRTY );clear_sbi_flag (sbi,SBI_NEED_CP );__set_cp_next_pack (sbi);
@@ -1381,7 +1379,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_bug_on (sbi,get_pages (sbi,F2FS_DIRTY_DENTS )); -return 0 ; +return unlikely (f2fs_cp_error (sbi)); }/*
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 2/3] f2fs: keep meta pages in cp_error state
Quoted 91 lines · Jaegeuk Kim
It turns out losing meta pages in shutdown period makes f2fs very unstable so that I could see many unexpected error conditions.
Let's keep meta pages for fault injection and sudden power-off tests.
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/checkpoint.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-)fs/f2fs/checkpoint.c +12
-14@@ -242,11 +242,8 @@ static int __f2fs_write_meta_page(struct page *page,trace_f2fs_writepage (page,META ); -if (unlikely (f2fs_cp_error (sbi))) { -dec_page_count (sbi,F2FS_DIRTY_META ); -unlock_page (page); -return 0 ; - } +if (unlikely (f2fs_cp_error (sbi))) + goto redirty_out;if (unlikely (is_sbi_flag_set (sbi,SBI_POR_DOING ))) goto redirty_out;if (wbc->for_reclaim && page->index <GET_SUM_BLOCK (sbi,0 ))@@ -1129,6 +1126,9 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)if (!get_pages (sbi,F2FS_WB_CP_DATA ))break ; +if (unlikely (f2fs_cp_error (sbi))) +break ; +io_schedule_timeout (5 *HZ ); }finish_wait (&sbi->cp_wait, &wait);@@ -1202,8 +1202,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,/* writeout cp pack 2 page */ err =__f2fs_write_meta_page (page, &wbc,FS_CP_META_IO ); -f2fs_bug_on (sbi, err); +if (unlikely (err &&f2fs_cp_error (sbi))) { +f2fs_put_page (page,1 ); +return ; + } +f2fs_bug_on (sbi, err);f2fs_put_page (page,0 );/* submit checkpoint (with barrier if NOBARRIER is not set) */ @@ -1229,7 +1233,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)while (get_pages (sbi,F2FS_DIRTY_META )) {f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; }/* @@ -1309,7 +1313,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; } }@@ -1350,9 +1354,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)/* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback (sbi); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -/* flush all device cache */ err =f2fs_flush_device_cache (sbi);if (err)@@ -1364,9 +1365,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_release_ino_entry (sbi, false); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -clear_sbi_flag (sbi,SBI_IS_DIRTY );clear_sbi_flag (sbi,SBI_NEED_CP );__set_cp_next_pack (sbi);
fs/f2fs/checkpoint.c static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) · line 1382
Quoted 5 lines
fs/f2fs/checkpoint.c +1
-1@@ -1381,7 +1379,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_bug_on (sbi,get_pages (sbi,F2FS_DIRTY_DENTS )); -return 0 ; +return unlikely (f2fs_cp_error (sbi));
return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0;
Quoted 4 lines
fs/f2fs/checkpoint.c +0
-0}/*
Jaegeuk Kim
maintainerRe: [PATCH 2/3] f2fs: keep meta pages in cp_error state
Quoted 93 lines · Chao Yu
Quoted 92 lines · Jaegeuk Kim
It turns out losing meta pages in shutdown period makes f2fs very unstable so that I could see many unexpected error conditions.
Let's keep meta pages for fault injection and sudden power-off tests.
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/checkpoint.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-)fs/f2fs/checkpoint.c +12
-14@@ -242,11 +242,8 @@ static int __f2fs_write_meta_page(struct page *page,trace_f2fs_writepage (page,META ); -if (unlikely (f2fs_cp_error (sbi))) { -dec_page_count (sbi,F2FS_DIRTY_META ); -unlock_page (page); -return 0 ; - } +if (unlikely (f2fs_cp_error (sbi))) + goto redirty_out;if (unlikely (is_sbi_flag_set (sbi,SBI_POR_DOING ))) goto redirty_out;if (wbc->for_reclaim && page->index <GET_SUM_BLOCK (sbi,0 ))@@ -1129,6 +1126,9 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)if (!get_pages (sbi,F2FS_WB_CP_DATA ))break ; +if (unlikely (f2fs_cp_error (sbi))) +break ; +io_schedule_timeout (5 *HZ ); }finish_wait (&sbi->cp_wait, &wait);@@ -1202,8 +1202,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,/* writeout cp pack 2 page */ err =__f2fs_write_meta_page (page, &wbc,FS_CP_META_IO ); -f2fs_bug_on (sbi, err); +if (unlikely (err &&f2fs_cp_error (sbi))) { +f2fs_put_page (page,1 ); +return ; + } +f2fs_bug_on (sbi, err);f2fs_put_page (page,0 );/* submit checkpoint (with barrier if NOBARRIER is not set) */ @@ -1229,7 +1233,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)while (get_pages (sbi,F2FS_DIRTY_META )) {f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; }/* @@ -1309,7 +1313,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_CP_META_IO );if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; +break ; } }@@ -1350,9 +1354,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)/* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback (sbi); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -/* flush all device cache */ err =f2fs_flush_device_cache (sbi);if (err)@@ -1364,9 +1365,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)f2fs_release_ino_entry (sbi, false); -if (unlikely (f2fs_cp_error (sbi))) -return -EIO ; -clear_sbi_flag (sbi,SBI_IS_DIRTY );clear_sbi_flag (sbi,SBI_NEED_CP );__set_cp_next_pack (sbi);@@ -1381,7 +1379,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
Quoted 7 lines
fs/f2fs/checkpoint.c static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) · line 1382
Quoted 4 lines
fs/f2fs/checkpoint.c +1
-1f2fs_bug_on (sbi,get_pages (sbi,F2FS_DIRTY_DENTS )); -return 0 ; +return unlikely (f2fs_cp_error (sbi));return unlikely(f2fs_cp_error(sbi)) ?
-EIO: 0;
Done.
Quoted 4 lines
Quoted 4 lines
fs/f2fs/checkpoint.c +0
-0}/*
Jaegeuk Kim
maintainerPATCH 3/3 f2fs: indicate shutdown f2fs to allow unmount successfully
In reply to Jaegeuk KimOnce we shutdown f2fs, we have to flush stale pages in order to unmount the system. In order to make stable, we need to stop fault injection as well.
--- fs/f2fs/checkpoint.c | 1 + fs/f2fs/f2fs.h | 7 +++++++ fs/f2fs/file.c | 4 ++++ fs/f2fs/inode.c | 3 +++ fs/f2fs/node.c | 3 ++- fs/f2fs/super.c | 5 +---- 6 files changed, 18 insertions(+), 5 deletions(-)
fs/f2fs/checkpoint.c +1 -0
@@ -28,6 +28,7 @@ struct kmem_cache *f2fs_inode_entry_slab;void f2fs_stop_checkpoint (struct f2fs_sb_info *sbi,bool end_io) { +f2fs_build_fault_attr (sbi,0 );set_ckpt_flags (sbi,CP_ERROR_FLAG );if (!end_io)f2fs_flush_merged_writes (sbi);
fs/f2fs/f2fs.h +7 -0
@@ -1066,6 +1066,7 @@ enum {SBI_NEED_SB_WRITE ,/* need to recover superblock */ SBI_NEED_CP ,/* need to checkpoint */ SBI_DISABLE_ATOMIC_WRITE ,/* turn off atomic write */ + SBI_IS_SHUTDOWN, /* shutdown by ioctl */ }; enum {
@@ -3373,4 +3374,10 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) F2FS_I_SB(inode)->s_ndevs); } +#ifdef CONFIG_F2FS_FAULT_INJECTION +extern void f2fs_build_fault_attr (struct f2fs_sb_info *sbi,unsigned int rate); +#else +#define f2fs_build_fault_attr (sbi, rate) do { } while (0) +#endif +#endif
fs/f2fs/file.c +4 -0
@@ -1893,6 +1893,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) }if (sb) {f2fs_stop_checkpoint (sbi, false); +set_sbi_flag (sbi,SBI_IS_SHUTDOWN );thaw_bdev (sb->s_bdev, sb); }break ;
@@ -1902,13 +1903,16 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)if (ret) goto out;f2fs_stop_checkpoint (sbi, false); +set_sbi_flag (sbi,SBI_IS_SHUTDOWN );break ;case F2FS_GOING_DOWN_NOSYNC :f2fs_stop_checkpoint (sbi, false); +set_sbi_flag (sbi,SBI_IS_SHUTDOWN );break ;case F2FS_GOING_DOWN_METAFLUSH :f2fs_sync_meta_pages (sbi,META ,LONG_MAX ,FS_META_IO );f2fs_stop_checkpoint (sbi, false); +set_sbi_flag (sbi,SBI_IS_SHUTDOWN );break ;default : ret = -EINVAL ;
fs/f2fs/inode.c +3 -0
@@ -159,6 +159,9 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)struct f2fs_inode *ri;__u32 provided, calculated; +if (unlikely (is_sbi_flag_set (sbi,SBI_IS_SHUTDOWN ))) +return true; +if (!f2fs_enable_inode_chksum (sbi, page) ||PageDirty (page) ||PageWriteback (page))return true;
fs/f2fs/node.c +2 -1
@@ -1146,7 +1146,8 @@ static int read_node_page(struct page *page, int op_flags)f2fs_get_node_info (sbi, page->index, &ni); -if (unlikely (ni.blk_addr ==NULL_ADDR )) { +if (unlikely (ni.blk_addr ==NULL_ADDR ) || +is_sbi_flag_set (sbi,SBI_IS_SHUTDOWN )) {ClearPageUptodate (page);return -ENOENT ; }
fs/f2fs/super.c +1 -4
@@ -57,8 +57,7 @@ char *fault_name[FAULT_MAX] = { [FAULT_CHECKPOINT] = "checkpoint error", }; -static void f2fs_build_fault_attr (struct f2fs_sb_info *sbi, -unsigned int rate) +void f2fs_build_fault_attr (struct f2fs_sb_info *sbi,unsigned int rate) {struct f2fs_fault_info *ffi = &F2FS_OPTION (sbi).fault_info;
@@ -1379,9 +1378,7 @@ static void default_options(struct f2fs_sb_info *sbi)set_opt (sbi,POSIX_ACL );#endif -#ifdef CONFIG_F2FS_FAULT_INJECTION f2fs_build_fault_attr (sbi,0 ); -#endif }#ifdef CONFIG_QUOTA
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Quoted 14 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.
Quoted 2 lines
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open atomic_write file for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.
Thanks,
Quoted 178 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/data.c | 7 ++++--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/file.c | 6 +++++- fs/f2fs/gc.c | 4 +--- fs/f2fs/segment.c | 21 +++++++++++---------- 5 files changed, 23 insertions(+), 19 deletions(-)fs/f2fs/data.c +4
-3@@ -2247,8 +2247,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { - err = -ENOMEM ; + (is_sbi_flag_set (sbi,SBI_DISABLE_ATOMIC_WRITE ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { + err = -EINVAL ; drop_atomic = true; goto fail; }@@ -2331,7 +2332,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,f2fs_put_page (page,1 );f2fs_write_failed (mapping, pos + len);if (drop_atomic) -f2fs_drop_inmem_pages_all (sbi, false); +f2fs_disable_atomic_write (sbi);return err; }fs/f2fs/f2fs.h +2
-2@@ -621,7 +621,6 @@ enum {enum {GC_FAILURE_PIN , -GC_FAILURE_ATOMIC ,MAX_GC_FAILURE };@@ -1066,6 +1065,7 @@ enum {SBI_POR_DOING ,/* recovery is doing or not */ SBI_NEED_SB_WRITE ,/* need to recover superblock */ SBI_NEED_CP ,/* need to checkpoint */ + SBI_DISABLE_ATOMIC_WRITE, /* turn off atomic write */ }; enum {@@ -2833,7 +2833,7 @@ void f2fs_destroy_node_manager_caches(void);*/ bool f2fs_need_SSR (struct f2fs_sb_info *sbi);void f2fs_register_inmem_page (struct inode *inode,struct page *page); -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure); +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi);void f2fs_drop_inmem_pages (struct inode *inode);void f2fs_drop_inmem_page (struct inode *inode,struct page *page);int f2fs_commit_inmem_pages (struct inode *inode);fs/f2fs/file.c +5
-1@@ -1682,6 +1682,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)if (!S_ISREG (inode->i_mode))return -EINVAL ; +if (is_sbi_flag_set (F2FS_I_SB (inode),SBI_DISABLE_ATOMIC_WRITE )) +return -EINVAL ; + ret =mnt_want_write_file (filp);if (ret)return ret;@@ -1750,7 +1753,6 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true);if (!ret) {clear_inode_flag (inode,FI_ATOMIC_FILE ); -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); } }else {@@ -1853,6 +1855,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);fs/f2fs/gc.c +1
-3@@ -629,7 +629,6 @@ static void move_data_block(struct inode *inode, block_t bidx, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -745,7 +744,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -1100,7 +1098,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,if (has_not_enough_free_secs (sbi, sec_freed,0 )) {if (skipped_round >MAX_SKIP_ATOMIC_COUNT && skipped_round *2 >= round) -f2fs_drop_inmem_pages_all (sbi, true); +f2fs_disable_atomic_write (sbi); segno =NULL_SEGNO ; goto gc_more; }fs/f2fs/segment.c +11
-10@@ -274,11 +274,14 @@ static int __revoke_inmem_pages(struct inode *inode,return err; } -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure) +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi) {struct list_head *head = &sbi->inode_list[ATOMIC_FILE ];struct inode *inode;struct f2fs_inode_info *fi; + +/* just turn it off */ +set_sbi_flag (sbi,SBI_DISABLE_ATOMIC_WRITE ); next:spin_lock (&sbi->inode_lock[ATOMIC_FILE ]);if (list_empty (head)) {@@ -290,17 +293,16 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)spin_unlock (&sbi->inode_lock[ATOMIC_FILE ]);if (inode) { -if (gc_failure) { -if (fi->i_gc_failures[GC_FAILURE_ATOMIC ]) - goto drop; - goto skip; +inode_lock (inode); +/* need to check whether it was already revoked */ +if (f2fs_is_atomic_file (inode)) { +f2fs_drop_inmem_pages (inode); +set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); } -drop: -set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); -f2fs_drop_inmem_pages (inode); +inode_unlock (inode);iput (inode); } -skip: +congestion_wait (BLK_RW_ASYNC ,HZ /50 );cond_resched (); goto next;@@ -320,7 +322,6 @@ void f2fs_drop_inmem_pages(struct inode *inode)mutex_unlock (&fi->inmem_lock);clear_inode_flag (inode,FI_ATOMIC_FILE ); - fi->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); }
Jaegeuk Kim
maintainerQuoted 15 lines · Chao Yu
Quoted 14 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.
Quoted 8 lines
Quoted 2 lines
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open
atomic_writefile for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.
The point here is stopping sqlite to keep going wrong data writes even after we already revoked blocks.
Thanks,
Quoted 181 lines
Thanks,
Quoted 178 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/data.c | 7 ++++--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/file.c | 6 +++++- fs/f2fs/gc.c | 4 +--- fs/f2fs/segment.c | 21 +++++++++++---------- 5 files changed, 23 insertions(+), 19 deletions(-)fs/f2fs/data.c +4
-3@@ -2247,8 +2247,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { - err = -ENOMEM ; + (is_sbi_flag_set (sbi,SBI_DISABLE_ATOMIC_WRITE ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { + err = -EINVAL ; drop_atomic = true; goto fail; }@@ -2331,7 +2332,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,f2fs_put_page (page,1 );f2fs_write_failed (mapping, pos + len);if (drop_atomic) -f2fs_drop_inmem_pages_all (sbi, false); +f2fs_disable_atomic_write (sbi);return err; }fs/f2fs/f2fs.h +2
-2@@ -621,7 +621,6 @@ enum {enum {GC_FAILURE_PIN , -GC_FAILURE_ATOMIC ,MAX_GC_FAILURE };@@ -1066,6 +1065,7 @@ enum {SBI_POR_DOING ,/* recovery is doing or not */ SBI_NEED_SB_WRITE ,/* need to recover superblock */ SBI_NEED_CP ,/* need to checkpoint */ + SBI_DISABLE_ATOMIC_WRITE, /* turn off atomic write */ }; enum {@@ -2833,7 +2833,7 @@ void f2fs_destroy_node_manager_caches(void);*/ bool f2fs_need_SSR (struct f2fs_sb_info *sbi);void f2fs_register_inmem_page (struct inode *inode,struct page *page); -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure); +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi);void f2fs_drop_inmem_pages (struct inode *inode);void f2fs_drop_inmem_page (struct inode *inode,struct page *page);int f2fs_commit_inmem_pages (struct inode *inode);fs/f2fs/file.c +5
-1@@ -1682,6 +1682,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)if (!S_ISREG (inode->i_mode))return -EINVAL ; +if (is_sbi_flag_set (F2FS_I_SB (inode),SBI_DISABLE_ATOMIC_WRITE )) +return -EINVAL ; + ret =mnt_want_write_file (filp);if (ret)return ret;@@ -1750,7 +1753,6 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true);if (!ret) {clear_inode_flag (inode,FI_ATOMIC_FILE ); -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); } }else {@@ -1853,6 +1855,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);fs/f2fs/gc.c +1
-3@@ -629,7 +629,6 @@ static void move_data_block(struct inode *inode, block_t bidx, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -745,7 +744,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -1100,7 +1098,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,if (has_not_enough_free_secs (sbi, sec_freed,0 )) {if (skipped_round >MAX_SKIP_ATOMIC_COUNT && skipped_round *2 >= round) -f2fs_drop_inmem_pages_all (sbi, true); +f2fs_disable_atomic_write (sbi); segno =NULL_SEGNO ; goto gc_more; }fs/f2fs/segment.c +11
-10@@ -274,11 +274,14 @@ static int __revoke_inmem_pages(struct inode *inode,return err; } -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure) +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi) {struct list_head *head = &sbi->inode_list[ATOMIC_FILE ];struct inode *inode;struct f2fs_inode_info *fi; + +/* just turn it off */ +set_sbi_flag (sbi,SBI_DISABLE_ATOMIC_WRITE ); next:spin_lock (&sbi->inode_lock[ATOMIC_FILE ]);if (list_empty (head)) {@@ -290,17 +293,16 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)spin_unlock (&sbi->inode_lock[ATOMIC_FILE ]);if (inode) { -if (gc_failure) { -if (fi->i_gc_failures[GC_FAILURE_ATOMIC ]) - goto drop; - goto skip; +inode_lock (inode); +/* need to check whether it was already revoked */ +if (f2fs_is_atomic_file (inode)) { +f2fs_drop_inmem_pages (inode); +set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); } -drop: -set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); -f2fs_drop_inmem_pages (inode); +inode_unlock (inode);iput (inode); } -skip: +congestion_wait (BLK_RW_ASYNC ,HZ /50 );cond_resched (); goto next;@@ -320,7 +322,6 @@ void f2fs_drop_inmem_pages(struct inode *inode)mutex_unlock (&fi->inmem_lock);clear_inode_flag (inode,FI_ATOMIC_FILE ); - fi->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); }
Chao Yu
maintainerQuoted 19 lines · Jaegeuk Kim
Quoted 18 lines · Chao Yu
Quoted 16 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Quoted 8 lines
Quoted 5 lines
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open
atomic_writefile for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.The point here is stopping sqlite to keep going wrong data writes even after we already revoked blocks.
Yes, that's correct, what I mean is that if we can do that with smaller granularity like just revoke blocks for file which is blocking fggc, it will affect system/sqlite flow much less than forcing closing all atomic_write.
Thanks,
Quoted 193 lines
Thanks,
Quoted 175 lines
Thanks,
Quoted 172 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/data.c | 7 ++++--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/file.c | 6 +++++- fs/f2fs/gc.c | 4 +--- fs/f2fs/segment.c | 21 +++++++++++---------- 5 files changed, 23 insertions(+), 19 deletions(-)fs/f2fs/data.c +4
-3@@ -2247,8 +2247,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { - err = -ENOMEM ; + (is_sbi_flag_set (sbi,SBI_DISABLE_ATOMIC_WRITE ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { + err = -EINVAL ; drop_atomic = true; goto fail; }@@ -2331,7 +2332,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,f2fs_put_page (page,1 );f2fs_write_failed (mapping, pos + len);if (drop_atomic) -f2fs_drop_inmem_pages_all (sbi, false); +f2fs_disable_atomic_write (sbi);return err; }fs/f2fs/f2fs.h +2
-2@@ -621,7 +621,6 @@ enum {enum {GC_FAILURE_PIN , -GC_FAILURE_ATOMIC ,MAX_GC_FAILURE };@@ -1066,6 +1065,7 @@ enum {SBI_POR_DOING ,/* recovery is doing or not */ SBI_NEED_SB_WRITE ,/* need to recover superblock */ SBI_NEED_CP ,/* need to checkpoint */ + SBI_DISABLE_ATOMIC_WRITE, /* turn off atomic write */ }; enum {@@ -2833,7 +2833,7 @@ void f2fs_destroy_node_manager_caches(void);*/ bool f2fs_need_SSR (struct f2fs_sb_info *sbi);void f2fs_register_inmem_page (struct inode *inode,struct page *page); -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure); +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi);void f2fs_drop_inmem_pages (struct inode *inode);void f2fs_drop_inmem_page (struct inode *inode,struct page *page);int f2fs_commit_inmem_pages (struct inode *inode);fs/f2fs/file.c +5
-1@@ -1682,6 +1682,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)if (!S_ISREG (inode->i_mode))return -EINVAL ; +if (is_sbi_flag_set (F2FS_I_SB (inode),SBI_DISABLE_ATOMIC_WRITE )) +return -EINVAL ; + ret =mnt_want_write_file (filp);if (ret)return ret;@@ -1750,7 +1753,6 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true);if (!ret) {clear_inode_flag (inode,FI_ATOMIC_FILE ); -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); } }else {@@ -1853,6 +1855,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);fs/f2fs/gc.c +1
-3@@ -629,7 +629,6 @@ static void move_data_block(struct inode *inode, block_t bidx, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -745,7 +744,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, goto out;if (f2fs_is_atomic_file (inode)) { -F2FS_I (inode)->i_gc_failures[GC_FAILURE_ATOMIC ]++;F2FS_I_SB (inode)->skipped_atomic_files[gc_type]++; goto out; }@@ -1100,7 +1098,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,if (has_not_enough_free_secs (sbi, sec_freed,0 )) {if (skipped_round >MAX_SKIP_ATOMIC_COUNT && skipped_round *2 >= round) -f2fs_drop_inmem_pages_all (sbi, true); +f2fs_disable_atomic_write (sbi); segno =NULL_SEGNO ; goto gc_more; }fs/f2fs/segment.c +11
-9@@ -274,11 +274,14 @@ static int __revoke_inmem_pages(struct inode *inode,return err; } -void f2fs_drop_inmem_pages_all (struct f2fs_sb_info *sbi,bool gc_failure) +void f2fs_disable_atomic_write (struct f2fs_sb_info *sbi) {struct list_head *head = &sbi->inode_list[ATOMIC_FILE ];struct inode *inode;struct f2fs_inode_info *fi; + +/* just turn it off */ +set_sbi_flag (sbi,SBI_DISABLE_ATOMIC_WRITE ); next:spin_lock (&sbi->inode_lock[ATOMIC_FILE ]);if (list_empty (head)) {@@ -290,17 +293,16 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)spin_unlock (&sbi->inode_lock[ATOMIC_FILE ]);if (inode) { -if (gc_failure) { -if (fi->i_gc_failures[GC_FAILURE_ATOMIC ]) - goto drop; - goto skip; +inode_lock (inode); +/* need to check whether it was already revoked */ +if (f2fs_is_atomic_file (inode)) { +f2fs_drop_inmem_pages (inode); +set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); } -drop: -set_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); -f2fs_drop_inmem_pages (inode); +inode_unlock (inode);iput (inode); } -skip: +congestion_wait (BLK_RW_ASYNC ,HZ /50 );cond_resched (); goto next;@@ -320,7 +322,6 @@ void f2fs_drop_inmem_pages(struct inode *inode)mutex_unlock (&fi->inmem_lock);Quoted 6 lines
fs/f2fs/segment.c void f2fs_drop_inmem_pages(struct inode *inode) · line 327
Quoted 6 lines
fs/f2fs/segment.c +0
-1clear_inode_flag (inode,FI_ATOMIC_FILE ); - fi->i_gc_failures[GC_FAILURE_ATOMIC ] =0 ;stat_dec_atomic_write (inode); }------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linux-f2fs-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Jaegeuk Kim
maintainerQuoted 26 lines · Chao Yu
Quoted 25 lines · Jaegeuk Kim
Quoted 23 lines · Chao Yu
Quoted 14 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.Quoted 2 lines
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open
atomic_writefile for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.
Quoted 6 lines
Quoted 2 lines
The point here is stopping sqlite to keep going wrong data writes even after we already revoked blocks.
Yes, that's correct, what I mean is that if we can do that with smaller granularity like just revoke blocks for file which is blocking fggc, it will affect system/sqlite flow much less than forcing closing all
atomic_write.
How about this?
Quoted 1 line
From
64d2becb82a496c2e2c04abeed42efa3b401ee20Mon Sep 17 00:00:00 2001
From: Jaegeuk Kim <[email protected]>
Date: Fri, 27 Jul 2018 18:15:11 +0900
Subject: [PATCH] f2fs: don't allow any writes on aborted atomic writes
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch tries to avoid further writes in write_begin().
--- fs/f2fs/data.c | 3 ++- fs/f2fs/file.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -1
@@ -2295,7 +2295,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { + (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { err = -ENOMEM ; drop_atomic = true; goto fail;
fs/f2fs/file.c +6 -1
@@ -1708,8 +1708,11 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)down_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]); -if (f2fs_is_atomic_file (inode)) +if (f2fs_is_atomic_file (inode)) { +if (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST )) + ret = -EINVAL ; goto out; + } ret =f2fs_convert_inline_inode (inode);if (ret)
@@ -1871,6 +1874,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Quoted 27 lines · Jaegeuk Kim
Quoted 26 lines · Chao Yu
Quoted 25 lines · Jaegeuk Kim
Quoted 23 lines · Chao Yu
Quoted 14 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.Quoted 2 lines
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open
atomic_writefile for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
The point here is stopping sqlite to keep going wrong data writes even after we already revoked blocks.
Yes, that's correct, what I mean is that if we can do that with smaller granularity like just revoke blocks for file which is blocking fggc, it will affect system/sqlite flow much less than forcing closing all
atomic_write.How about this?
Yes, it looks good to me. :)
Quoted 11 lines
From
64d2becb82a496c2e2c04abeed42efa3b401ee20Mon Sep 17 00:00:00 2001
From: Jaegeuk Kim <[email protected]>
Date: Fri, 27 Jul 2018 18:15:11 +0900
Subject: [PATCH] f2fs: don't allow any writes on aborted atomic writesIn order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Quoted 4 lines
Once f2fs detects such the abnormal behavior, this patch tries to avoid further writes in
write_begin().Signed-off-by Jaegeuk Kim <[email protected]>
Thanks,
Quoted 46 lines
--- fs/f2fs/data.c | 3 ++- fs/f2fs/file.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-1@@ -2295,7 +2295,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { + (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) { err = -ENOMEM ; drop_atomic = true; goto fail;fs/f2fs/file.c +6
-1@@ -1708,8 +1708,11 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)down_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]); -if (f2fs_is_atomic_file (inode)) +if (f2fs_is_atomic_file (inode)) { +if (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST )) + ret = -EINVAL ; goto out; + } ret =f2fs_convert_inline_inode (inode);if (ret)@@ -1871,6 +1874,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);
Jaegeuk Kim
maintainerQuoted 71 lines · Chao Yu
Quoted 27 lines · Jaegeuk Kim
Quoted 26 lines · Chao Yu
Quoted 25 lines · Jaegeuk Kim
Quoted 23 lines · Chao Yu
Quoted 14 lines · Jaegeuk Kim
In order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Once f2fs detects such the abnormal behavior, this patch simply disables all the atomic operations such as:
-write_begin()gives EINVAL to avoid stale data writes, and SQLite will callF2FS_IOC_ABORT_VOLATILE_WRITEto notify aborting the transaction,
-F2FS_IOC_START_ATOMIC_WRITEgives EINVAL for SQLite to fall back normaljournal_mode,
-F2FS_IOC_COMMIT_ATOMIC_WRITEgives EINVAL, if the file was revoked, so that Framework retries to submit the transaction given propagated SQLite error.Quoted 2 lines
Note that, this patch also turns off atomic operations, if foreground GC tries to move atomic files too frequently.
Well, how about just keeping original implementation: shutdown atomic write for those files which are really affect fggc? Since intention of the original behavior is targeting to abnormal atomic write usage, e.g. open
atomic_writefile for very long time, then fggc will be blocked each time when moving its block. So shutdown it, fggc will recover.Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
The point here is stopping sqlite to keep going wrong data writes even after we already revoked blocks.
Yes, that's correct, what I mean is that if we can do that with smaller granularity like just revoke blocks for file which is blocking fggc, it will affect system/sqlite flow much less than forcing closing all
atomic_write.How about this?
Yes, it looks good to me. :)
Quoted 11 lines
From
64d2becb82a496c2e2c04abeed42efa3b401ee20Mon Sep 17 00:00:00 2001
From: Jaegeuk Kim <[email protected]>
Date: Fri, 27 Jul 2018 18:15:11 +0900
Subject: [PATCH] f2fs: don't allow any writes on aborted atomic writesIn order to prevent abusing atomic writes by abnormal users, we've added a threshold, 20% over memory footprint, which disallows further atomic writes. Previously, however, SQLite doesn't know the files became normal, so that it could write stale data and commit on revoked normal database file.
Quoted 4 lines
Once f2fs detects such the abnormal behavior, this patch tries to avoid further writes in
write_begin().Signed-off-by Jaegeuk Kim <[email protected]>Reviewed-by Chao Yu <[email protected]>Thanks,
Quoted 12 lines
--- fs/f2fs/data.c | 3 ++- fs/f2fs/file.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-)fs/f2fs/data.c +0
-0@@ -2295,7 +2295,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,trace_f2fs_write_begin (inode, pos, len, flags);
Quoted 4 lines
fs/f2fs/data.c static int f2fs_write_begin(struct file *file, struct address_space *mapping, · line 2299
Quoted 4 lines
fs/f2fs/data.c +2
-1if (f2fs_is_atomic_file (inode) && - !f2fs_available_free_memory (sbi,INMEM_PAGES )) { + (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST ) || + !f2fs_available_free_memory (sbi,INMEM_PAGES ))) {
if ((f2fs_is_atomic_file(inode) &&
!f2fs_available_free_memory(sbi, INMEM_PAGES)) ||
is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) {-- Fixed wrong condition.
Quoted 30 lines
Quoted 30 lines
fs/f2fs/data.c +0
-0err = -ENOMEM ; drop_atomic = true; goto fail;fs/f2fs/file.c +6
-1@@ -1708,8 +1708,11 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)down_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]); -if (f2fs_is_atomic_file (inode)) +if (f2fs_is_atomic_file (inode)) { +if (is_inode_flag_set (inode,FI_ATOMIC_REVOKE_REQUEST )) + ret = -EINVAL ; goto out; + } ret =f2fs_convert_inline_inode (inode);if (ret)@@ -1871,6 +1874,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) ret =f2fs_do_sync_file (filp,0 ,LLONG_MAX ,0 , true); } +clear_inode_flag (inode,FI_ATOMIC_REVOKE_REQUEST ); +inode_unlock (inode);mnt_drop_write_file (filp);