aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2010-01-25 04:00:31 -0500
committerTheodore Ts'o <tytso@mit.edu>2010-01-25 04:00:31 -0500
commit5f634d064c709ea02c3cdaa850a08323a4a4bf28 (patch)
tree3f81e9c56cd8348b7bb94f1d54efff696374c929 /fs/ext4
parent1db913823c0f8360fccbd24ca67eb073966a5ffd (diff)
ext4: Fix quota accounting error with fallocate
When we fallocate a region of the file which we had recently written, and which is still in the page cache marked as delayed allocated blocks we need to make sure we don't do the quota update on writepage path. This is because the needed quota updated would have already be done by fallocate. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/extents.c21
-rw-r--r--fs/ext4/inode.c44
3 files changed, 54 insertions, 13 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index af7b62699ea9..b98de17e542a 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1443,6 +1443,8 @@ extern int ext4_block_truncate_page(handle_t *handle,
1443extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); 1443extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
1444extern qsize_t *ext4_get_reserved_space(struct inode *inode); 1444extern qsize_t *ext4_get_reserved_space(struct inode *inode);
1445extern int flush_aio_dio_completed_IO(struct inode *inode); 1445extern int flush_aio_dio_completed_IO(struct inode *inode);
1446extern void ext4_da_update_reserve_space(struct inode *inode,
1447 int used, int quota_claim);
1446/* ioctl.c */ 1448/* ioctl.c */
1447extern long ext4_ioctl(struct file *, unsigned int, unsigned long); 1449extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
1448extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); 1450extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7d7b74e94687..3b6ff72026f0 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3132,7 +3132,19 @@ out:
3132 unmap_underlying_metadata_blocks(inode->i_sb->s_bdev, 3132 unmap_underlying_metadata_blocks(inode->i_sb->s_bdev,
3133 newblock + max_blocks, 3133 newblock + max_blocks,
3134 allocated - max_blocks); 3134 allocated - max_blocks);
3135 allocated = max_blocks;
3135 } 3136 }
3137
3138 /*
3139 * If we have done fallocate with the offset that is already
3140 * delayed allocated, we would have block reservation
3141 * and quota reservation done in the delayed write path.
3142 * But fallocate would have already updated quota and block
3143 * count for this offset. So cancel these reservation
3144 */
3145 if (flags & EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE)
3146 ext4_da_update_reserve_space(inode, allocated, 0);
3147
3136map_out: 3148map_out:
3137 set_buffer_mapped(bh_result); 3149 set_buffer_mapped(bh_result);
3138out1: 3150out1:
@@ -3368,9 +3380,18 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
3368 /* previous routine could use block we allocated */ 3380 /* previous routine could use block we allocated */
3369 newblock = ext_pblock(&newex); 3381 newblock = ext_pblock(&newex);
3370 allocated = ext4_ext_get_actual_len(&newex); 3382 allocated = ext4_ext_get_actual_len(&newex);
3383 if (allocated > max_blocks)
3384 allocated = max_blocks;
3371 set_buffer_new(bh_result); 3385 set_buffer_new(bh_result);
3372 3386
3373 /* 3387 /*
3388 * Update reserved blocks/metadata blocks after successful
3389 * block allocation which had been deferred till now.
3390 */
3391 if (flags & EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE)
3392 ext4_da_update_reserve_space(inode, allocated, 1);
3393
3394 /*
3374 * Cache the extent and update transaction to commit on fdatasync only 3395 * Cache the extent and update transaction to commit on fdatasync only
3375 * when it is _not_ an uninitialized extent. 3396 * when it is _not_ an uninitialized extent.
3376 */ 3397 */
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 60b3a19e9927..c955f6490b78 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1053,11 +1053,12 @@ static int ext4_calc_metadata_amount(struct inode *inode, sector_t lblock)
1053 * Called with i_data_sem down, which is important since we can call 1053 * Called with i_data_sem down, which is important since we can call
1054 * ext4_discard_preallocations() from here. 1054 * ext4_discard_preallocations() from here.
1055 */ 1055 */
1056static void ext4_da_update_reserve_space(struct inode *inode, int used) 1056void ext4_da_update_reserve_space(struct inode *inode,
1057 int used, int quota_claim)
1057{ 1058{
1058 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1059 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
1059 struct ext4_inode_info *ei = EXT4_I(inode); 1060 struct ext4_inode_info *ei = EXT4_I(inode);
1060 int mdb_free = 0; 1061 int mdb_free = 0, allocated_meta_blocks = 0;
1061 1062
1062 spin_lock(&ei->i_block_reservation_lock); 1063 spin_lock(&ei->i_block_reservation_lock);
1063 if (unlikely(used > ei->i_reserved_data_blocks)) { 1064 if (unlikely(used > ei->i_reserved_data_blocks)) {
@@ -1073,6 +1074,7 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
1073 ei->i_reserved_data_blocks -= used; 1074 ei->i_reserved_data_blocks -= used;
1074 used += ei->i_allocated_meta_blocks; 1075 used += ei->i_allocated_meta_blocks;
1075 ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks; 1076 ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks;
1077 allocated_meta_blocks = ei->i_allocated_meta_blocks;
1076 ei->i_allocated_meta_blocks = 0; 1078 ei->i_allocated_meta_blocks = 0;
1077 percpu_counter_sub(&sbi->s_dirtyblocks_counter, used); 1079 percpu_counter_sub(&sbi->s_dirtyblocks_counter, used);
1078 1080
@@ -1090,9 +1092,23 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
1090 spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); 1092 spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
1091 1093
1092 /* Update quota subsystem */ 1094 /* Update quota subsystem */
1093 vfs_dq_claim_block(inode, used); 1095 if (quota_claim) {
1094 if (mdb_free) 1096 vfs_dq_claim_block(inode, used);
1095 vfs_dq_release_reservation_block(inode, mdb_free); 1097 if (mdb_free)
1098 vfs_dq_release_reservation_block(inode, mdb_free);
1099 } else {
1100 /*
1101 * We did fallocate with an offset that is already delayed
1102 * allocated. So on delayed allocated writeback we should
1103 * not update the quota for allocated blocks. But then
1104 * converting an fallocate region to initialized region would
1105 * have caused a metadata allocation. So claim quota for
1106 * that
1107 */
1108 if (allocated_meta_blocks)
1109 vfs_dq_claim_block(inode, allocated_meta_blocks);
1110 vfs_dq_release_reservation_block(inode, mdb_free + used);
1111 }
1096 1112
1097 /* 1113 /*
1098 * If we have done all the pending block allocations and if 1114 * If we have done all the pending block allocations and if
@@ -1292,18 +1308,20 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
1292 */ 1308 */
1293 EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE; 1309 EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE;
1294 } 1310 }
1295 }
1296 1311
1312 /*
1313 * Update reserved blocks/metadata blocks after successful
1314 * block allocation which had been deferred till now. We don't
1315 * support fallocate for non extent files. So we can update
1316 * reserve space here.
1317 */
1318 if ((retval > 0) &&
1319 (flags & EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE))
1320 ext4_da_update_reserve_space(inode, retval, 1);
1321 }
1297 if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) 1322 if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
1298 EXT4_I(inode)->i_delalloc_reserved_flag = 0; 1323 EXT4_I(inode)->i_delalloc_reserved_flag = 0;
1299 1324
1300 /*
1301 * Update reserved blocks/metadata blocks after successful
1302 * block allocation which had been deferred till now.
1303 */
1304 if ((retval > 0) && (flags & EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE))
1305 ext4_da_update_reserve_space(inode, retval);
1306
1307 up_write((&EXT4_I(inode)->i_data_sem)); 1325 up_write((&EXT4_I(inode)->i_data_sem));
1308 if (retval > 0 && buffer_mapped(bh)) { 1326 if (retval > 0 && buffer_mapped(bh)) {
1309 int ret = check_block_validity(inode, "file system " 1327 int ret = check_block_validity(inode, "file system "