lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 27 Oct 2012 17:58:27 +0400
From:	Vyacheslav Dubeyko <slava@...eyko.com>
To:	Jaegeuk Kim <jaegeuk.kim@...sung.com>
Cc:	linux-fsdevel@...r.kernel.org, linux-kernel@...r.kernel.org,
	gregkh@...uxfoundation.org, viro@...iv.linux.org.uk, arnd@...db.de,
	tytso@....edu, chur.lee@...sung.com, cm224.lee@...sung.com,
	jooyoung.hwang@...sung.com
Subject: Re: [PATCH 03/16 v2] f2fs: add superblock and major in-memory structure


On Oct 23, 2012, at 6:26 AM, Jaegeuk Kim wrote:

> This adds the following major in-memory structures in f2fs.
> 
> - f2fs_sb_info:
>  contains f2fs-specific information, two special inode pointers for node and
>  meta address spaces, and orphan inode management.
> 
> - f2fs_inode_info:
>  contains vfs_inode and other fs-specific information.
> 
> - f2fs_nm_info:
>  contains node manager information such as NAT entry cache, free nid list,
>  and NAT page management.
> 
> - f2fs_node_info:
>  represents a node as node id, inode number, block address, and its version.
> 
> - f2fs_sm_info:
>  contains segment manager information such as SIT entry cache, free segment
>  map, current active logs, dirty segment management, and segment utilization.
>  The specific structures are sit_info, free_segmap_info, dirty_seglist_info,
>  curseg_info.
> 
> Signed-off-by: Chul Lee <chur.lee@...sung.com>
> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@...sung.com>
> ---
> fs/f2fs/f2fs.h    |  982 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> fs/f2fs/node.h    |  330 ++++++++++++++++++
> fs/f2fs/segment.h |  594 ++++++++++++++++++++++++++++++++
> 3 files changed, 1906 insertions(+)
> create mode 100644 fs/f2fs/f2fs.h
> create mode 100644 fs/f2fs/node.h
> create mode 100644 fs/f2fs/segment.h
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> new file mode 100644
> index 0000000..bbe2f02
> --- /dev/null
> +++ b/fs/f2fs/f2fs.h
> @@ -0,0 +1,982 @@
> +/**
> + * fs/f2fs/f2fs.h
> + *
> + * 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.
> + */
> +#ifndef _LINUX_F2FS_H
> +#define _LINUX_F2FS_H
> +
> +#include <linux/types.h>
> +#include <linux/page-flags.h>
> +#include <linux/buffer_head.h>
> +#include <linux/version.h>
> +#include <linux/slab.h>
> +#include <linux/crc32.h>
> +
> +/**
> + * For mount options
> + */
> +#define F2FS_MOUNT_BG_GC		0x00000001
> +#define F2FS_MOUNT_DISABLE_ROLL_FORWARD	0x00000002
> +#define F2FS_MOUNT_DISCARD		0x00000004
> +#define F2FS_MOUNT_NOHEAP		0x00000008
> +#define F2FS_MOUNT_XATTR_USER		0x00000010
> +#define F2FS_MOUNT_POSIX_ACL		0x00000020
> +#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY	0x00000040
> +
> +#define clear_opt(sbi, option)	(sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
> +#define set_opt(sbi, option)	(sbi->mount_opt.opt |= F2FS_MOUNT_##option)
> +#define test_opt(sbi, option)	(sbi->mount_opt.opt & F2FS_MOUNT_##option)
> +
> +#define ver_after(a, b)	(typecheck(unsigned long long, a) &&		\
> +		typecheck(unsigned long long, b) &&			\
> +		((long long)((a) - (b)) > 0))
> +
> +typedef u64 block_t;
> +typedef u32 nid_t;
> +
> +struct f2fs_mount_info {
> +	unsigned int	opt;
> +};
> +
> +static inline __u32 f2fs_crc32(void *buff, size_t len)
> +{
> +	return crc32_le(F2FS_SUPER_MAGIC, buff, len);
> +}
> +
> +static inline bool f2fs_crc_valid(__u32 blk_crc, void *buff, size_t buff_size)
> +{
> +	return f2fs_crc32(buff, buff_size) == blk_crc;
> +}
> +
> +/**
> + * For checkpoint manager
> + */
> +#define CP_ERROR_FLAG		0x00000008
> +#define CP_COMPACT_SUM_FLAG	0x00000004
> +#define CP_ORPHAN_PRESENT_FLAG	0x00000002
> +#define CP_UMOUNT_FLAG		0x00000001
> +
> +enum {
> +	NAT_BITMAP,
> +	SIT_BITMAP
> +};
> +
> +struct orphan_inode_entry {
> +	struct list_head list;
> +	nid_t ino;
> +};
> +
> +struct dir_inode_entry {
> +	struct list_head list;
> +	struct inode *inode;
> +};
> +
> +struct fsync_inode_entry {
> +	struct list_head list;
> +	struct inode *inode;
> +	block_t blkaddr;
> +};
> +
> +#define nats_in_cursum(sum)		(le16_to_cpu(sum->n_nats))
> +#define sits_in_cursum(sum)		(le16_to_cpu(sum->n_sits))
> +
> +#define nat_in_journal(sum, i)		(sum->nat_j.entries[i].ne)
> +#define nid_in_journal(sum, i)		(sum->nat_j.entries[i].nid)
> +#define sit_in_journal(sum, i)		(sum->sit_j.entries[i].se)
> +#define segno_in_journal(sum, i)	(sum->sit_j.entries[i].segno)
> +
> +static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i)
> +{
> +	int before = nats_in_cursum(rs);
> +	rs->n_nats = cpu_to_le16(before + i);
> +	return before;
> +}
> +
> +static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
> +{
> +	int before = sits_in_cursum(rs);
> +	rs->n_sits = cpu_to_le16(before + i);
> +	return before;
> +}
> +
> +/**
> + * For INODE and NODE manager
> + */
> +#define XATTR_NODE_OFFSET	(-1)

This is a really strange declaration. Why does offset equal by -1? 

> +#define RDONLY_NODE		1
> +#define F2FS_LINK_MAX		32000
> +
> +struct extent_info {
> +	rwlock_t ext_lock;
> +	unsigned int fofs;
> +	u32 blk_addr;
> +	unsigned int len;
> +};
> +
> +#define FADVISE_COLD_BIT	0x01
> +/*
> + * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
> + */

Maybe, it makes sense to have this comment before declaration. I think that such comment before struct f2fs_inode_info can confuse.

> +struct f2fs_inode_info {
> +	struct inode vfs_inode;
> +	unsigned long i_flags;
> +	unsigned long flags;
> +	unsigned long long data_version;
> +	atomic_t dirty_dents;
> +	unsigned int current_depth;
> +	f2fs_hash_t chash;
> +	unsigned int clevel;
> +	nid_t i_xattr_nid;
> +	struct extent_info ext;
> +	umode_t i_acl_mode;
> +	unsigned char i_advise;		/* If true, this is cold data */
> +};

>From my point of view, it is very important to have descriptive comments for every key structure. But, as I can see, many key structures haven't any comment.

