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