diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-02-26 01:04:07 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-02-26 01:04:07 -0500 |
commit | ccd2506bd43113659aa904d5bea5d1300605e2a6 (patch) | |
tree | 99a95645b3c2c092427b7c537c5628d502cd9c22 /fs | |
parent | f63e6005bc63acc0a6bc3bdb8f971dcfbd827185 (diff) |
ext4: add EXT4_IOC_ALLOC_DA_BLKS ioctl
Add an ioctl which forces all of the delay allocated blocks to be
allocated. This also provides a function ext4_alloc_da_blocks() which
will be used by the following commits to force files to be fully
allocated to preserve application-expected ext3 behaviour.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/inode.c | 42 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 14 |
3 files changed, 59 insertions, 0 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 096456c8559b..b0ea70cc94db 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -317,7 +317,9 @@ struct ext4_new_group_data { | |||
317 | #define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) | 317 | #define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) |
318 | #define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) | 318 | #define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) |
319 | #define EXT4_IOC_MIGRATE _IO('f', 9) | 319 | #define EXT4_IOC_MIGRATE _IO('f', 9) |
320 | /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ | ||
320 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ | 321 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ |
322 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) | ||
321 | 323 | ||
322 | /* | 324 | /* |
323 | * ioctl commands in 32 bit emulation | 325 | * ioctl commands in 32 bit emulation |
@@ -1094,6 +1096,7 @@ extern int ext4_can_truncate(struct inode *inode); | |||
1094 | extern void ext4_truncate(struct inode *); | 1096 | extern void ext4_truncate(struct inode *); |
1095 | extern void ext4_set_inode_flags(struct inode *); | 1097 | extern void ext4_set_inode_flags(struct inode *); |
1096 | extern void ext4_get_inode_flags(struct ext4_inode_info *); | 1098 | extern void ext4_get_inode_flags(struct ext4_inode_info *); |
1099 | extern int ext4_alloc_da_blocks(struct inode *inode); | ||
1097 | extern void ext4_set_aops(struct inode *inode); | 1100 | extern void ext4_set_aops(struct inode *inode); |
1098 | extern int ext4_writepage_trans_blocks(struct inode *); | 1101 | extern int ext4_writepage_trans_blocks(struct inode *); |
1099 | extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); | 1102 | extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 24d0f9d2b320..8dd3d5de5861 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2837,6 +2837,48 @@ out: | |||
2837 | return; | 2837 | return; |
2838 | } | 2838 | } |
2839 | 2839 | ||
2840 | /* | ||
2841 | * Force all delayed allocation blocks to be allocated for a given inode. | ||
2842 | */ | ||
2843 | int ext4_alloc_da_blocks(struct inode *inode) | ||
2844 | { | ||
2845 | if (!EXT4_I(inode)->i_reserved_data_blocks && | ||
2846 | !EXT4_I(inode)->i_reserved_meta_blocks) | ||
2847 | return 0; | ||
2848 | |||
2849 | /* | ||
2850 | * We do something simple for now. The filemap_flush() will | ||
2851 | * also start triggering a write of the data blocks, which is | ||
2852 | * not strictly speaking necessary (and for users of | ||
2853 | * laptop_mode, not even desirable). However, to do otherwise | ||
2854 | * would require replicating code paths in: | ||
2855 | * | ||
2856 | * ext4_da_writepages() -> | ||
2857 | * write_cache_pages() ---> (via passed in callback function) | ||
2858 | * __mpage_da_writepage() --> | ||
2859 | * mpage_add_bh_to_extent() | ||
2860 | * mpage_da_map_blocks() | ||
2861 | * | ||
2862 | * The problem is that write_cache_pages(), located in | ||
2863 | * mm/page-writeback.c, marks pages clean in preparation for | ||
2864 | * doing I/O, which is not desirable if we're not planning on | ||
2865 | * doing I/O at all. | ||
2866 | * | ||
2867 | * We could call write_cache_pages(), and then redirty all of | ||
2868 | * the pages by calling redirty_page_for_writeback() but that | ||
2869 | * would be ugly in the extreme. So instead we would need to | ||
2870 | * replicate parts of the code in the above functions, | ||
2871 | * simplifying them becuase we wouldn't actually intend to | ||
2872 | * write out the pages, but rather only collect contiguous | ||
2873 | * logical block extents, call the multi-block allocator, and | ||
2874 | * then update the buffer heads with the block allocations. | ||
2875 | * | ||
2876 | * For now, though, we'll cheat by calling filemap_flush(), | ||
2877 | * which will map the blocks, and start the I/O, but not | ||
2878 | * actually wait for the I/O to complete. | ||
2879 | */ | ||
2880 | return filemap_flush(inode->i_mapping); | ||
2881 | } | ||
2840 | 2882 | ||
2841 | /* | 2883 | /* |
2842 | * bmap() is special. It gets used by applications such as lilo and by | 2884 | * bmap() is special. It gets used by applications such as lilo and by |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 22dd29f3ebc9..91e75f7a9e73 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -262,6 +262,20 @@ setversion_out: | |||
262 | return err; | 262 | return err; |
263 | } | 263 | } |
264 | 264 | ||
265 | case EXT4_IOC_ALLOC_DA_BLKS: | ||
266 | { | ||
267 | int err; | ||
268 | if (!is_owner_or_cap(inode)) | ||
269 | return -EACCES; | ||
270 | |||
271 | err = mnt_want_write(filp->f_path.mnt); | ||
272 | if (err) | ||
273 | return err; | ||
274 | err = ext4_alloc_da_blocks(inode); | ||
275 | mnt_drop_write(filp->f_path.mnt); | ||
276 | return err; | ||
277 | } | ||
278 | |||
265 | default: | 279 | default: |
266 | return -ENOTTY; | 280 | return -ENOTTY; |
267 | } | 281 | } |