]> Pileus Git - ~andy/linux/blobdiff - fs/ext4/migrate.c
Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / fs / ext4 / migrate.c
index 480acf4a085fa7be60982c8643e20675164ad8c4..49e8bdff9163e830931570f4c2660cea201ab3fd 100644 (file)
@@ -426,7 +426,6 @@ static int free_ext_block(handle_t *handle, struct inode *inode)
                        return retval;
        }
        return retval;
-
 }
 
 int ext4_ext_migrate(struct inode *inode)
@@ -606,3 +605,64 @@ out:
 
        return retval;
 }
+
+/*
+ * 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;
+
+       if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+                                      EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+               return -EOPNOTSUPP;
+
+       handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       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 || le16_to_cpu(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;
+               }
+       }
+
+       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);
+errout:
+       ext4_journal_stop(handle);
+       up_write(&EXT4_I(inode)->i_data_sem);
+       return ret;
+}