> +
> +static inline void get_extent_info(struct extent_info *ext,
> +					struct f2fs_extent i_ext)
> +{
> +	write_lock(&ext->ext_lock);
> +	ext->fofs = le32_to_cpu(i_ext.fofs);
> +	ext->blk_addr = le32_to_cpu(i_ext.blk_addr);
> +	ext->len = le32_to_cpu(i_ext.len);
> +	write_unlock(&ext->ext_lock);
> +}
> +
> +static inline void set_raw_extent(struct extent_info *ext,
> +					struct f2fs_extent *i_ext)
> +{
> +	read_lock(&ext->ext_lock);
> +	i_ext->fofs = cpu_to_le32(ext->fofs);
> +	i_ext->blk_addr = cpu_to_le32(ext->blk_addr);
> +	i_ext->len = cpu_to_le32(ext->len);
> +	read_unlock(&ext->ext_lock);
> +}
> +
> +struct f2fs_nm_info {
> +	block_t nat_blkaddr;		/* base disk address of NAT */
> +	unsigned int nat_segs;		/* the number of nat segments */
> +	unsigned int nat_blocks;	/* the number of nat blocks of
> +					   one size */
> +	nid_t max_nid;
> +	unsigned int nat_cnt;		/* the number of nodes in NAT Buffer */
> +	struct radix_tree_root nat_root;
> +	rwlock_t nat_tree_lock;		/* Protect nat_tree_lock */
> +	struct list_head nat_entries;	/* cached nat entry list (clean) */
> +	struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */
> +
> +	unsigned int fcnt;		/* the number of free node id */
> +	struct mutex build_lock;	/* lock for build free nids */
> +
> +	int nat_upd_blkoff[3];		/* Block offset
> +					   in the current journal segment
> +					   where the last NAT update happened */
> +	int lst_upd_blkoff[3];		/* Block offset
> +					   in current journal segment */
> +
> +	unsigned int written_valid_node_count;
> +	unsigned int written_valid_inode_count;
> +	char *nat_bitmap;		/* NAT bitmap pointer */
> +	int bitmap_size;		/* bitmap size */
> +
> +	nid_t init_scan_nid;		/* the first nid to be scanned */
> +	nid_t next_scan_nid;		/* the next nid to be scanned */
> +	struct list_head free_nid_list;
> +	spinlock_t free_nid_list_lock;	/* Protect free nid list */
> +};
> +
> +struct dnode_of_data {
> +	struct inode *inode;
> +	struct page *inode_page;
> +	struct page *node_page;
> +	nid_t nid;
> +	unsigned int ofs_in_node;
> +	bool inode_page_locked;
> +	block_t	data_blkaddr;
> +};
> +
> +static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,
> +		struct page *ipage, struct page *npage, nid_t nid)
> +{
> +	dn->inode = inode;
> +	dn->inode_page = ipage;
> +	dn->node_page = npage;
> +	dn->nid = nid;
> +	dn->inode_page_locked = 0;
> +}
> +
> +/**
> + * For SIT manager
> + */
> +#define	NR_CURSEG_DATA_TYPE	(3)
> +#define NR_CURSEG_NODE_TYPE	(3)
> +#define NR_CURSEG_TYPE	(NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)

It is really confusing to see two declarations with equal values. Why not different?

I think that here it needs to comment purpose of these declarations. Because it is not so easy to understand why NR_CURSEG_TYPE has such value.


> +
> +enum {
> +	CURSEG_HOT_DATA = 0,
> +	CURSEG_WARM_DATA,
> +	CURSEG_COLD_DATA,
> +	CURSEG_HOT_NODE,
> +	CURSEG_WARM_NODE,
> +	CURSEG_COLD_NODE,
> +	NO_CHECK_TYPE
> +};
> +
> +struct f2fs_sm_info {
> +	/* SIT information */
> +	struct sit_info *sit_info;
> +
> +	/* Free segmap infomation */
> +	struct free_segmap_info *free_info;
> +
> +	/* Dirty segments list information for GC victim */
> +	struct dirty_seglist_info *dirty_info;
> +
> +	/* Current working segments(i.e. logging point) information array */
> +	struct curseg_info *curseg_array;
> +
> +	/* list head of all under-writeback pages for flush handling */
> +	struct list_head	wblist_head;
> +	spinlock_t		wblist_lock;
> +
> +	block_t			seg0_blkaddr;
> +	block_t			main_blkaddr;
> +	unsigned int		segment_count;
> +	unsigned int		rsvd_segment_count;
> +	unsigned int		main_segment_count;
> +	block_t			ssa_blkaddr;
> +	unsigned int		segment_count_ssa;
> +};
> +
> +/**
> + * For Garbage Collection
> + */
> +struct f2fs_gc_info {
> +#ifdef CONFIG_F2FS_STAT_FS
> +	struct list_head	stat_list;
> +	struct f2fs_stat_info	*stat_info;
> +#endif
> +	int			cause;
> +	int			rsvd_segment_count;
> +	int			overp_segment_count;
> +};
> +
> +/**
> + * For directory operation
> + */
> +#define F2FS_INODE_SIZE		(17 * 4 + F2FS_MAX_NAME_LEN)
> +#define	NODE_DIR1_BLOCK		(ADDRS_PER_INODE + 1)
> +#define	NODE_DIR2_BLOCK		(ADDRS_PER_INODE + 2)
> +#define	NODE_IND1_BLOCK		(ADDRS_PER_INODE + 3)
> +#define	NODE_IND2_BLOCK		(ADDRS_PER_INODE + 4)
> +#define	NODE_DIND_BLOCK		(ADDRS_PER_INODE + 5)
> +

I think that it is really hard to understand why F2FS_INODE_SIZE is calculated as (17 * 4 + F2FS_MAX_NAME_LEN). What does it means 17 * 4?

