LCOV - code coverage report
Current view: top level - fs/ext4 - migrate.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 0 345 0.0 %
Date: 2023-07-31 20:08:27 Functions: 0 13 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: LGPL-2.1
       2             : /*
       3             :  * Copyright IBM Corporation, 2007
       4             :  * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
       5             :  *
       6             :  */
       7             : 
       8             : #include <linux/slab.h>
       9             : #include "ext4_jbd2.h"
      10             : #include "ext4_extents.h"
      11             : 
      12             : /*
      13             :  * The contiguous blocks details which can be
      14             :  * represented by a single extent
      15             :  */
      16             : struct migrate_struct {
      17             :         ext4_lblk_t first_block, last_block, curr_block;
      18             :         ext4_fsblk_t first_pblock, last_pblock;
      19             : };
      20             : 
      21           0 : static int finish_range(handle_t *handle, struct inode *inode,
      22             :                                 struct migrate_struct *lb)
      23             : 
      24             : {
      25           0 :         int retval = 0, needed;
      26           0 :         struct ext4_extent newext;
      27           0 :         struct ext4_ext_path *path;
      28           0 :         if (lb->first_pblock == 0)
      29             :                 return 0;
      30             : 
      31             :         /* Add the extent to temp inode*/
      32           0 :         newext.ee_block = cpu_to_le32(lb->first_block);
      33           0 :         newext.ee_len   = cpu_to_le16(lb->last_block - lb->first_block + 1);
      34           0 :         ext4_ext_store_pblock(&newext, lb->first_pblock);
      35             :         /* Locking only for convenience since we are operating on temp inode */
      36           0 :         down_write(&EXT4_I(inode)->i_data_sem);
      37           0 :         path = ext4_find_extent(inode, lb->first_block, NULL, 0);
      38           0 :         if (IS_ERR(path)) {
      39           0 :                 retval = PTR_ERR(path);
      40           0 :                 path = NULL;
      41           0 :                 goto err_out;
      42             :         }
      43             : 
      44             :         /*
      45             :          * Calculate the credit needed to inserting this extent
      46             :          * Since we are doing this in loop we may accumulate extra
      47             :          * credit. But below we try to not accumulate too much
      48             :          * of them by restarting the journal.
      49             :          */
      50           0 :         needed = ext4_ext_calc_credits_for_single_extent(inode,
      51           0 :                     lb->last_block - lb->first_block + 1, path);
      52             : 
      53           0 :         retval = ext4_datasem_ensure_credits(handle, inode, needed, needed, 0);
      54           0 :         if (retval < 0)
      55           0 :                 goto err_out;
      56           0 :         retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
      57           0 : err_out:
      58           0 :         up_write((&EXT4_I(inode)->i_data_sem));
      59           0 :         ext4_free_ext_path(path);
      60           0 :         lb->first_pblock = 0;
      61           0 :         return retval;
      62             : }
      63             : 
      64           0 : static int update_extent_range(handle_t *handle, struct inode *inode,
      65             :                                ext4_fsblk_t pblock, struct migrate_struct *lb)
      66             : {
      67           0 :         int retval;
      68             :         /*
      69             :          * See if we can add on to the existing range (if it exists)
      70             :          */
      71           0 :         if (lb->first_pblock &&
      72           0 :                 (lb->last_pblock+1 == pblock) &&
      73           0 :                 (lb->last_block+1 == lb->curr_block)) {
      74           0 :                 lb->last_pblock = pblock;
      75           0 :                 lb->last_block = lb->curr_block;
      76           0 :                 lb->curr_block++;
      77           0 :                 return 0;
      78             :         }
      79             :         /*
      80             :          * Start a new range.
      81             :          */
      82           0 :         retval = finish_range(handle, inode, lb);
      83           0 :         lb->first_pblock = lb->last_pblock = pblock;
      84           0 :         lb->first_block = lb->last_block = lb->curr_block;
      85           0 :         lb->curr_block++;
      86           0 :         return retval;
      87             : }
      88             : 
      89           0 : static int update_ind_extent_range(handle_t *handle, struct inode *inode,
      90             :                                    ext4_fsblk_t pblock,
      91             :                                    struct migrate_struct *lb)
      92             : {
      93           0 :         struct buffer_head *bh;
      94           0 :         __le32 *i_data;
      95           0 :         int i, retval = 0;
      96           0 :         unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
      97             : 
      98           0 :         bh = ext4_sb_bread(inode->i_sb, pblock, 0);
      99           0 :         if (IS_ERR(bh))
     100           0 :                 return PTR_ERR(bh);
     101             : 
     102           0 :         i_data = (__le32 *)bh->b_data;
     103           0 :         for (i = 0; i < max_entries; i++) {
     104           0 :                 if (i_data[i]) {
     105           0 :                         retval = update_extent_range(handle, inode,
     106             :                                                 le32_to_cpu(i_data[i]), lb);
     107           0 :                         if (retval)
     108             :                                 break;
     109             :                 } else {
     110           0 :                         lb->curr_block++;
     111             :                 }
     112             :         }
     113           0 :         put_bh(bh);
     114           0 :         return retval;
     115             : 
     116             : }
     117             : 
     118           0 : static int update_dind_extent_range(handle_t *handle, struct inode *inode,
     119             :                                     ext4_fsblk_t pblock,
     120             :                                     struct migrate_struct *lb)
     121             : {
     122           0 :         struct buffer_head *bh;
     123           0 :         __le32 *i_data;
     124           0 :         int i, retval = 0;
     125           0 :         unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
     126             : 
     127           0 :         bh = ext4_sb_bread(inode->i_sb, pblock, 0);
     128           0 :         if (IS_ERR(bh))
     129           0 :                 return PTR_ERR(bh);
     130             : 
     131           0 :         i_data = (__le32 *)bh->b_data;
     132           0 :         for (i = 0; i < max_entries; i++) {
     133           0 :                 if (i_data[i]) {
     134           0 :                         retval = update_ind_extent_range(handle, inode,
     135             :                                                 le32_to_cpu(i_data[i]), lb);
     136           0 :                         if (retval)
     137             :                                 break;
     138             :                 } else {
     139             :                         /* Only update the file block number */
     140           0 :                         lb->curr_block += max_entries;
     141             :                 }
     142             :         }
     143           0 :         put_bh(bh);
     144           0 :         return retval;
     145             : 
     146             : }
     147             : 
     148           0 : static int update_tind_extent_range(handle_t *handle, struct inode *inode,
     149             :                                     ext4_fsblk_t pblock,
     150             :                                     struct migrate_struct *lb)
     151             : {
     152           0 :         struct buffer_head *bh;
     153           0 :         __le32 *i_data;
     154           0 :         int i, retval = 0;
     155           0 :         unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
     156             : 
     157           0 :         bh = ext4_sb_bread(inode->i_sb, pblock, 0);
     158           0 :         if (IS_ERR(bh))
     159           0 :                 return PTR_ERR(bh);
     160             : 
     161           0 :         i_data = (__le32 *)bh->b_data;
     162           0 :         for (i = 0; i < max_entries; i++) {
     163           0 :                 if (i_data[i]) {
     164           0 :                         retval = update_dind_extent_range(handle, inode,
     165             :                                                 le32_to_cpu(i_data[i]), lb);
     166           0 :                         if (retval)
     167             :                                 break;
     168             :                 } else {
     169             :                         /* Only update the file block number */
     170           0 :                         lb->curr_block += max_entries * max_entries;
     171             :                 }
     172             :         }
     173           0 :         put_bh(bh);
     174           0 :         return retval;
     175             : 
     176             : }
     177             : 
     178           0 : static int free_dind_blocks(handle_t *handle,
     179             :                                 struct inode *inode, __le32 i_data)
     180             : {
     181           0 :         int i;
     182           0 :         __le32 *tmp_idata;
     183           0 :         struct buffer_head *bh;
     184           0 :         struct super_block *sb = inode->i_sb;
     185           0 :         unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
     186           0 :         int err;
     187             : 
     188           0 :         bh = ext4_sb_bread(sb, le32_to_cpu(i_data), 0);
     189           0 :         if (IS_ERR(bh))
     190           0 :                 return PTR_ERR(bh);
     191             : 
     192           0 :         tmp_idata = (__le32 *)bh->b_data;
     193           0 :         for (i = 0; i < max_entries; i++) {
     194           0 :                 if (tmp_idata[i]) {
     195           0 :                         err = ext4_journal_ensure_credits(handle,
     196             :                                 EXT4_RESERVE_TRANS_BLOCKS,
     197             :                                 ext4_free_metadata_revoke_credits(sb, 1));
     198           0 :                         if (err < 0) {
     199           0 :                                 put_bh(bh);
     200           0 :                                 return err;
     201             :                         }
     202           0 :                         ext4_free_blocks(handle, inode, NULL,
     203           0 :                                          le32_to_cpu(tmp_idata[i]), 1,
     204             :                                          EXT4_FREE_BLOCKS_METADATA |
     205             :                                          EXT4_FREE_BLOCKS_FORGET);
     206             :                 }
     207             :         }
     208           0 :         put_bh(bh);
     209           0 :         err = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
     210             :                                 ext4_free_metadata_revoke_credits(sb, 1));
     211           0 :         if (err < 0)
     212             :                 return err;
     213           0 :         ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
     214             :                          EXT4_FREE_BLOCKS_METADATA |
     215             :                          EXT4_FREE_BLOCKS_FORGET);
     216           0 :         return 0;
     217             : }
     218             : 
     219           0 : static int free_tind_blocks(handle_t *handle,
     220             :                                 struct inode *inode, __le32 i_data)
     221             : {
     222           0 :         int i, retval = 0;
     223           0 :         __le32 *tmp_idata;
     224           0 :         struct buffer_head *bh;
     225           0 :         unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
     226             : 
     227           0 :         bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
     228           0 :         if (IS_ERR(bh))
     229           0 :                 return PTR_ERR(bh);
     230             : 
     231           0 :         tmp_idata = (__le32 *)bh->b_data;
     232           0 :         for (i = 0; i < max_entries; i++) {
     233           0 :                 if (tmp_idata[i]) {
     234           0 :                         retval = free_dind_blocks(handle,
     235             :                                         inode, tmp_idata[i]);
     236           0 :                         if (retval) {
     237           0 :                                 put_bh(bh);
     238           0 :                                 return retval;
     239             :                         }
     240             :                 }
     241             :         }
     242           0 :         put_bh(bh);
     243           0 :         retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
     244             :                         ext4_free_metadata_revoke_credits(inode->i_sb, 1));
     245           0 :         if (retval < 0)
     246             :                 return retval;
     247           0 :         ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
     248             :                          EXT4_FREE_BLOCKS_METADATA |
     249             :                          EXT4_FREE_BLOCKS_FORGET);
     250           0 :         return 0;
     251             : }
     252             : 
     253           0 : static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
     254             : {
     255           0 :         int retval;
     256             : 
     257             :         /* ei->i_data[EXT4_IND_BLOCK] */
     258           0 :         if (i_data[0]) {
     259           0 :                 retval = ext4_journal_ensure_credits(handle,
     260             :                         EXT4_RESERVE_TRANS_BLOCKS,
     261             :                         ext4_free_metadata_revoke_credits(inode->i_sb, 1));
     262           0 :                 if (retval < 0)
     263             :                         return retval;
     264           0 :                 ext4_free_blocks(handle, inode, NULL,
     265           0 :                                 le32_to_cpu(i_data[0]), 1,
     266             :                                  EXT4_FREE_BLOCKS_METADATA |
     267             :                                  EXT4_FREE_BLOCKS_FORGET);
     268             :         }
     269             : 
     270             :         /* ei->i_data[EXT4_DIND_BLOCK] */
     271           0 :         if (i_data[1]) {
     272           0 :                 retval = free_dind_blocks(handle, inode, i_data[1]);
     273           0 :                 if (retval)
     274             :                         return retval;
     275             :         }
     276             : 
     277             :         /* ei->i_data[EXT4_TIND_BLOCK] */
     278           0 :         if (i_data[2]) {
     279           0 :                 retval = free_tind_blocks(handle, inode, i_data[2]);
     280           0 :                 if (retval)
     281           0 :                         return retval;
     282             :         }
     283             :         return 0;
     284             : }
     285             : 
     286           0 : static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
     287             :                                                 struct inode *tmp_inode)
     288             : {
     289           0 :         int retval, retval2 = 0;
     290           0 :         __le32  i_data[3];
     291           0 :         struct ext4_inode_info *ei = EXT4_I(inode);
     292           0 :         struct ext4_inode_info *tmp_ei = EXT4_I(tmp_inode);
     293             : 
     294             :         /*
     295             :          * One credit accounted for writing the
     296             :          * i_data field of the original inode
     297             :          */
     298           0 :         retval = ext4_journal_ensure_credits(handle, 1, 0);
     299           0 :         if (retval < 0)
     300           0 :                 goto err_out;
     301             : 
     302           0 :         i_data[0] = ei->i_data[EXT4_IND_BLOCK];
     303           0 :         i_data[1] = ei->i_data[EXT4_DIND_BLOCK];
     304           0 :         i_data[2] = ei->i_data[EXT4_TIND_BLOCK];
     305             : 
     306           0 :         down_write(&EXT4_I(inode)->i_data_sem);
     307             :         /*
     308             :          * if EXT4_STATE_EXT_MIGRATE is cleared a block allocation
     309             :          * happened after we started the migrate. We need to
     310             :          * fail the migrate
     311             :          */
     312           0 :         if (!ext4_test_inode_state(inode, EXT4_STATE_EXT_MIGRATE)) {
     313           0 :                 retval = -EAGAIN;
     314           0 :                 up_write(&EXT4_I(inode)->i_data_sem);
     315           0 :                 goto err_out;
     316             :         } else
     317           0 :                 ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
     318             :         /*
     319             :          * We have the extent map build with the tmp inode.
     320             :          * Now copy the i_data across
     321             :          */
     322           0 :         ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
     323           0 :         memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));
     324             : 
     325             :         /*
     326             :          * Update i_blocks with the new blocks that got
     327             :          * allocated while adding extents for extent index
     328             :          * blocks.
     329             :          *
     330             :          * While converting to extents we need not
     331             :          * update the original inode i_blocks for extent blocks
     332             :          * via quota APIs. The quota update happened via tmp_inode already.
     333             :          */
     334           0 :         spin_lock(&inode->i_lock);
     335           0 :         inode->i_blocks += tmp_inode->i_blocks;
     336           0 :         spin_unlock(&inode->i_lock);
     337           0 :         up_write(&EXT4_I(inode)->i_data_sem);
     338             : 
     339             :         /*
     340             :          * We mark the inode dirty after, because we decrement the
     341             :          * i_blocks when freeing the indirect meta-data blocks
     342             :          */
     343           0 :         retval = free_ind_block(handle, inode, i_data);
     344           0 :         retval2 = ext4_mark_inode_dirty(handle, inode);
     345           0 :         if (unlikely(retval2 && !retval))
     346           0 :                 retval = retval2;
     347             : 
     348           0 : err_out:
     349           0 :         return retval;
     350             : }
     351             : 
     352           0 : static int free_ext_idx(handle_t *handle, struct inode *inode,
     353             :                                         struct ext4_extent_idx *ix)
     354             : {
     355           0 :         int i, retval = 0;
     356           0 :         ext4_fsblk_t block;
     357           0 :         struct buffer_head *bh;
     358           0 :         struct ext4_extent_header *eh;
     359             : 
     360           0 :         block = ext4_idx_pblock(ix);
     361           0 :         bh = ext4_sb_bread(inode->i_sb, block, 0);
     362           0 :         if (IS_ERR(bh))
     363           0 :                 return PTR_ERR(bh);
     364             : 
     365           0 :         eh = (struct ext4_extent_header *)bh->b_data;
     366           0 :         if (eh->eh_depth != 0) {
     367           0 :                 ix = EXT_FIRST_INDEX(eh);
     368           0 :                 for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
     369           0 :                         retval = free_ext_idx(handle, inode, ix);
     370           0 :                         if (retval) {
     371           0 :                                 put_bh(bh);
     372           0 :                                 return retval;
     373             :                         }
     374             :                 }
     375             :         }
     376           0 :         put_bh(bh);
     377           0 :         retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS,
     378             :                         ext4_free_metadata_revoke_credits(inode->i_sb, 1));
     379           0 :         if (retval < 0)
     380             :                 return retval;
     381           0 :         ext4_free_blocks(handle, inode, NULL, block, 1,
     382             :                          EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
     383           0 :         return 0;
     384             : }
     385             : 
     386             : /*
     387             :  * Free the extent meta data blocks only
     388             :  */
     389           0 : static int free_ext_block(handle_t *handle, struct inode *inode)
     390             : {
     391           0 :         int i, retval = 0;
     392           0 :         struct ext4_inode_info *ei = EXT4_I(inode);
     393           0 :         struct ext4_extent_header *eh = (struct ext4_extent_header *)ei->i_data;
     394           0 :         struct ext4_extent_idx *ix;
     395           0 :         if (eh->eh_depth == 0)
     396             :                 /*
     397             :                  * No extra blocks allocated for extent meta data
     398             :                  */
     399             :                 return 0;
     400           0 :         ix = EXT_FIRST_INDEX(eh);
     401           0 :         for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
     402           0 :                 retval = free_ext_idx(handle, inode, ix);
     403           0 :                 if (retval)
     404           0 :                         return retval;
     405             :         }
     406             :         return retval;
     407             : }
     408             : 
     409           0 : int ext4_ext_migrate(struct inode *inode)
     410             : {
     411           0 :         handle_t *handle;
     412           0 :         int retval = 0, i;
     413           0 :         __le32 *i_data;
     414           0 :         struct ext4_inode_info *ei;
     415           0 :         struct inode *tmp_inode = NULL;
     416           0 :         struct migrate_struct lb;
     417           0 :         unsigned long max_entries;
     418           0 :         __u32 goal, tmp_csum_seed;
     419           0 :         uid_t owner[2];
     420           0 :         int alloc_ctx;
     421             : 
     422             :         /*
     423             :          * If the filesystem does not support extents, or the inode
     424             :          * already is extent-based, error out.
     425             :          */
     426           0 :         if (!ext4_has_feature_extents(inode->i_sb) ||
     427             :             ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
     428             :             ext4_has_inline_data(inode))
     429             :                 return -EINVAL;
     430             : 
     431           0 :         if (S_ISLNK(inode->i_mode) && inode->i_blocks == 0)
     432             :                 /*
     433             :                  * don't migrate fast symlink
     434             :                  */
     435             :                 return retval;
     436             : 
     437           0 :         alloc_ctx = ext4_writepages_down_write(inode->i_sb);
     438             : 
     439             :         /*
     440             :          * Worst case we can touch the allocation bitmaps and a block
     441             :          * group descriptor block.  We do need to worry about
     442             :          * credits for modifying the quota inode.
     443             :          */
     444           0 :         handle = ext4_journal_start(inode, EXT4_HT_MIGRATE,
     445             :                 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb));
     446             : 
     447           0 :         if (IS_ERR(handle)) {
     448           0 :                 retval = PTR_ERR(handle);
     449           0 :                 goto out_unlock;
     450             :         }
     451           0 :         goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
     452           0 :                 EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
     453           0 :         owner[0] = i_uid_read(inode);
     454           0 :         owner[1] = i_gid_read(inode);
     455           0 :         tmp_inode = ext4_new_inode(handle, d_inode(inode->i_sb->s_root),
     456             :                                    S_IFREG, NULL, goal, owner, 0);
     457           0 :         if (IS_ERR(tmp_inode)) {
     458           0 :                 retval = PTR_ERR(tmp_inode);
     459           0 :                 ext4_journal_stop(handle);
     460           0 :                 goto out_unlock;
     461             :         }
     462             :         /*
     463             :          * Use the correct seed for checksum (i.e. the seed from 'inode').  This
     464             :          * is so that the metadata blocks will have the correct checksum after
     465             :          * the migration.
     466             :          */
     467           0 :         ei = EXT4_I(inode);
     468           0 :         tmp_csum_seed = EXT4_I(tmp_inode)->i_csum_seed;
     469           0 :         EXT4_I(tmp_inode)->i_csum_seed = ei->i_csum_seed;
     470           0 :         i_size_write(tmp_inode, i_size_read(inode));
     471             :         /*
     472             :          * Set the i_nlink to zero so it will be deleted later
     473             :          * when we drop inode reference.
     474             :          */
     475           0 :         clear_nlink(tmp_inode);
     476             : 
     477           0 :         ext4_ext_tree_init(handle, tmp_inode);
     478           0 :         ext4_journal_stop(handle);
     479             : 
     480             :         /*
     481             :          * start with one credit accounted for
     482             :          * superblock modification.
     483             :          *
     484             :          * For the tmp_inode we already have committed the
     485             :          * transaction that created the inode. Later as and
     486             :          * when we add extents we extent the journal
     487             :          */
     488             :         /*
     489             :          * Even though we take i_rwsem we can still cause block
     490             :          * allocation via mmap write to holes. If we have allocated
     491             :          * new blocks we fail migrate.  New block allocation will
     492             :          * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
     493             :          * with i_data_sem held to prevent racing with block
     494             :          * allocation.
     495             :          */
     496           0 :         down_read(&EXT4_I(inode)->i_data_sem);
     497           0 :         ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
     498           0 :         up_read((&EXT4_I(inode)->i_data_sem));
     499             : 
     500           0 :         handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
     501           0 :         if (IS_ERR(handle)) {
     502           0 :                 retval = PTR_ERR(handle);
     503           0 :                 goto out_tmp_inode;
     504             :         }
     505             : 
     506           0 :         i_data = ei->i_data;
     507           0 :         memset(&lb, 0, sizeof(lb));
     508             : 
     509             :         /* 32 bit block address 4 bytes */
     510           0 :         max_entries = inode->i_sb->s_blocksize >> 2;
     511           0 :         for (i = 0; i < EXT4_NDIR_BLOCKS; i++) {
     512           0 :                 if (i_data[i]) {
     513           0 :                         retval = update_extent_range(handle, tmp_inode,
     514             :                                                 le32_to_cpu(i_data[i]), &lb);
     515           0 :                         if (retval)
     516           0 :                                 goto err_out;
     517             :                 } else
     518           0 :                         lb.curr_block++;
     519             :         }
     520           0 :         if (i_data[EXT4_IND_BLOCK]) {
     521           0 :                 retval = update_ind_extent_range(handle, tmp_inode,
     522             :                                 le32_to_cpu(i_data[EXT4_IND_BLOCK]), &lb);
     523           0 :                 if (retval)
     524           0 :                         goto err_out;
     525             :         } else
     526           0 :                 lb.curr_block += max_entries;
     527           0 :         if (i_data[EXT4_DIND_BLOCK]) {
     528           0 :                 retval = update_dind_extent_range(handle, tmp_inode,
     529             :                                 le32_to_cpu(i_data[EXT4_DIND_BLOCK]), &lb);
     530           0 :                 if (retval)
     531           0 :                         goto err_out;
     532             :         } else
     533           0 :                 lb.curr_block += max_entries * max_entries;
     534           0 :         if (i_data[EXT4_TIND_BLOCK]) {
     535           0 :                 retval = update_tind_extent_range(handle, tmp_inode,
     536             :                                 le32_to_cpu(i_data[EXT4_TIND_BLOCK]), &lb);
     537           0 :                 if (retval)
     538           0 :                         goto err_out;
     539             :         }
     540             :         /*
     541             :          * Build the last extent
     542             :          */
     543           0 :         retval = finish_range(handle, tmp_inode, &lb);
     544           0 : err_out:
     545           0 :         if (retval)
     546             :                 /*
     547             :                  * Failure case delete the extent information with the
     548             :                  * tmp_inode
     549             :                  */
     550           0 :                 free_ext_block(handle, tmp_inode);
     551             :         else {
     552           0 :                 retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
     553           0 :                 if (retval)
     554             :                         /*
     555             :                          * if we fail to swap inode data free the extent
     556             :                          * details of the tmp inode
     557             :                          */
     558           0 :                         free_ext_block(handle, tmp_inode);
     559             :         }
     560             : 
     561             :         /* We mark the tmp_inode dirty via ext4_ext_tree_init. */
     562           0 :         retval = ext4_journal_ensure_credits(handle, 1, 0);
     563           0 :         if (retval < 0)
     564           0 :                 goto out_stop;
     565             :         /*
     566             :          * Mark the tmp_inode as of size zero
     567             :          */
     568           0 :         i_size_write(tmp_inode, 0);
     569             : 
     570             :         /*
     571             :          * set the  i_blocks count to zero
     572             :          * so that the ext4_evict_inode() does the
     573             :          * right job
     574             :          *
     575             :          * We don't need to take the i_lock because
     576             :          * the inode is not visible to user space.
     577             :          */
     578           0 :         tmp_inode->i_blocks = 0;
     579           0 :         EXT4_I(tmp_inode)->i_csum_seed = tmp_csum_seed;
     580             : 
     581             :         /* Reset the extent details */
     582           0 :         ext4_ext_tree_init(handle, tmp_inode);
     583           0 : out_stop:
     584           0 :         ext4_journal_stop(handle);
     585           0 : out_tmp_inode:
     586           0 :         unlock_new_inode(tmp_inode);
     587           0 :         iput(tmp_inode);
     588           0 : out_unlock:
     589           0 :         ext4_writepages_up_write(inode->i_sb, alloc_ctx);
     590           0 :         return retval;
     591             : }
     592             : 
     593             : /*
     594             :  * Migrate a simple extent-based inode to use the i_blocks[] array
     595             :  */
     596           0 : int ext4_ind_migrate(struct inode *inode)
     597             : {
     598           0 :         struct ext4_extent_header       *eh;
     599           0 :         struct ext4_sb_info             *sbi = EXT4_SB(inode->i_sb);
     600           0 :         struct ext4_super_block         *es = sbi->s_es;
     601           0 :         struct ext4_inode_info          *ei = EXT4_I(inode);
     602           0 :         struct ext4_extent              *ex;
     603           0 :         unsigned int                    i, len;
     604           0 :         ext4_lblk_t                     start, end;
     605           0 :         ext4_fsblk_t                    blk;
     606           0 :         handle_t                        *handle;
     607           0 :         int                             ret, ret2 = 0;
     608           0 :         int                             alloc_ctx;
     609             : 
     610           0 :         if (!ext4_has_feature_extents(inode->i_sb) ||
     611             :             (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
     612             :                 return -EINVAL;
     613             : 
     614           0 :         if (ext4_has_feature_bigalloc(inode->i_sb))
     615             :                 return -EOPNOTSUPP;
     616             : 
     617             :         /*
     618             :          * In order to get correct extent info, force all delayed allocation
     619             :          * blocks to be allocated, otherwise delayed allocation blocks may not
     620             :          * be reflected and bypass the checks on extent header.
     621             :          */
     622           0 :         if (test_opt(inode->i_sb, DELALLOC))
     623           0 :                 ext4_alloc_da_blocks(inode);
     624             : 
     625           0 :         alloc_ctx = ext4_writepages_down_write(inode->i_sb);
     626             : 
     627           0 :         handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
     628           0 :         if (IS_ERR(handle)) {
     629           0 :                 ret = PTR_ERR(handle);
     630           0 :                 goto out_unlock;
     631             :         }
     632             : 
     633           0 :         down_write(&EXT4_I(inode)->i_data_sem);
     634           0 :         ret = ext4_ext_check_inode(inode);
     635           0 :         if (ret)
     636           0 :                 goto errout;
     637             : 
     638           0 :         eh = ext_inode_hdr(inode);
     639           0 :         ex  = EXT_FIRST_EXTENT(eh);
     640           0 :         if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS ||
     641           0 :             eh->eh_depth != 0 || le16_to_cpu(eh->eh_entries) > 1) {
     642           0 :                 ret = -EOPNOTSUPP;
     643           0 :                 goto errout;
     644             :         }
     645           0 :         if (eh->eh_entries == 0)
     646             :                 blk = len = start = end = 0;
     647             :         else {
     648           0 :                 len = le16_to_cpu(ex->ee_len);
     649           0 :                 blk = ext4_ext_pblock(ex);
     650           0 :                 start = le32_to_cpu(ex->ee_block);
     651           0 :                 end = start + len - 1;
     652           0 :                 if (end >= EXT4_NDIR_BLOCKS) {
     653           0 :                         ret = -EOPNOTSUPP;
     654           0 :                         goto errout;
     655             :                 }
     656             :         }
     657             : 
     658           0 :         ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
     659           0 :         memset(ei->i_data, 0, sizeof(ei->i_data));
     660           0 :         for (i = start; i <= end; i++)
     661           0 :                 ei->i_data[i] = cpu_to_le32(blk++);
     662           0 :         ret2 = ext4_mark_inode_dirty(handle, inode);
     663           0 :         if (unlikely(ret2 && !ret))
     664           0 :                 ret = ret2;
     665           0 : errout:
     666           0 :         ext4_journal_stop(handle);
     667           0 :         up_write(&EXT4_I(inode)->i_data_sem);
     668           0 : out_unlock:
     669           0 :         ext4_writepages_up_write(inode->i_sb, alloc_ctx);
     670           0 :         return ret;
     671             : }

Generated by: LCOV version 1.14