1 /**
2  * node.h
3  *
4  * Many parts of codes are copied from Linux kernel/fs/f2fs.
5  *
6  * Copyright (C) 2015 Huawei Ltd.
7  * Witten by:
8  *   Hou Pengyang <houpengyang@huawei.com>
9  *   Liu Shuoran <liushuoran@huawei.com>
10  *   Jaegeuk Kim <jaegeuk@kernel.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  */
16 #ifndef _NODE_H_
17 #define _NODE_H_
18 
19 #include "fsck.h"
20 
21 static inline int IS_INODE(struct f2fs_node *node)
22 {
23 	return ((node)->footer.nid == (node)->footer.ino);
24 }
25 
26 static inline unsigned int ADDRS_PER_PAGE(struct f2fs_sb_info *sbi,
27 		struct f2fs_node *node_blk, struct f2fs_node *inode_blk)
28 {
29 	nid_t ino = le32_to_cpu(node_blk->footer.ino);
30 	unsigned int nblocks;
31 
32 	if (IS_INODE(node_blk))
33 		return ADDRS_PER_INODE(&node_blk->i);
34 
35 	if (!inode_blk) {
36 		struct node_info ni;
37 
38 		inode_blk = calloc(BLOCK_SZ, 2);
39 		ASSERT(inode_blk);
40 
41 		get_node_info(sbi, ino, &ni);
42 		ASSERT(dev_read_block(inode_blk, ni.blk_addr) >= 0);
43 		nblocks = ADDRS_PER_BLOCK(&inode_blk->i);
44 		free(inode_blk);
45 	} else {
46 		nblocks = ADDRS_PER_BLOCK(&inode_blk->i);
47 	}
48 	return nblocks;
49 }
50 
51 static inline __le32 *blkaddr_in_inode(struct f2fs_node *node)
52 {
53 	return node->i.i_addr + get_extra_isize(node);
54 }
55 
56 static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
57 {
58 	return IS_INODE(node) ? blkaddr_in_inode(node) : node->dn.addr;
59 }
60 
61 static inline block_t datablock_addr(struct f2fs_node *node_page,
62 					unsigned int offset)
63 {
64 	__le32 *addr_array;
65 
66 	ASSERT(node_page);
67 	addr_array = blkaddr_in_node(node_page);
68 	return le32_to_cpu(addr_array[offset]);
69 }
70 
71 static inline void set_nid(struct f2fs_node * rn, int off, nid_t nid, int i)
72 {
73 	if (i)
74 		rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
75 	else
76 		rn->in.nid[off] = cpu_to_le32(nid);
77 }
78 
79 static inline nid_t get_nid(struct f2fs_node * rn, int off, int i)
80 {
81 	if (i)
82 		return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]);
83 	else
84 		return le32_to_cpu(rn->in.nid[off]);
85 }
86 
87 enum {
88 	ALLOC_NODE,	/* allocate a new node page if needed */
89 	LOOKUP_NODE,	/* lookup up a node without readahead */
90 	LOOKUP_NODE_RA,
91 };
92 
93 static inline void set_new_dnode(struct dnode_of_data *dn,
94 		struct f2fs_node *iblk, struct f2fs_node *nblk, nid_t nid)
95 {
96 	memset(dn, 0, sizeof(*dn));
97 	dn->inode_blk = iblk;
98 	dn->node_blk = nblk;
99 	dn->nid = nid;
100 	dn->idirty = 0;
101 	dn->ndirty = 0;
102 }
103 
104 static inline void inc_inode_blocks(struct dnode_of_data *dn)
105 {
106 	u64 blocks = le64_to_cpu(dn->inode_blk->i.i_blocks);
107 
108 	dn->inode_blk->i.i_blocks = cpu_to_le64(blocks + 1);
109 	dn->idirty = 1;
110 }
111 
112 static inline int IS_DNODE(struct f2fs_node *node_page)
113 {
114 	unsigned int ofs = ofs_of_node(node_page);
115 
116 	if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
117 			ofs == 5 + 2 * NIDS_PER_BLOCK)
118 		return 0;
119 
120 	if (ofs >= 6 + 2 * NIDS_PER_BLOCK) {
121 		ofs -= 6 + 2 * NIDS_PER_BLOCK;
122 		if (!((long int)ofs % (NIDS_PER_BLOCK + 1)))
123 			return 0;
124 	}
125 	return 1;
126 }
127 
128 static inline nid_t ino_of_node(struct f2fs_node *node_blk)
129 {
130 	return le32_to_cpu(node_blk->footer.ino);
131 }
132 
133 static inline __u64 cpver_of_node(struct f2fs_node *node_blk)
134 {
135 	return le64_to_cpu(node_blk->footer.cp_ver);
136 }
137 
138 static inline bool is_recoverable_dnode(struct f2fs_sb_info *sbi,
139 						struct f2fs_node *node_blk)
140 {
141 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
142 	__u64 cp_ver = cur_cp_version(ckpt);
143 
144 	/* Don't care crc part, if fsck.f2fs sets it. */
145 	if (is_set_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG))
146 		return (cp_ver << 32) == (cpver_of_node(node_blk) << 32);
147 
148 	if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG))
149 		cp_ver |= (cur_cp_crc(ckpt) << 32);
150 
151 	return cp_ver == cpver_of_node(node_blk);
152 }
153 
154 static inline block_t next_blkaddr_of_node(struct f2fs_node *node_blk)
155 {
156 	return le32_to_cpu(node_blk->footer.next_blkaddr);
157 }
158 
159 static inline int is_node(struct f2fs_node *node_blk, int type)
160 {
161 	return le32_to_cpu(node_blk->footer.flag) & (1 << type);
162 }
163 
164 #define is_fsync_dnode(node_blk)	is_node(node_blk, FSYNC_BIT_SHIFT)
165 #define is_dent_dnode(node_blk)		is_node(node_blk, DENT_BIT_SHIFT)
166 
167 #endif
168