diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ext4/inode.c | 63 |
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 | */ | ||
| 1310 | static 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 | */ | ||
| 1324 | repeat: | ||
| 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 | */ |
| 1310 | static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock) | 1359 | static 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, |
