f2fs二三事 block map 1

f2fs_map_blocks函数主要作用是为写入inode的数据分配内存空间(包括node block,data block),四个参数:

1) struct inode * inode: 操作的inode结构

2) struct f2fs_map_blocks * map: 要写入的block相关信息的参数

3) int create: 如果为true, 表示如果内中不存在相应的block, 则创建

4) int flag: map block 场景

f2fs_map_block结构:

struct f2fs_map_blocks {
    block_t m_pblk;
    block_t m_lblk;                     //block起始索引值
    unsigned int m_len;              //最大block个数
    unsigned int m_flags;
    pgoff_t *m_next_pgofs;        /* point next possible non-hole pgofs */
    pgoff_t *m_next_extent;        /* point to next possible extent */
    int m_seg_type;
};

对于create参数为true来说,主要关注m_lblk与m_len两个参数,如果create不为true,会从extent cache里面查找。

static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
						int create, int flag)
{
	unsigned int maxblocks = map->m_len; //map中包含的block总数,一共要map多少个blocks
	struct dnode_of_data dn;
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int mode = create ? ALLOC_NODE : LOOKUP_NODE_RA;//ALLOC_NODE mode如果不存在,直接创建
	pgoff_t pgofs, end_offset;
	int err = 0, ofs = 1;
	struct extent_info ei;
	bool allocated = false;

	map->m_len = 0;//后面每map一个block, m_len会加1
	map->m_flags = 0;

	/* it only supports block size == page size */
	pgofs =	(pgoff_t)map->m_lblk;//map的第一个block index,最小的block

	if (f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
		map->m_pblk = ei.blk + pgofs - ei.fofs;
		map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
		map->m_flags = F2FS_MAP_MAPPED;
		goto out;
	}

        //如果create为true, 表示需要lock住f2fs相关操作
	if (create)
		f2fs_lock_op(F2FS_I_SB(inode));

	/* When reading holes, we need its node page */
	set_new_dnode(&dn, inode, NULL, NULL, 0);
        /*
         * 得到pgofs起始的map block对应的直接node block,它得到的是pgofs(data block index)对 
         * 应的data block的直 
         * 属的(上一层的)direct node_block, 返回的参数包含其在上一层的node page对应的偏移
	 */
	err = get_dnode_of_data(&dn, pgofs, mode);
	
	if (err) {
		if (err == -ENOENT)
			err = 0;
		goto unlock_out;
	}


    /*
     * 若create为true,如果得到的direct node block,在其ofs_in_node偏移处的data block地址为空,则新申请一个data block作为map block
    */
	if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) {
		if (create) {
			if (unlikely(f2fs_cp_error(sbi))) {
				err = -EIO;
				goto put_out;
			}
			err = __allocate_data_block(&dn);//新申请一个data block
			if (err)
				goto put_out;
			allocated = true;
			map->m_flags = F2FS_MAP_NEW;
		} else {
			if (flag != F2FS_GET_BLOCK_FIEMAP ||
						dn.data_blkaddr != NEW_ADDR) {
				if (flag == F2FS_GET_BLOCK_BMAP)
					err = -ENOENT;
				goto put_out;
			}

			/*
			 * preallocated unwritten block should be mapped
			 * for fiemap.
			 */
			if (dn.data_blkaddr == NEW_ADDR)
				map->m_flags = F2FS_MAP_UNWRITTEN;
		}
	}

	map->m_flags |= F2FS_MAP_MAPPED;
	map->m_pblk = dn.data_blkaddr;//刚刚申请的block address
	map->m_len = 1;//已Map block length

    //node_page能表示的最大地址个数, 如果inode,则end_offset为873,表示最多873个data block地 
    //址,是inode去掉meta信息剩余的能表示地址的空间,如果是direct node,则为1018,表示最多能指向
    //1018个data block
	end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
	dn.ofs_in_node++; //在此node_page 中的下一个block address的offset
	pgofs++;//需要map的下一个地址

