aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-09-08 23:14:50 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-09-08 23:14:50 -0400
commit030ba6bc67b4f2bc5cd174f57785a1745c929abe (patch)
tree14c57b4f6f8afddac0bd2415bfa050fba8d25980 /fs/ext4
parenta30d542a0035b886ffaafd0057ced0a2b28c3a4f (diff)
ext4: Retry block reservation
During block reservation if we don't have enough blocks left, retry block reservation with smaller block counts. This makes sure we try fallocate and DIO with smaller request size and don't fail early. The delayed allocation reservation cannot try with smaller block count. So retry block reservation to handle temporary disk full conditions. Also print free blocks details if we fail block allocation during writepages. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/balloc.c8
-rw-r--r--fs/ext4/inode.c14
-rw-r--r--fs/ext4/mballoc.c7
3 files changed, 24 insertions, 5 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 1707850301d6..57909882c084 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -1738,10 +1738,16 @@ ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
1738 /* 1738 /*
1739 * With delalloc we already reserved the blocks 1739 * With delalloc we already reserved the blocks
1740 */ 1740 */
1741 if (ext4_claim_free_blocks(sbi, *count)) { 1741 while (*count && ext4_claim_free_blocks(sbi, *count)) {
1742 /* let others to free the space */
1743 yield();
1744 *count = *count >> 1;
1745 }
1746 if (!*count) {
1742 *errp = -ENOSPC; 1747 *errp = -ENOSPC;
1743 return 0; /*return with ENOSPC error */ 1748 return 0; /*return with ENOSPC error */
1744 } 1749 }
1750 num = *count;
1745 } 1751 }
1746 /* 1752 /*
1747 * Check quota for allocation of this block. 1753 * Check quota for allocation of this block.
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b778d5a33ea7..eb9d449817d0 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1521,6 +1521,7 @@ static int ext4_journalled_write_end(struct file *file,
1521 1521
1522static int ext4_da_reserve_space(struct inode *inode, int nrblocks) 1522static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
1523{ 1523{
1524 int retries = 0;
1524 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1525 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
1525 unsigned long md_needed, mdblocks, total = 0; 1526 unsigned long md_needed, mdblocks, total = 0;
1526 1527
@@ -1529,6 +1530,7 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
1529 * in order to allocate nrblocks 1530 * in order to allocate nrblocks
1530 * worse case is one extent per block 1531 * worse case is one extent per block
1531 */ 1532 */
1533repeat:
1532 spin_lock(&EXT4_I(inode)->i_block_reservation_lock); 1534 spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
1533 total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks; 1535 total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks;
1534 mdblocks = ext4_calc_metadata_amount(inode, total); 1536 mdblocks = ext4_calc_metadata_amount(inode, total);
@@ -1539,6 +1541,10 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
1539 1541
1540 if (ext4_claim_free_blocks(sbi, total)) { 1542 if (ext4_claim_free_blocks(sbi, total)) {
1541 spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); 1543 spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
1544 if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
1545 yield();
1546 goto repeat;
1547 }
1542 return -ENOSPC; 1548 return -ENOSPC;
1543 } 1549 }
1544 EXT4_I(inode)->i_reserved_data_blocks += nrblocks; 1550 EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
@@ -1825,20 +1831,18 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
1825static int mpage_da_map_blocks(struct mpage_da_data *mpd) 1831static int mpage_da_map_blocks(struct mpage_da_data *mpd)
1826{ 1832{
1827 int err = 0; 1833 int err = 0;
1834 struct buffer_head new;
1828 struct buffer_head *lbh = &mpd->lbh; 1835 struct buffer_head *lbh = &mpd->lbh;
1829 sector_t next = lbh->b_blocknr; 1836 sector_t next = lbh->b_blocknr;
1830 struct buffer_head new;
1831 1837
1832 /* 1838 /*
1833 * We consider only non-mapped and non-allocated blocks 1839 * We consider only non-mapped and non-allocated blocks
1834 */ 1840 */
1835 if (buffer_mapped(lbh) && !buffer_delay(lbh)) 1841 if (buffer_mapped(lbh) && !buffer_delay(lbh))
1836 return 0; 1842 return 0;
1837
1838 new.b_state = lbh->b_state; 1843 new.b_state = lbh->b_state;
1839 new.b_blocknr = 0; 1844 new.b_blocknr = 0;
1840 new.b_size = lbh->b_size; 1845 new.b_size = lbh->b_size;
1841
1842 /* 1846 /*
1843 * If we didn't accumulate anything 1847 * If we didn't accumulate anything
1844 * to write simply return 1848 * to write simply return
@@ -1871,6 +1875,10 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
1871 lbh->b_size >> mpd->inode->i_blkbits, err); 1875 lbh->b_size >> mpd->inode->i_blkbits, err);
1872 printk(KERN_EMERG "This should not happen.!! " 1876 printk(KERN_EMERG "This should not happen.!! "
1873 "Data will be lost\n"); 1877 "Data will be lost\n");
1878 if (err == -ENOSPC) {
1879 printk(KERN_CRIT "Total free blocks count %lld\n",
1880 ext4_count_free_blocks(mpd->inode->i_sb));
1881 }
1874 /* invlaidate all the pages */ 1882 /* invlaidate all the pages */
1875 ext4_da_block_invalidatepages(mpd, next, 1883 ext4_da_block_invalidatepages(mpd, next,
1876 lbh->b_size >> mpd->inode->i_blkbits); 1884 lbh->b_size >> mpd->inode->i_blkbits);
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 2c10b5058a8d..e4f30de11a9d 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4395,7 +4395,12 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
4395 /* 4395 /*
4396 * With delalloc we already reserved the blocks 4396 * With delalloc we already reserved the blocks
4397 */ 4397 */
4398 if (ext4_claim_free_blocks(sbi, ar->len)) { 4398 while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
4399 /* let others to free the space */
4400 yield();
4401 ar->len = ar->len >> 1;
4402 }
4403 if (!ar->len) {
4399 *errp = -ENOSPC; 4404 *errp = -ENOSPC;
4400 return 0; 4405 return 0;
4401 } 4406 }