diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-04-03 22:04:52 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-04-03 22:04:52 -0400 |
commit | 996bb9fddd5b68d1dfb5e27d30ca2c7a72448596 (patch) | |
tree | a066fe717c593c2189f886612fbe1282cfb7fdcc /fs/ext4 | |
parent | d76a3a77113db020d9bb1e894822869410450bd9 (diff) |
ext4: support simple conversion of extent-mapped inodes to use i_blocks
In order to make it simpler to test the code which support
i_blocks/indirect-mapped inodes, support the conversion of inodes
which are less than 12 blocks and which are contained in no more than
a single extent.
The primary intended use of this code is to converting freshly created
zero-length files and empty directories.
Note that the version of chattr in e2fsprogs 1.42.7 and earlier has a
check that prevents the clearing of the extent flag. A simple patch
which allows "chattr -e <file>" to work will be checked into the
e2fsprogs git repository.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/extents.c | 59 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 20 |
3 files changed, 69 insertions, 13 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index d05ba3886f33..73f3e60f7078 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -403,7 +403,7 @@ struct flex_groups { | |||
403 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ | 403 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ |
404 | 404 | ||
405 | #define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */ | 405 | #define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */ |
406 | #define EXT4_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */ | 406 | #define EXT4_FL_USER_MODIFIABLE 0x004380FF /* User modifiable flags */ |
407 | 407 | ||
408 | /* Flags that should be inherited by new inodes from their parent. */ | 408 | /* Flags that should be inherited by new inodes from their parent. */ |
409 | #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ | 409 | #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ |
@@ -2608,6 +2608,7 @@ extern int ext4_find_delalloc_range(struct inode *inode, | |||
2608 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); | 2608 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); |
2609 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 2609 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
2610 | __u64 start, __u64 len); | 2610 | __u64 start, __u64 len); |
2611 | extern int ext4_ind_migrate(struct inode *inode); | ||
2611 | 2612 | ||
2612 | 2613 | ||
2613 | /* move_extent.c */ | 2614 | /* move_extent.c */ |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index cbbe8a4deac6..235246719074 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4610,3 +4610,62 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
4610 | 4610 | ||
4611 | return error; | 4611 | return error; |
4612 | } | 4612 | } |
4613 | |||
4614 | /* | ||
4615 | * Migrate a simple extent-based inode to use the i_blocks[] array | ||
4616 | */ | ||
4617 | int ext4_ind_migrate(struct inode *inode) | ||
4618 | { | ||
4619 | struct ext4_extent_header *eh; | ||
4620 | struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; | ||
4621 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
4622 | struct ext4_extent *ex; | ||
4623 | unsigned int i, len; | ||
4624 | ext4_fsblk_t blk; | ||
4625 | handle_t *handle; | ||
4626 | int ret; | ||
4627 | |||
4628 | if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb, | ||
4629 | EXT4_FEATURE_INCOMPAT_EXTENTS) || | ||
4630 | (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) | ||
4631 | return -EINVAL; | ||
4632 | |||
4633 | down_write(&EXT4_I(inode)->i_data_sem); | ||
4634 | ret = ext4_ext_check_inode(inode); | ||
4635 | if (ret) | ||
4636 | goto errout; | ||
4637 | |||
4638 | eh = ext_inode_hdr(inode); | ||
4639 | ex = EXT_FIRST_EXTENT(eh); | ||
4640 | if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS || | ||
4641 | eh->eh_depth != 0 || eh->eh_entries > 1) { | ||
4642 | ret = -EOPNOTSUPP; | ||
4643 | goto errout; | ||
4644 | } | ||
4645 | if (eh->eh_entries == 0) | ||
4646 | blk = len = 0; | ||
4647 | else { | ||
4648 | len = le16_to_cpu(ex->ee_len); | ||
4649 | blk = ext4_ext_pblock(ex); | ||
4650 | if (len > EXT4_NDIR_BLOCKS) { | ||
4651 | ret = -EOPNOTSUPP; | ||
4652 | goto errout; | ||
4653 | } | ||
4654 | } | ||
4655 | |||
4656 | handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1); | ||
4657 | if (IS_ERR(handle)) { | ||
4658 | ret = PTR_ERR(handle); | ||
4659 | goto errout; | ||
4660 | } | ||
4661 | |||
4662 | ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); | ||
4663 | memset(ei->i_data, 0, sizeof(ei->i_data)); | ||
4664 | for (i=0; i < len; i++) | ||
4665 | ei->i_data[i] = cpu_to_le32(blk++); | ||
4666 | ext4_mark_inode_dirty(handle, inode); | ||
4667 | ext4_journal_stop(handle); | ||
4668 | errout: | ||
4669 | up_write(&EXT4_I(inode)->i_data_sem); | ||
4670 | return ret; | ||
4671 | } | ||
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 721f4d33e148..a07b7bc0856a 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -83,17 +83,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
83 | if (!capable(CAP_SYS_RESOURCE)) | 83 | if (!capable(CAP_SYS_RESOURCE)) |
84 | goto flags_out; | 84 | goto flags_out; |
85 | } | 85 | } |
86 | if (oldflags & EXT4_EXTENTS_FL) { | 86 | if ((flags ^ oldflags) & EXT4_EXTENTS_FL) |
87 | /* We don't support clearning extent flags */ | ||
88 | if (!(flags & EXT4_EXTENTS_FL)) { | ||
89 | err = -EOPNOTSUPP; | ||
90 | goto flags_out; | ||
91 | } | ||
92 | } else if (flags & EXT4_EXTENTS_FL) { | ||
93 | /* migrate the file */ | ||
94 | migrate = 1; | 87 | migrate = 1; |
95 | flags &= ~EXT4_EXTENTS_FL; | ||
96 | } | ||
97 | 88 | ||
98 | if (flags & EXT4_EOFBLOCKS_FL) { | 89 | if (flags & EXT4_EOFBLOCKS_FL) { |
99 | /* we don't support adding EOFBLOCKS flag */ | 90 | /* we don't support adding EOFBLOCKS flag */ |
@@ -137,8 +128,13 @@ flags_err: | |||
137 | err = ext4_change_inode_journal_flag(inode, jflag); | 128 | err = ext4_change_inode_journal_flag(inode, jflag); |
138 | if (err) | 129 | if (err) |
139 | goto flags_out; | 130 | goto flags_out; |
140 | if (migrate) | 131 | if (migrate) { |
141 | err = ext4_ext_migrate(inode); | 132 | if (flags & EXT4_EXTENTS_FL) |
133 | err = ext4_ext_migrate(inode); | ||
134 | else | ||
135 | err = ext4_ind_migrate(inode); | ||
136 | } | ||
137 | |||
142 | flags_out: | 138 | flags_out: |
143 | mutex_unlock(&inode->i_mutex); | 139 | mutex_unlock(&inode->i_mutex); |
144 | mnt_drop_write_file(filp); | 140 | mnt_drop_write_file(filp); |