• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 void 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 
71 	ASSERT(dn->node_blk);
72 	memset(block, 0, BLOCK_SZ);
73 
74 	get_node_info(sbi, dn->nid, &ni);
75 	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
76 	reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
77 
78 	if (blkaddr == NULL_ADDR)
79 		inc_inode_blocks(dn);
80 	else if (blkaddr == NEW_ADDR)
81 		dn->idirty = 1;
82 	set_data_blkaddr(dn);
83 }
84 
f2fs_read(struct f2fs_sb_info * sbi,nid_t ino,u8 * buffer,u64 count,pgoff_t offset)85 u64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
86 					u64 count, pgoff_t offset)
87 {
88 	struct dnode_of_data dn;
89 	struct node_info ni;
90 	struct f2fs_node *inode;
91 	char *blk_buffer;
92 	u64 filesize;
93 	u64 off_in_blk;
94 	u64 len_in_blk;
95 	u64 read_count;
96 	u64 remained_blkentries;
97 	block_t blkaddr;
98 	void *index_node = NULL;
99 
100 	memset(&dn, 0, sizeof(dn));
101 
102 	/* Memory allocation for block buffer and inode. */
103 	blk_buffer = calloc(BLOCK_SZ, 2);
104 	ASSERT(blk_buffer);
105 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
106 
107 	/* Read inode */
108 	get_node_info(sbi, ino, &ni);
109 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
110 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
111 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
112 
113 	/* Adjust count with file length. */
114 	filesize = le64_to_cpu(inode->i.i_size);
115 	if (offset > filesize)
116 		count = 0;
117 	else if (count + offset > filesize)
118 		count = filesize - offset;
119 
120 	/* Main loop for file blocks */
121 	read_count = remained_blkentries = 0;
122 	while (count > 0) {
123 		if (remained_blkentries == 0) {
124 			set_new_dnode(&dn, inode, NULL, ino);
125 			get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
126 					LOOKUP_NODE);
127 			if (index_node)
128 				free(index_node);
129 			index_node = (dn.node_blk == dn.inode_blk) ?
130 							NULL : dn.node_blk;
131 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
132 		}
133 		ASSERT(remained_blkentries > 0);
134 
135 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
136 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR)
137 			break;
138 
139 		off_in_blk = offset % BLOCK_SZ;
140 		len_in_blk = BLOCK_SZ - off_in_blk;
141 		if (len_in_blk > count)
142 			len_in_blk = count;
143 
144 		/* Read data from single block. */
145 		if (len_in_blk < BLOCK_SZ) {
146 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
147 			memcpy(buffer, blk_buffer + off_in_blk, len_in_blk);
148 		} else {
149 			/* Direct read */
150 			ASSERT(dev_read_block(buffer, blkaddr) >= 0);
151 		}
152 
153 		offset += len_in_blk;
154 		count -= len_in_blk;
155 		buffer += len_in_blk;
156 		read_count += len_in_blk;
157 
158 		dn.ofs_in_node++;
159 		remained_blkentries--;
160 	}
161 	if (index_node)
162 		free(index_node);
163 	free(blk_buffer);
164 
165 	return read_count;
166 }
167 
f2fs_write(struct f2fs_sb_info * sbi,nid_t ino,u8 * buffer,u64 count,pgoff_t offset)168 u64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
169 					u64 count, pgoff_t offset)
170 {
171 	struct dnode_of_data dn;
172 	struct node_info ni;
173 	struct f2fs_node *inode;
174 	char *blk_buffer;
175 	u64 off_in_blk;
176 	u64 len_in_blk;
177 	u64 written_count;
178 	u64 remained_blkentries;
179 	block_t blkaddr;
180 	void* index_node = NULL;
181 	int idirty = 0;
182 
183 	/* Memory allocation for block buffer and inode. */
184 	blk_buffer = calloc(BLOCK_SZ, 2);
185 	ASSERT(blk_buffer);
186 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
187 
188 	/* Read inode */
189 	get_node_info(sbi, ino, &ni);
190 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
191 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
192 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
193 
194 	/* Main loop for file blocks */
195 	written_count = remained_blkentries = 0;
196 	while (count > 0) {
197 		if (remained_blkentries == 0) {
198 			set_new_dnode(&dn, inode, NULL, ino);
199 			get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
200 					ALLOC_NODE);
201 			idirty |= dn.idirty;
202 			if (index_node)
203 				free(index_node);
204 			index_node = (dn.node_blk == dn.inode_blk) ?
205 							NULL : dn.node_blk;
206 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
207 		}
208 		ASSERT(remained_blkentries > 0);
209 
210 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
211 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
212 			new_data_block(sbi, blk_buffer, &dn, CURSEG_WARM_DATA);
213 			blkaddr = dn.data_blkaddr;
214 		}
215 
216 		off_in_blk = offset % BLOCK_SZ;
217 		len_in_blk = BLOCK_SZ - off_in_blk;
218 		if (len_in_blk > count)
219 			len_in_blk = count;
220 
221 		/* Write data to single block. */
222 		if (len_in_blk < BLOCK_SZ) {
223 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
224 			memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
225 			ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
226 		} else {
227 			/* Direct write */
228 			ASSERT(dev_write_block(buffer, blkaddr) >= 0);
229 		}
230 
231 		offset += len_in_blk;
232 		count -= len_in_blk;
233 		buffer += len_in_blk;
234 		written_count += len_in_blk;
235 
236 		dn.ofs_in_node++;
237 		if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
238 			ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr) >= 0);
239 	}
240 	if (offset > le64_to_cpu(inode->i.i_size)) {
241 		inode->i.i_size = cpu_to_le64(offset);
242 		idirty = 1;
243 	}
244 	if (idirty) {
245 		ASSERT(inode == dn.inode_blk);
246 		write_inode(ni.blk_addr, inode);
247 	}
248 	if (index_node)
249 		free(index_node);
250 	free(blk_buffer);
251 
252 	return written_count;
253 }
254 
255 /* This function updates only inode->i.i_size */
f2fs_filesize_update(struct f2fs_sb_info * sbi,nid_t ino,u64 filesize)256 void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)
257 {
258 	struct node_info ni;
259 	struct f2fs_node *inode;
260 
261 	inode = calloc(BLOCK_SZ, 1);
262 	ASSERT(inode);
263 	get_node_info(sbi, ino, &ni);
264 
265 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
266 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
267 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
268 
269 	inode->i.i_size = cpu_to_le64(filesize);
270 
271 	write_inode(ni.blk_addr, inode);
272 	free(inode);
273 }
274 
f2fs_build_file(struct f2fs_sb_info * sbi,struct dentry * de)275 int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
276 {
277 	int fd, n;
278 	pgoff_t off = 0;
279 	u8 buffer[BLOCK_SZ];
280 
281 	if (de->ino == 0)
282 		return -1;
283 
284 	fd = open(de->full_path, O_RDONLY);
285 	if (fd < 0) {
286 		MSG(0, "Skip: Fail to open %s\n", de->full_path);
287 		return -1;
288 	}
289 
290 	/* inline_data support */
291 	if (de->size <= DEF_MAX_INLINE_DATA) {
292 		struct node_info ni;
293 		struct f2fs_node *node_blk;
294 		int ret;
295 
296 		get_node_info(sbi, de->ino, &ni);
297 
298 		node_blk = calloc(BLOCK_SZ, 1);
299 		ASSERT(node_blk);
300 
301 		ret = dev_read_block(node_blk, ni.blk_addr);
302 		ASSERT(ret >= 0);
303 
304 		node_blk->i.i_inline |= F2FS_INLINE_DATA;
305 		node_blk->i.i_inline |= F2FS_DATA_EXIST;
306 
307 		if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
308 			node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
309 			node_blk->i.i_extra_isize =
310 				cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
311 		}
312 		n = read(fd, buffer, BLOCK_SZ);
313 		ASSERT((unsigned long)n == de->size);
314 		memcpy(inline_data_addr(node_blk), buffer, de->size);
315 		node_blk->i.i_size = cpu_to_le64(de->size);
316 		write_inode(ni.blk_addr, node_blk);
317 		free(node_blk);
318 	} else {
319 		while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
320 			f2fs_write(sbi, de->ino, buffer, n, off);
321 			off += n;
322 		}
323 	}
324 
325 	close(fd);
326 	if (n < 0)
327 		return -1;
328 
329 	update_free_segments(sbi);
330 
331 	MSG(1, "Info: Create %s -> %s\n"
332 		"  -- ino=%x, type=%x, mode=%x, uid=%x, "
333 		"gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
334 		de->full_path, de->path,
335 		de->ino, de->file_type, de->mode,
336 		de->uid, de->gid, de->capabilities, de->size, de->pino);
337 	return 0;
338 }
339