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 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 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 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 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