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