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