diff options
Diffstat (limited to 'fs/f2fs/gc.c')
| -rw-r--r-- | fs/f2fs/gc.c | 102 | 
1 files changed, 38 insertions, 64 deletions
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 644aa380827..c386910dacc 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -78,7 +78,7 @@ static int gc_thread_func(void *data)  		sbi->bg_gc++; -		if (f2fs_gc(sbi, 1) == GC_NONE) +		if (f2fs_gc(sbi) == GC_NONE)  			wait_ms = GC_THREAD_NOGC_SLEEP_TIME;  		else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)  			wait_ms = GC_THREAD_MAX_SLEEP_TIME; @@ -390,9 +390,7 @@ next_step:  		}  		err = check_valid_map(sbi, segno, off); -		if (err == GC_ERROR) -			return err; -		else if (err == GC_NEXT) +		if (err == GC_NEXT)  			continue;  		if (initial) { @@ -426,32 +424,30 @@ next_step:  }  /* - * Calculate start block index that this node page contains + * Calculate start block index indicating the given node offset. + * Be careful, caller should give this node offset only indicating direct node + * blocks. If any node offsets, which point the other types of node blocks such + * as indirect or double indirect node blocks, are given, it must be a caller's + * bug.   */  block_t start_bidx_of_node(unsigned int node_ofs)  { -	block_t start_bidx; -	unsigned int bidx, indirect_blks; -	int dec; +	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; +	unsigned int bidx; -	indirect_blks = 2 * NIDS_PER_BLOCK + 4; +	if (node_ofs == 0) +		return 0; -	start_bidx = 1; -	if (node_ofs == 0) { -		start_bidx = 0; -	} else if (node_ofs <= 2) { +	if (node_ofs <= 2) {  		bidx = node_ofs - 1;  	} else if (node_ofs <= indirect_blks) { -		dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); +		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);  		bidx = node_ofs - 2 - dec;  	} else { -		dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); +		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);  		bidx = node_ofs - 5 - dec;  	} - -	if (start_bidx) -		start_bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; -	return start_bidx; +	return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE;  }  static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, @@ -556,9 +552,7 @@ next_step:  		}  		err = check_valid_map(sbi, segno, off); -		if (err == GC_ERROR) -			goto stop; -		else if (err == GC_NEXT) +		if (err == GC_NEXT)  			continue;  		if (phase == 0) { @@ -568,9 +562,7 @@ next_step:  		/* Get an inode by ino with checking validity */  		err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs); -		if (err == GC_ERROR) -			goto stop; -		else if (err == GC_NEXT) +		if (err == GC_NEXT)  			continue;  		if (phase == 1) { @@ -663,62 +655,44 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,  	return ret;  } -int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) +int f2fs_gc(struct f2fs_sb_info *sbi)  { -	unsigned int segno; -	int old_free_secs, cur_free_secs; -	int gc_status, nfree;  	struct list_head ilist; +	unsigned int segno, i;  	int gc_type = BG_GC; +	int gc_status = GC_NONE;  	INIT_LIST_HEAD(&ilist);  gc_more: -	nfree = 0; -	gc_status = GC_NONE; +	if (!(sbi->sb->s_flags & MS_ACTIVE)) +		goto stop;  	if (has_not_enough_free_secs(sbi)) -		old_free_secs = reserved_sections(sbi); -	else -		old_free_secs = free_sections(sbi); - -	while (sbi->sb->s_flags & MS_ACTIVE) { -		int i; -		if (has_not_enough_free_secs(sbi)) -			gc_type = FG_GC; +		gc_type = FG_GC; -		cur_free_secs = free_sections(sbi) + nfree; +	if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) +		goto stop; -		/* We got free space successfully. */ -		if (nGC < cur_free_secs - old_free_secs) -			break; - -		if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) +	for (i = 0; i < sbi->segs_per_sec; i++) { +		/* +		 * do_garbage_collect will give us three gc_status: +		 * GC_ERROR, GC_DONE, and GC_BLOCKED. +		 * If GC is finished uncleanly, we have to return +		 * the victim to dirty segment list. +		 */ +		gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type); +		if (gc_status != GC_DONE)  			break; - -		for (i = 0; i < sbi->segs_per_sec; i++) { -			/* -			 * do_garbage_collect will give us three gc_status: -			 * GC_ERROR, GC_DONE, and GC_BLOCKED. -			 * If GC is finished uncleanly, we have to return -			 * the victim to dirty segment list. -			 */ -			gc_status = do_garbage_collect(sbi, segno + i, -					&ilist, gc_type); -			if (gc_status != GC_DONE) -				goto stop; -			nfree++; -		}  	} -stop: -	if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) { +	if (has_not_enough_free_secs(sbi)) {  		write_checkpoint(sbi, (gc_status == GC_BLOCKED), false); -		if (nfree) +		if (has_not_enough_free_secs(sbi))  			goto gc_more;  	} +stop:  	mutex_unlock(&sbi->gc_mutex);  	put_gc_inode(&ilist); -	BUG_ON(!list_empty(&ilist));  	return gc_status;  } @@ -727,7 +701,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi)  	DIRTY_I(sbi)->v_ops = &default_v_ops;  } -int create_gc_caches(void) +int __init create_gc_caches(void)  {  	winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes",  			sizeof(struct inode_entry), NULL);  |