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