Пример #1
0
static void __allocate_data_blocks(struct inode *inode, loff_t offset,
							size_t count)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct dnode_of_data dn;
	u64 start = F2FS_BYTES_TO_BLK(offset);
	u64 len = F2FS_BYTES_TO_BLK(count);
	bool allocated;
	u64 end_offset;

	while (len) {
		f2fs_balance_fs(sbi);
		f2fs_lock_op(sbi);

		/* When reading holes, we need its node page */
		set_new_dnode(&dn, inode, NULL, NULL, 0);
		if (get_dnode_of_data(&dn, start, ALLOC_NODE))
			goto out;

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

		while (dn.ofs_in_node < end_offset && len) {
			block_t blkaddr;

			if (unlikely(f2fs_cp_error(sbi)))
				goto sync_out;

			blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
			if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
				if (__allocate_data_block(&dn))
					goto sync_out;
				allocated = true;
			}
			len--;
			start++;
			dn.ofs_in_node++;
		}

		if (allocated)
			sync_inode_page(&dn);

		f2fs_put_dnode(&dn);
		f2fs_unlock_op(sbi);
	}
	return;

sync_out:
	if (allocated)
		sync_inode_page(&dn);
	f2fs_put_dnode(&dn);
out:
	f2fs_unlock_op(sbi);
	return;
}
Пример #2
0
/*
 * f2fs_map_blocks() now supported readahead/bmap/rw direct_IO with
 * f2fs_map_blocks structure.
 * If original data blocks are allocated, then give them to blockdev.
 * Otherwise,
 *     a. preallocate requested block addresses
 *     b. do not use extent cache for better performance
 *     c. give the block addresses to blockdev
 */
static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
                           int create, int flag)
{
    unsigned int maxblocks = map->m_len;
    struct dnode_of_data dn;
    int mode = create ? ALLOC_NODE : LOOKUP_NODE_RA;
    pgoff_t pgofs, end_offset;
    int err = 0, ofs = 1;
    struct extent_info ei;
    bool allocated = false;

    map->m_len = 0;
    map->m_flags = 0;

    /* it only supports block size == page size */
    pgofs =	(pgoff_t)map->m_lblk;

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

    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);
    err = get_dnode_of_data(&dn, pgofs, mode);
    if (err) {
        if (err == -ENOENT)
            err = 0;
        goto unlock_out;
    }
    if (dn.data_blkaddr == NEW_ADDR) {
        if (flag == F2FS_GET_BLOCK_BMAP) {
            err = -ENOENT;
            goto put_out;
        } else if (flag == F2FS_GET_BLOCK_READ ||
                   flag == F2FS_GET_BLOCK_DIO) {
            goto put_out;
        }
        /*
         * if it is in fiemap call path (flag = F2FS_GET_BLOCK_FIEMAP),
         * mark it as mapped and unwritten block.
         */
    }

    if (dn.data_blkaddr != NULL_ADDR) {
        map->m_flags = F2FS_MAP_MAPPED;
        map->m_pblk = dn.data_blkaddr;
        if (dn.data_blkaddr == NEW_ADDR)
            map->m_flags |= F2FS_MAP_UNWRITTEN;
    } else if (create) {
        err = __allocate_data_block(&dn);
        if (err)
            goto put_out;
        allocated = true;
        map->m_flags = F2FS_MAP_NEW | F2FS_MAP_MAPPED;
        map->m_pblk = dn.data_blkaddr;
    } else {
        if (flag == F2FS_GET_BLOCK_BMAP)
            err = -ENOENT;
        goto put_out;
    }

    end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
    map->m_len = 1;
    dn.ofs_in_node++;
    pgofs++;

get_next:
    if (dn.ofs_in_node >= end_offset) {
        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;
        }

        if (dn.data_blkaddr == NEW_ADDR &&
                flag != F2FS_GET_BLOCK_FIEMAP)
            goto put_out;

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

    if (maxblocks > map->m_len) {
        block_t blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
        if (blkaddr == NULL_ADDR && create) {
            err = __allocate_data_block(&dn);
            if (err)
                goto sync_out;
            allocated = true;
            map->m_flags |= F2FS_MAP_NEW;
            blkaddr = dn.data_blkaddr;
        }
        /* Give more consecutive addresses for the readahead */
        if ((map->m_pblk != NEW_ADDR &&
                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;
}