1/**
2 * node.c
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#include "fsck.h"
17#include "node.h"
18
19void f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid, int inode)
20{
21	struct f2fs_nm_info *nm_i = NM_I(sbi);
22	struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
23	nid_t i, inode_cnt, node_cnt;
24
25	for (i = 0; i < nm_i->max_nid; i++)
26		if(f2fs_test_bit(i, nm_i->nid_bitmap) == 0)
27			break;
28
29	ASSERT(i < nm_i->max_nid);
30	f2fs_set_bit(i, nm_i->nid_bitmap);
31	*nid = i;
32
33	inode_cnt = get_cp(valid_inode_count);
34	node_cnt = get_cp(valid_node_count);
35	if (inode)
36		set_cp(valid_inode_count, inode_cnt + 1);
37	set_cp(valid_node_count, node_cnt + 1);
38}
39
40void set_data_blkaddr(struct dnode_of_data *dn)
41{
42	__le32 *addr_array;
43	struct f2fs_node *node_blk = dn->node_blk;
44	unsigned int ofs_in_node = dn->ofs_in_node;
45
46	addr_array = blkaddr_in_node(node_blk);
47	addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
48	if (dn->node_blk != dn->inode_blk)
49		dn->ndirty = 1;
50	else
51		dn->idirty = 1;
52}
53
54/*
55 * In this function, we get a new node blk, and write back
56 * node_blk would be sloadd in RAM, linked by dn->node_blk
57 */
58block_t new_node_block(struct f2fs_sb_info *sbi,
59				struct dnode_of_data *dn, unsigned int ofs)
60{
61	struct f2fs_node *f2fs_inode;
62	struct f2fs_node *node_blk;
63	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
64	struct f2fs_summary sum;
65	struct node_info ni;
66	block_t blkaddr;
67	int type;
68
69	f2fs_inode = dn->inode_blk;
70
71	node_blk = calloc(BLOCK_SZ, 1);
72	ASSERT(node_blk);
73
74	node_blk->footer.nid = cpu_to_le32(dn->nid);
75	node_blk->footer.ino = f2fs_inode->footer.ino;
76	node_blk->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT);
77	node_blk->footer.cp_ver = ckpt->checkpoint_ver;
78
79	type = CURSEG_COLD_NODE;
80	if (IS_DNODE(node_blk)) {
81		if (S_ISDIR(le16_to_cpu(f2fs_inode->i.i_mode)))
82			type = CURSEG_HOT_NODE;
83		else
84			type = CURSEG_WARM_NODE;
85	}
86
87	get_node_info(sbi, dn->nid, &ni);
88	set_summary(&sum, dn->nid, 0, ni.version);
89	reserve_new_block(sbi, &blkaddr, &sum, type);
90
91	/* update nat info */
92	update_nat_blkaddr(sbi, le32_to_cpu(f2fs_inode->footer.ino),
93						dn->nid, blkaddr);
94
95	dn->node_blk = node_blk;
96	inc_inode_blocks(dn);
97	return blkaddr;
98}
99
100/*
101 * get_node_path - Get the index path of pgoff_t block
102 * @offset: offset in the current index node block.
103 * @noffset: NO. of the index block within a file.
104 * return: depth of the index path.
105 *
106 * By default, it sets inline_xattr and inline_data
107 */
108static int get_node_path(unsigned long block,
109				int offset[4], unsigned int noffset[4])
110{
111	const long direct_index = DEF_ADDRS_PER_INODE_INLINE_XATTR;
112	const long direct_blks = ADDRS_PER_BLOCK;
113	const long dptrs_per_blk = NIDS_PER_BLOCK;
114	const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
115	const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK;
116	int n = 0;
117	int level = 0;
118
119	noffset[0] = 0;
120	if (block < direct_index) {
121		offset[n] = block;
122		goto got;
123	}
124
125	block -= direct_index;
126	if (block < direct_blks) {
127		offset[n++] = NODE_DIR1_BLOCK;
128		noffset[n]= 1;
129		offset[n] = block;
130		level = 1;
131		goto got;
132	}
133	block -= direct_blks;
134	if (block < direct_blks) {
135		offset[n++] = NODE_DIR2_BLOCK;
136		noffset[n] = 2;
137		offset[n] = block;
138		level = 1;
139		goto got;
140	}
141	block -= direct_blks;
142	if (block < indirect_blks) {
143		offset[n++] = NODE_IND1_BLOCK;
144		noffset[n] = 3;
145		offset[n++] = block / direct_blks;
146		noffset[n] = 4 + offset[n - 1];
147		offset[n] = block % direct_blks;
148		level = 2;
149		goto got;
150	}
151	block -= indirect_blks;
152	if (block < indirect_blks) {
153		offset[n++] = NODE_IND2_BLOCK;
154		noffset[n] = 4 + dptrs_per_blk;
155		offset[n++] = block / direct_blks;
156		noffset[n] = 5 + dptrs_per_blk + offset[n - 1];
157		offset[n] = block % direct_blks;
158		level = 2;
159		goto got;
160	}
161	block -= indirect_blks;
162	if (block < dindirect_blks) {
163		offset[n++] = NODE_DIND_BLOCK;
164		noffset[n] = 5 + (dptrs_per_blk * 2);
165		offset[n++] = block / indirect_blks;
166		noffset[n] = 6 + (dptrs_per_blk * 2) +
167			offset[n - 1] * (dptrs_per_blk + 1);
168		offset[n++] = (block / direct_blks) % dptrs_per_blk;
169		noffset[n] = 7 + (dptrs_per_blk * 2) +
170			offset[n - 2] * (dptrs_per_blk + 1) +
171			offset[n - 1];
172		offset[n] = block % direct_blks;
173		level = 3;
174		goto got;
175	} else {
176		ASSERT(0);
177	}
178got:
179	return level;
180}
181
182void get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
183						pgoff_t index, int mode)
184{
185	int offset[4];
186	unsigned int noffset[4];
187	struct f2fs_node *parent = NULL;
188	nid_t nids[4];
189	block_t nblk[4];
190	struct node_info ni;
191	int level, i;
192	int ret;
193
194	level = get_node_path(index, offset, noffset);
195
196	nids[0] = dn->nid;
197	parent = dn->inode_blk;
198	if (level != 0)
199		nids[1] = get_nid(parent, offset[0], 1);
200	else
201		dn->node_blk = dn->inode_blk;
202
203	get_node_info(sbi, nids[0], &ni);
204	nblk[0] = ni.blk_addr;
205
206	for (i = 1; i <= level; i++) {
207		if (!nids[i] && mode == ALLOC_NODE) {
208			f2fs_alloc_nid(sbi, &nids[i], 0);
209
210			dn->nid = nids[i];
211
212			/* Function new_node_blk get a new f2fs_node blk and update*/
213			/* We should make sure that dn->node_blk == NULL*/
214			nblk[i] = new_node_block(sbi, dn, noffset[i]);
215			ASSERT(nblk[i]);
216
217			set_nid(parent, offset[i - 1], nids[i], i == 1);
218		} else {
219			/* If Sparse file no read API, */
220			struct node_info ni;
221
222			get_node_info(sbi, nids[i], &ni);
223			dn->node_blk = calloc(BLOCK_SZ, 1);
224			ASSERT(dn->node_blk);
225
226			ret = dev_read_block(dn->node_blk, ni.blk_addr);
227			ASSERT(ret >= 0);
228
229			nblk[i] = ni.blk_addr;
230		}
231
232		if (mode == ALLOC_NODE){
233			/* Parent node may have changed */
234			ret = dev_write_block(parent, nblk[i - 1]);
235			ASSERT(ret >= 0);
236		}
237		if (i != 1)
238			free(parent);
239
240		if (i < level) {
241			parent = dn->node_blk;
242			nids[i + 1] = get_nid(parent, offset[i], 0);
243		}
244	}
245
246	dn->nid = nids[level];
247	dn->ofs_in_node = offset[level];
248	dn->data_blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node);
249	dn->node_blkaddr = nblk[level];
250}
251