1 /**
2  * segment.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 
write_inode(u64 blkaddr,struct f2fs_node * inode)19 static void write_inode(u64 blkaddr, struct f2fs_node *inode)
20 {
21 	if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
22 		inode->i.i_inode_checksum =
23 			cpu_to_le32(f2fs_inode_chksum(inode));
24 	ASSERT(dev_write_block(inode, blkaddr) >= 0);
25 }
26 
reserve_new_block(struct f2fs_sb_info * sbi,block_t * to,struct f2fs_summary * sum,int type)27 void reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
28 			struct f2fs_summary *sum, int type)
29 {
30 	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
31 	struct seg_entry *se;
32 	u64 blkaddr, offset;
33 	u64 old_blkaddr = *to;
34 
35 	blkaddr = SM_I(sbi)->main_blkaddr;
36 
37 	if (find_next_free_block(sbi, &blkaddr, 0, type)) {
38 		ERR_MSG("Not enough space to allocate blocks");
39 		ASSERT(0);
40 	}
41 
42 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
43 	offset = OFFSET_IN_SEG(sbi, blkaddr);
44 	se->type = type;
45 	se->valid_blocks++;
46 	f2fs_set_bit(offset, (char *)se->cur_valid_map);
47 	if (c.func == FSCK) {
48 		f2fs_set_main_bitmap(sbi, blkaddr, type);
49 		f2fs_set_sit_bitmap(sbi, blkaddr);
50 	}
51 
52 	if (old_blkaddr == NULL_ADDR) {
53 		sbi->total_valid_block_count++;
54 		if (c.func == FSCK)
55 			fsck->chk.valid_blk_cnt++;
56 	}
57 	se->dirty = 1;
58 
59 	/* read/write SSA */
60 	*to = (block_t)blkaddr;
61 	update_sum_entry(sbi, *to, sum);
62 }
63 
new_data_block(struct f2fs_sb_info * sbi,void * block,struct dnode_of_data * dn,int type)64 int new_data_block(struct f2fs_sb_info *sbi, void *block,
65 				struct dnode_of_data *dn, int type)
66 {
67 	struct f2fs_summary sum;
68 	struct node_info ni;
69 	unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node);
70 	struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
71 
72 	if (!is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) {
73 		c.alloc_failed = 1;
74 		return -EINVAL;
75 	}
76 
77 	ASSERT(dn->node_blk);
78 	memset(block, 0, BLOCK_SZ);
79 
80 	get_node_info(sbi, dn->nid, &ni);
81 	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
82 	reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
83 
84 	if (blkaddr == NULL_ADDR)
85 		inc_inode_blocks(dn);
86 	else if (blkaddr == NEW_ADDR)
87 		dn->idirty = 1;
88 	set_data_blkaddr(dn);
89 	return 0;
90 }
91 
f2fs_read(struct f2fs_sb_info * sbi,nid_t ino,u8 * buffer,u64 count,pgoff_t offset)92 u64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
93 					u64 count, pgoff_t offset)
94 {
95 	struct dnode_of_data dn;
96 	struct node_info ni;
97 	struct f2fs_node *inode;
98 	char *blk_buffer;
99 	u64 filesize;
100 	u64 off_in_blk;
101 	u64 len_in_blk;
102 	u64 read_count;
103 	u64 remained_blkentries;
104 	block_t blkaddr;
105 	void *index_node = NULL;
106 
107 	memset(&dn, 0, sizeof(dn));
108 
109 	/* Memory allocation for block buffer and inode. */
110 	blk_buffer = calloc(BLOCK_SZ, 2);
111 	ASSERT(blk_buffer);
112 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
113 
114 	/* Read inode */
115 	get_node_info(sbi, ino, &ni);
116 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
117 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
118 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
119 
120 	/* Adjust count with file length. */
121 	filesize = le64_to_cpu(inode->i.i_size);
122 	if (offset > filesize)
123 		count = 0;
124 	else if (count + offset > filesize)
125 		count = filesize - offset;
126 
127 	/* Main loop for file blocks */
128 	read_count = remained_blkentries = 0;
129 	while (count > 0) {
130 		if (remained_blkentries == 0) {
131 			set_new_dnode(&dn, inode, NULL, ino);
132 			get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
133 					LOOKUP_NODE);
134 			if (index_node)
135 				free(index_node);
136 			index_node = (dn.node_blk == dn.inode_blk) ?
137 							NULL : dn.node_blk;
138 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
139 		}
140 		ASSERT(remained_blkentries > 0);
141 
142 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
143 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR)
144 			break;
145 
146 		off_in_blk = offset % BLOCK_SZ;
147 		len_in_blk = BLOCK_SZ - off_in_blk;
148 		if (len_in_blk > count)
149 			len_in_blk = count;
150 
151 		/* Read data from single block. */
152 		if (len_in_blk < BLOCK_SZ) {
153 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
154 			memcpy(buffer, blk_buffer + off_in_blk, len_in_blk);
155 		} else {
156 			/* Direct read */
157 			ASSERT(dev_read_block(buffer, blkaddr) >= 0);
158 		}
159 
160 		offset += len_in_blk;
161 		count -= len_in_blk;
162 		buffer += len_in_blk;
163 		read_count += len_in_blk;
164 
165 		dn.ofs_in_node++;
166 		remained_blkentries--;
167 	}
168 	if (index_node)
169 		free(index_node);
170 	free(blk_buffer);
171 
172 	return read_count;
173 }
174 
f2fs_write(struct f2fs_sb_info * sbi,nid_t ino,u8 * buffer,u64 count,pgoff_t offset)175 u64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
176 					u64 count, pgoff_t offset)
177 {
178 	struct dnode_of_data dn;
179 	struct node_info ni;
180 	struct f2fs_node *inode;
181 	char *blk_buffer;
182 	u64 off_in_blk;
183 	u64 len_in_blk;
184 	u64 written_count;
185 	u64 remained_blkentries;
186 	block_t blkaddr;
187 	void* index_node = NULL;
188 	int idirty = 0;
189 	int err;
190 
191 	/* Memory allocation for block buffer and inode. */
192 	blk_buffer = calloc(BLOCK_SZ, 2);
193 	ASSERT(blk_buffer);
194 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
195 
196 	/* Read inode */
197 	get_node_info(sbi, ino, &ni);
198 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
199 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
200 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
201 
202 	/* Main loop for file blocks */
203 	written_count = remained_blkentries = 0;
204 	while (count > 0) {
205 		if (remained_blkentries == 0) {
206 			set_new_dnode(&dn, inode, NULL, ino);
207 			err = get_dnode_of_data(sbi, &dn,
208 					F2FS_BYTES_TO_BLK(offset), ALLOC_NODE);
209 			if (err)
210 				break;
211 			idirty |= dn.idirty;
212 			if (index_node)
213 				free(index_node);
214 			index_node = (dn.node_blk == dn.inode_blk) ?
215 							NULL : dn.node_blk;
216 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
217 		}
218 		ASSERT(remained_blkentries > 0);
219 
220 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
221 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
222 			err = new_data_block(sbi, blk_buffer,
223 						&dn, CURSEG_WARM_DATA);
224 			if (err)
225 				break;
226 			blkaddr = dn.data_blkaddr;
227 		}
228 
229 		off_in_blk = offset % BLOCK_SZ;
230 		len_in_blk = BLOCK_SZ - off_in_blk;
231 		if (len_in_blk > count)
232 			len_in_blk = count;
233 
234 		/* Write data to single block. */
235 		if (len_in_blk < BLOCK_SZ) {
236 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
237 			memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
238 			ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
239 		} else {
240 			/* Direct write */
241 			ASSERT(dev_write_block(buffer, blkaddr) >= 0);
242 		}
243 
244 		offset += len_in_blk;
245 		count -= len_in_blk;
246 		buffer += len_in_blk;
247 		written_count += len_in_blk;
248 
249 		dn.ofs_in_node++;
250 		if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
251 			ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr) >= 0);
252 	}
253 	if (offset > le64_to_cpu(inode->i.i_size)) {
254 		inode->i.i_size = cpu_to_le64(offset);
255 		idirty = 1;
256 	}
257 	if (idirty) {
258 		ASSERT(inode == dn.inode_blk);
259 		write_inode(ni.blk_addr, inode);
260 	}
261 	if (index_node)
262 		free(index_node);
263 	free(blk_buffer);
264 
265 	return written_count;
266 }
267 
268 /* This function updates only inode->i.i_size */
f2fs_filesize_update(struct f2fs_sb_info * sbi,nid_t ino,u64 filesize)269 void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)
270 {
271 	struct node_info ni;
272 	struct f2fs_node *inode;
273 
274 	inode = calloc(BLOCK_SZ, 1);
275 	ASSERT(inode);
276 	get_node_info(sbi, ino, &ni);
277 
278 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
279 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
280 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
281 
282 	inode->i.i_size = cpu_to_le64(filesize);
283 
284 	write_inode(ni.blk_addr, inode);
285 	free(inode);
286 }
287 
f2fs_build_file(struct f2fs_sb_info * sbi,struct dentry * de)288 int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
289 {
290 	int fd, n;
291 	pgoff_t off = 0;
292 	u8 buffer[BLOCK_SZ];
293 
294 	if (de->ino == 0)
295 		return -1;
296 
297 	fd = open(de->full_path, O_RDONLY);
298 	if (fd < 0) {
299 		MSG(0, "Skip: Fail to open %s\n", de->full_path);
300 		return -1;
301 	}
302 
303 	/* inline_data support */
304 	if (de->size <= DEF_MAX_INLINE_DATA) {
305 		struct node_info ni;
306 		struct f2fs_node *node_blk;
307 		int ret;
308 
309 		get_node_info(sbi, de->ino, &ni);
310 
311 		node_blk = calloc(BLOCK_SZ, 1);
312 		ASSERT(node_blk);
313 
314 		ret = dev_read_block(node_blk, ni.blk_addr);
315 		ASSERT(ret >= 0);
316 
317 		node_blk->i.i_inline |= F2FS_INLINE_DATA;
318 		node_blk->i.i_inline |= F2FS_DATA_EXIST;
319 
320 		if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
321 			node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
322 			node_blk->i.i_extra_isize =
323 				cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
324 		}
325 		n = read(fd, buffer, BLOCK_SZ);
326 		ASSERT((unsigned long)n == de->size);
327 		memcpy(inline_data_addr(node_blk), buffer, de->size);
328 		node_blk->i.i_size = cpu_to_le64(de->size);
329 		write_inode(ni.blk_addr, node_blk);
330 		free(node_blk);
331 	} else {
332 		while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
333 			f2fs_write(sbi, de->ino, buffer, n, off);
334 			off += n;
335 		}
336 	}
337 
338 	close(fd);
339 	if (n < 0)
340 		return -1;
341 
342 	update_free_segments(sbi);
343 
344 	MSG(1, "Info: Create %s -> %s\n"
345 		"  -- ino=%x, type=%x, mode=%x, uid=%x, "
346 		"gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
347 		de->full_path, de->path,
348 		de->ino, de->file_type, de->mode,
349 		de->uid, de->gid, de->capabilities, de->size, de->pino);
350 	return 0;
351 }
352