aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-04-03 12:47:17 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-03 12:47:17 -0400
commit819c4920b7e60ecfd6f0f61d890af4cdf3873d18 (patch)
tree85f995b14c7308080d196d85b9b3d148337a6382
parent26a4c0c6ccecf6814cf44f951c97222bd795bc1a (diff)
ext4: refactor truncate code
Move common code in ext4_ind_truncate() and ext4_ext_truncate() into ext4_truncate(). This saves over 60 lines of code. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h4
-rw-r--r--fs/ext4/extents.c60
-rw-r--r--fs/ext4/indirect.c88
-rw-r--r--fs/ext4/inode.c74
4 files changed, 78 insertions, 148 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0649253804c4..d05ba3886f33 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2109,7 +2109,7 @@ extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
2109 unsigned long nr_segs); 2109 unsigned long nr_segs);
2110extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); 2110extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
2111extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk); 2111extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk);
2112extern void ext4_ind_truncate(struct inode *inode); 2112extern void ext4_ind_truncate(handle_t *, struct inode *inode);
2113extern int ext4_free_hole_blocks(handle_t *handle, struct inode *inode, 2113extern int ext4_free_hole_blocks(handle_t *handle, struct inode *inode,
2114 ext4_lblk_t first, ext4_lblk_t stop); 2114 ext4_lblk_t first, ext4_lblk_t stop);
2115 2115
@@ -2575,7 +2575,7 @@ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
2575 int chunk); 2575 int chunk);
2576extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, 2576extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
2577 struct ext4_map_blocks *map, int flags); 2577 struct ext4_map_blocks *map, int flags);
2578extern void ext4_ext_truncate(struct inode *); 2578extern void ext4_ext_truncate(handle_t *, struct inode *);
2579extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, 2579extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
2580 ext4_lblk_t end); 2580 ext4_lblk_t end);
2581extern void ext4_ext_init(struct super_block *); 2581extern void ext4_ext_init(struct super_block *);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index d58365e40df7..cbbe8a4deac6 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4257,48 +4257,13 @@ out3:
4257 return err ? err : allocated; 4257 return err ? err : allocated;
4258} 4258}
4259 4259
4260void ext4_ext_truncate(struct inode *inode) 4260void ext4_ext_truncate(handle_t *handle, struct inode *inode)
4261{ 4261{
4262 struct address_space *mapping = inode->i_mapping;
4263 struct super_block *sb = inode->i_sb; 4262 struct super_block *sb = inode->i_sb;
4264 ext4_lblk_t last_block; 4263 ext4_lblk_t last_block;
4265 handle_t *handle;
4266 loff_t page_len;
4267 int err = 0; 4264 int err = 0;
4268 4265
4269 /* 4266 /*
4270 * finish any pending end_io work so we won't run the risk of
4271 * converting any truncated blocks to initialized later
4272 */
4273 ext4_flush_unwritten_io(inode);
4274
4275 /*
4276 * probably first extent we're gonna free will be last in block
4277 */
4278 err = ext4_writepage_trans_blocks(inode);
4279 handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, err);
4280 if (IS_ERR(handle))
4281 return;
4282
4283 if (inode->i_size % PAGE_CACHE_SIZE != 0) {
4284 page_len = PAGE_CACHE_SIZE -
4285 (inode->i_size & (PAGE_CACHE_SIZE - 1));
4286
4287 err = ext4_discard_partial_page_buffers(handle,
4288 mapping, inode->i_size, page_len, 0);
4289
4290 if (err)
4291 goto out_stop;
4292 }
4293
4294 if (ext4_orphan_add(handle, inode))
4295 goto out_stop;
4296
4297 down_write(&EXT4_I(inode)->i_data_sem);
4298
4299 ext4_discard_preallocations(inode);
4300
4301 /*
4302 * TODO: optimization is possible here. 4267 * TODO: optimization is possible here.
4303 * Probably we need not scan at all, 4268 * Probably we need not scan at all,
4304 * because page truncation is enough. 4269 * because page truncation is enough.
@@ -4313,29 +4278,6 @@ void ext4_ext_truncate(struct inode *inode)
4313 err = ext4_es_remove_extent(inode, last_block, 4278 err = ext4_es_remove_extent(inode, last_block,
4314 EXT_MAX_BLOCKS - last_block); 4279 EXT_MAX_BLOCKS - last_block);
4315 err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); 4280 err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
4316
4317 /* In a multi-transaction truncate, we only make the final
4318 * transaction synchronous.
4319 */
4320 if (IS_SYNC(inode))
4321 ext4_handle_sync(handle);
4322
4323 up_write(&EXT4_I(inode)->i_data_sem);
4324
4325out_stop:
4326 /*
4327 * If this was a simple ftruncate() and the file will remain alive,
4328 * then we need to clear up the orphan record which we created above.
4329 * However, if this was a real unlink then we were called by
4330 * ext4_delete_inode(), and we allow that function to clean up the
4331 * orphan info for us.
4332 */
4333 if (inode->i_nlink)
4334 ext4_orphan_del(handle, inode);
4335
4336 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
4337 ext4_mark_inode_dirty(handle, inode);
4338 ext4_journal_stop(handle);
4339} 4281}
4340 4282
4341static void ext4_falloc_update_inode(struct inode *inode, 4283static void ext4_falloc_update_inode(struct inode *inode,
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index d8846779f4ea..98be6f697463 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -806,26 +806,9 @@ int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk)
806 * be able to restart the transaction at a conventient checkpoint to make 806 * be able to restart the transaction at a conventient checkpoint to make
807 * sure we don't overflow the journal. 807 * sure we don't overflow the journal.
808 * 808 *
809 * start_transaction gets us a new handle for a truncate transaction, 809 * Try to extend this transaction for the purposes of truncation. If
810 * and extend_transaction tries to extend the existing one a bit. If
811 * extend fails, we need to propagate the failure up and restart the 810 * extend fails, we need to propagate the failure up and restart the
812 * transaction in the top-level truncate loop. --sct 811 * transaction in the top-level truncate loop. --sct
813 */
814static handle_t *start_transaction(struct inode *inode)
815{
816 handle_t *result;
817
818 result = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
819 ext4_blocks_for_truncate(inode));
820 if (!IS_ERR(result))
821 return result;
822
823 ext4_std_error(inode->i_sb, PTR_ERR(result));
824 return result;
825}
826
827/*
828 * Try to extend this transaction for the purposes of truncation.
829 * 812 *
830 * Returns 0 if we managed to create more room. If we can't create more 813 * Returns 0 if we managed to create more room. If we can't create more
831 * room, and the transaction must be restarted we return 1. 814 * room, and the transaction must be restarted we return 1.
@@ -1218,68 +1201,30 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
1218 } 1201 }
1219} 1202}
1220 1203
1221void ext4_ind_truncate(struct inode *inode) 1204void ext4_ind_truncate(handle_t *handle, struct inode *inode)
1222{ 1205{
1223 handle_t *handle;
1224 struct ext4_inode_info *ei = EXT4_I(inode); 1206 struct ext4_inode_info *ei = EXT4_I(inode);
1225 __le32 *i_data = ei->i_data; 1207 __le32 *i_data = ei->i_data;
1226 int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); 1208 int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
1227 struct address_space *mapping = inode->i_mapping;
1228 ext4_lblk_t offsets[4]; 1209 ext4_lblk_t offsets[4];
1229 Indirect chain[4]; 1210 Indirect chain[4];
1230 Indirect *partial; 1211 Indirect *partial;
1231 __le32 nr = 0; 1212 __le32 nr = 0;
1232 int n = 0; 1213 int n = 0;
1233 ext4_lblk_t last_block, max_block; 1214 ext4_lblk_t last_block, max_block;
1234 loff_t page_len;
1235 unsigned blocksize = inode->i_sb->s_blocksize; 1215 unsigned blocksize = inode->i_sb->s_blocksize;
1236 int err;
1237
1238 handle = start_transaction(inode);
1239 if (IS_ERR(handle))
1240 return; /* AKPM: return what? */
1241 1216
1242 last_block = (inode->i_size + blocksize-1) 1217 last_block = (inode->i_size + blocksize-1)
1243 >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); 1218 >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
1244 max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) 1219 max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
1245 >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); 1220 >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
1246 1221
1247 if (inode->i_size % PAGE_CACHE_SIZE != 0) {
1248 page_len = PAGE_CACHE_SIZE -
1249 (inode->i_size & (PAGE_CACHE_SIZE - 1));
1250
1251 err = ext4_discard_partial_page_buffers(handle,
1252 mapping, inode->i_size, page_len, 0);
1253
1254 if (err)
1255 goto out_stop;
1256 }
1257
1258 if (last_block != max_block) { 1222 if (last_block != max_block) {
1259 n = ext4_block_to_path(inode, last_block, offsets, NULL); 1223 n = ext4_block_to_path(inode, last_block, offsets, NULL);
1260 if (n == 0) 1224 if (n == 0)
1261 goto out_stop; /* error */ 1225 return;
1262 } 1226 }
1263 1227
1264 /*
1265 * OK. This truncate is going to happen. We add the inode to the
1266 * orphan list, so that if this truncate spans multiple transactions,
1267 * and we crash, we will resume the truncate when the filesystem
1268 * recovers. It also marks the inode dirty, to catch the new size.
1269 *
1270 * Implication: the file must always be in a sane, consistent
1271 * truncatable state while each transaction commits.
1272 */
1273 if (ext4_orphan_add(handle, inode))
1274 goto out_stop;
1275
1276 /*
1277 * From here we block out all ext4_get_block() callers who want to
1278 * modify the block allocation tree.
1279 */
1280 down_write(&ei->i_data_sem);
1281
1282 ext4_discard_preallocations(inode);
1283 ext4_es_remove_extent(inode, last_block, EXT_MAX_BLOCKS - last_block); 1228 ext4_es_remove_extent(inode, last_block, EXT_MAX_BLOCKS - last_block);
1284 1229
1285 /* 1230 /*
@@ -1296,7 +1241,7 @@ void ext4_ind_truncate(struct inode *inode)
1296 * It is unnecessary to free any data blocks if last_block is 1241 * It is unnecessary to free any data blocks if last_block is
1297 * equal to the indirect block limit. 1242 * equal to the indirect block limit.
1298 */ 1243 */
1299 goto out_unlock; 1244 return;
1300 } else if (n == 1) { /* direct blocks */ 1245 } else if (n == 1) { /* direct blocks */
1301 ext4_free_data(handle, inode, NULL, i_data+offsets[0], 1246 ext4_free_data(handle, inode, NULL, i_data+offsets[0],
1302 i_data + EXT4_NDIR_BLOCKS); 1247 i_data + EXT4_NDIR_BLOCKS);
@@ -1356,31 +1301,6 @@ do_indirects:
1356 case EXT4_TIND_BLOCK: 1301 case EXT4_TIND_BLOCK:
1357 ; 1302 ;
1358 } 1303 }
1359
1360out_unlock:
1361 up_write(&ei->i_data_sem);
1362 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
1363 ext4_mark_inode_dirty(handle, inode);
1364
1365 /*
1366 * In a multi-transaction truncate, we only make the final transaction
1367 * synchronous
1368 */
1369 if (IS_SYNC(inode))
1370 ext4_handle_sync(handle);
1371out_stop:
1372 /*
1373 * If this was a simple ftruncate(), and the file will remain alive
1374 * then we need to clear up the orphan record which we created above.
1375 * However, if this was a real unlink then we were called by
1376 * ext4_delete_inode(), and we allow that function to clean up the
1377 * orphan info for us.
1378 */
1379 if (inode->i_nlink)
1380 ext4_orphan_del(handle, inode);
1381
1382 ext4_journal_stop(handle);
1383 trace_ext4_truncate_exit(inode);
1384} 1304}
1385 1305
1386static int free_hole_blocks(handle_t *handle, struct inode *inode, 1306static int free_hole_blocks(handle_t *handle, struct inode *inode,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9bda50aa34e2..49c80e4ac5ac 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3738,9 +3738,9 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
3738 stop_block); 3738 stop_block);
3739 3739
3740 ext4_discard_preallocations(inode); 3740 ext4_discard_preallocations(inode);
3741 up_write(&EXT4_I(inode)->i_data_sem);
3741 if (IS_SYNC(inode)) 3742 if (IS_SYNC(inode))
3742 ext4_handle_sync(handle); 3743 ext4_handle_sync(handle);
3743 up_write(&EXT4_I(inode)->i_data_sem);
3744 inode->i_mtime = inode->i_ctime = ext4_current_time(inode); 3744 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
3745 ext4_mark_inode_dirty(handle, inode); 3745 ext4_mark_inode_dirty(handle, inode);
3746out_stop: 3746out_stop:
@@ -3782,6 +3782,12 @@ out_mutex:
3782 */ 3782 */
3783void ext4_truncate(struct inode *inode) 3783void ext4_truncate(struct inode *inode)
3784{ 3784{
3785 struct ext4_inode_info *ei = EXT4_I(inode);
3786 unsigned int credits;
3787 handle_t *handle;
3788 struct address_space *mapping = inode->i_mapping;
3789 loff_t page_len;
3790
3785 trace_ext4_truncate_enter(inode); 3791 trace_ext4_truncate_enter(inode);
3786 3792
3787 if (!ext4_can_truncate(inode)) 3793 if (!ext4_can_truncate(inode))
@@ -3800,10 +3806,72 @@ void ext4_truncate(struct inode *inode)
3800 return; 3806 return;
3801 } 3807 }
3802 3808
3809 /*
3810 * finish any pending end_io work so we won't run the risk of
3811 * converting any truncated blocks to initialized later
3812 */
3813 ext4_flush_unwritten_io(inode);
3814
3815 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
3816 credits = ext4_writepage_trans_blocks(inode);
3817 else
3818 credits = ext4_blocks_for_truncate(inode);
3819
3820 handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
3821 if (IS_ERR(handle)) {
3822 ext4_std_error(inode->i_sb, PTR_ERR(handle));
3823 return;
3824 }
3825
3826 if (inode->i_size % PAGE_CACHE_SIZE != 0) {
3827 page_len = PAGE_CACHE_SIZE -
3828 (inode->i_size & (PAGE_CACHE_SIZE - 1));
3829
3830 if (ext4_discard_partial_page_buffers(handle,
3831 mapping, inode->i_size, page_len, 0))
3832 goto out_stop;
3833 }
3834
3835 /*
3836 * We add the inode to the orphan list, so that if this
3837 * truncate spans multiple transactions, and we crash, we will
3838 * resume the truncate when the filesystem recovers. It also
3839 * marks the inode dirty, to catch the new size.
3840 *
3841 * Implication: the file must always be in a sane, consistent
3842 * truncatable state while each transaction commits.
3843 */
3844 if (ext4_orphan_add(handle, inode))
3845 goto out_stop;
3846
3847 down_write(&EXT4_I(inode)->i_data_sem);
3848
3849 ext4_discard_preallocations(inode);
3850
3803 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) 3851 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
3804 ext4_ext_truncate(inode); 3852 ext4_ext_truncate(handle, inode);
3805 else 3853 else
3806 ext4_ind_truncate(inode); 3854 ext4_ind_truncate(handle, inode);
3855
3856 up_write(&ei->i_data_sem);
3857
3858 if (IS_SYNC(inode))
3859 ext4_handle_sync(handle);
3860
3861out_stop:
3862 /*
3863 * If this was a simple ftruncate() and the file will remain alive,
3864 * then we need to clear up the orphan record which we created above.
3865 * However, if this was a real unlink then we were called by
3866 * ext4_delete_inode(), and we allow that function to clean up the
3867 * orphan info for us.
3868 */
3869 if (inode->i_nlink)
3870 ext4_orphan_del(handle, inode);
3871
3872 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
3873 ext4_mark_inode_dirty(handle, inode);
3874 ext4_journal_stop(handle);
3807 3875
3808 trace_ext4_truncate_exit(inode); 3876 trace_ext4_truncate_exit(inode);
3809} 3877}