> +/**
> + * For superblock
> + */
> +enum count_type {
> +	F2FS_WRITEBACK,
> +	F2FS_DIRTY_DENTS,
> +	F2FS_DIRTY_NODES,
> +	F2FS_DIRTY_META,
> +	NR_COUNT_TYPE,
> +};
> +
> +/*
> + * FS_LOCK nesting subclasses for the lock validator:
> + *
> + * The locking order between these classes is
> + * RENAME -> DENTRY_OPS -> DATA_WRITE -> DATA_NEW
> + *    -> DATA_TRUNC -> NODE_WRITE -> NODE_NEW -> NODE_TRUNC
> + */
> +enum lock_type {
> +	RENAME,		/* for renaming operations */
> +	DENTRY_OPS,	/* for directory operations */
> +	DATA_WRITE,	/* for data write */
> +	DATA_NEW,	/* for data allocation */
> +	DATA_TRUNC,	/* for data truncate */
> +	NODE_NEW,	/* for node allocation */
> +	NODE_TRUNC,	/* for node truncate */
> +	NODE_WRITE,	/* for node write */
> +	NR_LOCK_TYPE,
> +};
> +
> +/*
> + * The below are the page types of bios used in submti_bio().
> + * The available types are:
> + * DATA			User data pages. It operates as async mode.
> + * NODE			Node pages. It operates as async mode.
> + * META			FS metadata pages such as SIT, NAT, CP.
> + * NR_PAGE_TYPE		The number of page types.
> + * META_FLUSH		Make sure the previous pages are written
> + *			with waiting the bio's completion
> + * ...			Only can be used with META.
> + */
> +enum page_type {
> +	DATA,
> +	NODE,
> +	META,
> +	NR_PAGE_TYPE,
> +	META_FLUSH,
> +};
> +
> +struct f2fs_sb_info {
> +	struct super_block *sb;			/* Pointer to VFS super block */
> +	int s_dirty;
> +	struct f2fs_super_block *raw_super;	/* Pointer to the super block
> +						   in the buffer */
> +	struct buffer_head *raw_super_buf;	/* Buffer containing
> +						   the f2fs raw super block */
> +	struct f2fs_checkpoint *ckpt;		/* Pointer to the checkpoint
> +						   in the buffer */
> +	struct mutex orphan_inode_mutex;
> +	spinlock_t dir_inode_lock;
> +	struct mutex cp_mutex;
> +	/* orphan Inode list to be written in Journal block during CP  */
> +	struct list_head orphan_inode_list;
> +	struct list_head dir_inode_list;
> +	unsigned int n_orphans, n_dirty_dirs;
> +
> +	unsigned int log_sectorsize;
> +	unsigned int log_sectors_per_block;
> +	unsigned int log_blocksize;
> +	unsigned int blocksize;
> +	unsigned int root_ino_num;		/* Root Inode Number*/
> +	unsigned int node_ino_num;		/* Root Inode Number*/
> +	unsigned int meta_ino_num;		/* Root Inode Number*/
> +	unsigned int log_blocks_per_seg;
> +	unsigned int blocks_per_seg;
> +	unsigned int segs_per_sec;
> +	unsigned int secs_per_zone;
> +	unsigned int total_sections;
> +	unsigned int total_node_count;
> +	unsigned int total_valid_node_count;
> +	unsigned int total_valid_inode_count;
> +	unsigned int segment_count[2];
> +	unsigned int block_count[2];
> +	unsigned int last_victim[2];
> +	int active_logs;
> +	block_t user_block_count;
> +	block_t total_valid_block_count;
> +	block_t alloc_valid_block_count;
> +	block_t last_valid_block_count;
> +	atomic_t nr_pages[NR_COUNT_TYPE];
> +
> +	struct f2fs_mount_info mount_opt;
> +
> +	/* related to NM */
> +	struct f2fs_nm_info *nm_info;		/* Node Manager information */
> +
> +	/* related to SM */
> +	struct f2fs_sm_info *sm_info;		/* Segment Manager
> +						   information */
> +	int total_hit_ext, read_hit_ext;
> +	int rr_flush;
> +
> +	/* related to GC */
> +	struct proc_dir_entry *s_proc;
> +	struct f2fs_gc_info *gc_info;		/* Garbage Collector
> +						   information */
> +	struct mutex gc_mutex;			/* mutex for GC */
> +	struct mutex fs_lock[NR_LOCK_TYPE];	/* mutex for GP */
> +	struct mutex write_inode;		/* mutex for write inode */
> +	struct mutex writepages;		/* mutex for writepages() */
> +	struct f2fs_gc_kthread	*gc_thread;	/* GC thread */
> +	int bg_gc;
> +	int last_gc_status;
> +	int por_doing;
> +
> +	struct inode *node_inode;
> +	struct inode *meta_inode;
> +
> +	struct bio *bio[NR_PAGE_TYPE];
> +	sector_t last_block_in_bio[NR_PAGE_TYPE];
> +	struct rw_semaphore bio_sem;
> +	spinlock_t stat_lock;			/* lock for handling the number
> +						   of valid blocks and
> +						   valid nodes */
> +};
> +
> +/**
> + * Inline functions
> + */
> +static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
> +{
> +	return container_of(inode, struct f2fs_inode_info, vfs_inode);
> +}
> +
> +static inline struct f2fs_sb_info *F2FS_SB(struct super_block *sb)
> +{
> +	return sb->s_fs_info;
> +}
> +
> +static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi)
> +{
> +	return (struct f2fs_super_block *)(sbi->raw_super);
> +}
> +
> +static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
> +{
> +	return (struct f2fs_checkpoint *)(sbi->ckpt);
> +}
> +
> +static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
> +{
> +	return (struct f2fs_nm_info *)(sbi->nm_info);
> +}
> +
> +static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi)
> +{
> +	return (struct f2fs_sm_info *)(sbi->sm_info);
> +}
> +
> +static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi)
> +{
> +	return (struct sit_info *)(SM_I(sbi)->sit_info);
> +}
> +
> +static inline struct free_segmap_info *FREE_I(struct f2fs_sb_info *sbi)
> +{
> +	return (struct free_segmap_info *)(SM_I(sbi)->free_info);
> +}
> +
> +static inline struct dirty_seglist_info *DIRTY_I(struct f2fs_sb_info *sbi)
> +{
> +	return (struct dirty_seglist_info *)(SM_I(sbi)->dirty_info);
> +}
> +
> +static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi)
> +{
> +	sbi->s_dirty = 1;
> +}
> +
> +static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi)
> +{
> +	sbi->s_dirty = 0;
> +}
> +
> +static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t)
> +{
> +	mutex_lock_nested(&sbi->fs_lock[t], t);
> +}
> +
> +static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, enum lock_type t)
> +{
> +	mutex_unlock(&sbi->fs_lock[t]);
> +}
> +
> +/**
> + * Check whether the given nid is within node id range.
> + */
> +static inline void check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
> +{
> +	BUG_ON((nid >= NM_I(sbi)->max_nid));
> +}
> +
> +#define F2FS_DEFAULT_ALLOCATED_BLOCKS	1
> +
> +/**
> + * Check whether the inode has blocks or not
> + */
> +static inline int F2FS_HAS_BLOCKS(struct inode *inode)
> +{
> +	if (F2FS_I(inode)->i_xattr_nid)
> +		return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1);
> +	else
> +		return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS);
> +}
> +
> +static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
> +				 struct inode *inode, blkcnt_t count)
> +{
> +	block_t	valid_block_count;
> +
> +	spin_lock(&sbi->stat_lock);
> +	valid_block_count =
> +		sbi->total_valid_block_count + (block_t)count;
> +	if (valid_block_count > sbi->user_block_count) {
> +		spin_unlock(&sbi->stat_lock);
> +		return false;
> +	}
> +	inode->i_blocks += count;
> +	sbi->total_valid_block_count = valid_block_count;
> +	sbi->alloc_valid_block_count += (block_t)count;
> +	spin_unlock(&sbi->stat_lock);
> +	return true;
> +}
> +
> +static inline int dec_valid_block_count(struct f2fs_sb_info *sbi,
> +						struct inode *inode,
> +						blkcnt_t count)
> +{
> +	spin_lock(&sbi->stat_lock);
> +	BUG_ON(sbi->total_valid_block_count < (block_t) count);
> +	BUG_ON(inode->i_blocks < count);
> +	inode->i_blocks -= count;
> +	sbi->total_valid_block_count -= (block_t)count;
> +	spin_unlock(&sbi->stat_lock);
> +	return 0;
> +}
> +
> +static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
> +{
> +	atomic_inc(&sbi->nr_pages[count_type]);
> +	F2FS_SET_SB_DIRT(sbi);
> +}
> +
> +static inline void inode_inc_dirty_dents(struct inode *inode)
> +{
> +	atomic_inc(&F2FS_I(inode)->dirty_dents);
> +}
> +
> +static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
> +{
> +	atomic_dec(&sbi->nr_pages[count_type]);
> +}
> +
> +static inline void inode_dec_dirty_dents(struct inode *inode)
> +{
> +	atomic_dec(&F2FS_I(inode)->dirty_dents);
> +}
> +
> +static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
> +{
> +	return atomic_read(&sbi->nr_pages[count_type]);
> +}
> +
> +static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi)
> +{
> +	block_t ret;
> +	spin_lock(&sbi->stat_lock);
> +	ret = sbi->total_valid_block_count;
> +	spin_unlock(&sbi->stat_lock);
> +	return ret;
> +}
> +
> +static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
> +{
> +	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
> +
> +	/* return NAT or SIT bitmap */
> +	if (flag == NAT_BITMAP)
> +		return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
> +	else if (flag == SIT_BITMAP)
> +		return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
> +
> +	return 0;
> +}
> +
> +static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
> +{
> +	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
> +	int offset = (flag == NAT_BITMAP) ? ckpt->sit_ver_bitmap_bytesize : 0;
> +	return &ckpt->sit_nat_version_bitmap + offset;
> +}
> +
> +static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
> +{
> +	block_t start_addr;
> +	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
> +	unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver);
> +
> +	start_addr = le64_to_cpu(F2FS_RAW_SUPER(sbi)->start_segment_checkpoint);
> +
> +	/*
> +	 * odd numbered checkpoint shoukd at cp segment 0

It needs to correct "shoukd" on "should".

> +	 * and even segent must be at cp segment 1
> +	 */
> +	if (!(ckpt_version & 1))
> +		start_addr += sbi->blocks_per_seg;
> +
> +	return start_addr;
> +}
> +
> +static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
> +{
> +	return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
> +}
> +
> +static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi,
> +						struct inode *inode,
> +						unsigned int count)
> +{
> +	block_t	valid_block_count;
> +	unsigned int valid_node_count;
> +
> +	spin_lock(&sbi->stat_lock);
> +
> +	valid_block_count = sbi->total_valid_block_count + (block_t)count;
> +	sbi->alloc_valid_block_count += (block_t)count;
> +	valid_node_count = sbi->total_valid_node_count + count;
> +
> +	if (valid_block_count > sbi->user_block_count) {
> +		spin_unlock(&sbi->stat_lock);
> +		return false;
> +	}
> +
> +	if (valid_node_count > sbi->total_node_count) {
> +		spin_unlock(&sbi->stat_lock);
> +		return false;
> +	}
> +
> +	if (inode)
> +		inode->i_blocks += count;
> +	sbi->total_valid_node_count = valid_node_count;
> +	sbi->total_valid_block_count = valid_block_count;
> +	spin_unlock(&sbi->stat_lock);
> +
> +	return true;
> +}
> +
> +static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
> +						struct inode *inode,
> +						unsigned int count)
> +{
> +	spin_lock(&sbi->stat_lock);
> +
> +	BUG_ON(sbi->total_valid_block_count < count);
> +	BUG_ON(sbi->total_valid_node_count < count);
> +	BUG_ON(inode->i_blocks < count);
> +
> +	inode->i_blocks -= count;
> +	sbi->total_valid_node_count -= count;
> +	sbi->total_valid_block_count -= (block_t)count;
> +
> +	spin_unlock(&sbi->stat_lock);
> +}
> +
> +static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
> +{
> +	unsigned int ret;
> +	spin_lock(&sbi->stat_lock);
> +	ret = sbi->total_valid_node_count;
> +	spin_unlock(&sbi->stat_lock);
> +	return ret;
> +}
> +
> +static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
> +{
> +	spin_lock(&sbi->stat_lock);
> +	BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count);
> +	sbi->total_valid_inode_count++;
> +	spin_unlock(&sbi->stat_lock);
> +}
> +
> +static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi)
> +{
> +	spin_lock(&sbi->stat_lock);
> +	BUG_ON(!sbi->total_valid_inode_count);
> +	sbi->total_valid_inode_count--;
> +	spin_unlock(&sbi->stat_lock);
> +	return 0;
> +}
> +
> +static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi)
> +{
> +	unsigned int ret;
> +	spin_lock(&sbi->stat_lock);
> +	ret = sbi->total_valid_inode_count;
> +	spin_unlock(&sbi->stat_lock);
> +	return ret;
> +}
> +
> +static inline void f2fs_put_page(struct page *page, int unlock)
> +{
> +	if (!page || IS_ERR(page))
> +		return;
> +
> +	if (unlock) {
> +		BUG_ON(!PageLocked(page));
> +		unlock_page(page);
> +	}
> +	page_cache_release(page);
> +}
> +
> +static inline void f2fs_put_dnode(struct dnode_of_data *dn)
> +{
> +	if (dn->node_page)
> +		f2fs_put_page(dn->node_page, 1);
> +	if (dn->inode_page && dn->node_page != dn->inode_page)
> +		f2fs_put_page(dn->inode_page, 0);
> +	dn->node_page = NULL;
> +	dn->inode_page = NULL;
> +}
> +
> +static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
> +					size_t size, void (*ctor)(void *))
> +{
> +	return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
> +}
> +
> +#define RAW_IS_INODE(p)	((p)->footer.nid == (p)->footer.ino)
> +
> +static inline bool IS_INODE(struct page *page)
> +{
> +	struct f2fs_node *p = (struct f2fs_node *)page_address(page);
> +	return RAW_IS_INODE(p);
> +}
> +
> +static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
> +{
> +	return RAW_IS_INODE(node) ? node->i.i_addr : node->dn.addr;
> +}
> +
> +static inline block_t datablock_addr(struct page *node_page,
> +		unsigned int offset)
> +{
> +	struct f2fs_node *raw_node;
> +	__le32 *addr_array;
> +	raw_node = (struct f2fs_node *)page_address(node_page);
> +	addr_array = blkaddr_in_node(raw_node);
> +	return le32_to_cpu(addr_array[offset]);
> +}
> +
> +static inline int f2fs_test_bit(unsigned int nr, char *addr)
> +{
> +	int mask;
> +
> +	addr += (nr >> 3);
> +	mask = 1 << (7 - (nr & 0x07));
> +	return mask & *addr;
> +}
> +
> +static inline int f2fs_set_bit(unsigned int nr, char *addr)
> +{
> +	int mask;
> +	int ret;
> +
> +	addr += (nr >> 3);
> +	mask = 1 << (7 - (nr & 0x07));
> +	ret = mask & *addr;
> +	*addr |= mask;
> +	return ret;
> +}
> +
> +static inline int f2fs_clear_bit(unsigned int nr, char *addr)
> +{
> +	int mask;
> +	int ret;
> +
> +	addr += (nr >> 3);
> +	mask = 1 << (7 - (nr & 0x07));
> +	ret = mask & *addr;
> +	*addr &= ~mask;
> +	return ret;
> +}
> +
> +enum {
> +	FI_NEW_INODE,
> +	FI_NEED_CP,
> +	FI_INC_LINK,
> +	FI_ACL_MODE,
> +	FI_NO_ALLOC,
> +};

