aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2013-03-10 22:50:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-03-10 22:50:00 -0400
commit386ad67c9ac043890121c066186883d1640348a4 (patch)
tree24f0962f8709cea70091460c5da9c938fdc08c7c /fs/ext4
parent232ec8720d4e45405e37144c67053042c6b886d3 (diff)
ext4: reserve metadata block for every delayed write
Currently we only reserve space (data+metadata) in delayed allocation if we're allocating from new cluster (which is always in non-bigalloc file system) which is ok for data blocks, because we reserve the whole cluster. However we have to reserve metadata for every delayed block we're going to write because every block could potentially require metedata block when we need to grow the extent tree. Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/inode.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 48fc023ab0a2..65bbc9339aca 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1305,6 +1305,55 @@ static int ext4_journalled_write_end(struct file *file,
1305} 1305}
1306 1306
1307/* 1307/*
1308 * Reserve a metadata for a single block located at lblock
1309 */
1310static int ext4_da_reserve_metadata(struct inode *inode, ext4_lblk_t lblock)
1311{
1312 int retries = 0;
1313 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
1314 struct ext4_inode_info *ei = EXT4_I(inode);
1315 unsigned int md_needed;
1316 ext4_lblk_t save_last_lblock;
1317 int save_len;
1318
1319 /*
1320 * recalculate the amount of metadata blocks to reserve
1321 * in order to allocate nrblocks
1322 * worse case is one extent per block
1323 */
1324repeat:
1325 spin_lock(&ei->i_block_reservation_lock);
1326 /*
1327 * ext4_calc_metadata_amount() has side effects, which we have
1328 * to be prepared undo if we fail to claim space.
1329 */
1330 save_len = ei->i_da_metadata_calc_len;
1331 save_last_lblock = ei->i_da_metadata_calc_last_lblock;
1332 md_needed = EXT4_NUM_B2C(sbi,
1333 ext4_calc_metadata_amount(inode, lblock));
1334 trace_ext4_da_reserve_space(inode, md_needed);
1335
1336 /*
1337 * We do still charge estimated metadata to the sb though;
1338 * we cannot afford to run out of free blocks.
1339 */
1340 if (ext4_claim_free_clusters(sbi, md_needed, 0)) {
1341 ei->i_da_metadata_calc_len = save_len;
1342 ei->i_da_metadata_calc_last_lblock = save_last_lblock;
1343 spin_unlock(&ei->i_block_reservation_lock);
1344 if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
1345 cond_resched();
1346 goto repeat;
1347 }
1348 return -ENOSPC;
1349 }
1350 ei->i_reserved_meta_blocks += md_needed;
1351 spin_unlock(&ei->i_block_reservation_lock);
1352
1353 return 0; /* success */
1354}
1355
1356/*
1308 * Reserve a single cluster located at lblock 1357 * Reserve a single cluster located at lblock
1309 */ 1358 */
1310static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock) 1359static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock)
@@ -1940,8 +1989,11 @@ add_delayed:
1940 * XXX: __block_prepare_write() unmaps passed block, 1989 * XXX: __block_prepare_write() unmaps passed block,
1941 * is it OK? 1990 * is it OK?
1942 */ 1991 */
1943 /* If the block was allocated from previously allocated cluster, 1992 /*
1944 * then we dont need to reserve it again. */ 1993 * If the block was allocated from previously allocated cluster,
1994 * then we don't need to reserve it again. However we still need
1995 * to reserve metadata for every block we're going to write.
1996 */
1945 if (!(map->m_flags & EXT4_MAP_FROM_CLUSTER)) { 1997 if (!(map->m_flags & EXT4_MAP_FROM_CLUSTER)) {
1946 ret = ext4_da_reserve_space(inode, iblock); 1998 ret = ext4_da_reserve_space(inode, iblock);
1947 if (ret) { 1999 if (ret) {
@@ -1949,6 +2001,13 @@ add_delayed:
1949 retval = ret; 2001 retval = ret;
1950 goto out_unlock; 2002 goto out_unlock;
1951 } 2003 }
2004 } else {
2005 ret = ext4_da_reserve_metadata(inode, iblock);
2006 if (ret) {
2007 /* not enough space to reserve */
2008 retval = ret;
2009 goto out_unlock;
2010 }
1952 } 2011 }
1953 2012
1954 ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, 2013 ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,