ext4 ext4_map_blocks

来源:互联网 发布:人工智能爱酱cv 编辑:程序博客网 时间:2024/04/30 11:43
struct ext4_map_blocks {ext4_fsblk_t m_pblk;ext4_lblk_t m_lblk;unsigned int m_len;unsigned int m_flags;};
/* * The ext4_map_blocks() function tries to look up the requested blocks, * and returns if the blocks are already mapped. * * Otherwise it takes the write lock of the i_data_sem and allocate blocks * and store the allocated blocks in the result buffer head and mark it * mapped. * * If file type is extents based, it will call ext4_ext_map_blocks(), * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping * based files * * On success, it returns the number of blocks being mapped or allocated.  if * create==0 and the blocks are pre-allocated and unwritten, the resulting @map * is marked as unwritten. If the create == 1, it will mark @map as mapped. * * It returns 0 if plain look up failed (blocks have not been allocated), in * that case, @map is returned as unmapped but we still do fill map->m_len to * indicate the length of a hole starting at map->m_lblk. * * It returns the error in case of allocation failure. */int ext4_map_blocks(handle_t *handle, struct inode *inode,    struct ext4_map_blocks *map, int flags){struct extent_status es;int retval;int ret = 0;#ifdef ES_AGGRESSIVE_TESTstruct ext4_map_blocks orig_map;memcpy(&orig_map, map, sizeof(*map));#endifmap->m_flags = 0;ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"  "logical block %lu\n", inode->i_ino, flags, map->m_len,  (unsigned long) map->m_lblk);/* * ext4_map_blocks returns an int, and m_len is an unsigned int */if (unlikely(map->m_len > INT_MAX))map->m_len = INT_MAX;/* We can handle the block number less than EXT_MAX_BLOCKS */if (unlikely(map->m_lblk >= EXT_MAX_BLOCKS))return -EFSCORRUPTED;/* Lookup extent status tree firstly */if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {map->m_pblk = ext4_es_pblock(&es) +map->m_lblk - es.es_lblk;map->m_flags |= ext4_es_is_written(&es) ?EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN;retval = es.es_len - (map->m_lblk - es.es_lblk);if (retval > map->m_len)retval = map->m_len;map->m_len = retval;} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {map->m_pblk = 0;retval = es.es_len - (map->m_lblk - es.es_lblk);if (retval > map->m_len)retval = map->m_len;map->m_len = retval;retval = 0;} else {BUG_ON(1);}#ifdef ES_AGGRESSIVE_TESText4_map_blocks_es_recheck(handle, inode, map,   &orig_map, flags);#endifgoto found;}/* * Try to see if we can get the block without requesting a new * file system block. */down_read(&EXT4_I(inode)->i_data_sem);if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {retval = ext4_ext_map_blocks(handle, inode, map, flags &     EXT4_GET_BLOCKS_KEEP_SIZE);} else {retval = ext4_ind_map_blocks(handle, inode, map, flags &     EXT4_GET_BLOCKS_KEEP_SIZE);}if (retval > 0) {unsigned int status;if (unlikely(retval != map->m_len)) {ext4_warning(inode->i_sb,     "ES len assertion failed for inode "     "%lu: retval %d != map->m_len %d",     inode->i_ino, retval, map->m_len);WARN_ON(1);}status = map->m_flags & EXT4_MAP_UNWRITTEN ?EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&    !(status & EXTENT_STATUS_WRITTEN) &&    ext4_find_delalloc_range(inode, map->m_lblk,     map->m_lblk + map->m_len - 1))status |= EXTENT_STATUS_DELAYED;ret = ext4_es_insert_extent(inode, map->m_lblk,    map->m_len, map->m_pblk, status);if (ret < 0)retval = ret;}up_read((&EXT4_I(inode)->i_data_sem));found:if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {ret = check_block_validity(inode, map);if (ret != 0)return ret;}/* If it is only a block(s) look up */if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)return retval;/* * Returns if the blocks have already allocated * * Note that if blocks have been preallocated * ext4_ext_get_block() returns the create = 0 * with buffer head unmapped. */if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)/* * If we need to convert extent to unwritten * we continue and do the actual work in * ext4_ext_map_blocks() */if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))return retval;/* * Here we clear m_flags because after allocating an new extent, * it will be set again. */map->m_flags &= ~EXT4_MAP_FLAGS;/* * New blocks allocate and/or writing to unwritten extent * will possibly result in updating i_data, so we take * the write lock of i_data_sem, and call get_block() * with create == 1 flag. */down_write(&EXT4_I(inode)->i_data_sem);/* * We need to check for EXT4 here because migrate * could have changed the inode type in between */if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {retval = ext4_ext_map_blocks(handle, inode, map, flags);} else {retval = ext4_ind_map_blocks(handle, inode, map, flags);if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {/* * We allocated new blocks which will result in * i_data's format changing.  Force the migrate * to fail by clearing migrate flags */ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);}/* * Update reserved blocks/metadata blocks after successful * block allocation which had been deferred till now. We don't * support fallocate for non extent files. So we can update * reserve space here. */if ((retval > 0) &&(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE))ext4_da_update_reserve_space(inode, retval, 1);}if (retval > 0) {unsigned int status;if (unlikely(retval != map->m_len)) {ext4_warning(inode->i_sb,     "ES len assertion failed for inode "     "%lu: retval %d != map->m_len %d",     inode->i_ino, retval, map->m_len);WARN_ON(1);}/* * We have to zeroout blocks before inserting them into extent * status tree. Otherwise someone could look them up there and * use them before they are really zeroed. We also have to * unmap metadata before zeroing as otherwise writeback can * overwrite zeros with stale data from block device. */if (flags & EXT4_GET_BLOCKS_ZERO &&    map->m_flags & EXT4_MAP_MAPPED &&    map->m_flags & EXT4_MAP_NEW) {ext4_lblk_t i;for (i = 0; i < map->m_len; i++) {unmap_underlying_metadata(inode->i_sb->s_bdev,  map->m_pblk + i);}ret = ext4_issue_zeroout(inode, map->m_lblk, map->m_pblk, map->m_len);if (ret) {retval = ret;goto out_sem;}}/* * If the extent has been zeroed out, we don't need to update * extent status tree. */if ((flags & EXT4_GET_BLOCKS_PRE_IO) &&    ext4_es_lookup_extent(inode, map->m_lblk, &es)) {if (ext4_es_is_written(&es))goto out_sem;}status = map->m_flags & EXT4_MAP_UNWRITTEN ?EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&    !(status & EXTENT_STATUS_WRITTEN) &&    ext4_find_delalloc_range(inode, map->m_lblk,     map->m_lblk + map->m_len - 1))status |= EXTENT_STATUS_DELAYED;ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,    map->m_pblk, status);if (ret < 0) {retval = ret;goto out_sem;}}out_sem:up_write((&EXT4_I(inode)->i_data_sem));if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {ret = check_block_validity(inode, map);if (ret != 0)return ret;/* * Inodes with freshly allocated blocks where contents will be * visible after transaction commit must be on transaction's * ordered data list. */if (map->m_flags & EXT4_MAP_NEW &&    !(map->m_flags & EXT4_MAP_UNWRITTEN) &&    !(flags & EXT4_GET_BLOCKS_ZERO) &&    !IS_NOQUOTA(inode) &&    ext4_should_order_data(inode)) {if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)ret = ext4_jbd2_inode_add_wait(handle, inode);elseret = ext4_jbd2_inode_add_write(handle, inode);if (ret)return ret;}}return retval;}
                                             
0 0
原创粉丝点击