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 (at) huawei.com> 9 * Liu Shuoran <liushuoran (at) huawei.com> 10 * Jaegeuk Kim <jaegeuk (at) 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 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 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 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 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 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 */ 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 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