Home | History | Annotate | Download | only in fsck
      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 int 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 	struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
     71 
     72 	if (!is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) {
     73 		c.alloc_failed = 1;
     74 		return -EINVAL;
     75 	}
     76 
     77 	ASSERT(dn->node_blk);
     78 	memset(block, 0, BLOCK_SZ);
     79 
     80 	get_node_info(sbi, dn->nid, &ni);
     81 	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
     82 	reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
     83 
     84 	if (blkaddr == NULL_ADDR)
     85 		inc_inode_blocks(dn);
     86 	else if (blkaddr == NEW_ADDR)
     87 		dn->idirty = 1;
     88 	set_data_blkaddr(dn);
     89 	return 0;
     90 }
     91 
     92 u64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
     93 					u64 count, pgoff_t offset)
     94 {
     95 	struct dnode_of_data dn;
     96 	struct node_info ni;
     97 	struct f2fs_node *inode;
     98 	char *blk_buffer;
     99 	u64 filesize;
    100 	u64 off_in_blk;
    101 	u64 len_in_blk;
    102 	u64 read_count;
    103 	u64 remained_blkentries;
    104 	block_t blkaddr;
    105 	void *index_node = NULL;
    106 
    107 	memset(&dn, 0, sizeof(dn));
    108 
    109 	/* Memory allocation for block buffer and inode. */
    110 	blk_buffer = calloc(BLOCK_SZ, 2);
    111 	ASSERT(blk_buffer);
    112 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
    113 
    114 	/* Read inode */
    115 	get_node_info(sbi, ino, &ni);
    116 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
    117 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
    118 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
    119 
    120 	/* Adjust count with file length. */
    121 	filesize = le64_to_cpu(inode->i.i_size);
    122 	if (offset > filesize)
    123 		count = 0;
    124 	else if (count + offset > filesize)
    125 		count = filesize - offset;
    126 
    127 	/* Main loop for file blocks */
    128 	read_count = remained_blkentries = 0;
    129 	while (count > 0) {
    130 		if (remained_blkentries == 0) {
    131 			set_new_dnode(&dn, inode, NULL, ino);
    132 			get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
    133 					LOOKUP_NODE);
    134 			if (index_node)
    135 				free(index_node);
    136 			index_node = (dn.node_blk == dn.inode_blk) ?
    137 							NULL : dn.node_blk;
    138 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
    139 		}
    140 		ASSERT(remained_blkentries > 0);
    141 
    142 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
    143 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR)
    144 			break;
    145 
    146 		off_in_blk = offset % BLOCK_SZ;
    147 		len_in_blk = BLOCK_SZ - off_in_blk;
    148 		if (len_in_blk > count)
    149 			len_in_blk = count;
    150 
    151 		/* Read data from single block. */
    152 		if (len_in_blk < BLOCK_SZ) {
    153 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
    154 			memcpy(buffer, blk_buffer + off_in_blk, len_in_blk);
    155 		} else {
    156 			/* Direct read */
    157 			ASSERT(dev_read_block(buffer, blkaddr) >= 0);
    158 		}
    159 
    160 		offset += len_in_blk;
    161 		count -= len_in_blk;
    162 		buffer += len_in_blk;
    163 		read_count += len_in_blk;
    164 
    165 		dn.ofs_in_node++;
    166 		remained_blkentries--;
    167 	}
    168 	if (index_node)
    169 		free(index_node);
    170 	free(blk_buffer);
    171 
    172 	return read_count;
    173 }
    174 
    175 u64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
    176 					u64 count, pgoff_t offset)
    177 {
    178 	struct dnode_of_data dn;
    179 	struct node_info ni;
    180 	struct f2fs_node *inode;
    181 	char *blk_buffer;
    182 	u64 off_in_blk;
    183 	u64 len_in_blk;
    184 	u64 written_count;
    185 	u64 remained_blkentries;
    186 	block_t blkaddr;
    187 	void* index_node = NULL;
    188 	int idirty = 0;
    189 	int err;
    190 
    191 	/* Memory allocation for block buffer and inode. */
    192 	blk_buffer = calloc(BLOCK_SZ, 2);
    193 	ASSERT(blk_buffer);
    194 	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
    195 
    196 	/* Read inode */
    197 	get_node_info(sbi, ino, &ni);
    198 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
    199 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
    200 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
    201 
    202 	/* Main loop for file blocks */
    203 	written_count = remained_blkentries = 0;
    204 	while (count > 0) {
    205 		if (remained_blkentries == 0) {
    206 			set_new_dnode(&dn, inode, NULL, ino);
    207 			err = get_dnode_of_data(sbi, &dn,
    208 					F2FS_BYTES_TO_BLK(offset), ALLOC_NODE);
    209 			if (err)
    210 				break;
    211 			idirty |= dn.idirty;
    212 			if (index_node)
    213 				free(index_node);
    214 			index_node = (dn.node_blk == dn.inode_blk) ?
    215 							NULL : dn.node_blk;
    216 			remained_blkentries = ADDRS_PER_PAGE(dn.node_blk);
    217 		}
    218 		ASSERT(remained_blkentries > 0);
    219 
    220 		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
    221 		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
    222 			err = new_data_block(sbi, blk_buffer,
    223 						&dn, CURSEG_WARM_DATA);
    224 			if (err)
    225 				break;
    226 			blkaddr = dn.data_blkaddr;
    227 		}
    228 
    229 		off_in_blk = offset % BLOCK_SZ;
    230 		len_in_blk = BLOCK_SZ - off_in_blk;
    231 		if (len_in_blk > count)
    232 			len_in_blk = count;
    233 
    234 		/* Write data to single block. */
    235 		if (len_in_blk < BLOCK_SZ) {
    236 			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
    237 			memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
    238 			ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
    239 		} else {
    240 			/* Direct write */
    241 			ASSERT(dev_write_block(buffer, blkaddr) >= 0);
    242 		}
    243 
    244 		offset += len_in_blk;
    245 		count -= len_in_blk;
    246 		buffer += len_in_blk;
    247 		written_count += len_in_blk;
    248 
    249 		dn.ofs_in_node++;
    250 		if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
    251 			ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr) >= 0);
    252 	}
    253 	if (offset > le64_to_cpu(inode->i.i_size)) {
    254 		inode->i.i_size = cpu_to_le64(offset);
    255 		idirty = 1;
    256 	}
    257 	if (idirty) {
    258 		ASSERT(inode == dn.inode_blk);
    259 		write_inode(ni.blk_addr, inode);
    260 	}
    261 	if (index_node)
    262 		free(index_node);
    263 	free(blk_buffer);
    264 
    265 	return written_count;
    266 }
    267 
    268 /* This function updates only inode->i.i_size */
    269 void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)
    270 {
    271 	struct node_info ni;
    272 	struct f2fs_node *inode;
    273 
    274 	inode = calloc(BLOCK_SZ, 1);
    275 	ASSERT(inode);
    276 	get_node_info(sbi, ino, &ni);
    277 
    278 	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
    279 	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
    280 	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
    281 
    282 	inode->i.i_size = cpu_to_le64(filesize);
    283 
    284 	write_inode(ni.blk_addr, inode);
    285 	free(inode);
    286 }
    287 
    288 int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
    289 {
    290 	int fd, n;
    291 	pgoff_t off = 0;
    292 	u8 buffer[BLOCK_SZ];
    293 
    294 	if (de->ino == 0)
    295 		return -1;
    296 
    297 	fd = open(de->full_path, O_RDONLY);
    298 	if (fd < 0) {
    299 		MSG(0, "Skip: Fail to open %s\n", de->full_path);
    300 		return -1;
    301 	}
    302 
    303 	/* inline_data support */
    304 	if (de->size <= DEF_MAX_INLINE_DATA) {
    305 		struct node_info ni;
    306 		struct f2fs_node *node_blk;
    307 		int ret;
    308 
    309 		get_node_info(sbi, de->ino, &ni);
    310 
    311 		node_blk = calloc(BLOCK_SZ, 1);
    312 		ASSERT(node_blk);
    313 
    314 		ret = dev_read_block(node_blk, ni.blk_addr);
    315 		ASSERT(ret >= 0);
    316 
    317 		node_blk->i.i_inline |= F2FS_INLINE_DATA;
    318 		node_blk->i.i_inline |= F2FS_DATA_EXIST;
    319 
    320 		if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
    321 			node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
    322 			node_blk->i.i_extra_isize =
    323 				cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
    324 		}
    325 		n = read(fd, buffer, BLOCK_SZ);
    326 		ASSERT((unsigned long)n == de->size);
    327 		memcpy(inline_data_addr(node_blk), buffer, de->size);
    328 		node_blk->i.i_size = cpu_to_le64(de->size);
    329 		write_inode(ni.blk_addr, node_blk);
    330 		free(node_blk);
    331 	} else {
    332 		while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
    333 			f2fs_write(sbi, de->ino, buffer, n, off);
    334 			off += n;
    335 		}
    336 	}
    337 
    338 	close(fd);
    339 	if (n < 0)
    340 		return -1;
    341 
    342 	update_free_segments(sbi);
    343 
    344 	MSG(1, "Info: Create %s -> %s\n"
    345 		"  -- ino=%x, type=%x, mode=%x, uid=%x, "
    346 		"gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
    347 		de->full_path, de->path,
    348 		de->ino, de->file_type, de->mode,
    349 		de->uid, de->gid, de->capabilities, de->size, de->pino);
    350 	return 0;
    351 }
    352