I think that it needs to have some comment about these declarations.
 
> +
> +static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
> +{
> +	set_bit(flag, &fi->flags);
> +}
> +
> +static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag)
> +{
> +	return test_bit(flag, &fi->flags);
> +}
> +
> +static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag)
> +{
> +	clear_bit(flag, &fi->flags);
> +}
> +
> +static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode)
> +{
> +	fi->i_acl_mode = mode;
> +	set_inode_flag(fi, FI_ACL_MODE);
> +}
> +
> +static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
> +{
> +	if (is_inode_flag_set(fi, FI_ACL_MODE)) {
> +		clear_inode_flag(fi, FI_ACL_MODE);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * file.c
> + */
> +int f2fs_sync_file(struct file *, loff_t, loff_t, int);
> +void truncate_data_blocks(struct dnode_of_data *);
> +void f2fs_truncate(struct inode *);
> +int f2fs_setattr(struct dentry *, struct iattr *);
> +int truncate_hole(struct inode *, pgoff_t, pgoff_t);
> +long f2fs_ioctl(struct file *, unsigned int, unsigned long);
> +
> +/**
> + * inode.c
> + */
> +void f2fs_set_inode_flags(struct inode *);
> +struct inode *f2fs_iget_nowait(struct super_block *, unsigned long);
> +struct inode *f2fs_iget(struct super_block *, unsigned long);
> +void update_inode(struct inode *, struct page *);
> +int f2fs_write_inode(struct inode *, struct writeback_control *);
> +void f2fs_evict_inode(struct inode *);
> +
> +/**
> + * dir.c
> + */
> +struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
> +							struct page **);
> +struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
> +void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
> +				struct page *, struct inode *);
> +void init_dent_inode(struct dentry *, struct page *);
> +int f2fs_add_link(struct dentry *, struct inode *);
> +void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
> +int f2fs_make_empty(struct inode *, struct inode *);
> +bool f2fs_empty_dir(struct inode *);
> +
> +/**
> + * super.c
> + */
> +int f2fs_sync_fs(struct super_block *, int);
> +
> +/**
> + * hash.c
> + */
> +f2fs_hash_t f2fs_dentry_hash(const char *, int);
> +
> +/**
> + * node.c
> + */
> +struct dnode_of_data;
> +struct node_info;
> +
> +int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
> +void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
> +int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
> +int truncate_inode_blocks(struct inode *, pgoff_t);
> +int remove_inode_page(struct inode *);
> +int new_inode_page(struct inode *, struct dentry *);
> +struct page *new_node_page(struct dnode_of_data *, unsigned int);
> +void ra_node_page(struct f2fs_sb_info *, nid_t);
> +struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
> +struct page *get_node_page_ra(struct page *, int);
> +void sync_inode_page(struct dnode_of_data *);
> +int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
> +bool alloc_nid(struct f2fs_sb_info *, nid_t *);
> +void alloc_nid_done(struct f2fs_sb_info *, nid_t);
> +void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
> +void recover_node_page(struct f2fs_sb_info *, struct page *,
> +		struct f2fs_summary *, struct node_info *, block_t);
> +int recover_inode_page(struct f2fs_sb_info *, struct page *);
> +int restore_node_summary(struct f2fs_sb_info *, unsigned int,
> +				struct f2fs_summary_block *);
> +void flush_nat_entries(struct f2fs_sb_info *);
> +int build_node_manager(struct f2fs_sb_info *);
> +void destroy_node_manager(struct f2fs_sb_info *);
> +int create_node_manager_caches(void);
> +void destroy_node_manager_caches(void);
> +
> +/**
> + * segment.c
> + */
> +void f2fs_balance_fs(struct f2fs_sb_info *);
> +void invalidate_blocks(struct f2fs_sb_info *, block_t);
> +void locate_dirty_segment(struct f2fs_sb_info *, unsigned int);
> +void clear_prefree_segments(struct f2fs_sb_info *);
> +int npages_for_summary_flush(struct f2fs_sb_info *);
> +void allocate_new_segments(struct f2fs_sb_info *);
> +struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
> +struct bio *f2fs_bio_alloc(struct block_device *, sector_t, int, gfp_t);
> +void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync);
> +int write_meta_page(struct f2fs_sb_info *, struct page *,
> +					struct writeback_control *);
> +void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
> +					block_t, block_t *);
> +void write_data_page(struct inode *, struct page *, struct dnode_of_data*,
> +					block_t, block_t *);
> +void rewrite_data_page(struct f2fs_sb_info *, struct page *, block_t);
> +void recover_data_page(struct f2fs_sb_info *, struct page *,
> +				struct f2fs_summary *, block_t, block_t);
> +void rewrite_node_page(struct f2fs_sb_info *, struct page *,
> +				struct f2fs_summary *, block_t, block_t);
> +void write_data_summaries(struct f2fs_sb_info *, block_t);
> +void write_node_summaries(struct f2fs_sb_info *, block_t);
> +int lookup_journal_in_cursum(struct f2fs_summary_block *,
> +					int, unsigned int, int);
> +void flush_sit_entries(struct f2fs_sb_info *);
> +int build_segment_manager(struct f2fs_sb_info *);
> +void reset_victim_segmap(struct f2fs_sb_info *);
> +void destroy_segment_manager(struct f2fs_sb_info *);
> +
> +/**
> + * checkpoint.c
> + */
> +struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
> +struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
> +long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
> +int check_orphan_space(struct f2fs_sb_info *);
> +void add_orphan_inode(struct f2fs_sb_info *, nid_t);
> +void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
> +int recover_orphan_inodes(struct f2fs_sb_info *);
> +int get_valid_checkpoint(struct f2fs_sb_info *);
> +void set_dirty_dir_page(struct inode *, struct page *);
> +void remove_dirty_dir_inode(struct inode *);
> +void sync_dirty_dir_inodes(struct f2fs_sb_info *);
> +void block_operations(struct f2fs_sb_info *);
> +void write_checkpoint(struct f2fs_sb_info *, bool, bool);
> +void init_orphan_info(struct f2fs_sb_info *);
> +int create_checkpoint_caches(void);
> +void destroy_checkpoint_caches(void);
> +
> +/**
> + * data.c
> + */
> +int reserve_new_block(struct dnode_of_data *);
> +void update_extent_cache(block_t, struct dnode_of_data *);
> +struct page *find_data_page(struct inode *, pgoff_t);
> +struct page *get_lock_data_page(struct inode *, pgoff_t);
> +struct page *get_new_data_page(struct inode *, pgoff_t, bool);
> +int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int);
> +int do_write_data_page(struct page *);
> +
> +/**
> + * gc.c
> + */
> +int start_gc_thread(struct f2fs_sb_info *);
> +void stop_gc_thread(struct f2fs_sb_info *);
> +block_t start_bidx_of_node(unsigned int);
> +int f2fs_gc(struct f2fs_sb_info *, int);
> +#ifdef CONFIG_F2FS_STAT_FS
> +void f2fs_update_stat(struct f2fs_sb_info *);
> +void f2fs_update_gc_metric(struct f2fs_sb_info *);
> +int f2fs_stat_init(struct f2fs_sb_info *);
> +void f2fs_stat_exit(struct f2fs_sb_info *);
> +#endif
> +int build_gc_manager(struct f2fs_sb_info *);
> +void destroy_gc_manager(struct f2fs_sb_info *);
> +int create_gc_caches(void);
> +void destroy_gc_caches(void);
> +
> +/**
> + * recovery.c
> + */
> +void recover_fsync_data(struct f2fs_sb_info *);
> +bool space_for_roll_forward(struct f2fs_sb_info *);
> +
> +extern const struct file_operations f2fs_dir_operations;
> +extern const struct file_operations f2fs_file_operations;
> +extern const struct inode_operations f2fs_file_inode_operations;
> +extern const struct address_space_operations f2fs_dblock_aops;
> +extern const struct address_space_operations f2fs_node_aops;
> +extern const struct address_space_operations f2fs_meta_aops;
> +extern const struct inode_operations f2fs_dir_inode_operations;
> +extern const struct inode_operations f2fs_symlink_inode_operations;
> +extern const struct inode_operations f2fs_special_inode_operations;
> +#endif
> diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
> new file mode 100644
> index 0000000..99ac689
> --- /dev/null
> +++ b/fs/f2fs/node.h
> @@ -0,0 +1,330 @@
> +/**
> + * fs/f2fs/node.h
> + *
> + * 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.
> + */
> +#define	START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK)
> +#define	NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK)
> +
> +#define FREE_NID_PAGES 4
> +#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES)
> +
> +#define MAX_RA_NODE		128	/* Max. readahead size for node */
> +#define NM_WOUT_THRESHOLD	(64 * NAT_ENTRY_PER_BLOCK)
> +#define NATVEC_SIZE	64
> +
> +/**
> + * For node information
> + */
> +struct node_info {
> +	nid_t nid;	/* node id */
> +	nid_t ino;	/* inode number of the node's owner */
> +	block_t	blk_addr;	/* block address of the node */
> +	unsigned char version;	/* version of the node */
> +};
> +
> +static inline unsigned char inc_node_version(unsigned char version)
> +{
> +	return ++version;
> +}
> +
> +struct nat_entry {
> +	struct list_head list;	/* for clean or dirty nat list */
> +	bool checkpointed;
> +	struct node_info ni;
> +};
> +
> +#define nat_get_nid(nat)		(nat->ni.nid)
> +#define nat_set_nid(nat, n)		(nat->ni.nid = n)
> +#define nat_get_blkaddr(nat)		(nat->ni.blk_addr)
> +#define nat_set_blkaddr(nat, b)		(nat->ni.blk_addr = b)
> +#define nat_get_ino(nat)		(nat->ni.ino)
> +#define nat_set_ino(nat, i)		(nat->ni.ino = i)
> +#define nat_get_version(nat)		(nat->ni.version)
> +#define nat_set_version(nat, v)		(nat->ni.version = v)
> +#define __set_nat_cache_dirty(nm_i, ne)				\
> +	list_move_tail(&ne->list, &nm_i->dirty_nat_entries);
> +#define __clear_nat_cache_dirty(nm_i, ne)				\
> +	list_move_tail(&ne->list, &nm_i->nat_entries);
> +
> +static inline void node_info_from_raw_nat(struct node_info *ni,
> +						struct f2fs_nat_entry *raw_ne)
> +{
> +	ni->ino = le32_to_cpu(raw_ne->ino);
> +	ni->blk_addr = le32_to_cpu(raw_ne->block_addr);
> +	ni->version = raw_ne->version;
> +}
> +
> +/**
> + * For free nid mangement
> + */
> +enum nid_state {
> +	NID_NEW,
> +	NID_ALLOC
> +};
> +
> +struct free_nid {
> +	nid_t nid;
> +	int state;
> +	struct list_head list;
> +};
> +
> +static inline int next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
> +{
> +	struct f2fs_nm_info *nm_i = NM_I(sbi);
> +	struct free_nid *fnid;
> +
> +	if (nm_i->fcnt <= 0)
> +		return -1;
> +	spin_lock(&nm_i->free_nid_list_lock);
> +	fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list);
> +	*nid = fnid->nid;
> +	spin_unlock(&nm_i->free_nid_list_lock);
> +	return 0;
> +}
> +
> +/**
> + * inline functions
> + */
> +static inline void get_nat_bitmap(struct f2fs_sb_info *sbi, void *addr)
> +{
> +	struct f2fs_nm_info *nm_i = NM_I(sbi);
> +	memcpy(addr, nm_i->nat_bitmap, nm_i->bitmap_size);
> +}
> +
> +static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
> +{
> +	struct f2fs_nm_info *nm_i = NM_I(sbi);
> +	pgoff_t block_off;
> +	pgoff_t block_addr;
> +	int seg_off;
> +
> +	block_off = NAT_BLOCK_OFFSET(start);
> +	seg_off = block_off >> sbi->log_blocks_per_seg;
> +
> +	block_addr = (pgoff_t)(nm_i->nat_blkaddr +
> +		(seg_off << sbi->log_blocks_per_seg << 1) +
> +		(block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
> +
> +	if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
> +		block_addr += sbi->blocks_per_seg;
> +
> +	return block_addr;
> +}
> +
> +static inline pgoff_t next_nat_addr(struct f2fs_sb_info *sbi,
> +						pgoff_t block_addr)
> +{
> +	struct f2fs_nm_info *nm_i = NM_I(sbi);
> +
> +	block_addr -= nm_i->nat_blkaddr;
> +	if ((block_addr >> sbi->log_blocks_per_seg) % 2)
> +		block_addr -= sbi->blocks_per_seg;
> +	else
> +		block_addr += sbi->blocks_per_seg;
> +
> +	return block_addr + nm_i->nat_blkaddr;
> +}
> +
> +static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid)
> +{
> +	unsigned int block_off = NAT_BLOCK_OFFSET(start_nid);
> +
> +	if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
> +		f2fs_clear_bit(block_off, nm_i->nat_bitmap);
> +	else
> +		f2fs_set_bit(block_off, nm_i->nat_bitmap);
> +}
> +
> +static inline void fill_node_footer(struct page *page, nid_t nid,
> +				nid_t ino, unsigned int ofs, bool reset)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	if (reset)
> +		memset(rn, 0, sizeof(*rn));
> +	rn->footer.nid = cpu_to_le32(nid);
> +	rn->footer.ino = cpu_to_le32(ino);
> +	rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT);
> +}
> +
> +static inline void copy_node_footer(struct page *dst, struct page *src)
> +{
> +	void *src_addr = page_address(src);
> +	void *dst_addr = page_address(dst);
> +	struct f2fs_node *src_rn = (struct f2fs_node *)src_addr;
> +	struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr;
> +	memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer));
> +}
> +
> +static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
> +{
> +	struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
> +	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	rn->footer.cp_ver = ckpt->checkpoint_ver;
> +	rn->footer.next_blkaddr = blkaddr;
> +}
> +
> +static inline nid_t ino_of_node(struct page *node_page)
> +{
> +	void *kaddr = page_address(node_page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	return le32_to_cpu(rn->footer.ino);
> +}
> +
> +static inline nid_t nid_of_node(struct page *node_page)
> +{
> +	void *kaddr = page_address(node_page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	return le32_to_cpu(rn->footer.nid);
> +}
> +
> +static inline unsigned int ofs_of_node(struct page *node_page)
> +{
> +	void *kaddr = page_address(node_page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned flag = le32_to_cpu(rn->footer.flag);
> +	return flag >> OFFSET_BIT_SHIFT;
> +}
> +
> +static inline unsigned long long cpver_of_node(struct page *node_page)
> +{
> +	void *kaddr = page_address(node_page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	return le64_to_cpu(rn->footer.cp_ver);
> +}
> +
> +static inline block_t next_blkaddr_of_node(struct page *node_page)
> +{
> +	void *kaddr = page_address(node_page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	return le32_to_cpu(rn->footer.next_blkaddr);
> +}
> +
> +static inline bool IS_DNODE(struct page *node_page)
> +{
> +	unsigned int ofs = ofs_of_node(node_page);
> +	if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
> +			ofs == 5 + 2 * NIDS_PER_BLOCK)
> +		return false;
> +	if (ofs >= 6 + 2 * NIDS_PER_BLOCK) {
> +		ofs -= 6 + 2 * NIDS_PER_BLOCK;
> +		if ((long int)ofs % (NIDS_PER_BLOCK + 1))
> +			return false;
> +	}
> +	return true;
> +}

The IS_DNODE() contains really many hardcoded constants. It is not so easy to understand why it is used such values. I suggest to change hardcoded values on declarations.

> +
> +static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
> +{
> +	struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
> +
> +	wait_on_page_writeback(p);
> +
> +	if (i)
> +		rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
> +	else
> +		rn->in.nid[off] = cpu_to_le32(nid);
> +	set_page_dirty(p);
> +}
> +
> +static inline nid_t get_nid(struct page *p, int off, bool i)
> +{
> +	struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
> +	if (i)
> +		return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]);
> +	return le32_to_cpu(rn->in.nid[off]);
> +}
> +
> +/**
> + * Coldness identification:
> + *  - Mark cold files in f2fs_inode_info
> + *  - Mark cold node blocks in their node footer
> + *  - Mark cold data pages in page cache
> + */
> +static inline int is_cold_file(struct inode *inode)
> +{
> +	return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT;
> +}
> +
> +static inline int is_cold_data(struct page *page)
> +{
> +	return PageChecked(page);
> +}
> +
> +static inline void set_cold_data(struct page *page)
> +{
> +	SetPageChecked(page);
> +}
> +
> +static inline void clear_cold_data(struct page *page)
> +{
> +	ClearPageChecked(page);
> +}
> +
> +static inline int is_cold_node(struct page *page)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +	return flag & (0x1 << COLD_BIT_SHIFT);
> +}
> +
> +static inline unsigned char is_fsync_dnode(struct page *page)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +	return flag & (0x1 << FSYNC_BIT_SHIFT);
> +}
> +
> +static inline unsigned char is_dent_dnode(struct page *page)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +	return flag & (0x1 << DENT_BIT_SHIFT);
> +}
> +
> +static inline void set_cold_node(struct inode *inode, struct page *page)
> +{
> +	struct f2fs_node *rn = (struct f2fs_node *)page_address(page);
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +
> +	if (S_ISDIR(inode->i_mode))
> +		flag &= ~(0x1 << COLD_BIT_SHIFT);
> +	else
> +		flag |= (0x1 << COLD_BIT_SHIFT);
> +	rn->footer.flag = cpu_to_le32(flag);
> +}
> +
> +static inline void set_fsync_mark(struct page *page, int mark)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +	if (mark)
> +		flag |= (0x1 << FSYNC_BIT_SHIFT);
> +	else
> +		flag &= ~(0x1 << FSYNC_BIT_SHIFT);
> +	rn->footer.flag = cpu_to_le32(flag);
> +}
> +
> +static inline void set_dentry_mark(struct page *page, int mark)
> +{
> +	void *kaddr = page_address(page);
> +	struct f2fs_node *rn = (struct f2fs_node *)kaddr;
> +	unsigned int flag = le32_to_cpu(rn->footer.flag);
> +	if (mark)
> +		flag |= (0x1 << DENT_BIT_SHIFT);
> +	else
> +		flag &= ~(0x1 << DENT_BIT_SHIFT);
> +	rn->footer.flag = cpu_to_le32(flag);
> +}
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> new file mode 100644
> index 0000000..cd6268e
> --- /dev/null
> +++ b/fs/f2fs/segment.h
> @@ -0,0 +1,594 @@
> +/**
> + * fs/f2fs/segment.h
> + *
> + * 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.
> + */
> +/* constant macro */
> +#define NULL_SEGNO			((unsigned int)(~0))
> +#define SUM_TYPE_NODE			(1)
> +#define SUM_TYPE_DATA			(0)
> +
> +/* V: Logical segment # in volume, R: Relative segment # in main area */
> +#define GET_L2R_SEGNO(free_i, segno)	(segno - free_i->start_segno)
> +#define GET_R2L_SEGNO(free_i, segno)	(segno + free_i->start_segno)
> +
> +#define IS_DATASEG(t)							\
> +	((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) ||		\
> +	(t == CURSEG_WARM_DATA))
> +
> +#define IS_NODESEG(t)							\
> +	((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) ||		\
> +	(t == CURSEG_WARM_NODE))
> +
> +#define IS_CURSEG(sbi, segno)						\
> +	((segno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
> +	 (segno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
> +	 (segno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) ||	\
> +	 (segno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) ||	\
> +	 (segno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) ||	\
> +	 (segno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
> +
> +#define IS_CURSEC(sbi, secno)						\
> +	((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno /		\
> +	  sbi->segs_per_sec) ||	\
> +	 (secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno /		\
> +	  sbi->segs_per_sec) ||	\
> +	 (secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno /		\
> +	  sbi->segs_per_sec) ||	\
> +	 (secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno /		\
> +	  sbi->segs_per_sec) ||	\
> +	 (secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno /		\
> +	  sbi->segs_per_sec) ||	\
> +	 (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /		\
> +	  sbi->segs_per_sec))	\
> +
> +#define START_BLOCK(sbi, segno)						\
> +	(SM_I(sbi)->seg0_blkaddr +					\
> +	 (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg))
> +#define NEXT_FREE_BLKADDR(sbi, curseg)					\
> +	(START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff)
> +
> +#define MAIN_BASE_BLOCK(sbi)	(SM_I(sbi)->main_blkaddr)
> +
> +#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr)				\
> +	((blk_addr) - SM_I(sbi)->seg0_blkaddr)
> +#define GET_SEGNO_FROM_SEG0(sbi, blk_addr)				\
> +	(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
> +#define GET_SEGNO(sbi, blk_addr)					\
> +	(((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ?		\
> +	NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),			\
> +		GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
> +#define GET_SECNO(sbi, segno)					\
> +	((segno) / sbi->segs_per_sec)
> +#define GET_ZONENO_FROM_SEGNO(sbi, segno)				\
> +	((segno / sbi->segs_per_sec) / sbi->secs_per_zone)
> +
> +#define GET_SUM_BLOCK(sbi, segno)				\
> +	((sbi->sm_info->ssa_blkaddr) + segno)
> +
> +#define GET_SUM_TYPE(footer) ((footer)->entry_type)
> +#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type)
> +
> +#define SIT_ENTRY_OFFSET(sit_i, segno)					\
> +	(segno % sit_i->sents_per_block)
> +#define SIT_BLOCK_OFFSET(sit_i, segno)					\
> +	(segno / SIT_ENTRY_PER_BLOCK)
> +#define	START_SEGNO(sit_i, segno)		\
> +	(SIT_BLOCK_OFFSET(sit_i, segno) * SIT_ENTRY_PER_BLOCK)
> +#define f2fs_bitmap_size(nr)			\
> +	(BITS_TO_LONGS(nr) * sizeof(unsigned long))
> +#define TOTAL_SEGS(sbi)	(SM_I(sbi)->main_segment_count)
> +
> +enum {
> +	LFS = 0,
> +	SSR
> +};

I can't understand what means LFS or SSR. I think that these declarations have to be commented.

> +
> +enum {
> +	ALLOC_RIGHT = 0,
> +	ALLOC_LEFT
> +};
> +
> +#define SET_SSR_TYPE(type)	(((type) + 1) << 16)
> +#define GET_SSR_TYPE(type)	(((type) >> 16) - 1)
> +#define IS_SSR_TYPE(type)	((type) >= (0x1 << 16))

I can't understand what means these calculations with hardcoded constants.

> +#define IS_NEXT_SEG(sbi, curseg, type)					\
> +	(DIRTY_I(sbi)->v_ops->get_victim(sbi, &(curseg)->next_segno,	\
> +				     BG_GC, SET_SSR_TYPE(type)))
> +/**
> + * The MSB 6 bits of f2fs_sit_entry->vblocks has segment type,
> + * and LSB 10 bits has valid blocks.
> + */
> +#define VBLOCKS_MASK		((1 << 10) - 1)
> +
> +#define GET_SIT_VBLOCKS(raw_sit)	\
> +	(le16_to_cpu((raw_sit)->vblocks) & VBLOCKS_MASK)
> +#define GET_SIT_TYPE(raw_sit)		\
> +	((le16_to_cpu((raw_sit)->vblocks) & ~VBLOCKS_MASK) >> 10)
> +
> +struct bio_private {
> +	struct f2fs_sb_info *sbi;
> +	bool is_sync;
> +	void *wait;
> +};
> +
> +enum {
> +	GC_CB = 0,
> +	GC_GREEDY
> +};

I guess that GC_GREEDY means greedy policy of GC. But what does GC_CB means?

> +
> +struct victim_sel_policy {
> +	int alloc_mode;
> +	int gc_mode;
> +	int type;
> +	unsigned long *dirty_segmap;
> +	unsigned int offset;
> +	unsigned int ofs_unit;
> +	unsigned int min_cost;
> +	unsigned int min_segno;
> +};

Need to comment, from my point of view.

> +
> +struct seg_entry {
> +	unsigned short valid_blocks;
> +	unsigned char *cur_valid_map;
> +	unsigned short ckpt_valid_blocks;
> +	unsigned char *ckpt_valid_map;
> +	unsigned char type;
> +	unsigned long long mtime;
> +};

Need to comment, from my point of view.

> +
> +struct sec_entry {
> +	unsigned int valid_blocks;
> +};
> +
> +struct segment_allocation {
> +	void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
> +};

Need to comment, from my point of view.

> +
> +struct sit_info {
> +	const struct segment_allocation *s_ops;
> +
> +	block_t sit_base_addr;
> +	block_t sit_blocks;
> +	block_t written_valid_blocks;		/* total number of valid blocks
> +						   in main area */
> +	char *sit_bitmap;			/* SIT bitmap pointer */
> +	unsigned int bitmap_size;
> +
> +	unsigned int dirty_sentries;		/* # of dirty sentries */
> +	unsigned long *dirty_sentries_bitmap;	/* bitmap for dirty sentries */
> +	unsigned int sents_per_block;		/* number of SIT entries
> +						   per SIT block */
> +	struct mutex sentry_lock;		/* to protect SIT entries */
> +	struct seg_entry *sentries;
> +	struct sec_entry *sec_entries;
> +
> +	unsigned long long elapsed_time;
> +	unsigned long long mounted_time;
> +	unsigned long long min_mtime;
> +	unsigned long long max_mtime;
> +};

Need to comment, from my point of view.

> +
> +struct free_segmap_info {
> +	unsigned int start_segno;
> +	unsigned int free_segments;
> +	unsigned int free_sections;
> +	rwlock_t segmap_lock;		/* free segmap lock */
> +	unsigned long *free_segmap;
> +	unsigned long *free_secmap;
> +};

Need to comment, from my point of view.

> +
> +/* Notice: The order of dirty type is same with CURSEG_XXX in f2fs.h */
> +enum dirty_type {
> +	DIRTY_HOT_DATA,		/* a few valid blocks in a data segment */
> +	DIRTY_WARM_DATA,
> +	DIRTY_COLD_DATA,
> +	DIRTY_HOT_NODE,		/* a few valid blocks in a node segment */
> +	DIRTY_WARM_NODE,
> +	DIRTY_COLD_NODE,
> +	DIRTY,
> +	PRE,			/* no valid blocks in a segment */
> +	NR_DIRTY_TYPE
> +};
> +
> +enum {
> +	BG_GC,
> +	FG_GC
> +};

What do these declarations mean? Need to comment, from my point of view.

> +
> +struct dirty_seglist_info {
> +	const struct victim_selection *v_ops;
> +	struct mutex seglist_lock;
> +	unsigned long *dirty_segmap[NR_DIRTY_TYPE];
> +	int nr_dirty[NR_DIRTY_TYPE];
> +	unsigned long *victim_segmap[2];	/* BG_GC, FG_GC */
> +};

Need to comment, from my point of view.

> +
> +struct victim_selection {
> +	int (*get_victim)(struct f2fs_sb_info *, unsigned int *, int, int);
> +};

Need to comment, from my point of view.

> +
> +struct curseg_info {
> +	struct mutex curseg_mutex;
> +	struct f2fs_summary_block *sum_blk;
> +	unsigned char alloc_type;
> +	unsigned int segno;
> +	unsigned short next_blkoff;
> +	unsigned int zone;
> +	unsigned int next_segno;
> +};

Need to comment, from my point of view.

> +
> +/**
> + * inline functions
> + */
> +static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
> +{
> +	return (struct curseg_info *)(SM_I(sbi)->curseg_array + type);
> +}
> +
> +static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,
> +						unsigned int segno)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	return &sit_i->sentries[segno];
> +}
> +
> +static inline struct sec_entry *get_sec_entry(struct f2fs_sb_info *sbi,
> +						unsigned int segno)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	return &sit_i->sec_entries[GET_SECNO(sbi, segno)];
> +}
> +
> +static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
> +				unsigned int segno, int section)
> +{
> +	if (section > 1)
> +		return get_sec_entry(sbi, segno)->valid_blocks;
> +	else
> +		return get_seg_entry(sbi, segno)->valid_blocks;
> +}

What difference is in two branches in the get_valid_blocks()?

> +
> +static inline void seg_info_from_raw_sit(struct seg_entry *se,
> +					struct f2fs_sit_entry *rs)
> +{
> +	se->valid_blocks = GET_SIT_VBLOCKS(rs);
> +	se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs);
> +	memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
> +	memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
> +	se->type = GET_SIT_TYPE(rs);
> +	se->mtime = le64_to_cpu(rs->mtime);
> +}
> +
> +static inline void seg_info_to_raw_sit(struct seg_entry *se,
> +					struct f2fs_sit_entry *rs)
> +{
> +	unsigned short raw_vblocks = (se->type << 10) | se->valid_blocks;

What does hardcoded 10 value means here?

> +	rs->vblocks = cpu_to_le16(raw_vblocks);
> +	memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
> +	memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
> +	se->ckpt_valid_blocks = se->valid_blocks;
> +	rs->mtime = cpu_to_le64(se->mtime);
> +}
> +
> +static inline unsigned int find_next_inuse(struct free_segmap_info *free_i,
> +		unsigned int max, unsigned int segno)
> +{
> +	unsigned int ret;
> +	read_lock(&free_i->segmap_lock);
> +	ret = find_next_bit(free_i->free_segmap, max, segno);
> +	read_unlock(&free_i->segmap_lock);
> +	return ret;
> +}
> +
> +static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int secno = segno / sbi->segs_per_sec;
> +	unsigned int start_segno = secno * sbi->segs_per_sec;
> +	unsigned int next;
> +
> +	write_lock(&free_i->segmap_lock);
> +	clear_bit(segno, free_i->free_segmap);
> +	free_i->free_segments++;
> +
> +	next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno);
> +	if (next >= start_segno + sbi->segs_per_sec) {
> +		clear_bit(secno, free_i->free_secmap);
> +		free_i->free_sections++;
> +	}
> +	write_unlock(&free_i->segmap_lock);
> +}
> +
> +static inline void __set_inuse(struct f2fs_sb_info *sbi,
> +		unsigned int segno)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int secno = segno / sbi->segs_per_sec;
> +	set_bit(segno, free_i->free_segmap);
> +	free_i->free_segments--;
> +	if (!test_and_set_bit(secno, free_i->free_secmap))
> +		free_i->free_sections--;
> +}
> +
> +static inline void __set_test_and_free(struct f2fs_sb_info *sbi,
> +		unsigned int segno)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int secno = segno / sbi->segs_per_sec;
> +	unsigned int start_segno = secno * sbi->segs_per_sec;
> +	unsigned int next;
> +
> +	write_lock(&free_i->segmap_lock);
> +	if (test_and_clear_bit(segno, free_i->free_segmap)) {
> +		free_i->free_segments++;
> +
> +		next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi),
> +								start_segno);
> +		if (next >= start_segno + sbi->segs_per_sec) {
> +			if (test_and_clear_bit(secno, free_i->free_secmap))
> +				free_i->free_sections++;
> +		}
> +	}
> +	write_unlock(&free_i->segmap_lock);
> +}
> +
> +static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi,
> +		unsigned int segno)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int secno = segno / sbi->segs_per_sec;
> +	write_lock(&free_i->segmap_lock);
> +	if (!test_and_set_bit(segno, free_i->free_segmap)) {
> +		free_i->free_segments--;
> +		if (!test_and_set_bit(secno, free_i->free_secmap))
> +			free_i->free_sections--;
> +	}
> +	write_unlock(&free_i->segmap_lock);
> +}
> +
> +static inline void get_sit_bitmap(struct f2fs_sb_info *sbi,
> +		void *dst_addr)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size);
> +}
> +
> +static inline block_t written_block_count(struct f2fs_sb_info *sbi)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	block_t vblocks;
> +
> +	mutex_lock(&sit_i->sentry_lock);
> +	vblocks = sit_i->written_valid_blocks;
> +	mutex_unlock(&sit_i->sentry_lock);
> +
> +	return vblocks;
> +}
> +
> +static inline unsigned int free_segments(struct f2fs_sb_info *sbi)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int free_segs;
> +
> +	read_lock(&free_i->segmap_lock);
> +	free_segs = free_i->free_segments;
> +	read_unlock(&free_i->segmap_lock);
> +
> +	return free_segs;
> +}
> +
> +static inline int reserved_segments(struct f2fs_sb_info *sbi)
> +{
> +	struct f2fs_gc_info *gc_i = sbi->gc_info;
> +	return gc_i->rsvd_segment_count;
> +}
> +
> +static inline unsigned int free_sections(struct f2fs_sb_info *sbi)
> +{
> +	struct free_segmap_info *free_i = FREE_I(sbi);
> +	unsigned int free_secs;
> +
> +	read_lock(&free_i->segmap_lock);
> +	free_secs = free_i->free_sections;
> +	read_unlock(&free_i->segmap_lock);
> +
> +	return free_secs;
> +}
> +
> +static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi)
> +{
> +	return DIRTY_I(sbi)->nr_dirty[PRE];
> +}
> +
> +static inline unsigned int dirty_segments(struct f2fs_sb_info *sbi)
> +{
> +	return DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_DATA] +
> +		DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_DATA] +
> +		DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_DATA] +
> +		DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_NODE] +
> +		DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_NODE] +
> +		DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_NODE];
> +}
> +
> +static inline int overprovision_segments(struct f2fs_sb_info *sbi)
> +{
> +	struct f2fs_gc_info *gc_i = sbi->gc_info;
> +	return gc_i->overp_segment_count;
> +}
> +
> +static inline int overprovision_sections(struct f2fs_sb_info *sbi)
> +{
> +	struct f2fs_gc_info *gc_i = sbi->gc_info;
> +	return ((unsigned int) gc_i->overp_segment_count) / sbi->segs_per_sec;
> +}
> +
> +static inline int reserved_sections(struct f2fs_sb_info *sbi)
> +{
> +	struct f2fs_gc_info *gc_i = sbi->gc_info;
> +	return ((unsigned int) gc_i->rsvd_segment_count) / sbi->segs_per_sec;
> +}
> +
> +static inline bool need_SSR(struct f2fs_sb_info *sbi)
> +{
> +	return (free_sections(sbi) < overprovision_sections(sbi));
> +}
> +
> +static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi)
> +{
> +	return free_sections(sbi) <= reserved_sections(sbi);
> +}
> +
> +static inline int utilization(struct f2fs_sb_info *sbi)
> +{
> +	return (long int)valid_user_blocks(sbi) * 100 /
> +			(long int)sbi->user_block_count;
> +}
> +
> +/* Disable In-Place-Update by default */
> +#define MIN_IPU_UTIL		100

