|
@@ -4610,3 +4610,62 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|
|
|
|
|
return error;
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Migrate a simple extent-based inode to use the i_blocks[] array
|
|
|
+ */
|
|
|
+int ext4_ind_migrate(struct inode *inode)
|
|
|
+{
|
|
|
+ struct ext4_extent_header *eh;
|
|
|
+ struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
|
|
+ struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
+ struct ext4_extent *ex;
|
|
|
+ unsigned int i, len;
|
|
|
+ ext4_fsblk_t blk;
|
|
|
+ handle_t *handle;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
|
|
|
+ EXT4_FEATURE_INCOMPAT_EXTENTS) ||
|
|
|
+ (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ down_write(&EXT4_I(inode)->i_data_sem);
|
|
|
+ ret = ext4_ext_check_inode(inode);
|
|
|
+ if (ret)
|
|
|
+ goto errout;
|
|
|
+
|
|
|
+ eh = ext_inode_hdr(inode);
|
|
|
+ ex = EXT_FIRST_EXTENT(eh);
|
|
|
+ if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS ||
|
|
|
+ eh->eh_depth != 0 || eh->eh_entries > 1) {
|
|
|
+ ret = -EOPNOTSUPP;
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ if (eh->eh_entries == 0)
|
|
|
+ blk = len = 0;
|
|
|
+ else {
|
|
|
+ len = le16_to_cpu(ex->ee_len);
|
|
|
+ blk = ext4_ext_pblock(ex);
|
|
|
+ if (len > EXT4_NDIR_BLOCKS) {
|
|
|
+ ret = -EOPNOTSUPP;
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
|
|
|
+ if (IS_ERR(handle)) {
|
|
|
+ ret = PTR_ERR(handle);
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
|
|
|
+ memset(ei->i_data, 0, sizeof(ei->i_data));
|
|
|
+ for (i=0; i < len; i++)
|
|
|
+ ei->i_data[i] = cpu_to_le32(blk++);
|
|
|
+ ext4_mark_inode_dirty(handle, inode);
|
|
|
+ ext4_journal_stop(handle);
|
|
|
+errout:
|
|
|
+ up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
+ return ret;
|
|
|
+}
|