18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2007
48c2ecf20Sopenharmony_ci * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include "ext4_jbd2.h"
108c2ecf20Sopenharmony_ci#include "ext4_extents.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/*
138c2ecf20Sopenharmony_ci * The contiguous blocks details which can be
148c2ecf20Sopenharmony_ci * represented by a single extent
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_cistruct migrate_struct {
178c2ecf20Sopenharmony_ci	ext4_lblk_t first_block, last_block, curr_block;
188c2ecf20Sopenharmony_ci	ext4_fsblk_t first_pblock, last_pblock;
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic int finish_range(handle_t *handle, struct inode *inode,
228c2ecf20Sopenharmony_ci				struct migrate_struct *lb)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	int retval = 0, needed;
268c2ecf20Sopenharmony_ci	struct ext4_extent newext;
278c2ecf20Sopenharmony_ci	struct ext4_ext_path *path;
288c2ecf20Sopenharmony_ci	if (lb->first_pblock == 0)
298c2ecf20Sopenharmony_ci		return 0;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	/* Add the extent to temp inode*/
328c2ecf20Sopenharmony_ci	newext.ee_block = cpu_to_le32(lb->first_block);
338c2ecf20Sopenharmony_ci	newext.ee_len   = cpu_to_le16(lb->last_block - lb->first_block + 1);
348c2ecf20Sopenharmony_ci	ext4_ext_store_pblock(&newext, lb->first_pblock);
358c2ecf20Sopenharmony_ci	/* Locking only for convenience since we are operating on temp inode */
368c2ecf20Sopenharmony_ci	down_write(&EXT4_I(inode)->i_data_sem);
378c2ecf20Sopenharmony_ci	path = ext4_find_extent(inode, lb->first_block, NULL, 0);
388c2ecf20Sopenharmony_ci	if (IS_ERR(path)) {
398c2ecf20Sopenharmony_ci		retval = PTR_ERR(path);
408c2ecf20Sopenharmony_ci		path = NULL;
418c2ecf20Sopenharmony_ci		goto err_out;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	/*
458c2ecf20Sopenharmony_ci	 * Calculate the credit needed to inserting this extent
468c2ecf20Sopenharmony_ci	 * Since we are doing this in loop we may accumulate extra
478c2ecf20Sopenharmony_ci	 * credit. But below we try to not accumulate too much
488c2ecf20Sopenharmony_ci	 * of them by restarting the journal.
498c2ecf20Sopenharmony_ci	 */
508c2ecf20Sopenharmony_ci	needed = ext4_ext_calc_credits_for_single_extent(inode,
518c2ecf20Sopenharmony_ci		    lb->last_block - lb->first_block + 1, path);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	retval = ext4_datasem_ensure_credits(handle, inode, needed, needed, 0);
548c2ecf20Sopenharmony_ci	if (retval < 0)
558c2ecf20Sopenharmony_ci		goto err_out;
568c2ecf20Sopenharmony_ci	retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
578c2ecf20Sopenharmony_cierr_out:
588c2ecf20Sopenharmony_ci	up_write((&EXT4_I(inode)->i_data_sem));
598c2ecf20Sopenharmony_ci	ext4_ext_drop_refs(path);
608c2ecf20Sopenharmony_ci	kfree(path);
618c2ecf20Sopenharmony_ci	lb->first_pblock = 0;
628c2ecf20Sopenharmony_ci	return retval;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int update_extent_range(handle_t *handle, struct inode *inode,
668c2ecf20Sopenharmony_ci			       ext4_fsblk_t pblock, struct migrate_struct *lb)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	int retval;
698c2ecf20Sopenharmony_ci	/*
708c2ecf20Sopenharmony_ci	 * See if we can add on to the existing range (if it exists)
718c2ecf20Sopenharmony_ci	 */
728c2ecf20Sopenharmony_ci	if (lb->first_pblock &&
738c2ecf20Sopenharmony_ci		(lb->last_pblock+1 == pblock) &&
748c2ecf20Sopenharmony_ci		(lb->last_block+1 == lb->curr_block)) {
758c2ecf20Sopenharmony_ci		lb->last_pblock = pblock;
768c2ecf20Sopenharmony_ci		lb->last_block = lb->curr_block;
778c2ecf20Sopenharmony_ci		lb->curr_block++;
788c2ecf20Sopenharmony_ci		return 0;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci	/*
818c2ecf20Sopenharmony_ci	 * Start a new range.
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci	retval = finish_range(handle, inode, lb);
848c2ecf20Sopenharmony_ci	lb->first_pblock = lb->last_pblock = pblock;
858c2ecf20Sopenharmony_ci	lb->first_block = lb->last_block = lb->curr_block;
868c2ecf20Sopenharmony_ci	lb->curr_block++;
878c2ecf20Sopenharmony_ci	return retval;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int update_ind_extent_range(handle_t *handle, struct inode *inode,
918c2ecf20Sopenharmony_ci				   ext4_fsblk_t pblock,
928c2ecf20Sopenharmony_ci				   struct migrate_struct *lb)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct buffer_head *bh;
958c2ecf20Sopenharmony_ci	__le32 *i_data;
968c2ecf20Sopenharmony_ci	int i, retval = 0;
978c2ecf20Sopenharmony_ci	unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(inode->i_sb, pblock, 0);
1008c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
1018c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	i_data = (__le32 *)bh->b_data;
1048c2ecf20Sopenharmony_ci	for (i = 0; i < max_entries; i++) {
1058c2ecf20Sopenharmony_ci		if (i_data[i]) {
1068c2ecf20Sopenharmony_ci			retval = update_extent_range(handle, inode,
1078c2ecf20Sopenharmony_ci						le32_to_cpu(i_data[i]), lb);
1088c2ecf20Sopenharmony_ci			if (retval)
1098c2ecf20Sopenharmony_ci				break;
1108c2ecf20Sopenharmony_ci		} else {
1118c2ecf20Sopenharmony_ci			lb->curr_block++;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	put_bh(bh);
1158c2ecf20Sopenharmony_ci	return retval;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int update_dind_extent_range(handle_t *handle, struct inode *inode,
1208c2ecf20Sopenharmony_ci				    ext4_fsblk_t pblock,
1218c2ecf20Sopenharmony_ci				    struct migrate_struct *lb)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct buffer_head *bh;
1248c2ecf20Sopenharmony_ci	__le32 *i_data;
1258c2ecf20Sopenharmony_ci	int i, retval = 0;
1268c2ecf20Sopenharmony_ci	unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(inode->i_sb, pblock, 0);
1298c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
1308c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	i_data = (__le32 *)bh->b_data;
1338c2ecf20Sopenharmony_ci	for (i = 0; i < max_entries; i++) {
1348c2ecf20Sopenharmony_ci		if (i_data[i]) {
1358c2ecf20Sopenharmony_ci			retval = update_ind_extent_range(handle, inode,
1368c2ecf20Sopenharmony_ci						le32_to_cpu(i_data[i]), lb);
1378c2ecf20Sopenharmony_ci			if (retval)
1388c2ecf20Sopenharmony_ci				break;
1398c2ecf20Sopenharmony_ci		} else {
1408c2ecf20Sopenharmony_ci			/* Only update the file block number */
1418c2ecf20Sopenharmony_ci			lb->curr_block += max_entries;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	put_bh(bh);
1458c2ecf20Sopenharmony_ci	return retval;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int update_tind_extent_range(handle_t *handle, struct inode *inode,
1508c2ecf20Sopenharmony_ci				    ext4_fsblk_t pblock,
1518c2ecf20Sopenharmony_ci				    struct migrate_struct *lb)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct buffer_head *bh;
1548c2ecf20Sopenharmony_ci	__le32 *i_data;
1558c2ecf20Sopenharmony_ci	int i, retval = 0;
1568c2ecf20Sopenharmony_ci	unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(inode->i_sb, pblock, 0);
1598c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
1608c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	i_data = (__le32 *)bh->b_data;
1638c2ecf20Sopenharmony_ci	for (i = 0; i < max_entries; i++) {
1648c2ecf20Sopenharmony_ci		if (i_data[i]) {
1658c2ecf20Sopenharmony_ci			retval = update_dind_extent_range(handle, inode,
1668c2ecf20Sopenharmony_ci						le32_to_cpu(i_data[i]), lb);
1678c2ecf20Sopenharmony_ci			if (retval)
1688c2ecf20Sopenharmony_ci				break;
1698c2ecf20Sopenharmony_ci		} else {
1708c2ecf20Sopenharmony_ci			/* Only update the file block number */
1718c2ecf20Sopenharmony_ci			lb->curr_block += max_entries * max_entries;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci	put_bh(bh);
1758c2ecf20Sopenharmony_ci	return retval;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int free_dind_blocks(handle_t *handle,
1808c2ecf20Sopenharmony_ci				struct inode *inode, __le32 i_data)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	int i;
1838c2ecf20Sopenharmony_ci	__le32 *tmp_idata;
1848c2ecf20Sopenharmony_ci	struct buffer_head *bh;
1858c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1868c2ecf20Sopenharmony_ci	unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
1878c2ecf20Sopenharmony_ci	int err;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(sb, le32_to_cpu(i_data), 0);
1908c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
1918c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	tmp_idata = (__le32 *)bh->b_data;
1948c2ecf20Sopenharmony_ci	for (i = 0; i < max_entries; i++) {
1958c2ecf20Sopenharmony_ci		if (tmp_idata[i]) {
1968c2ecf20Sopenharmony_ci			err = ext4_journal_ensure_credits(handle,
1978c2ecf20Sopenharmony_ci				EXT4_RESERVE_TRANS_BLOCKS,
1988c2ecf20Sopenharmony_ci				ext4_free_metadata_revoke_credits(sb, 1));
1998c2ecf20Sopenharmony_ci			if (err < 0) {
2008c2ecf20Sopenharmony_ci				put_bh(bh);
2018c2ecf20Sopenharmony_ci				return err;
2028c2ecf20Sopenharmony_ci			}
2038c2ecf20Sopenharmony_ci			ext4_free_blocks(handle, inode, NULL,
2048c2ecf20Sopenharmony_ci					 le32_to_cpu(tmp_idata[i]), 1,
2058c2ecf20Sopenharmony_ci					 EXT4_FREE_BLOCKS_METADATA |
2068c2ecf20Sopenharmony_ci					 EXT4_FREE_BLOCKS_FORGET);
2078c2ecf20Sopenharmony_ci		}
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	put_bh(bh);
2108c2ecf20Sopenharmony_ci	err = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
2118c2ecf20Sopenharmony_ci				ext4_free_metadata_revoke_credits(sb, 1));
2128c2ecf20Sopenharmony_ci	if (err < 0)
2138c2ecf20Sopenharmony_ci		return err;
2148c2ecf20Sopenharmony_ci	ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
2158c2ecf20Sopenharmony_ci			 EXT4_FREE_BLOCKS_METADATA |
2168c2ecf20Sopenharmony_ci			 EXT4_FREE_BLOCKS_FORGET);
2178c2ecf20Sopenharmony_ci	return 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic int free_tind_blocks(handle_t *handle,
2218c2ecf20Sopenharmony_ci				struct inode *inode, __le32 i_data)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	int i, retval = 0;
2248c2ecf20Sopenharmony_ci	__le32 *tmp_idata;
2258c2ecf20Sopenharmony_ci	struct buffer_head *bh;
2268c2ecf20Sopenharmony_ci	unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
2298c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
2308c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	tmp_idata = (__le32 *)bh->b_data;
2338c2ecf20Sopenharmony_ci	for (i = 0; i < max_entries; i++) {
2348c2ecf20Sopenharmony_ci		if (tmp_idata[i]) {
2358c2ecf20Sopenharmony_ci			retval = free_dind_blocks(handle,
2368c2ecf20Sopenharmony_ci					inode, tmp_idata[i]);
2378c2ecf20Sopenharmony_ci			if (retval) {
2388c2ecf20Sopenharmony_ci				put_bh(bh);
2398c2ecf20Sopenharmony_ci				return retval;
2408c2ecf20Sopenharmony_ci			}
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	put_bh(bh);
2448c2ecf20Sopenharmony_ci	retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
2458c2ecf20Sopenharmony_ci			ext4_free_metadata_revoke_credits(inode->i_sb, 1));
2468c2ecf20Sopenharmony_ci	if (retval < 0)
2478c2ecf20Sopenharmony_ci		return retval;
2488c2ecf20Sopenharmony_ci	ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
2498c2ecf20Sopenharmony_ci			 EXT4_FREE_BLOCKS_METADATA |
2508c2ecf20Sopenharmony_ci			 EXT4_FREE_BLOCKS_FORGET);
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	int retval;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	/* ei->i_data[EXT4_IND_BLOCK] */
2598c2ecf20Sopenharmony_ci	if (i_data[0]) {
2608c2ecf20Sopenharmony_ci		retval = ext4_journal_ensure_credits(handle,
2618c2ecf20Sopenharmony_ci			EXT4_RESERVE_TRANS_BLOCKS,
2628c2ecf20Sopenharmony_ci			ext4_free_metadata_revoke_credits(inode->i_sb, 1));
2638c2ecf20Sopenharmony_ci		if (retval < 0)
2648c2ecf20Sopenharmony_ci			return retval;
2658c2ecf20Sopenharmony_ci		ext4_free_blocks(handle, inode, NULL,
2668c2ecf20Sopenharmony_ci				le32_to_cpu(i_data[0]), 1,
2678c2ecf20Sopenharmony_ci				 EXT4_FREE_BLOCKS_METADATA |
2688c2ecf20Sopenharmony_ci				 EXT4_FREE_BLOCKS_FORGET);
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* ei->i_data[EXT4_DIND_BLOCK] */
2728c2ecf20Sopenharmony_ci	if (i_data[1]) {
2738c2ecf20Sopenharmony_ci		retval = free_dind_blocks(handle, inode, i_data[1]);
2748c2ecf20Sopenharmony_ci		if (retval)
2758c2ecf20Sopenharmony_ci			return retval;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* ei->i_data[EXT4_TIND_BLOCK] */
2798c2ecf20Sopenharmony_ci	if (i_data[2]) {
2808c2ecf20Sopenharmony_ci		retval = free_tind_blocks(handle, inode, i_data[2]);
2818c2ecf20Sopenharmony_ci		if (retval)
2828c2ecf20Sopenharmony_ci			return retval;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci	return 0;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
2888c2ecf20Sopenharmony_ci						struct inode *tmp_inode)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	int retval, retval2 = 0;
2918c2ecf20Sopenharmony_ci	__le32	i_data[3];
2928c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
2938c2ecf20Sopenharmony_ci	struct ext4_inode_info *tmp_ei = EXT4_I(tmp_inode);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/*
2968c2ecf20Sopenharmony_ci	 * One credit accounted for writing the
2978c2ecf20Sopenharmony_ci	 * i_data field of the original inode
2988c2ecf20Sopenharmony_ci	 */
2998c2ecf20Sopenharmony_ci	retval = ext4_journal_ensure_credits(handle, 1, 0);
3008c2ecf20Sopenharmony_ci	if (retval < 0)
3018c2ecf20Sopenharmony_ci		goto err_out;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	i_data[0] = ei->i_data[EXT4_IND_BLOCK];
3048c2ecf20Sopenharmony_ci	i_data[1] = ei->i_data[EXT4_DIND_BLOCK];
3058c2ecf20Sopenharmony_ci	i_data[2] = ei->i_data[EXT4_TIND_BLOCK];
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	down_write(&EXT4_I(inode)->i_data_sem);
3088c2ecf20Sopenharmony_ci	/*
3098c2ecf20Sopenharmony_ci	 * if EXT4_STATE_EXT_MIGRATE is cleared a block allocation
3108c2ecf20Sopenharmony_ci	 * happened after we started the migrate. We need to
3118c2ecf20Sopenharmony_ci	 * fail the migrate
3128c2ecf20Sopenharmony_ci	 */
3138c2ecf20Sopenharmony_ci	if (!ext4_test_inode_state(inode, EXT4_STATE_EXT_MIGRATE)) {
3148c2ecf20Sopenharmony_ci		retval = -EAGAIN;
3158c2ecf20Sopenharmony_ci		up_write(&EXT4_I(inode)->i_data_sem);
3168c2ecf20Sopenharmony_ci		goto err_out;
3178c2ecf20Sopenharmony_ci	} else
3188c2ecf20Sopenharmony_ci		ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
3198c2ecf20Sopenharmony_ci	/*
3208c2ecf20Sopenharmony_ci	 * We have the extent map build with the tmp inode.
3218c2ecf20Sopenharmony_ci	 * Now copy the i_data across
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
3248c2ecf20Sopenharmony_ci	memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/*
3278c2ecf20Sopenharmony_ci	 * Update i_blocks with the new blocks that got
3288c2ecf20Sopenharmony_ci	 * allocated while adding extents for extent index
3298c2ecf20Sopenharmony_ci	 * blocks.
3308c2ecf20Sopenharmony_ci	 *
3318c2ecf20Sopenharmony_ci	 * While converting to extents we need not
3328c2ecf20Sopenharmony_ci	 * update the original inode i_blocks for extent blocks
3338c2ecf20Sopenharmony_ci	 * via quota APIs. The quota update happened via tmp_inode already.
3348c2ecf20Sopenharmony_ci	 */
3358c2ecf20Sopenharmony_ci	spin_lock(&inode->i_lock);
3368c2ecf20Sopenharmony_ci	inode->i_blocks += tmp_inode->i_blocks;
3378c2ecf20Sopenharmony_ci	spin_unlock(&inode->i_lock);
3388c2ecf20Sopenharmony_ci	up_write(&EXT4_I(inode)->i_data_sem);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/*
3418c2ecf20Sopenharmony_ci	 * We mark the inode dirty after, because we decrement the
3428c2ecf20Sopenharmony_ci	 * i_blocks when freeing the indirect meta-data blocks
3438c2ecf20Sopenharmony_ci	 */
3448c2ecf20Sopenharmony_ci	retval = free_ind_block(handle, inode, i_data);
3458c2ecf20Sopenharmony_ci	retval2 = ext4_mark_inode_dirty(handle, inode);
3468c2ecf20Sopenharmony_ci	if (unlikely(retval2 && !retval))
3478c2ecf20Sopenharmony_ci		retval = retval2;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cierr_out:
3508c2ecf20Sopenharmony_ci	return retval;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int free_ext_idx(handle_t *handle, struct inode *inode,
3548c2ecf20Sopenharmony_ci					struct ext4_extent_idx *ix)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	int i, retval = 0;
3578c2ecf20Sopenharmony_ci	ext4_fsblk_t block;
3588c2ecf20Sopenharmony_ci	struct buffer_head *bh;
3598c2ecf20Sopenharmony_ci	struct ext4_extent_header *eh;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	block = ext4_idx_pblock(ix);
3628c2ecf20Sopenharmony_ci	bh = ext4_sb_bread(inode->i_sb, block, 0);
3638c2ecf20Sopenharmony_ci	if (IS_ERR(bh))
3648c2ecf20Sopenharmony_ci		return PTR_ERR(bh);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	eh = (struct ext4_extent_header *)bh->b_data;
3678c2ecf20Sopenharmony_ci	if (eh->eh_depth != 0) {
3688c2ecf20Sopenharmony_ci		ix = EXT_FIRST_INDEX(eh);
3698c2ecf20Sopenharmony_ci		for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
3708c2ecf20Sopenharmony_ci			retval = free_ext_idx(handle, inode, ix);
3718c2ecf20Sopenharmony_ci			if (retval) {
3728c2ecf20Sopenharmony_ci				put_bh(bh);
3738c2ecf20Sopenharmony_ci				return retval;
3748c2ecf20Sopenharmony_ci			}
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	put_bh(bh);
3788c2ecf20Sopenharmony_ci	retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
3798c2ecf20Sopenharmony_ci			ext4_free_metadata_revoke_credits(inode->i_sb, 1));
3808c2ecf20Sopenharmony_ci	if (retval < 0)
3818c2ecf20Sopenharmony_ci		return retval;
3828c2ecf20Sopenharmony_ci	ext4_free_blocks(handle, inode, NULL, block, 1,
3838c2ecf20Sopenharmony_ci			 EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/*
3888c2ecf20Sopenharmony_ci * Free the extent meta data blocks only
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_cistatic int free_ext_block(handle_t *handle, struct inode *inode)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int i, retval = 0;
3938c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
3948c2ecf20Sopenharmony_ci	struct ext4_extent_header *eh = (struct ext4_extent_header *)ei->i_data;
3958c2ecf20Sopenharmony_ci	struct ext4_extent_idx *ix;
3968c2ecf20Sopenharmony_ci	if (eh->eh_depth == 0)
3978c2ecf20Sopenharmony_ci		/*
3988c2ecf20Sopenharmony_ci		 * No extra blocks allocated for extent meta data
3998c2ecf20Sopenharmony_ci		 */
4008c2ecf20Sopenharmony_ci		return 0;
4018c2ecf20Sopenharmony_ci	ix = EXT_FIRST_INDEX(eh);
4028c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
4038c2ecf20Sopenharmony_ci		retval = free_ext_idx(handle, inode, ix);
4048c2ecf20Sopenharmony_ci		if (retval)
4058c2ecf20Sopenharmony_ci			return retval;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci	return retval;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ciint ext4_ext_migrate(struct inode *inode)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
4138c2ecf20Sopenharmony_ci	handle_t *handle;
4148c2ecf20Sopenharmony_ci	int retval = 0, i;
4158c2ecf20Sopenharmony_ci	__le32 *i_data;
4168c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei;
4178c2ecf20Sopenharmony_ci	struct inode *tmp_inode = NULL;
4188c2ecf20Sopenharmony_ci	struct migrate_struct lb;
4198c2ecf20Sopenharmony_ci	unsigned long max_entries;
4208c2ecf20Sopenharmony_ci	__u32 goal, tmp_csum_seed;
4218c2ecf20Sopenharmony_ci	uid_t owner[2];
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * If the filesystem does not support extents, or the inode
4258c2ecf20Sopenharmony_ci	 * already is extent-based, error out.
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	if (!ext4_has_feature_extents(inode->i_sb) ||
4288c2ecf20Sopenharmony_ci	    ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
4298c2ecf20Sopenharmony_ci	    ext4_has_inline_data(inode))
4308c2ecf20Sopenharmony_ci		return -EINVAL;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (S_ISLNK(inode->i_mode) && inode->i_blocks == 0)
4338c2ecf20Sopenharmony_ci		/*
4348c2ecf20Sopenharmony_ci		 * don't migrate fast symlink
4358c2ecf20Sopenharmony_ci		 */
4368c2ecf20Sopenharmony_ci		return retval;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	percpu_down_write(&sbi->s_writepages_rwsem);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * Worst case we can touch the allocation bitmaps and a block
4428c2ecf20Sopenharmony_ci	 * group descriptor block.  We do need need to worry about
4438c2ecf20Sopenharmony_ci	 * credits for modifying the quota inode.
4448c2ecf20Sopenharmony_ci	 */
4458c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_MIGRATE,
4468c2ecf20Sopenharmony_ci		3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb));
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
4498c2ecf20Sopenharmony_ci		retval = PTR_ERR(handle);
4508c2ecf20Sopenharmony_ci		goto out_unlock;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci	goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
4538c2ecf20Sopenharmony_ci		EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
4548c2ecf20Sopenharmony_ci	owner[0] = i_uid_read(inode);
4558c2ecf20Sopenharmony_ci	owner[1] = i_gid_read(inode);
4568c2ecf20Sopenharmony_ci	tmp_inode = ext4_new_inode(handle, d_inode(inode->i_sb->s_root),
4578c2ecf20Sopenharmony_ci				   S_IFREG, NULL, goal, owner, 0);
4588c2ecf20Sopenharmony_ci	if (IS_ERR(tmp_inode)) {
4598c2ecf20Sopenharmony_ci		retval = PTR_ERR(tmp_inode);
4608c2ecf20Sopenharmony_ci		ext4_journal_stop(handle);
4618c2ecf20Sopenharmony_ci		goto out_unlock;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci	/*
4648c2ecf20Sopenharmony_ci	 * Use the correct seed for checksum (i.e. the seed from 'inode').  This
4658c2ecf20Sopenharmony_ci	 * is so that the metadata blocks will have the correct checksum after
4668c2ecf20Sopenharmony_ci	 * the migration.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci	ei = EXT4_I(inode);
4698c2ecf20Sopenharmony_ci	tmp_csum_seed = EXT4_I(tmp_inode)->i_csum_seed;
4708c2ecf20Sopenharmony_ci	EXT4_I(tmp_inode)->i_csum_seed = ei->i_csum_seed;
4718c2ecf20Sopenharmony_ci	i_size_write(tmp_inode, i_size_read(inode));
4728c2ecf20Sopenharmony_ci	/*
4738c2ecf20Sopenharmony_ci	 * Set the i_nlink to zero so it will be deleted later
4748c2ecf20Sopenharmony_ci	 * when we drop inode reference.
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci	clear_nlink(tmp_inode);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	ext4_ext_tree_init(handle, tmp_inode);
4798c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/*
4828c2ecf20Sopenharmony_ci	 * start with one credit accounted for
4838c2ecf20Sopenharmony_ci	 * superblock modification.
4848c2ecf20Sopenharmony_ci	 *
4858c2ecf20Sopenharmony_ci	 * For the tmp_inode we already have committed the
4868c2ecf20Sopenharmony_ci	 * transaction that created the inode. Later as and
4878c2ecf20Sopenharmony_ci	 * when we add extents we extent the journal
4888c2ecf20Sopenharmony_ci	 */
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * Even though we take i_mutex we can still cause block
4918c2ecf20Sopenharmony_ci	 * allocation via mmap write to holes. If we have allocated
4928c2ecf20Sopenharmony_ci	 * new blocks we fail migrate.  New block allocation will
4938c2ecf20Sopenharmony_ci	 * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
4948c2ecf20Sopenharmony_ci	 * with i_data_sem held to prevent racing with block
4958c2ecf20Sopenharmony_ci	 * allocation.
4968c2ecf20Sopenharmony_ci	 */
4978c2ecf20Sopenharmony_ci	down_read(&EXT4_I(inode)->i_data_sem);
4988c2ecf20Sopenharmony_ci	ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
4998c2ecf20Sopenharmony_ci	up_read((&EXT4_I(inode)->i_data_sem));
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
5028c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
5038c2ecf20Sopenharmony_ci		retval = PTR_ERR(handle);
5048c2ecf20Sopenharmony_ci		goto out_tmp_inode;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	i_data = ei->i_data;
5088c2ecf20Sopenharmony_ci	memset(&lb, 0, sizeof(lb));
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* 32 bit block address 4 bytes */
5118c2ecf20Sopenharmony_ci	max_entries = inode->i_sb->s_blocksize >> 2;
5128c2ecf20Sopenharmony_ci	for (i = 0; i < EXT4_NDIR_BLOCKS; i++) {
5138c2ecf20Sopenharmony_ci		if (i_data[i]) {
5148c2ecf20Sopenharmony_ci			retval = update_extent_range(handle, tmp_inode,
5158c2ecf20Sopenharmony_ci						le32_to_cpu(i_data[i]), &lb);
5168c2ecf20Sopenharmony_ci			if (retval)
5178c2ecf20Sopenharmony_ci				goto err_out;
5188c2ecf20Sopenharmony_ci		} else
5198c2ecf20Sopenharmony_ci			lb.curr_block++;
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci	if (i_data[EXT4_IND_BLOCK]) {
5228c2ecf20Sopenharmony_ci		retval = update_ind_extent_range(handle, tmp_inode,
5238c2ecf20Sopenharmony_ci				le32_to_cpu(i_data[EXT4_IND_BLOCK]), &lb);
5248c2ecf20Sopenharmony_ci		if (retval)
5258c2ecf20Sopenharmony_ci			goto err_out;
5268c2ecf20Sopenharmony_ci	} else
5278c2ecf20Sopenharmony_ci		lb.curr_block += max_entries;
5288c2ecf20Sopenharmony_ci	if (i_data[EXT4_DIND_BLOCK]) {
5298c2ecf20Sopenharmony_ci		retval = update_dind_extent_range(handle, tmp_inode,
5308c2ecf20Sopenharmony_ci				le32_to_cpu(i_data[EXT4_DIND_BLOCK]), &lb);
5318c2ecf20Sopenharmony_ci		if (retval)
5328c2ecf20Sopenharmony_ci			goto err_out;
5338c2ecf20Sopenharmony_ci	} else
5348c2ecf20Sopenharmony_ci		lb.curr_block += max_entries * max_entries;
5358c2ecf20Sopenharmony_ci	if (i_data[EXT4_TIND_BLOCK]) {
5368c2ecf20Sopenharmony_ci		retval = update_tind_extent_range(handle, tmp_inode,
5378c2ecf20Sopenharmony_ci				le32_to_cpu(i_data[EXT4_TIND_BLOCK]), &lb);
5388c2ecf20Sopenharmony_ci		if (retval)
5398c2ecf20Sopenharmony_ci			goto err_out;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	/*
5428c2ecf20Sopenharmony_ci	 * Build the last extent
5438c2ecf20Sopenharmony_ci	 */
5448c2ecf20Sopenharmony_ci	retval = finish_range(handle, tmp_inode, &lb);
5458c2ecf20Sopenharmony_cierr_out:
5468c2ecf20Sopenharmony_ci	if (retval)
5478c2ecf20Sopenharmony_ci		/*
5488c2ecf20Sopenharmony_ci		 * Failure case delete the extent information with the
5498c2ecf20Sopenharmony_ci		 * tmp_inode
5508c2ecf20Sopenharmony_ci		 */
5518c2ecf20Sopenharmony_ci		free_ext_block(handle, tmp_inode);
5528c2ecf20Sopenharmony_ci	else {
5538c2ecf20Sopenharmony_ci		retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
5548c2ecf20Sopenharmony_ci		if (retval)
5558c2ecf20Sopenharmony_ci			/*
5568c2ecf20Sopenharmony_ci			 * if we fail to swap inode data free the extent
5578c2ecf20Sopenharmony_ci			 * details of the tmp inode
5588c2ecf20Sopenharmony_ci			 */
5598c2ecf20Sopenharmony_ci			free_ext_block(handle, tmp_inode);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
5638c2ecf20Sopenharmony_ci	retval = ext4_journal_ensure_credits(handle, 1, 0);
5648c2ecf20Sopenharmony_ci	if (retval < 0)
5658c2ecf20Sopenharmony_ci		goto out_stop;
5668c2ecf20Sopenharmony_ci	/*
5678c2ecf20Sopenharmony_ci	 * Mark the tmp_inode as of size zero
5688c2ecf20Sopenharmony_ci	 */
5698c2ecf20Sopenharmony_ci	i_size_write(tmp_inode, 0);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	/*
5728c2ecf20Sopenharmony_ci	 * set the  i_blocks count to zero
5738c2ecf20Sopenharmony_ci	 * so that the ext4_evict_inode() does the
5748c2ecf20Sopenharmony_ci	 * right job
5758c2ecf20Sopenharmony_ci	 *
5768c2ecf20Sopenharmony_ci	 * We don't need to take the i_lock because
5778c2ecf20Sopenharmony_ci	 * the inode is not visible to user space.
5788c2ecf20Sopenharmony_ci	 */
5798c2ecf20Sopenharmony_ci	tmp_inode->i_blocks = 0;
5808c2ecf20Sopenharmony_ci	EXT4_I(tmp_inode)->i_csum_seed = tmp_csum_seed;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Reset the extent details */
5838c2ecf20Sopenharmony_ci	ext4_ext_tree_init(handle, tmp_inode);
5848c2ecf20Sopenharmony_ciout_stop:
5858c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
5868c2ecf20Sopenharmony_ciout_tmp_inode:
5878c2ecf20Sopenharmony_ci	unlock_new_inode(tmp_inode);
5888c2ecf20Sopenharmony_ci	iput(tmp_inode);
5898c2ecf20Sopenharmony_ciout_unlock:
5908c2ecf20Sopenharmony_ci	percpu_up_write(&sbi->s_writepages_rwsem);
5918c2ecf20Sopenharmony_ci	return retval;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/*
5958c2ecf20Sopenharmony_ci * Migrate a simple extent-based inode to use the i_blocks[] array
5968c2ecf20Sopenharmony_ci */
5978c2ecf20Sopenharmony_ciint ext4_ind_migrate(struct inode *inode)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct ext4_extent_header	*eh;
6008c2ecf20Sopenharmony_ci	struct ext4_sb_info		*sbi = EXT4_SB(inode->i_sb);
6018c2ecf20Sopenharmony_ci	struct ext4_super_block		*es = sbi->s_es;
6028c2ecf20Sopenharmony_ci	struct ext4_inode_info		*ei = EXT4_I(inode);
6038c2ecf20Sopenharmony_ci	struct ext4_extent		*ex;
6048c2ecf20Sopenharmony_ci	unsigned int			i, len;
6058c2ecf20Sopenharmony_ci	ext4_lblk_t			start, end;
6068c2ecf20Sopenharmony_ci	ext4_fsblk_t			blk;
6078c2ecf20Sopenharmony_ci	handle_t			*handle;
6088c2ecf20Sopenharmony_ci	int				ret, ret2 = 0;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if (!ext4_has_feature_extents(inode->i_sb) ||
6118c2ecf20Sopenharmony_ci	    (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
6128c2ecf20Sopenharmony_ci		return -EINVAL;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (ext4_has_feature_bigalloc(inode->i_sb))
6158c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/*
6188c2ecf20Sopenharmony_ci	 * In order to get correct extent info, force all delayed allocation
6198c2ecf20Sopenharmony_ci	 * blocks to be allocated, otherwise delayed allocation blocks may not
6208c2ecf20Sopenharmony_ci	 * be reflected and bypass the checks on extent header.
6218c2ecf20Sopenharmony_ci	 */
6228c2ecf20Sopenharmony_ci	if (test_opt(inode->i_sb, DELALLOC))
6238c2ecf20Sopenharmony_ci		ext4_alloc_da_blocks(inode);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	percpu_down_write(&sbi->s_writepages_rwsem);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
6288c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
6298c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
6308c2ecf20Sopenharmony_ci		goto out_unlock;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	down_write(&EXT4_I(inode)->i_data_sem);
6348c2ecf20Sopenharmony_ci	ret = ext4_ext_check_inode(inode);
6358c2ecf20Sopenharmony_ci	if (ret)
6368c2ecf20Sopenharmony_ci		goto errout;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	eh = ext_inode_hdr(inode);
6398c2ecf20Sopenharmony_ci	ex  = EXT_FIRST_EXTENT(eh);
6408c2ecf20Sopenharmony_ci	if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS ||
6418c2ecf20Sopenharmony_ci	    eh->eh_depth != 0 || le16_to_cpu(eh->eh_entries) > 1) {
6428c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
6438c2ecf20Sopenharmony_ci		goto errout;
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci	if (eh->eh_entries == 0)
6468c2ecf20Sopenharmony_ci		blk = len = start = end = 0;
6478c2ecf20Sopenharmony_ci	else {
6488c2ecf20Sopenharmony_ci		len = le16_to_cpu(ex->ee_len);
6498c2ecf20Sopenharmony_ci		blk = ext4_ext_pblock(ex);
6508c2ecf20Sopenharmony_ci		start = le32_to_cpu(ex->ee_block);
6518c2ecf20Sopenharmony_ci		end = start + len - 1;
6528c2ecf20Sopenharmony_ci		if (end >= EXT4_NDIR_BLOCKS) {
6538c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
6548c2ecf20Sopenharmony_ci			goto errout;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
6598c2ecf20Sopenharmony_ci	memset(ei->i_data, 0, sizeof(ei->i_data));
6608c2ecf20Sopenharmony_ci	for (i = start; i <= end; i++)
6618c2ecf20Sopenharmony_ci		ei->i_data[i] = cpu_to_le32(blk++);
6628c2ecf20Sopenharmony_ci	ret2 = ext4_mark_inode_dirty(handle, inode);
6638c2ecf20Sopenharmony_ci	if (unlikely(ret2 && !ret))
6648c2ecf20Sopenharmony_ci		ret = ret2;
6658c2ecf20Sopenharmony_cierrout:
6668c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
6678c2ecf20Sopenharmony_ci	up_write(&EXT4_I(inode)->i_data_sem);
6688c2ecf20Sopenharmony_ciout_unlock:
6698c2ecf20Sopenharmony_ci	percpu_up_write(&sbi->s_writepages_rwsem);
6708c2ecf20Sopenharmony_ci	return ret;
6718c2ecf20Sopenharmony_ci}
672