• Chao Yu's avatar
    f2fs: fix to update user block counts in block_operations() · f06c0f82
    Chao Yu authored
    Commit 59c9081b ("f2fs: allow write page cache when writting cp")
    allows write() to write data to page cache during checkpoint, so block
    count fields like .total_valid_block_count, .alloc_valid_block_count
    and .rf_node_block_count may encounter race condition as below:
    
    CP				Thread A
    - write_checkpoint
     - block_operations
      - f2fs_down_write(&sbi->node_change)
      - __prepare_cp_block
      : ckpt->valid_block_count = .total_valid_block_count
      - f2fs_up_write(&sbi->node_change)
    				- write
    				 - f2fs_preallocate_blocks
    				  - f2fs_map_blocks(,F2FS_GET_BLOCK_PRE_AIO)
    				   - f2fs_map_lock
    				    - f2fs_down_read(&sbi->node_change)
    				   - f2fs_reserve_new_blocks
    				    - inc_valid_block_count
    				    : percpu_counter_add(&sbi->alloc_valid_block_count, count)
    				    : sbi->total_valid_block_count += count
    				    - f2fs_up_read(&sbi->node_change)
     - do_checkpoint
     : sbi->last_valid_block_count = sbi->total_valid_block_count
     : percpu_counter_set(&sbi->alloc_valid_block_count, 0)
     : percpu_counter_set(&sbi->rf_node_block_count, 0)
    				- fsync
    				 - need_do_checkpoint
    				  - f2fs_space_for_roll_forward
    				  : alloc_valid_block_count was reset to zero,
    				    so, it may missed last data during checkpoint
    
    Let's change to update .total_valid_block_count, .alloc_valid_block_count
    and .rf_node_block_count in block_operations(), then their access can be
    protected by .node_change and .cp_rwsem lock, so that it can avoid above
    race condition.
    
    Fixes: 59c9081b ("f2fs: allow write page cache when writting cp")
    Cc: Yunlei He <heyunlei@oppo.com>
    Signed-off-by: default avatarChao Yu <chao@kernel.org>
    Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
    f06c0f82
checkpoint.c 48.2 KB