• 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 
reserve_new_block(struct f2fs_sb_info * sbi,block_t * to,struct f2fs_summary * sum,int type)19 void reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
20 			struct f2fs_summary *sum, int type)
21 {
22 	struct seg_entry *se;
23 	u64 blkaddr;
24 	u64 offset;
25 
26 	blkaddr = SM_I(sbi)->main_blkaddr;
27 
28 	if (find_next_free_block(sbi, &blkaddr, 0, type)) {
29 		ERR_MSG("Not enough space to allocate blocks");
30 		ASSERT(0);
31 	}
32 
33 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
34 	offset = OFFSET_IN_SEG(sbi, blkaddr);
35 	se->type = type;
36 	se->valid_blocks++;
37 	f2fs_set_bit(offset, (char *)se->cur_valid_map);
38 	sbi->total_valid_block_count++;
39 	se->dirty = 1;
40 
41 	/* read/write SSA */
42 	*to = (block_t)blkaddr;
43 	update_sum_entry(sbi, *to, sum);
44 }
45 
new_data_block(struct f2fs_sb_info * sbi,void * block,struct dnode_of_data * dn,int type)46 void new_data_block(struct f2fs_sb_info *sbi, void *block,
47 				struct dnode_of_data *dn, int type)
48 {
49 	struct f2fs_summary sum;
50 	struct node_info ni;
51 
52 	ASSERT(dn->node_blk);
53 	memset(block, 0, BLOCK_SZ);
54 
55 	get_node_info(sbi, dn->nid, &ni);
56 	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
57 	reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
58 
59 	inc_inode_blocks(dn);
60 	set_data_blkaddr(dn);
61 }
62 
f2fs_write_block(struct f2fs_sb_info * sbi,nid_t ino,void * buffer,u64 count,pgoff_t offset)63 static void f2fs_write_block(struct f2fs_sb_info *sbi, nid_t ino, void *buffer,
64 					u64 count, pgoff_t offset)
65 {
66 	u64 start = F2FS_BYTES_TO_BLK(offset);
67 	u64 len = F2FS_BYTES_TO_BLK(count);
68 	u64 end_offset;
69 	u64 off_in_block, len_in_block, len_already;
70 	struct dnode_of_data dn = {0};
71 	void *data_blk;
72 	struct node_info ni;
73 	struct f2fs_node *inode;
74 	int ret = -1;
75 
76 	get_node_info(sbi, ino, &ni);
77 	inode = calloc(BLOCK_SZ, 1);
78 	ASSERT(inode);
79 
80 	ret = dev_read_block(inode, ni.blk_addr);
81 	ASSERT(ret >= 0);
82 
83 	if (S_ISDIR(le16_to_cpu(inode->i.i_mode)) ||
84 			S_ISLNK(le16_to_cpu(inode->i.i_mode)))
85 		ASSERT(0);
86 
87 	off_in_block = offset & ((1 << F2FS_BLKSIZE_BITS) - 1);
88 	len_in_block = (1 << F2FS_BLKSIZE_BITS) - off_in_block;
89 	len_already = 0;
90 
91 	/*
92 	 * When calculate how many blocks this 'count' stride accross,
93 	 * We should take offset in a block in account.
94 	 */
95 	len = F2FS_BYTES_TO_BLK(count + off_in_block
96 			+ ((1 << F2FS_BLKSIZE_BITS) - 1));
97 
98 	data_blk = calloc(BLOCK_SZ, 1);
99 	ASSERT(data_blk);
100 
101 	set_new_dnode(&dn, inode, NULL, ino);
102 
103 	while (len) {
104 		if (dn.node_blk != dn.inode_blk)
105 			free(dn.node_blk);
106 
107 		set_new_dnode(&dn, inode, NULL, ino);
108 		get_dnode_of_data(sbi, &dn, start, ALLOC_NODE);
109 
110 		end_offset = ADDRS_PER_PAGE(dn.node_blk);
111 
112 		while (dn.ofs_in_node < end_offset && len) {
113 			block_t blkaddr;
114 
115 			blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
116 
117 			/* A new page from WARM_DATA */
118 			if (blkaddr == NULL_ADDR)
119 				new_data_block(sbi, data_blk, &dn,
120 							CURSEG_WARM_DATA);
121 
122 			/* Copy data from buffer to file */
123 			ret = dev_read_block(data_blk, dn.data_blkaddr);
124 			ASSERT(ret >= 0);
125 
126 			memcpy(data_blk + off_in_block, buffer, len_in_block);
127 
128 			ret = dev_write_block(data_blk, dn.data_blkaddr);
129 			ASSERT(ret >= 0);
130 
131 			off_in_block = 0;
132 			len_already += len_in_block;
133 			if ((count - len_already) > (1 << F2FS_BLKSIZE_BITS))
134 				len_in_block = 1 << F2FS_BLKSIZE_BITS;
135 			else
136 				len_in_block = count - len_already;
137 			len--;
138 			start++;
139 			dn.ofs_in_node++;
140 		}
141 		/* Update the direct node */
142 		if (dn.ndirty) {
143 			ret = dev_write_block(dn.node_blk, dn.node_blkaddr);
144 			ASSERT(ret >= 0);
145 		}
146 	}
147 
148 	/* Update the inode info */
149 	if (le64_to_cpu(inode->i.i_size) < offset + count) {
150 		inode->i.i_size = cpu_to_le64(offset + count);
151 		dn.idirty = 1;
152 	}
153 
154 	if (dn.idirty) {
155 		ASSERT(inode == dn.inode_blk);
156 		ret = dev_write_block(inode, ni.blk_addr);
157 		ASSERT(ret >= 0);
158 	}
159 
160 	if (dn.node_blk && dn.node_blk != dn.inode_blk)
161 		free(dn.node_blk);
162 	free(data_blk);
163 	free(inode);
164 }
165 
f2fs_build_file(struct f2fs_sb_info * sbi,struct dentry * de)166 int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
167 {
168 	int fd, n;
169 	pgoff_t off = 0;
170 	char buffer[BLOCK_SZ];
171 
172 	if (de->ino == 0)
173 		return -1;
174 
175 	fd = open(de->full_path, O_RDONLY);
176 	if (fd < 0) {
177 		MSG(0, "Skip: Fail to open %s\n", de->full_path);
178 		return -1;
179 	}
180 
181 	/* inline_data support */
182 	if (de->size <= MAX_INLINE_DATA) {
183 		struct node_info ni;
184 		struct f2fs_node *node_blk;
185 		int ret;
186 
187 		get_node_info(sbi, de->ino, &ni);
188 
189 		node_blk = calloc(BLOCK_SZ, 1);
190 		ASSERT(node_blk);
191 
192 		ret = dev_read_block(node_blk, ni.blk_addr);
193 		ASSERT(ret >= 0);
194 
195 		node_blk->i.i_inline |= F2FS_INLINE_DATA;
196 		node_blk->i.i_inline |= F2FS_DATA_EXIST;
197 		n = read(fd, buffer, BLOCK_SZ);
198 		ASSERT(n == de->size);
199 		memcpy(&node_blk->i.i_addr[1], buffer, de->size);
200 
201 		node_blk->i.i_size = cpu_to_le64(de->size);
202 
203 		ret = dev_write_block(node_blk, ni.blk_addr);
204 		ASSERT(ret >= 0);
205 		free(node_blk);
206 	} else {
207 		while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
208 			f2fs_write_block(sbi, de->ino, buffer, n, off);
209 			off += n;
210 		}
211 	}
212 
213 	close(fd);
214 	if (n < 0)
215 		return -1;
216 
217 	update_free_segments(sbi);
218 
219 	MSG(1, "Info: built a file %s, size=%lu\n", de->full_path, de->size);
220 	return 0;
221 }
222