get_next://下一个block
	if (dn.ofs_in_node >= end_offset) {//如果node block的下一个地址已经超过了end_offset, 
                                       //node_block中的最大地址,即此node_block的地址已用 
                                       //完,则需要重新查找分配node data block
		if (allocated)
			sync_inode_page(&dn);
		allocated = false;
		f2fs_put_dnode(&dn);

		set_new_dnode(&dn, inode, NULL, NULL, 0);
		err = get_dnode_of_data(&dn, pgofs, mode);
		if (err) {
			if (err == -ENOENT)
				err = 0;
			goto unlock_out;
		}

		end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
	}

	if (maxblocks > map->m_len) {//如果已经map了的长度没有达到maxblocks,即还没有map完
		block_t blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);

		if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {//如果下一个data block为new或者 
                                                          //null,重新申请一个
			if (create) {
				if (unlikely(f2fs_cp_error(sbi))) {
					err = -EIO;
					goto sync_out;
				}
				err = __allocate_data_block(&dn);
				if (err)
					goto sync_out;
				allocated = true;
				map->m_flags |= F2FS_MAP_NEW;
				blkaddr = dn.data_blkaddr;
			} else {
				/*
				 * we only merge preallocated unwritten blocks
				 * for fiemap.
				 */
				if (flag != F2FS_GET_BLOCK_FIEMAP ||
						blkaddr != NEW_ADDR)
					goto sync_out;
			}
		}

		/* Give more consecutive addresses for the readahead */
		if ((map->m_pblk != NEW_ADDR &&  //如果新分配的block地址连续,则继续
				blkaddr == (map->m_pblk + ofs)) ||
				(map->m_pblk == NEW_ADDR &&
				blkaddr == NEW_ADDR)) {
			ofs++;
			dn.ofs_in_node++;
			pgofs++;
			map->m_len++;
			goto get_next;
		}
	}
sync_out:
	if (allocated)
		sync_inode_page(&dn);
put_out:
	f2fs_put_dnode(&dn);
unlock_out:
	if (create)
		f2fs_unlock_op(F2FS_I_SB(inode));
out:
	trace_f2fs_map_blocks(inode, map, err);
	return err;
}

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
f2fs文件系统调用主要涉及以下几个组件和函数: 1. 文件系统类型定义:在f2fs文件系统中,通过定义一个file_system_type结构体来表示文件系统类型。其中包括了文件系统的名称、挂载函数、卸载函数等信息。在f2fs中,文件系统类型定义如下: static struct file_system_type f2fs_fs_type = { .owner = THIS_MODULE, .name = "f2fs", .mount = f2fs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; 2. 挂载函数:f2fs_mount函数是用来将块设备挂载成f2fs文件系统的函数。它是通过调用mount_bdev函数来实现的。具体的挂载过程包括了填充f2fs super block信息等操作。在f2fs中,挂载函数定义如下: static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); } 3. 填充super block信息:f2fs_fill_super函数用来填充f2fs文件系统的super block信息。它会读取块设备上的super block数据,并将其解析为内存中的数据结构。在f2fs中,填充super block信息的函数定义如下: static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { // 填充super block信息的具体实现 } 通过以上组件和函数,f2fs文件系统可以被调用和使用。当用户在用户空间执行mount操作时,会回调到文件系统类型中定义的mount函数,即f2fs_mount函数。在f2fs_mount函数中,会调用mount_bdev函数来实现具体的挂载过程,包括填充super block信息等操作。最终,f2fs文件系统就可以被成功挂载和使用。 #### 引用[.reference_title] - *1* [f2fs学习笔记 - 4. f2fs文件系统组件说明](https://blog.csdn.net/jasonactions/article/details/122417105)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [f2fs学习四: f2fs文件系统挂载](https://blog.csdn.net/guozhidixian/article/details/115498708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值