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