Skip to content

Commit

Permalink
f2fs: fix to flush multiple device in checkpoint
Browse files Browse the repository at this point in the history
If f2fs manages multiple devices, in checkpoint, we need to issue flush
in those devices which contain dirty data/node in their cache before
we write checkpoint region, otherwise, filesystem metadata could be
corrupted if hitting SPO after checkpoint.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
  • Loading branch information
Chao Yu authored and Jaegeuk Kim committed Oct 10, 2017
1 parent 39d787b commit 1228b48
Showing 4 changed files with 41 additions and 0 deletions.
6 changes: 6 additions & 0 deletions fs/f2fs/checkpoint.c
Original file line number Diff line number Diff line change
@@ -1172,6 +1172,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct super_block *sb = sbi->sb;
struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
u64 kbytes_written;
int err;

/* Flush all the NAT/SIT pages */
while (get_pages(sbi, F2FS_DIRTY_META)) {
@@ -1265,6 +1266,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;

/* flush all device cache */
err = f2fs_flush_device_cache(sbi);
if (err)
return err;

/* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++);

3 changes: 3 additions & 0 deletions fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
@@ -1122,6 +1122,8 @@ struct f2fs_sb_info {
struct list_head s_list;
int s_ndevs; /* number of devices */
struct f2fs_dev_info *devs; /* for device list */
unsigned int dirty_device; /* for checkpoint data flush */
spinlock_t dev_lock; /* protect dirty_device */
struct mutex umount_mutex;
unsigned int shrinker_run_no;

@@ -2527,6 +2529,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need);
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi);
int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino);
int create_flush_cmd_control(struct f2fs_sb_info *sbi);
int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);
void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free);
void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
29 changes: 29 additions & 0 deletions fs/f2fs/segment.c
Original file line number Diff line number Diff line change
@@ -659,6 +659,28 @@ void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
}
}

int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
{
int ret = 0, i;

if (!sbi->s_ndevs)
return 0;

for (i = 1; i < sbi->s_ndevs; i++) {
if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
continue;
ret = __submit_flush_wait(sbi, FDEV(i).bdev);
if (ret)
break;

spin_lock(&sbi->dev_lock);
f2fs_clear_bit(i, (char *)&sbi->dirty_device);
spin_unlock(&sbi->dev_lock);
}

return ret;
}

static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
enum dirty_type dirty_type)
{
@@ -2402,6 +2424,13 @@ static void update_device_state(struct f2fs_io_info *fio)

/* update device state for fsync */
set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);

/* update device state for checkpoint */
if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
spin_lock(&sbi->dev_lock);
f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
spin_unlock(&sbi->dev_lock);
}
}

static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
3 changes: 3 additions & 0 deletions fs/f2fs/super.c
Original file line number Diff line number Diff line change
@@ -1965,6 +1965,9 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
for (j = HOT; j < NR_TEMP_TYPE; j++)
mutex_init(&sbi->wio_mutex[i][j]);
spin_lock_init(&sbi->cp_lock);

sbi->dirty_device = 0;
spin_lock_init(&sbi->dev_lock);
}

static int init_percpu_info(struct f2fs_sb_info *sbi)

0 comments on commit 1228b48

Please sign in to comment.