Exemplo n.º 1
0
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
			struct inode *inode, nid_t ino, umode_t mode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct page *ipage;
	unsigned int bit_pos;
	f2fs_hash_t name_hash;
	size_t namelen = name->len;
	struct f2fs_inline_dentry *dentry_blk = NULL;
	struct f2fs_dentry_ptr d;
	int slots = GET_DENTRY_SLOTS(namelen);
	struct page *page = NULL;
	int err = 0;

	ipage = get_node_page(sbi, dir->i_ino);
	if (IS_ERR(ipage))
		return PTR_ERR(ipage);

	dentry_blk = inline_data_addr(ipage);
	bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
						slots, NR_INLINE_DENTRY);
	if (bit_pos >= NR_INLINE_DENTRY) {
		err = f2fs_convert_inline_dir(dir, ipage, dentry_blk);
		if (err)
			return err;
		err = -EAGAIN;
		goto out;
	}

	if (inode) {
		down_write(&F2FS_I(inode)->i_sem);
		page = init_inode_metadata(inode, dir, name, ipage);
		if (IS_ERR(page)) {
			err = PTR_ERR(page);
			goto fail;
		}
	}

	f2fs_wait_on_page_writeback(ipage, NODE, true);

	name_hash = f2fs_dentry_hash(name);
	make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
	f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos);

	set_page_dirty(ipage);

	/* we don't need to mark_inode_dirty now */
	if (inode) {
		f2fs_i_pino_write(inode, dir->i_ino);
		f2fs_put_page(page, 1);
	}

	update_parent_metadata(dir, inode, 0);
fail:
	if (inode)
		up_write(&F2FS_I(inode)->i_sem);
out:
	f2fs_put_page(ipage, 1);
	return err;
}
Exemplo n.º 2
0
/*
 * f2fs_add_link - Add a new file(dir) to parent dir.
 */
int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent,
			const unsigned char *name, int name_len, nid_t ino,
			int file_type, block_t p_blkaddr, int inc_link)
{
	int level = 0, current_depth, bit_pos;
	int nbucket, nblock, bidx, block;
	int slots = GET_DENTRY_SLOTS(name_len);
	f2fs_hash_t dentry_hash = f2fs_dentry_hash(name, name_len);
	struct f2fs_dentry_block *dentry_blk;
	struct f2fs_dentry_ptr d;
	struct dnode_of_data dn;
	nid_t pino = le32_to_cpu(parent->footer.ino);
	unsigned int dir_level = parent->i.i_dir_level;
	int ret;

	if (parent == NULL)
		return -EINVAL;

	if (!pino) {
		ERR_MSG("Wrong parent ino:%d \n", pino);
		return -EINVAL;
	}

	dentry_blk = calloc(BLOCK_SZ, 1);
	ASSERT(dentry_blk);

	current_depth = le32_to_cpu(parent->i.i_current_depth);
start:
	if (current_depth == MAX_DIR_HASH_DEPTH) {
		free(dentry_blk);
		ERR_MSG("\tError: MAX_DIR_HASH\n");
		return -ENOSPC;
	}

	/* Need a new dentry block */
	if (level == current_depth)
		++current_depth;

	nbucket = dir_buckets(level, dir_level);
	nblock = bucket_blocks(level);
	bidx = dir_block_index(level, dir_level, le32_to_cpu(dentry_hash) % nbucket);

	memset(&dn, 0, sizeof(dn));
	for (block = bidx; block <= (bidx + nblock - 1); block++) {

		/* Firstly, we should know the direct node of target data blk */
		if (dn.node_blk && dn.node_blk != dn.inode_blk)
			free(dn.node_blk);

		set_new_dnode(&dn, parent, NULL, pino);
		get_dnode_of_data(sbi, &dn, block, ALLOC_NODE);

		if (dn.data_blkaddr == NULL_ADDR) {
			new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
		} else {
			ret = dev_read_block(dentry_blk, dn.data_blkaddr);
			ASSERT(ret >= 0);
		}
		bit_pos = room_for_filename(dentry_blk->dentry_bitmap,
				slots, NR_DENTRY_IN_BLOCK);

		if (bit_pos < NR_DENTRY_IN_BLOCK)
			goto add_dentry;
	}
	level ++;
	goto start;

add_dentry:
	make_dentry_ptr(&d, NULL, (void *)dentry_blk, 1);
	f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos);

	ret = dev_write_block(dentry_blk, dn.data_blkaddr);
	ASSERT(ret >= 0);

	/*
	 * Parent inode needs updating, because its inode info may be changed.
	 * such as i_current_depth and i_blocks.
	 */
	if (parent->i.i_current_depth != cpu_to_le32(current_depth)) {
		parent->i.i_current_depth = cpu_to_le32(current_depth);
		dn.idirty = 1;
	}

	/* Update parent's i_links info*/
	if (inc_link && (file_type == F2FS_FT_DIR)){
		u32 links = le32_to_cpu(parent->i.i_links);
		parent->i.i_links = cpu_to_le32(links + 1);
		dn.idirty = 1;
	}

	if ((__u64)((block + 1) * F2FS_BLKSIZE) >
					le64_to_cpu(parent->i.i_size)) {
		parent->i.i_size = cpu_to_le64((block + 1) * F2FS_BLKSIZE);
		dn.idirty = 1;
	}

	if (dn.ndirty) {
		ret = dev_write_block(dn.node_blk, dn.node_blkaddr);
		ASSERT(ret >= 0);
	}

	if (dn.idirty) {
		ASSERT(parent == dn.inode_blk);
		ret = dev_write_block(dn.inode_blk, p_blkaddr);
		ASSERT(ret >= 0);
	}

	if (dn.node_blk != dn.inode_blk)
		free(dn.node_blk);
	free(dentry_blk);
	return 0;
}
/*
 * Caller should grab and release a rwsem by calling f2fs_lock_op() and
 * f2fs_unlock_op().
 */
