When fs utilization is almost full, f2fs_sync_file should do checkpoint if
there is not enough space for roll-forward later. (i.e. space_for_roll_forward)
So, currently we have no lock for sbi->alloc_valid_block_count, resulting in
race condition.

In rare case, we can get -ENOSPC when doing roll-forward which triggers

        if (is_valid_blkaddr(sbi, dest, META_POR)) {
                if (src == NULL_ADDR) {
                        err = reserve_new_block(&dn);
                        f2fs_bug_on(sbi, err);
                        ...
                }
                ...
        }
in do_recover_data.

So, this patch avoids that situation in advance.

Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org>
---
 fs/f2fs/f2fs.h | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 7a57279..3098109 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1147,24 +1147,33 @@ static inline void f2fs_i_blocks_write(struct inode *, 
blkcnt_t, bool);
 static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
                                 struct inode *inode, blkcnt_t *count)
 {
+       blkcnt_t diff;
+
 #ifdef CONFIG_F2FS_FAULT_INJECTION
        if (time_to_inject(FAULT_BLOCK))
                return false;
 #endif
+       /*
+        * let's increase this in prior to actual block count change in order
+        * for f2fs_sync_file to avoid data races when deciding checkpoint.
+        */
+       percpu_counter_add(&sbi->alloc_valid_block_count, (*count));
+
        spin_lock(&sbi->stat_lock);
        sbi->total_valid_block_count += (block_t)(*count);
        if (unlikely(sbi->total_valid_block_count > sbi->user_block_count)) {
-               *count -= sbi->total_valid_block_count - sbi->user_block_count;
+               diff = sbi->total_valid_block_count - sbi->user_block_count;
+               *count -= diff;
                sbi->total_valid_block_count = sbi->user_block_count;
                if (!*count) {
                        spin_unlock(&sbi->stat_lock);
+                       percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
                        return false;
                }
        }
        spin_unlock(&sbi->stat_lock);
 
        f2fs_i_blocks_write(inode, *count, true);
-       percpu_counter_add(&sbi->alloc_valid_block_count, (*count));
        return true;
 }
 
-- 
2.8.3


------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports.http://sdm.link/zohodev2dev
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to