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