diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 134 | 
1 files changed, 83 insertions, 51 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 085f548be7a3..f25f0e07e26f 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -25,7 +25,6 @@  #define __reverse_ffz(x) __reverse_ffs(~(x))  static struct kmem_cache *discard_entry_slab; -static struct kmem_cache *flush_cmd_slab;  /*   * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since @@ -200,20 +199,20 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)  static int issue_flush_thread(void *data)  {  	struct f2fs_sb_info *sbi = data; -	struct f2fs_sm_info *sm_i = SM_I(sbi); -	wait_queue_head_t *q = &sm_i->flush_wait_queue; +	struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; +	wait_queue_head_t *q = &fcc->flush_wait_queue;  repeat:  	if (kthread_should_stop())  		return 0; -	spin_lock(&sm_i->issue_lock); -	if (sm_i->issue_list) { -		sm_i->dispatch_list = sm_i->issue_list; -		sm_i->issue_list = sm_i->issue_tail = NULL; +	spin_lock(&fcc->issue_lock); +	if (fcc->issue_list) { +		fcc->dispatch_list = fcc->issue_list; +		fcc->issue_list = fcc->issue_tail = NULL;  	} -	spin_unlock(&sm_i->issue_lock); +	spin_unlock(&fcc->issue_lock); -	if (sm_i->dispatch_list) { +	if (fcc->dispatch_list) {  		struct bio *bio = bio_alloc(GFP_NOIO, 0);  		struct flush_cmd *cmd, *next;  		int ret; @@ -221,47 +220,79 @@ repeat:  		bio->bi_bdev = sbi->sb->s_bdev;  		ret = submit_bio_wait(WRITE_FLUSH, bio); -		for (cmd = sm_i->dispatch_list; cmd; cmd = next) { +		for (cmd = fcc->dispatch_list; cmd; cmd = next) {  			cmd->ret = ret;  			next = cmd->next;  			complete(&cmd->wait);  		} -		sm_i->dispatch_list = NULL; +		bio_put(bio); +		fcc->dispatch_list = NULL;  	} -	wait_event_interruptible(*q, kthread_should_stop() || sm_i->issue_list); +	wait_event_interruptible(*q, +			kthread_should_stop() || fcc->issue_list);  	goto repeat;  }  int f2fs_issue_flush(struct f2fs_sb_info *sbi)  { -	struct f2fs_sm_info *sm_i = SM_I(sbi); -	struct flush_cmd *cmd; -	int ret; +	struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; +	struct flush_cmd cmd;  	if (!test_opt(sbi, FLUSH_MERGE))  		return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL); -	cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC); -	cmd->next = NULL; -	cmd->ret = 0; -	init_completion(&cmd->wait); +	init_completion(&cmd.wait); +	cmd.next = NULL; -	spin_lock(&sm_i->issue_lock); -	if (sm_i->issue_list) -		sm_i->issue_tail->next = cmd; +	spin_lock(&fcc->issue_lock); +	if (fcc->issue_list) +		fcc->issue_tail->next = &cmd;  	else -		sm_i->issue_list = cmd; -	sm_i->issue_tail = cmd; -	spin_unlock(&sm_i->issue_lock); +		fcc->issue_list = &cmd; +	fcc->issue_tail = &cmd; +	spin_unlock(&fcc->issue_lock); -	if (!sm_i->dispatch_list) -		wake_up(&sm_i->flush_wait_queue); +	if (!fcc->dispatch_list) +		wake_up(&fcc->flush_wait_queue); -	wait_for_completion(&cmd->wait); -	ret = cmd->ret; -	kmem_cache_free(flush_cmd_slab, cmd); -	return ret; +	wait_for_completion(&cmd.wait); + +	return cmd.ret; +} + +int create_flush_cmd_control(struct f2fs_sb_info *sbi) +{ +	dev_t dev = sbi->sb->s_bdev->bd_dev; +	struct flush_cmd_control *fcc; +	int err = 0; + +	fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL); +	if (!fcc) +		return -ENOMEM; +	spin_lock_init(&fcc->issue_lock); +	init_waitqueue_head(&fcc->flush_wait_queue); +	fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, +				"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); +	if (IS_ERR(fcc->f2fs_issue_flush)) { +		err = PTR_ERR(fcc->f2fs_issue_flush); +		kfree(fcc); +		return err; +	} +	sbi->sm_info->cmd_control_info = fcc; + +	return err; +} + +void destroy_flush_cmd_control(struct f2fs_sb_info *sbi) +{ +	struct flush_cmd_control *fcc = +				sbi->sm_info->cmd_control_info; + +	if (fcc && fcc->f2fs_issue_flush) +		kthread_stop(fcc->f2fs_issue_flush); +	kfree(fcc); +	sbi->sm_info->cmd_control_info = NULL;  }  static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, @@ -336,13 +367,26 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)  	mutex_unlock(&dirty_i->seglist_lock);  } -static void f2fs_issue_discard(struct f2fs_sb_info *sbi, +static int f2fs_issue_discard(struct f2fs_sb_info *sbi,  				block_t blkstart, block_t blklen)  {  	sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart);  	sector_t len = SECTOR_FROM_BLOCK(sbi, blklen); -	blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);  	trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); +	return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0); +} + +void discard_next_dnode(struct f2fs_sb_info *sbi) +{ +	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); +	block_t blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + +	if (f2fs_issue_discard(sbi, blkaddr, 1)) { +		struct page *page = grab_meta_page(sbi, blkaddr); +		/* zero-filled page */ +		set_page_dirty(page); +		f2fs_put_page(page, 1); +	}  }  static void add_discard_addrs(struct f2fs_sb_info *sbi, @@ -1832,7 +1876,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)  {  	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);  	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); -	dev_t dev = sbi->sb->s_bdev->bd_dev;  	struct f2fs_sm_info *sm_info;  	int err; @@ -1860,14 +1903,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)  	sm_info->nr_discards = 0;  	sm_info->max_discards = 0; -	if (test_opt(sbi, FLUSH_MERGE)) { -		spin_lock_init(&sm_info->issue_lock); -		init_waitqueue_head(&sm_info->flush_wait_queue); - -		sm_info->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, -				"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); -		if (IS_ERR(sm_info->f2fs_issue_flush)) -			return PTR_ERR(sm_info->f2fs_issue_flush); +	if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) { +		err = create_flush_cmd_control(sbi); +		if (err) +			return err;  	}  	err = build_sit_info(sbi); @@ -1976,10 +2015,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)  void destroy_segment_manager(struct f2fs_sb_info *sbi)  {  	struct f2fs_sm_info *sm_info = SM_I(sbi); +  	if (!sm_info)  		return; -	if (sm_info->f2fs_issue_flush) -		kthread_stop(sm_info->f2fs_issue_flush); +	destroy_flush_cmd_control(sbi);  	destroy_dirty_segmap(sbi);  	destroy_curseg(sbi);  	destroy_free_segmap(sbi); @@ -1994,17 +2033,10 @@ int __init create_segment_manager_caches(void)  			sizeof(struct discard_entry));  	if (!discard_entry_slab)  		return -ENOMEM; -	flush_cmd_slab = f2fs_kmem_cache_create("flush_command", -			sizeof(struct flush_cmd)); -	if (!flush_cmd_slab) { -		kmem_cache_destroy(discard_entry_slab); -		return -ENOMEM; -	}  	return 0;  }  void destroy_segment_manager_caches(void)  {  	kmem_cache_destroy(discard_entry_slab); -	kmem_cache_destroy(flush_cmd_slab);  }  |