1760 lines · 40.9 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" static struct kmem_cache *nat_entry_slab;static struct kmem_cache *free_nid_slab; static void clear_node_page_dirty(struct page *page){	struct address_space *mapping = page->mapping;	struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);	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(sbi, 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); 	/* Dirty src_page means that it is already the new target NAT page. */	if (PageDirty(src_page))		return src_page; 	dst_page = grab_meta_page(sbi, dst_off); 	src_addr = page_address(src_page);	dst_addr = page_address(dst_page);	memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE);	set_page_dirty(dst_page);	f2fs_put_page(src_page, 1); 	set_to_next_nat(nm_i, nid); 	return dst_page;} /* * Readahead NAT pages */static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid){	struct address_space *mapping = sbi->meta_inode->i_mapping;	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct page *page;	pgoff_t index;	int i; 	for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) {		if (nid >= nm_i->max_nid)			nid = 0;		index = current_nat_addr(sbi, nid); 		page = grab_cache_page(mapping, index);		if (!page)			continue;		if (f2fs_readpage(sbi, page, index, READ)) {			f2fs_put_page(page, 1);			continue;		}		page_cache_release(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);} int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e;	int is_cp = 1; 	read_lock(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, nid);	if (e && !e->checkpointed)		is_cp = 0;	read_unlock(&nm_i->nat_tree_lock);	return is_cp;} static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid){	struct nat_entry *new; 	new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC);	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);	list_add_tail(&new->list, &nm_i->nat_entries);	nm_i->nat_cnt++;	return new;} static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,						struct f2fs_nat_entry *ne){	struct nat_entry *e;retry:	write_lock(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, nid);	if (!e) {		e = grab_nat_entry(nm_i, nid);		if (!e) {			write_unlock(&nm_i->nat_tree_lock);			goto retry;		}		nat_set_blkaddr(e, le32_to_cpu(ne->block_addr));		nat_set_ino(e, le32_to_cpu(ne->ino));		nat_set_version(e, ne->version);		e->checkpointed = true;	}	write_unlock(&nm_i->nat_tree_lock);} static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,			block_t new_blkaddr){	struct f2fs_nm_info *nm_i = NM_I(sbi);	struct nat_entry *e;retry:	write_lock(&nm_i->nat_tree_lock);	e = __lookup_nat_cache(nm_i, ni->nid);	if (!e) {		e = grab_nat_entry(nm_i, ni->nid);		if (!e) {			write_unlock(&nm_i->nat_tree_lock);			goto retry;		}		e->ni = *ni;		e->checkpointed = true;		BUG_ON(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.		 */		e->ni = *ni;		BUG_ON(ni->blk_addr != NULL_ADDR);	} 	if (new_blkaddr == NEW_ADDR)		e->checkpointed = false; 	/* sanity check */	BUG_ON(nat_get_blkaddr(e) != ni->blk_addr);	BUG_ON(nat_get_blkaddr(e) == NULL_ADDR &&			new_blkaddr == NULL_ADDR);	BUG_ON(nat_get_blkaddr(e) == NEW_ADDR &&			new_blkaddr == NEW_ADDR);	BUG_ON(nat_get_blkaddr(e) != NEW_ADDR &&			nat_get_blkaddr(e) != NULL_ADDR &&			new_blkaddr == NEW_ADDR); 	/* increament 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));	} 	/* change address */	nat_set_blkaddr(e, new_blkaddr);	__set_nat_cache_dirty(nm_i, e);	write_unlock(&nm_i->nat_tree_lock);} static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink){	struct f2fs_nm_info *nm_i = NM_I(sbi); 	if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD)		return 0; 	write_lock(&nm_i->nat_tree_lock);	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--;	}	write_unlock(&nm_i->nat_tree_lock);	return nr_shrink;} /* * This function returns always 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_summary_block *sum = curseg->sum_blk;	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;	int i; 	memset(&ne, 0, sizeof(struct f2fs_nat_entry));	ni->nid = nid; 	/* Check nat cache */	read_lock(&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);	}	read_unlock(&nm_i->nat_tree_lock);	if (e)		return; 	/* Check current segment summary */	mutex_lock(&curseg->curseg_mutex);	i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);	if (i >= 0) {		ne = nat_in_journal(sum, i);		node_info_from_raw_nat(ni, &ne);	}	mutex_unlock(&curseg->curseg_mutex);	if (i >= 0)		goto cache; 	/* Fill node_info from nat page */	page = get_current_nat_page(sbi, start_nid);	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 */	cache_nat_entry(NM_I(sbi), nid, &ne);} /* * The maximum depth is four. * Offset[0] will have raw inode offset. */static int get_node_path(long block, int offset[4], unsigned int noffset[4]){	const long direct_index = ADDRS_PER_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; 	if (block < direct_index) {		offset[n++] = block;		level = 0;		goto got;	}	block -= direct_index;	if (block < direct_blks) {		offset[n++] = NODE_DIR1_BLOCK;		noffset[n] = 1;		offset[n++] = block;		level = 1;		goto got;	}	block -= direct_blks;	if (block < direct_blks) {		offset[n++] = NODE_DIR2_BLOCK;		noffset[n] = 2;		offset[n++] = block;		level = 1;		goto got;	}	block -= direct_blks;	if (block < indirect_blks) {		offset[n++] = NODE_IND1_BLOCK;		noffset[n] = 3;		offset[n++] = block / direct_blks;		noffset[n] = 4 + offset[n - 1];		offset[n++] = block % direct_blks;		level = 2;		goto got;	}	block -= indirect_blks;	if (block < indirect_blks) {		offset[n++] = NODE_IND2_BLOCK;		noffset[n] = 4 + dptrs_per_blk;		offset[n++] = block / direct_blks;		noffset[n] = 5 + dptrs_per_blk + offset[n - 1];		offset[n++] = block % direct_blks;		level = 2;		goto got;	}	block -= indirect_blks;	if (block < dindirect_blks) {		offset[n++] = NODE_DIND_BLOCK;		noffset[n] = 5 + (dptrs_per_blk * 2);		offset[n++] = block / indirect_blks;		noffset[n] = 6 + (dptrs_per_blk * 2) +			      offset[n - 1] * (dptrs_per_blk + 1);		offset[n++] = (block / direct_blks) % dptrs_per_blk;		noffset[n] = 7 + (dptrs_per_blk * 2) +			      offset[n - 2] * (dptrs_per_blk + 1) +			      offset[n - 1];		offset[n++] = block % direct_blks;		level = 3;		goto got;	} else {		BUG();	}got:	return level;} /* * Caller should call f2fs_put_dnode(dn). */int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro){	struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);	struct page *npage[4];	struct page *parent;	int offset[4];	unsigned int noffset[4];	nid_t nids[4];	int level, i;	int err = 0; 	level = get_node_path(index, offset, noffset); 	nids[0] = dn->inode->i_ino;	npage[0] = get_node_page(sbi, nids[0]);	if (IS_ERR(npage[0]))		return PTR_ERR(npage[0]); 	parent = npage[0];	nids[1] = get_nid(parent, offset[0], true);	dn->inode_page = npage[0];	dn->inode_page_locked = true; 	/* get indirect or direct nodes */	for (i = 1; i <= level; i++) {		bool done = false; 		if (!nids[i] && !ro) {			mutex_lock_op(sbi, NODE_NEW); 			/* alloc new node */			if (!alloc_nid(sbi, &(nids[i]))) {				mutex_unlock_op(sbi, NODE_NEW);				err = -ENOSPC;				goto release_pages;			} 			dn->nid = nids[i];			npage[i] = new_node_page(dn, noffset[i]);			if (IS_ERR(npage[i])) {				alloc_nid_failed(sbi, nids[i]);				mutex_unlock_op(sbi, NODE_NEW);				err = PTR_ERR(npage[i]);				goto release_pages;			} 			set_nid(parent, offset[i - 1], nids[i], i == 1);			alloc_nid_done(sbi, nids[i]);			mutex_unlock_op(sbi, NODE_NEW);			done = true;		} else if (ro && i == level && level > 1) {			npage[i] = get_node_page_ra(parent, offset[i - 1]);			if (IS_ERR(npage[i])) {				err = PTR_ERR(npage[i]);				goto release_pages;			}			done = true;		}		if (i == 1) {			dn->inode_page_locked = false;			unlock_page(parent);		} else {			f2fs_put_page(parent, 1);		} 		if (!done) {			npage[i] = get_node_page(sbi, nids[i]);			if (IS_ERR(npage[i])) {				err = PTR_ERR(npage[i]);				f2fs_put_page(npage[0], 0);				goto release_out;			}		}		if (i < level) {			parent = npage[i];			nids[i + 1] = get_nid(parent, offset[i], false);		}	}	dn->nid = nids[level];	dn->ofs_in_node = offset[level];	dn->node_page = npage[level];	dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);	return 0; release_pages:	f2fs_put_page(parent, 1);	if (i > 1)		f2fs_put_page(npage[0], 0);release_out:	dn->inode_page = NULL;	dn->node_page = NULL;	return err;} static void truncate_node(struct dnode_of_data *dn){	struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);	struct node_info ni; 	get_node_info(sbi, dn->nid, &ni);	if (dn->inode->i_blocks == 0) {		BUG_ON(ni.blk_addr != NULL_ADDR);		goto invalidate;	}	BUG_ON(ni.blk_addr == NULL_ADDR); 	/* Deallocate node address */	invalidate_blocks(sbi, ni.blk_addr);	dec_valid_node_count(sbi, dn->inode, 1);	set_node_addr(sbi, &ni, NULL_ADDR); 	if (dn->nid == dn->inode->i_ino) {		remove_orphan_inode(sbi, dn->nid);		dec_valid_inode_count(sbi);

Lines 1–500 of 1760.