1 /** 2 * node.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 f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid, int inode) 20 { 21 struct f2fs_nm_info *nm_i = NM_I(sbi); 22 struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 23 nid_t i, inode_cnt, node_cnt; 24 25 for (i = 0; i < nm_i->max_nid; i++) 26 if(f2fs_test_bit(i, nm_i->nid_bitmap) == 0) 27 break; 28 29 ASSERT(i < nm_i->max_nid); 30 f2fs_set_bit(i, nm_i->nid_bitmap); 31 *nid = i; 32 33 inode_cnt = get_cp(valid_inode_count); 34 node_cnt = get_cp(valid_node_count); 35 if (inode) 36 set_cp(valid_inode_count, inode_cnt + 1); 37 set_cp(valid_node_count, node_cnt + 1); 38 } 39 40 void set_data_blkaddr(struct dnode_of_data *dn) 41 { 42 __le32 *addr_array; 43 struct f2fs_node *node_blk = dn->node_blk; 44 unsigned int ofs_in_node = dn->ofs_in_node; 45 46 addr_array = blkaddr_in_node(node_blk); 47 addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr); 48 if (dn->node_blk != dn->inode_blk) 49 dn->ndirty = 1; 50 else 51 dn->idirty = 1; 52 } 53 54 /* 55 * In this function, we get a new node blk, and write back 56 * node_blk would be sloadd in RAM, linked by dn->node_blk 57 */ 58 block_t new_node_block(struct f2fs_sb_info *sbi, 59 struct dnode_of_data *dn, unsigned int ofs) 60 { 61 struct f2fs_node *f2fs_inode; 62 struct f2fs_node *node_blk; 63 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 64 struct f2fs_summary sum; 65 struct node_info ni; 66 block_t blkaddr; 67 int type; 68 69 f2fs_inode = dn->inode_blk; 70 71 node_blk = calloc(BLOCK_SZ, 1); 72 ASSERT(node_blk); 73 74 node_blk->footer.nid = cpu_to_le32(dn->nid); 75 node_blk->footer.ino = f2fs_inode->footer.ino; 76 node_blk->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); 77 node_blk->footer.cp_ver = ckpt->checkpoint_ver; 78 79 type = CURSEG_COLD_NODE; 80 if (IS_DNODE(node_blk)) { 81 if (S_ISDIR(le16_to_cpu(f2fs_inode->i.i_mode))) 82 type = CURSEG_HOT_NODE; 83 else 84 type = CURSEG_WARM_NODE; 85 } 86 87 get_node_info(sbi, dn->nid, &ni); 88 set_summary(&sum, dn->nid, 0, ni.version); 89 reserve_new_block(sbi, &blkaddr, &sum, type); 90 91 /* update nat info */ 92 update_nat_blkaddr(sbi, le32_to_cpu(f2fs_inode->footer.ino), 93 dn->nid, blkaddr); 94 95 dn->node_blk = node_blk; 96 inc_inode_blocks(dn); 97 return blkaddr; 98 } 99 100 /* 101 * get_node_path - Get the index path of pgoff_t block 102 * @offset: offset in the current index node block. 103 * @noffset: NO. of the index block within a file. 104 * return: depth of the index path. 105 * 106 * By default, it sets inline_xattr and inline_data 107 */ 108 static int get_node_path(unsigned long block, 109 int offset[4], unsigned int noffset[4]) 110 { 111 const long direct_index = DEF_ADDRS_PER_INODE_INLINE_XATTR; 112 const long direct_blks = ADDRS_PER_BLOCK; 113 const long dptrs_per_blk = NIDS_PER_BLOCK; 114 const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; 115 const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK; 116 int n = 0; 117 int level = 0; 118 119 noffset[0] = 0; 120 if (block < direct_index) { 121 offset[n] = block; 122 goto got; 123 } 124 125 block -= direct_index; 126 if (block < direct_blks) { 127 offset[n++] = NODE_DIR1_BLOCK; 128 noffset[n]= 1; 129 offset[n] = block; 130 level = 1; 131 goto got; 132 } 133 block -= direct_blks; 134 if (block < direct_blks) { 135 offset[n++] = NODE_DIR2_BLOCK; 136 noffset[n] = 2; 137 offset[n] = block; 138 level = 1; 139 goto got; 140 } 141 block -= direct_blks; 142 if (block < indirect_blks) { 143 offset[n++] = NODE_IND1_BLOCK; 144 noffset[n] = 3; 145 offset[n++] = block / direct_blks; 146 noffset[n] = 4 + offset[n - 1]; 147 offset[n] = block % direct_blks; 148 level = 2; 149 goto got; 150 } 151 block -= indirect_blks; 152 if (block < indirect_blks) { 153 offset[n++] = NODE_IND2_BLOCK; 154 noffset[n] = 4 + dptrs_per_blk; 155 offset[n++] = block / direct_blks; 156 noffset[n] = 5 + dptrs_per_blk + offset[n - 1]; 157 offset[n] = block % direct_blks; 158 level = 2; 159 goto got; 160 } 161 block -= indirect_blks; 162 if (block < dindirect_blks) { 163 offset[n++] = NODE_DIND_BLOCK; 164 noffset[n] = 5 + (dptrs_per_blk * 2); 165 offset[n++] = block / indirect_blks; 166 noffset[n] = 6 + (dptrs_per_blk * 2) + 167 offset[n - 1] * (dptrs_per_blk + 1); 168 offset[n++] = (block / direct_blks) % dptrs_per_blk; 169 noffset[n] = 7 + (dptrs_per_blk * 2) + 170 offset[n - 2] * (dptrs_per_blk + 1) + 171 offset[n - 1]; 172 offset[n] = block % direct_blks; 173 level = 3; 174 goto got; 175 } else { 176 ASSERT(0); 177 } 178 got: 179 return level; 180 } 181 182 void get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, 183 pgoff_t index, int mode) 184 { 185 int offset[4]; 186 unsigned int noffset[4]; 187 struct f2fs_node *parent = NULL; 188 nid_t nids[4]; 189 block_t nblk[4]; 190 struct node_info ni; 191 int level, i; 192 int ret; 193 194 level = get_node_path(index, offset, noffset); 195 196 nids[0] = dn->nid; 197 parent = dn->inode_blk; 198 if (level != 0) 199 nids[1] = get_nid(parent, offset[0], 1); 200 else 201 dn->node_blk = dn->inode_blk; 202 203 get_node_info(sbi, nids[0], &ni); 204 nblk[0] = ni.blk_addr; 205 206 for (i = 1; i <= level; i++) { 207 if (!nids[i] && mode == ALLOC_NODE) { 208 f2fs_alloc_nid(sbi, &nids[i], 0); 209 210 dn->nid = nids[i]; 211 212 /* Function new_node_blk get a new f2fs_node blk and update*/ 213 /* We should make sure that dn->node_blk == NULL*/ 214 nblk[i] = new_node_block(sbi, dn, noffset[i]); 215 ASSERT(nblk[i]); 216 217 set_nid(parent, offset[i - 1], nids[i], i == 1); 218 } else { 219 /* If Sparse file no read API, */ 220 struct node_info ni; 221 222 get_node_info(sbi, nids[i], &ni); 223 dn->node_blk = calloc(BLOCK_SZ, 1); 224 ASSERT(dn->node_blk); 225 226 ret = dev_read_block(dn->node_blk, ni.blk_addr); 227 ASSERT(ret >= 0); 228 229 nblk[i] = ni.blk_addr; 230 } 231 232 if (mode == ALLOC_NODE){ 233 /* Parent node may have changed */ 234 ret = dev_write_block(parent, nblk[i - 1]); 235 ASSERT(ret >= 0); 236 } 237 if (i != 1) 238 free(parent); 239 240 if (i < level) { 241 parent = dn->node_blk; 242 nids[i + 1] = get_nid(parent, offset[i], 0); 243 } 244 } 245 246 dn->nid = nids[level]; 247 dn->ofs_in_node = offset[level]; 248 dn->data_blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node); 249 dn->node_blkaddr = nblk[level]; 250 } 251