• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
f2fs_alloc_nid(struct f2fs_sb_info * sbi,nid_t * nid,int inode)19 void 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 
set_data_blkaddr(struct dnode_of_data * dn)40 void 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  */
new_node_block(struct f2fs_sb_info * sbi,struct dnode_of_data * dn,unsigned int ofs)58 block_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 = NULL_ADDR;
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  */
get_node_path(struct f2fs_node * node,long block,int offset[4],unsigned int noffset[4])108 static int get_node_path(struct f2fs_node *node, long block,
109 				int offset[4], unsigned int noffset[4])
110 {
111 	const long direct_index = ADDRS_PER_INODE(&node->i);
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 	}
178 got:
179 	return level;
180 }
181 
get_dnode_of_data(struct f2fs_sb_info * sbi,struct dnode_of_data * dn,pgoff_t index,int mode)182 void 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(dn->inode_blk, 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