From 844e93f87eabea39c240fb5c19b0a9abbc2bb3c2 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 21 Jun 2015 21:12:29 -0400 Subject: [PATCH] add patch prevent-ext4_quota_write-from-failing --- prevent-ext4_quota_write-from-failing | 128 ++++++++++++++++++++++++++++++++++ series | 1 + timestamps | 9 +-- 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 prevent-ext4_quota_write-from-failing diff --git a/prevent-ext4_quota_write-from-failing b/prevent-ext4_quota_write-from-failing new file mode 100644 index 00000000..72c2a2de --- /dev/null +++ b/prevent-ext4_quota_write-from-failing @@ -0,0 +1,128 @@ +ext4: prevent ext4_quota_write() from failing due to ENOSPC + +In order to prevent quota block tracking to be inaccurate when +ext4_quota_write() fails with ENOSPC, we make two changes. The quota +file can now use the reserved block (since the quota file is arguably +file system metadata), and ext4_quota_write() now uses +ext4_should_retry_alloc() to retry the block allocation after a commit +has completed and released some blocks for allocation. + +This fixes failures of xfstests generic/270: + +Quota error (device vdc): write_blk: dquota write failed +Quota error (device vdc): qtree_write_dquot: Error -28 occurred while creating quota + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/extents.c | 2 ++ + fs/ext4/indirect.c | 2 ++ + fs/ext4/inode.c | 10 +++++----- + fs/ext4/namei.c | 2 +- + fs/ext4/super.c | 8 +++++++- + 5 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 338473b..a1a54f5 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4456,6 +4456,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, + ar.flags |= EXT4_MB_HINT_NOPREALLOC; + if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) + ar.flags |= EXT4_MB_DELALLOC_RESERVED; ++ if (flags & EXT4_GET_BLOCKS_METADATA_NOFAIL) ++ ar.flags |= EXT4_MB_USE_RESERVED; + newblock = ext4_mb_new_blocks(handle, &ar, &err); + if (!newblock) + goto out2; +diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c +index 9588240..9962d57 100644 +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -576,6 +576,8 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, + ar.flags = EXT4_MB_HINT_DATA; + if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) + ar.flags |= EXT4_MB_DELALLOC_RESERVED; ++ if (flags & EXT4_GET_BLOCKS_METADATA_NOFAIL) ++ ar.flags |= EXT4_MB_USE_RESERVED; + + ar.goal = ext4_find_goal(inode, map->m_lblk, partial); + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 263a46c..e8a67b8 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -731,18 +731,18 @@ int ext4_get_block(struct inode *inode, sector_t iblock, + * `handle' can be NULL if create is zero + */ + struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, +- ext4_lblk_t block, int create) ++ ext4_lblk_t block, int map_flags) + { + struct ext4_map_blocks map; + struct buffer_head *bh; ++ int create = map_flags & EXT4_GET_BLOCKS_CREATE; + int err; + + J_ASSERT(handle != NULL || create == 0); + + map.m_lblk = block; + map.m_len = 1; +- err = ext4_map_blocks(handle, inode, &map, +- create ? EXT4_GET_BLOCKS_CREATE : 0); ++ err = ext4_map_blocks(handle, inode, &map, map_flags); + + if (err == 0) + return create ? ERR_PTR(-ENOSPC) : NULL; +@@ -788,11 +788,11 @@ errout: + } + + struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, +- ext4_lblk_t block, int create) ++ ext4_lblk_t block, int map_flags) + { + struct buffer_head *bh; + +- bh = ext4_getblk(handle, inode, block, create); ++ bh = ext4_getblk(handle, inode, block, map_flags); + if (IS_ERR(bh)) + return bh; + if (!bh || buffer_uptodate(bh)) +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 5e7676f..e230b31 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -61,7 +61,7 @@ static struct buffer_head *ext4_append(handle_t *handle, + + *block = inode->i_size >> inode->i_sb->s_blocksize_bits; + +- bh = ext4_bread(handle, inode, *block, 1); ++ bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE); + if (IS_ERR(bh)) + return bh; + inode->i_size += inode->i_sb->s_blocksize; +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 2858ac0..bd4df9d 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -5438,6 +5438,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, + struct inode *inode = sb_dqopt(sb)->files[type]; + ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); + int err, offset = off & (sb->s_blocksize - 1); ++ int retries = 0; + struct buffer_head *bh; + handle_t *handle = journal_current_handle(); + +@@ -5458,7 +5459,12 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, + return -EIO; + } + +- bh = ext4_bread(handle, inode, blk, 1); ++ do { ++ bh = ext4_bread(handle, inode, blk, ++ EXT4_GET_BLOCKS_CREATE | ++ EXT4_GET_BLOCKS_METADATA_NOFAIL); ++ } while (IS_ERR(bh) && (PTR_ERR(bh) == -ENOSPC) && ++ ext4_should_retry_alloc(inode->i_sb, &retries)); + if (IS_ERR(bh)) + return PTR_ERR(bh); + if (!bh) diff --git a/series b/series index ac5ba234..4e0afdb0 100644 --- a/series +++ b/series @@ -55,6 +55,7 @@ jbd2-get-rid-of-open-coded-allocation-retry-loop speedup-jbd2_journal_dirty_metadata sync-before-invalidating-blockdev +prevent-ext4_quota_write-from-failing ########################################## # unstable patches diff --git a/timestamps b/timestamps index f6282a82..c36adba6 100755 --- a/timestamps +++ b/timestamps @@ -68,9 +68,10 @@ touch -d @1434342778 mballoc-avoid-20-argument-function-call touch -d @1434393361 fix-ocfs2-corrupt-when-updating-journal-superblock-fails touch -d @1434394226 improve-warning-directory-handling-messages touch -d @1434397558 jbd2-get-rid-of-open-coded-allocation-retry-loop -touch -d @1434397618 stable-boundary touch -d @1434851057 speedup-jbd2_journal_dirty_metadata -touch -d @1434854818 series touch -d @1434855033 sync-before-invalidating-blockdev -touch -d @1434855034 status -touch -d @1434855068 timestamps +touch -d @1434863965 series +touch -d @1434864329 prevent-ext4_quota_write-from-failing +touch -d @1434864389 stable-boundary +touch -d @1434931801 status +touch -d @1434935530 timestamps -- 2.11.4.GIT