Home | History | Annotate | Download | only in fsck
      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 = NULL_ADDR;
     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(struct f2fs_node *node, long block,
    109 				int offset[4], unsigned int noffset[4])
    110 {
    111 	const long direct_index = ADDRS_PER_INODE(&node->i);
    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(dn->inode_blk, 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