int __f2fs_add_link(struct inode *dir, const struct qstr *name,
                    struct inode *inode)
{
    unsigned int bit_pos;
    unsigned int level;
    unsigned int current_depth;
    unsigned long bidx, block;
    f2fs_hash_t dentry_hash;
    unsigned int nbucket, nblock;
    size_t namelen = name->len;
    struct page *dentry_page = NULL;
    struct f2fs_dentry_block *dentry_blk = NULL;
    struct f2fs_dentry_ptr d;
    int slots = GET_DENTRY_SLOTS(namelen);
    struct page *page;
    int err = 0;

    if (f2fs_has_inline_dentry(dir)) {
        err = f2fs_add_inline_entry(dir, name, inode);
        if (!err || err != -EAGAIN)
            return err;
        else
            err = 0;
    }

    dentry_hash = f2fs_dentry_hash(name);
    level = 0;
    current_depth = F2FS_I(dir)->i_current_depth;
    if (F2FS_I(dir)->chash == dentry_hash) {
        level = F2FS_I(dir)->clevel;
        F2FS_I(dir)->chash = 0;
    }

start:
    if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
        return -ENOSPC;

    /* Increase the depth, if required */
    if (level == current_depth)
        ++current_depth;

    nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
    nblock = bucket_blocks(level);

    bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level,
                           (le32_to_cpu(dentry_hash) % nbucket));

    for (block = bidx; block <= (bidx + nblock - 1); block++) {
        dentry_page = get_new_data_page(dir, NULL, block, true);
        if (IS_ERR(dentry_page))
            return PTR_ERR(dentry_page);

        dentry_blk = kmap(dentry_page);
        bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
                                    slots, NR_DENTRY_IN_BLOCK);
        if (bit_pos < NR_DENTRY_IN_BLOCK)
            goto add_dentry;

        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
    }

    /* Move to next level to find the empty slot for new dentry */
    ++level;
    goto start;
add_dentry:
    f2fs_wait_on_page_writeback(dentry_page, DATA);

    down_write(&F2FS_I(inode)->i_sem);
    page = init_inode_metadata(inode, dir, name, NULL);
    if (IS_ERR(page)) {
        err = PTR_ERR(page);
        goto fail;
    }

    make_dentry_ptr(&d, (void *)dentry_blk, 1);
    f2fs_update_dentry(inode, &d, name, dentry_hash, bit_pos);

    set_page_dirty(dentry_page);

    /* we don't need to mark_inode_dirty now */
    F2FS_I(inode)->i_pino = dir->i_ino;
    update_inode(inode, page);
    f2fs_put_page(page, 1);

    update_parent_metadata(dir, inode, current_depth);
fail:
    up_write(&F2FS_I(inode)->i_sem);

    if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
        update_inode_page(dir);
        clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
    }
    kunmap(dentry_page);
    f2fs_put_page(dentry_page, 1);
    return err;
}