6018 lines · 153.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * fs/f2fs/segment.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. *             http://www.samsung.com/ */#include <linux/fs.h>#include <linux/f2fs_fs.h>#include <linux/bio.h>#include <linux/blkdev.h>#include <linux/sched/mm.h>#include <linux/prefetch.h>#include <linux/kthread.h>#include <linux/swap.h>#include <linux/timer.h>#include <linux/freezer.h>#include <linux/sched/signal.h>#include <linux/random.h>#include <linux/fserror.h> #include "f2fs.h"#include "segment.h"#include "node.h"#include "gc.h"#include "iostat.h"#include <trace/events/f2fs.h> #define __reverse_ffz(x) __reverse_ffs(~(x)) static struct kmem_cache *discard_entry_slab;static struct kmem_cache *discard_cmd_slab;static struct kmem_cache *sit_entry_set_slab;static struct kmem_cache *revoke_entry_slab; static unsigned long __reverse_ulong(unsigned char *str){	unsigned long tmp = 0;	int shift = 24, idx = 0; #if BITS_PER_LONG == 64	shift = 56;#endif	while (shift >= 0) {		tmp |= (unsigned long)str[idx++] << shift;		shift -= BITS_PER_BYTE;	}	return tmp;} /* * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since * MSB and LSB are reversed in a byte by f2fs_set_bit. */static inline unsigned long __reverse_ffs(unsigned long word){	int num = 0; #if BITS_PER_LONG == 64	if ((word & 0xffffffff00000000UL) == 0)		num += 32;	else		word >>= 32;#endif	if ((word & 0xffff0000) == 0)		num += 16;	else		word >>= 16; 	if ((word & 0xff00) == 0)		num += 8;	else		word >>= 8; 	if ((word & 0xf0) == 0)		num += 4;	else		word >>= 4; 	if ((word & 0xc) == 0)		num += 2;	else		word >>= 2; 	if ((word & 0x2) == 0)		num += 1;	return num;} /* * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because * f2fs_set_bit makes MSB and LSB reversed in a byte. * @size must be integral times of unsigned long. * Example: *                             MSB <--> LSB *   f2fs_set_bit(0, bitmap) => 1000 0000 *   f2fs_set_bit(7, bitmap) => 0000 0001 */static unsigned long __find_rev_next_bit(const unsigned long *addr,			unsigned long size, unsigned long offset){	const unsigned long *p = addr + BIT_WORD(offset);	unsigned long result = size;	unsigned long tmp; 	if (offset >= size)		return size; 	size -= (offset & ~(BITS_PER_LONG - 1));	offset %= BITS_PER_LONG; 	while (1) {		if (*p == 0)			goto pass; 		tmp = __reverse_ulong((unsigned char *)p); 		tmp &= ~0UL >> offset;		if (size < BITS_PER_LONG)			tmp &= (~0UL << (BITS_PER_LONG - size));		if (tmp)			goto found;pass:		if (size <= BITS_PER_LONG)			break;		size -= BITS_PER_LONG;		offset = 0;		p++;	}	return result;found:	return result - size + __reverse_ffs(tmp);} static unsigned long __find_rev_next_zero_bit(const unsigned long *addr,			unsigned long size, unsigned long offset){	const unsigned long *p = addr + BIT_WORD(offset);	unsigned long result = size;	unsigned long tmp; 	if (offset >= size)		return size; 	size -= (offset & ~(BITS_PER_LONG - 1));	offset %= BITS_PER_LONG; 	while (1) {		if (*p == ~0UL)			goto pass; 		tmp = __reverse_ulong((unsigned char *)p); 		if (offset)			tmp |= ~0UL << (BITS_PER_LONG - offset);		if (size < BITS_PER_LONG)			tmp |= ~0UL >> size;		if (tmp != ~0UL)			goto found;pass:		if (size <= BITS_PER_LONG)			break;		size -= BITS_PER_LONG;		offset = 0;		p++;	}	return result;found:	return result - size + __reverse_ffz(tmp);} bool f2fs_need_SSR(struct f2fs_sb_info *sbi){	int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);	int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);	int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); 	if (f2fs_lfs_mode(sbi))		return false;	if (sbi->gc_mode == GC_URGENT_HIGH)		return true;	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))		return true; 	return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +			SM_I(sbi)->min_ssr_sections + reserved_sections(sbi));} void f2fs_abort_atomic_write(struct inode *inode, bool clean){	struct f2fs_inode_info *fi = F2FS_I(inode); 	if (!f2fs_is_atomic_file(inode))		return; 	if (clean)		truncate_inode_pages_final(inode->i_mapping); 	release_atomic_write_cnt(inode);	clear_inode_flag(inode, FI_ATOMIC_COMMITTED);	clear_inode_flag(inode, FI_ATOMIC_REPLACE);	clear_inode_flag(inode, FI_ATOMIC_FILE);	if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) {		clear_inode_flag(inode, FI_ATOMIC_DIRTIED);		/*		 * The vfs inode keeps clean during commit, but the f2fs inode		 * doesn't. So clear the dirty state after commit and let		 * f2fs_mark_inode_dirty_sync ensure a consistent dirty state.		 */		f2fs_inode_synced(inode);		f2fs_mark_inode_dirty_sync(inode, true);	}	stat_dec_atomic_inode(inode); 	F2FS_I(inode)->atomic_write_task = NULL; 	if (clean) {		f2fs_i_size_write(inode, fi->original_i_size);		fi->original_i_size = 0;	}	/* avoid stale dirty inode during eviction */	sync_inode_metadata(inode, 0);} static int __replace_atomic_write_block(struct inode *inode, pgoff_t index,			block_t new_addr, block_t *old_addr, bool recover){	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);	struct dnode_of_data dn;	struct node_info ni;	int err; retry:	set_new_dnode(&dn, inode, NULL, NULL, 0);	err = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);	if (err) {		if (err == -ENOMEM) {			memalloc_retry_wait(GFP_NOFS);			goto retry;		}		return err;	} 	err = f2fs_get_node_info(sbi, dn.nid, &ni, false);	if (err) {		f2fs_put_dnode(&dn);		return err;	} 	if (recover) {		/* dn.data_blkaddr is always valid */		if (!__is_valid_data_blkaddr(new_addr)) {			if (new_addr == NULL_ADDR)				dec_valid_block_count(sbi, inode, 1);			f2fs_invalidate_blocks(sbi, dn.data_blkaddr, 1);			f2fs_update_data_blkaddr(&dn, new_addr);		} else {			f2fs_replace_block(sbi, &dn, dn.data_blkaddr,				new_addr, ni.version, true, true);		}	} else {		blkcnt_t count = 1; 		err = inc_valid_block_count(sbi, inode, &count, true, false);		if (err) {			f2fs_put_dnode(&dn);			return err;		} 		*old_addr = dn.data_blkaddr;		f2fs_truncate_data_blocks_range(&dn, 1);		dec_valid_block_count(sbi, F2FS_I(inode)->cow_inode, count); 		f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr,					ni.version, true, false);	} 	f2fs_put_dnode(&dn); 	trace_f2fs_replace_atomic_write_block(inode, F2FS_I(inode)->cow_inode,			index, old_addr ? *old_addr : 0, new_addr, recover);	return 0;} static void __complete_revoke_list(struct inode *inode, struct list_head *head,					bool revoke){	struct revoke_entry *cur, *tmp;	pgoff_t start_index = 0;	bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE); 	list_for_each_entry_safe(cur, tmp, head, list) {		if (revoke) {			__replace_atomic_write_block(inode, cur->index,						cur->old_addr, NULL, true);		} else if (truncate) {			f2fs_truncate_hole(inode, start_index, cur->index);			start_index = cur->index + 1;		} 		list_del(&cur->list);		kmem_cache_free(revoke_entry_slab, cur);	} 	if (!revoke && truncate)		f2fs_do_truncate_blocks(inode, start_index * PAGE_SIZE, false);} static int __f2fs_commit_atomic_write(struct inode *inode){	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);	struct f2fs_inode_info *fi = F2FS_I(inode);	struct inode *cow_inode = fi->cow_inode;	struct revoke_entry *new;	struct list_head revoke_list;	block_t blkaddr;	struct dnode_of_data dn;	pgoff_t len = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);	pgoff_t off = 0, blen, index;	int ret = 0, i; 	INIT_LIST_HEAD(&revoke_list); 	while (len) {		blen = min_t(pgoff_t, ADDRS_PER_BLOCK(cow_inode), len); 		set_new_dnode(&dn, cow_inode, NULL, NULL, 0);		ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);		if (ret && ret != -ENOENT) {			goto out;		} else if (ret == -ENOENT) {			ret = 0;			if (dn.max_level == 0)				goto out;			goto next;		} 		blen = min((pgoff_t)ADDRS_PER_PAGE(dn.node_folio, cow_inode),				len);		index = off;		for (i = 0; i < blen; i++, dn.ofs_in_node++, index++) {			blkaddr = f2fs_data_blkaddr(&dn); 			if (!__is_valid_data_blkaddr(blkaddr)) {				continue;			} else if (!f2fs_is_valid_blkaddr(sbi, blkaddr,					DATA_GENERIC_ENHANCE)) {				f2fs_put_dnode(&dn);				ret = -EFSCORRUPTED;				goto out;			} 			new = f2fs_kmem_cache_alloc(revoke_entry_slab, GFP_NOFS,							true, NULL); 			ret = __replace_atomic_write_block(inode, index, blkaddr,							&new->old_addr, false);			if (ret) {				f2fs_put_dnode(&dn);				kmem_cache_free(revoke_entry_slab, new);				goto out;			} 			f2fs_update_data_blkaddr(&dn, NULL_ADDR);			new->index = index;			list_add_tail(&new->list, &revoke_list);		}		f2fs_put_dnode(&dn);next:		off += blen;		len -= blen;	} out:	if (time_to_inject(sbi, FAULT_ATOMIC_TIMEOUT))		f2fs_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT, true); 	if (ret) {		sbi->revoked_atomic_block += fi->atomic_write_cnt;	} else {		sbi->committed_atomic_block += fi->atomic_write_cnt;		set_inode_flag(inode, FI_ATOMIC_COMMITTED); 		/*		 * inode may has no FI_ATOMIC_DIRTIED flag due to no write		 * before commit.		 */		if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) {			/* clear atomic dirty status and set vfs dirty status */			clear_inode_flag(inode, FI_ATOMIC_DIRTIED);			f2fs_mark_inode_dirty_sync(inode, true);		}	} 	__complete_revoke_list(inode, &revoke_list, ret ? true : false); 	return ret;} int f2fs_commit_atomic_write(struct inode *inode){	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);	struct f2fs_inode_info *fi = F2FS_I(inode);	struct f2fs_lock_context lc;	int err; 	err = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);	if (err)		return err; 	f2fs_down_write(&fi->i_gc_rwsem[WRITE]);	f2fs_lock_op(sbi, &lc); 	err = __f2fs_commit_atomic_write(inode); 	f2fs_unlock_op(sbi, &lc);	f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 	return err;} /* * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. */void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need){	if (f2fs_cp_error(sbi))		return; 	if (time_to_inject(sbi, FAULT_CHECKPOINT))		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT); 	/* balance_fs_bg is able to be pending */	if (need && excess_cached_nats(sbi))		f2fs_balance_fs_bg(sbi, false); 	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))		return; 	/*	 * We should do GC or end up with checkpoint, if there are so many dirty	 * dir/node pages without enough free segments.	 */	if (has_enough_free_secs(sbi, 0, 0))		return; 	/*	 * Submit all cached OPU/IPU DATA bios before triggering	 * foreground GC to avoid potential deadlocks.	 */	f2fs_submit_merged_write(sbi, DATA);	f2fs_submit_all_merged_ipu_writes(sbi); 	if (test_opt(sbi, GC_MERGE) && sbi->gc_thread.f2fs_gc_task) {		DEFINE_WAIT(wait); 		prepare_to_wait(&sbi->gc_thread.fggc_wq, &wait,					TASK_UNINTERRUPTIBLE);		wake_up(&sbi->gc_thread.gc_wait_queue_head);		io_schedule();		finish_wait(&sbi->gc_thread.fggc_wq, &wait);	} else {		struct f2fs_gc_control gc_control = {			.victim_segno = NULL_SEGNO,			.init_gc_type = f2fs_sb_has_blkzoned(sbi) ?				FG_GC : BG_GC,			.no_bg_gc = true,			.should_migrate_blocks = false,			.err_gc_skipped = false,			.nr_free_secs = 1 }; 		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);		stat_inc_gc_call_count(sbi, FOREGROUND);		f2fs_gc(sbi, &gc_control);	}} static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi){	int factor = f2fs_rwsem_is_locked(&sbi->cp_rwsem) ? 3 : 2;	unsigned int dents = get_pages(sbi, F2FS_DIRTY_DENTS);	unsigned int qdata = get_pages(sbi, F2FS_DIRTY_QDATA);	unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES);	unsigned int meta = get_pages(sbi, F2FS_DIRTY_META);	unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA);	unsigned int threshold =		SEGS_TO_BLKS(sbi, (factor * DEFAULT_DIRTY_THRESHOLD));	unsigned int global_threshold = threshold * 3 / 2; 	if (dents >= threshold || qdata >= threshold ||		nodes >= threshold || meta >= threshold ||		imeta >= threshold)		return true;	return dents + qdata + nodes + meta + imeta >  global_threshold;} void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg){	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))

Lines 1–500 of 6018.