What does 100 means?

> +static inline bool need_inplace_update(struct inode *inode)
> +{
> +	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
> +	if (S_ISDIR(inode->i_mode))
> +		return false;
> +	if (need_SSR(sbi) && utilization(sbi) > MIN_IPU_UTIL)
> +		return true;
> +	return false;
> +}
> +
> +static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
> +		int type)
> +{
> +	struct curseg_info *curseg = CURSEG_I(sbi, type);
> +	return curseg->segno;
> +}
> +
> +static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi,
> +		int type)
> +{
> +	struct curseg_info *curseg = CURSEG_I(sbi, type);
> +	return curseg->alloc_type;
> +}
> +
> +static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type)
> +{
> +	struct curseg_info *curseg = CURSEG_I(sbi, type);
> +	return curseg->next_blkoff;
> +}
> +
> +static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
> +{
> +	unsigned int end_segno = SM_I(sbi)->segment_count - 1;
> +	BUG_ON(segno > end_segno);
> +}
> +
> +/*
> + * This function is used for only debugging.
> + * NOTE: In future, we have to remove this function.
> + */
> +static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
> +{
> +	struct f2fs_sm_info *sm_info = SM_I(sbi);
> +	block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg;
> +	block_t start_addr = sm_info->seg0_blkaddr;
> +	block_t end_addr = start_addr + total_blks - 1;
> +	BUG_ON(blk_addr < start_addr);
> +	BUG_ON(blk_addr > end_addr);
> +}
> +
> +/**
> + * Summary block is always treated as invalid block
> + */
> +static inline void check_block_count(struct f2fs_sb_info *sbi,
> +		int segno, struct f2fs_sit_entry *raw_sit)
> +{
> +	struct f2fs_sm_info *sm_info = SM_I(sbi);
> +	unsigned int end_segno = sm_info->segment_count - 1;
> +	int valid_blocks = 0;
> +	int i;
> +
> +	/* check segment usage */
> +	BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg);
> +
> +	/* check boundary of a given segment number */
> +	BUG_ON(segno > end_segno);
> +
> +	/* check bitmap with valid block count */
> +	for (i = 0; i < sbi->blocks_per_seg; i++)
> +		if (f2fs_test_bit(i, raw_sit->valid_map))
> +			valid_blocks++;
> +	BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
> +}
> +
> +static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
> +						unsigned int start)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	unsigned int offset = SIT_BLOCK_OFFSET(sit_i, start);
> +	block_t blk_addr = sit_i->sit_base_addr + offset;
> +
> +	check_seg_range(sbi, start);
> +
> +	/* calculate sit block address */
> +	if (f2fs_test_bit(offset, sit_i->sit_bitmap))
> +		blk_addr += sit_i->sit_blocks;
> +
> +	return blk_addr;
> +}
> +
> +static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi,
> +						pgoff_t block_addr)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	block_addr -= sit_i->sit_base_addr;
> +	if (block_addr < sit_i->sit_blocks)
> +		block_addr += sit_i->sit_blocks;
> +	else
> +		block_addr -= sit_i->sit_blocks;
> +
> +	return block_addr + sit_i->sit_base_addr;
> +}
> +
> +static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start)
> +{
> +	unsigned int block_off = SIT_BLOCK_OFFSET(sit_i, start);
> +
> +	if (f2fs_test_bit(block_off, sit_i->sit_bitmap))
> +		f2fs_clear_bit(block_off, sit_i->sit_bitmap);
> +	else
> +		f2fs_set_bit(block_off, sit_i->sit_bitmap);
> +}
> +
> +static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi)
> +{
> +	struct sit_info *sit_i = SIT_I(sbi);
> +	return sit_i->elapsed_time + CURRENT_TIME_SEC.tv_sec -
> +						sit_i->mounted_time;
> +}
> +
> +static inline void set_summary(struct f2fs_summary *sum, nid_t nid,
> +			unsigned int ofs_in_node, unsigned char version)
> +{
> +	sum->nid = cpu_to_le32(nid);
> +	sum->ofs_in_node = cpu_to_le16(ofs_in_node);
> +	sum->version = version;
> +}
> +
> +static inline block_t start_sum_block(struct f2fs_sb_info *sbi)
> +{
> +	return __start_cp_addr(sbi) +
> +		le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
> +}
> +
> +static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
> +{
> +	return __start_cp_addr(sbi) +
> +		le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count)
> +				- (base + 1) + type;
> +}
> -- 
> 1.7.9.5
> 
> 
> 
> 
> ---
> Jaegeuk Kim
> Samsung
> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

With the best regards,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