2802 lines · 67.1 KB · C
RawDownload
/* * fs/f2fs/node.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. *             http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/fs.h>#include <linux/f2fs_fs.h>#include <linux/mpage.h>#include <linux/backing-dev.h>#include <linux/blkdev.h>#include <linux/pagevec.h>#include <linux/swap.h> #include "f2fs.h"#include "node.h"#include "segment.h"#include "trace.h"#include <trace/events/f2fs.h> #define on_build_free_nids(nmi) mutex_is_locked(&(nm_i)->build_lock) static struct kmem_cache *nat_entry_slab;static struct kmem_cache *free_nid_slab;static struct kmem_cache *nat_entry_set_slab; bool available_free_memory(struct f2fs_sb_info *sbi, int type){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct sysinfo val;	unsigned long avail_ram;	unsigned long mem_size = 0;	bool res = false; 	si_meminfo(&val); 	/* only uses low memory */	avail_ram = val.totalram - val.totalhigh; 	/*	 * give 25%, 25%, 50%, 50%, 50% memory for each components respectively	 */	if (type == FREE_NIDS) {		mem_size = (nm_i->nid_cnt[FREE_NID_LIST] *				sizeof(struct free_nid)) >> PAGE_SHIFT;		res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);	} else if (type == NAT_ENTRIES) {		mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>							PAGE_SHIFT;		res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);		if (excess_cached_nats(sbi))			res = false;	} else if (type == DIRTY_DENTS) {		if (sbi->sb->s_bdi->wb.dirty_exceeded)			return false;		mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);		res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);	} else if (type == INO_ENTRIES) {		int i; 		for (i = 0; i <= UPDATE_INO; i++)			mem_size += sbi->im[i].ino_num *						sizeof(struct ino_entry);		mem_size >>= PAGE_SHIFT;		res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);	} else if (type == EXTENT_CACHE) {		mem_size = (atomic_read(&sbi->total_ext_tree) *				sizeof(struct extent_tree) +				atomic_read(&sbi->total_ext_node) *				sizeof(struct extent_node)) >> PAGE_SHIFT;		res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);	} else {		if (!sbi->sb->s_bdi->wb.dirty_exceeded)			return true;	}	return res;} static void clear_node_page_dirty(struct page *page){	struct address_space *mapping = page->mapping;	unsigned int long flags; 	if (PageDirty(page)) {		spin_lock_irqsave(&mapping->tree_lock, flags);		radix_tree_tag_clear(&mapping->page_tree,				page_index(page),				PAGECACHE_TAG_DIRTY);		spin_unlock_irqrestore(&mapping->tree_lock, flags); 		clear_page_dirty_for_io(page);		dec_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES);	}	ClearPageUptodate(page);} static struct page *get_current_nat_page(struct f2fs_sb_info *sbi, nid_t nid){	pgoff_t index = current_nat_addr(sbi, nid);	return get_meta_page(sbi, index);} static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid){	struct page *src_page;	struct page *dst_page;	pgoff_t src_off;	pgoff_t dst_off;	void *src_addr;	void *dst_addr;	struct f2fs_nm_info *nm_i = NM_I(sbi); 	src_off = current_nat_addr(sbi, nid);	dst_off = next_nat_addr(sbi, src_off); 	/* get current nat block page with lock */	src_page = get_meta_page(sbi, src_off);	dst_page = grab_meta_page(sbi, dst_off);	f2fs_bug_on(sbi, PageDirty(src_page)); 	src_addr = page_address(src_page);	dst_addr = page_address(dst_page);	memcpy(dst_addr, src_addr, PAGE_SIZE);	set_page_dirty(dst_page);	f2fs_put_page(src_page, 1); 	set_to_next_nat(nm_i, nid); 	return dst_page;} static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n){	return radix_tree_lookup(&nm_i->nat_root, n);} static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i,		nid_t start, unsigned int nr, struct nat_entry **ep){	return radix_tree_gang_lookup(&nm_i->nat_root, (void **)ep, start, nr);} static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e){	list_del(&e->list);	radix_tree_delete(&nm_i->nat_root, nat_get_nid(e));	nm_i->nat_cnt--;	kmem_cache_free(nat_entry_slab, e);} static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,						struct nat_entry *ne){	nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);	struct nat_entry_set *head; 	head = radix_tree_lookup(&nm_i->nat_set_root, set);	if (!head) {		head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS); 		INIT_LIST_HEAD(&head->entry_list);		INIT_LIST_HEAD(&head->set_list);		head->set = set;		head->entry_cnt = 0;		f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);	} 	if (get_nat_flag(ne, IS_DIRTY))		goto refresh_list; 	nm_i->dirty_nat_cnt++;	head->entry_cnt++;	set_nat_flag(ne, IS_DIRTY, true);refresh_list:	if (nat_get_blkaddr(ne) == NEW_ADDR)		list_del_init(&ne->list);	else		list_move_tail(&ne->list, &head->entry_list);} static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,		struct nat_entry_set *set, struct nat_entry *ne){	list_move_tail(&ne->list, &nm_i->nat_entries);	set_nat_flag(ne, IS_DIRTY, false);	set->entry_cnt--;	nm_i->dirty_nat_cnt--;} static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,		nid_t start, unsigned int nr, struct nat_entry_set **ep){	return radix_tree_gang_lookup(&nm_i->nat_set_root, (void **)ep,							start, nr);} int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e;	bool need = false; 	down_read(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, nid);	if (e) {		if (!get_nat_flag(e, IS_CHECKPOINTED) &&				!get_nat_flag(e, HAS_FSYNCED_INODE))			need = true;	}	up_read(&nm_i->nat_tree_lock);	return need;} bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e;	bool is_cp = true; 	down_read(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, nid);	if (e && !get_nat_flag(e, IS_CHECKPOINTED))		is_cp = false;	up_read(&nm_i->nat_tree_lock);	return is_cp;} bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e;	bool need_update = true; 	down_read(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, ino);	if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&			(get_nat_flag(e, IS_CHECKPOINTED) ||			 get_nat_flag(e, HAS_FSYNCED_INODE)))		need_update = false;	up_read(&nm_i->nat_tree_lock);	return need_update;} static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,								bool no_fail){	struct nat_entry *new; 	if (no_fail) {		new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_NOFS);		f2fs_radix_tree_insert(&nm_i->nat_root, nid, new);	} else {		new = kmem_cache_alloc(nat_entry_slab, GFP_NOFS);		if (!new)			return NULL;		if (radix_tree_insert(&nm_i->nat_root, nid, new)) {			kmem_cache_free(nat_entry_slab, new);			return NULL;		}	} 	memset(new, 0, sizeof(struct nat_entry));	nat_set_nid(new, nid);	nat_reset_flag(new);	list_add_tail(&new->list, &nm_i->nat_entries);	nm_i->nat_cnt++;	return new;} static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,						struct f2fs_nat_entry *ne){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e; 	e = __lookup_nat_cache(nm_i, nid);	if (!e) {		e = grab_nat_entry(nm_i, nid, false);		if (e)			node_info_from_raw_nat(&e->ni, ne);	} else {		f2fs_bug_on(sbi, nat_get_ino(e) != le32_to_cpu(ne->ino) ||				nat_get_blkaddr(e) !=					le32_to_cpu(ne->block_addr) ||				nat_get_version(e) != ne->version);	}} static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,			block_t new_blkaddr, bool fsync_done){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e; 	down_write(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, ni->nid);	if (!e) {		e = grab_nat_entry(nm_i, ni->nid, true);		copy_node_info(&e->ni, ni);		f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR);	} else if (new_blkaddr == NEW_ADDR) {		/*		 * when nid is reallocated,		 * previous nat entry can be remained in nat cache.		 * So, reinitialize it with new information.		 */		copy_node_info(&e->ni, ni);		f2fs_bug_on(sbi, ni->blk_addr != NULL_ADDR);	} 	/* sanity check */	f2fs_bug_on(sbi, nat_get_blkaddr(e) != ni->blk_addr);	f2fs_bug_on(sbi, nat_get_blkaddr(e) == NULL_ADDR &&			new_blkaddr == NULL_ADDR);	f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&			new_blkaddr == NEW_ADDR);	f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR &&			nat_get_blkaddr(e) != NULL_ADDR &&			new_blkaddr == NEW_ADDR); 	/* increment version no as node is removed */	if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) {		unsigned char version = nat_get_version(e);		nat_set_version(e, inc_node_version(version)); 		/* in order to reuse the nid */		if (nm_i->next_scan_nid > ni->nid)			nm_i->next_scan_nid = ni->nid;	} 	/* change address */	nat_set_blkaddr(e, new_blkaddr);	if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)		set_nat_flag(e, IS_CHECKPOINTED, false);	__set_nat_cache_dirty(nm_i, e); 	/* update fsync_mark if its inode nat entry is still alive */	if (ni->nid != ni->ino)		e = __lookup_nat_cache(nm_i, ni->ino);	if (e) {		if (fsync_done && ni->nid == ni->ino)			set_nat_flag(e, HAS_FSYNCED_INODE, true);		set_nat_flag(e, HAS_LAST_FSYNC, fsync_done);	}	up_write(&nm_i->nat_tree_lock);} int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink){	struct f2fs_nm_info *nm_i = NM_I(sbi);	int nr = nr_shrink; 	if (!down_write_trylock(&nm_i->nat_tree_lock))		return 0; 	while (nr_shrink && !list_empty(&nm_i->nat_entries)) {		struct nat_entry *ne;		ne = list_first_entry(&nm_i->nat_entries,					struct nat_entry, list);		__del_from_nat_cache(nm_i, ne);		nr_shrink--;	}	up_write(&nm_i->nat_tree_lock);	return nr - nr_shrink;} /* * This function always returns success */void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);	struct f2fs_journal *journal = curseg->journal;	nid_t start_nid = START_NID(nid);	struct f2fs_nat_block *nat_blk;	struct page *page = NULL;	struct f2fs_nat_entry ne;	struct nat_entry *e;	pgoff_t index;	int i; 	ni->nid = nid; 	/* Check nat cache */	down_read(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, nid);	if (e) {		ni->ino = nat_get_ino(e);		ni->blk_addr = nat_get_blkaddr(e);		ni->version = nat_get_version(e);		up_read(&nm_i->nat_tree_lock);		return;	} 	memset(&ne, 0, sizeof(struct f2fs_nat_entry)); 	/* Check current segment summary */	down_read(&curseg->journal_rwsem);	i = lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);	if (i >= 0) {		ne = nat_in_journal(journal, i);		node_info_from_raw_nat(ni, &ne);	}	up_read(&curseg->journal_rwsem);	if (i >= 0) {		up_read(&nm_i->nat_tree_lock);		goto cache;	} 	/* Fill node_info from nat page */	index = current_nat_addr(sbi, nid);	up_read(&nm_i->nat_tree_lock); 	page = get_meta_page(sbi, index);	nat_blk = (struct f2fs_nat_block *)page_address(page);	ne = nat_blk->entries[nid - start_nid];	node_info_from_raw_nat(ni, &ne);	f2fs_put_page(page, 1);cache:	/* cache nat entry */	down_write(&nm_i->nat_tree_lock);	cache_nat_entry(sbi, nid, &ne);	up_write(&nm_i->nat_tree_lock);} /* * readahead MAX_RA_NODE number of node pages. */static void ra_node_pages(struct page *parent, int start, int n){	struct f2fs_sb_info *sbi = F2FS_P_SB(parent);	struct blk_plug plug;	int i, end;	nid_t nid; 	blk_start_plug(&plug); 	/* Then, try readahead for siblings of the desired node */	end = start + n;	end = min(end, NIDS_PER_BLOCK);	for (i = start; i < end; i++) {		nid = get_nid(parent, i, false);		ra_node_page(sbi, nid);	} 	blk_finish_plug(&plug);} pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs){	const long direct_index = ADDRS_PER_INODE(dn->inode);	const long direct_blks = ADDRS_PER_BLOCK;	const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;	unsigned int skipped_unit = ADDRS_PER_BLOCK;	int cur_level = dn->cur_level;	int max_level = dn->max_level;	pgoff_t base = 0; 	if (!dn->max_level)		return pgofs + 1; 	while (max_level-- > cur_level)		skipped_unit *= NIDS_PER_BLOCK; 	switch (dn->max_level) {	case 3:		base += 2 * indirect_blks;	case 2:		base += 2 * direct_blks;	case 1:		base += direct_index;		break;	default:		f2fs_bug_on(F2FS_I_SB(dn->inode), 1);	} 	return ((pgofs - base) / skipped_unit + 1) * skipped_unit + base;} /* * The maximum depth is four. * Offset[0] will have raw inode offset. */static int get_node_path(struct inode *inode, long block,				int offset[4], unsigned int noffset[4]){	const long direct_index = ADDRS_PER_INODE(inode);	const long direct_blks = ADDRS_PER_BLOCK;	const long dptrs_per_blk = NIDS_PER_BLOCK;	const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;	const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK;	int n = 0;	int level = 0; 	noffset[0] = 0;

Lines 1–500 of 2802.