From: Greg Kroah-Hartman Date: Wed, 28 Jan 2015 00:23:45 +0000 (-0800) Subject: 3.10-stable patches X-Git-Tag: v3.10.67~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d6fd337c4303935fa2889d98731e7708334ed2c0;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: ext4-fix-warning-in-ext4_da_update_reserve_space.patch quota-provide-interface-for-readding-allocated-space-into-reserved-space.patch --- diff --git a/queue-3.10/ext4-fix-warning-in-ext4_da_update_reserve_space.patch b/queue-3.10/ext4-fix-warning-in-ext4_da_update_reserve_space.patch new file mode 100644 index 00000000000..f170d0c012d --- /dev/null +++ b/queue-3.10/ext4-fix-warning-in-ext4_da_update_reserve_space.patch @@ -0,0 +1,106 @@ +From 7d7345322d60edb0fa49a64a89b31360f01d09cb Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Sat, 17 Aug 2013 09:36:54 -0400 +Subject: ext4: fix warning in ext4_da_update_reserve_space() + +From: Jan Kara + +commit 7d7345322d60edb0fa49a64a89b31360f01d09cb upstream. + +reaim workfile.dbase test easily triggers warning in +ext4_da_update_reserve_space(): + +EXT4-fs warning (device ram0): ext4_da_update_reserve_space:365: +ino 12, allocated 1 with only 0 reserved metadata blocks (releasing 1 +blocks with reserved 9 data blocks) + +The problem is that (one of) tests creates file and then randomly writes +to it with O_SYNC. That results in writing back pages of the file in +random order so we create extents for written blocks say 0, 2, 4, 6, 8 +- this last allocation also allocates new block for extents. Then we +writeout block 1 so we have extents 0-2, 4, 6, 8 and we release +indirect extent block because extents fit in the inode again. Then we +writeout block 10 and we need to allocate indirect extent block again +which triggers the warning because we don't have the reservation +anymore. + +Fix the problem by giving back freed metadata blocks resulting from +extent merging into inode's reservation pool. + +Signed-off-by: Jan Kara +Cc: Josh Hunt +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/ext4.h | 1 + + fs/ext4/extents.c | 3 ++- + fs/ext4/mballoc.c | 21 +++++++++++++++++---- + 3 files changed, 20 insertions(+), 5 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -589,6 +589,7 @@ enum { + #define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008 + #define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010 + #define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020 ++#define EXT4_FREE_BLOCKS_RESERVE 0x0040 + + /* + * Flags used by ext4_discard_partial_page_buffers +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -1722,7 +1722,8 @@ static void ext4_ext_try_to_merge_up(han + + brelse(path[1].p_bh); + ext4_free_blocks(handle, inode, NULL, blk, 1, +- EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); ++ EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET | ++ EXT4_FREE_BLOCKS_RESERVE); + } + + /* +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -4610,6 +4610,7 @@ void ext4_free_blocks(handle_t *handle, + struct buffer_head *gd_bh; + ext4_group_t block_group; + struct ext4_sb_info *sbi; ++ struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_buddy e4b; + unsigned int count_clusters; + int err = 0; +@@ -4808,7 +4809,6 @@ do_more: + ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh); + ext4_group_desc_csum_set(sb, block_group, gdp); + ext4_unlock_group(sb, block_group); +- percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); + + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group = ext4_flex_group(sbi, block_group); +@@ -4816,10 +4816,23 @@ do_more: + &sbi->s_flex_groups[flex_group].free_clusters); + } + +- ext4_mb_unload_buddy(&e4b); +- +- if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) ++ if (flags & EXT4_FREE_BLOCKS_RESERVE && ei->i_reserved_data_blocks) { ++ percpu_counter_add(&sbi->s_dirtyclusters_counter, ++ count_clusters); ++ spin_lock(&ei->i_block_reservation_lock); ++ if (flags & EXT4_FREE_BLOCKS_METADATA) ++ ei->i_reserved_meta_blocks += count_clusters; ++ else ++ ei->i_reserved_data_blocks += count_clusters; ++ spin_unlock(&ei->i_block_reservation_lock); ++ if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) ++ dquot_reclaim_block(inode, ++ EXT4_C2B(sbi, count_clusters)); ++ } else if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) + dquot_free_block(inode, EXT4_C2B(sbi, count_clusters)); ++ percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); ++ ++ ext4_mb_unload_buddy(&e4b); + + /* We dirtied the bitmap block */ + BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); diff --git a/queue-3.10/quota-provide-interface-for-readding-allocated-space-into-reserved-space.patch b/queue-3.10/quota-provide-interface-for-readding-allocated-space-into-reserved-space.patch new file mode 100644 index 00000000000..039aa104be4 --- /dev/null +++ b/queue-3.10/quota-provide-interface-for-readding-allocated-space-into-reserved-space.patch @@ -0,0 +1,177 @@ +From 1c8924eb106c1ac755d5d35ce9b3ff42e89e2511 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Sat, 17 Aug 2013 09:32:32 -0400 +Subject: quota: provide interface for readding allocated space into reserved space + +From: Jan Kara + +commit 1c8924eb106c1ac755d5d35ce9b3ff42e89e2511 upstream. + +ext4 needs to convert allocated (metadata) blocks back into blocks +reserved for delayed allocation. Add functions into quota code for +supporting such operation. + +Signed-off-by: Jan Kara +Signed-off-by: "Theodore Ts'o" +Cc: Josh Hunt +Signed-off-by: Greg Kroah-Hartman + +--- + fs/quota/dquot.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/stat.c | 11 +++++++++-- + include/linux/fs.h | 1 + + include/linux/quotaops.h | 15 +++++++++++++++ + 4 files changed, 71 insertions(+), 2 deletions(-) + +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -1102,6 +1102,14 @@ static void dquot_claim_reserved_space(s + dquot->dq_dqb.dqb_rsvspace -= number; + } + ++static void dquot_reclaim_reserved_space(struct dquot *dquot, qsize_t number) ++{ ++ if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number)) ++ number = dquot->dq_dqb.dqb_curspace; ++ dquot->dq_dqb.dqb_rsvspace += number; ++ dquot->dq_dqb.dqb_curspace -= number; ++} ++ + static inline + void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) + { +@@ -1536,6 +1544,15 @@ void inode_claim_rsv_space(struct inode + } + EXPORT_SYMBOL(inode_claim_rsv_space); + ++void inode_reclaim_rsv_space(struct inode *inode, qsize_t number) ++{ ++ spin_lock(&inode->i_lock); ++ *inode_reserved_space(inode) += number; ++ __inode_sub_bytes(inode, number); ++ spin_unlock(&inode->i_lock); ++} ++EXPORT_SYMBOL(inode_reclaim_rsv_space); ++ + void inode_sub_rsv_space(struct inode *inode, qsize_t number) + { + spin_lock(&inode->i_lock); +@@ -1710,6 +1727,35 @@ int dquot_claim_space_nodirty(struct ino + EXPORT_SYMBOL(dquot_claim_space_nodirty); + + /* ++ * Convert allocated space back to in-memory reserved quotas ++ */ ++void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) ++{ ++ int cnt; ++ ++ if (!dquot_active(inode)) { ++ inode_reclaim_rsv_space(inode, number); ++ return; ++ } ++ ++ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); ++ spin_lock(&dq_data_lock); ++ /* Claim reserved quotas to allocated quotas */ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (inode->i_dquot[cnt]) ++ dquot_reclaim_reserved_space(inode->i_dquot[cnt], ++ number); ++ } ++ /* Update inode bytes */ ++ inode_reclaim_rsv_space(inode, number); ++ spin_unlock(&dq_data_lock); ++ mark_all_dquot_dirty(inode->i_dquot); ++ up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); ++ return; ++} ++EXPORT_SYMBOL(dquot_reclaim_space_nodirty); ++ ++/* + * This operation can block, but only after everything is updated + */ + void __dquot_free_space(struct inode *inode, qsize_t number, int flags) +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -447,9 +447,8 @@ void inode_add_bytes(struct inode *inode + + EXPORT_SYMBOL(inode_add_bytes); + +-void inode_sub_bytes(struct inode *inode, loff_t bytes) ++void __inode_sub_bytes(struct inode *inode, loff_t bytes) + { +- spin_lock(&inode->i_lock); + inode->i_blocks -= bytes >> 9; + bytes &= 511; + if (inode->i_bytes < bytes) { +@@ -457,6 +456,14 @@ void inode_sub_bytes(struct inode *inode + inode->i_bytes += 512; + } + inode->i_bytes -= bytes; ++} ++ ++EXPORT_SYMBOL(__inode_sub_bytes); ++ ++void inode_sub_bytes(struct inode *inode, loff_t bytes) ++{ ++ spin_lock(&inode->i_lock); ++ __inode_sub_bytes(inode, bytes); + spin_unlock(&inode->i_lock); + } + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2489,6 +2489,7 @@ extern void generic_fillattr(struct inod + extern int vfs_getattr(struct path *, struct kstat *); + void __inode_add_bytes(struct inode *inode, loff_t bytes); + void inode_add_bytes(struct inode *inode, loff_t bytes); ++void __inode_sub_bytes(struct inode *inode, loff_t bytes); + void inode_sub_bytes(struct inode *inode, loff_t bytes); + loff_t inode_get_bytes(struct inode *inode); + void inode_set_bytes(struct inode *inode, loff_t bytes); +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -41,6 +41,7 @@ void __quota_error(struct super_block *s + void inode_add_rsv_space(struct inode *inode, qsize_t number); + void inode_claim_rsv_space(struct inode *inode, qsize_t number); + void inode_sub_rsv_space(struct inode *inode, qsize_t number); ++void inode_reclaim_rsv_space(struct inode *inode, qsize_t number); + + void dquot_initialize(struct inode *inode); + void dquot_drop(struct inode *inode); +@@ -59,6 +60,7 @@ int dquot_alloc_inode(const struct inode + + int dquot_claim_space_nodirty(struct inode *inode, qsize_t number); + void dquot_free_inode(const struct inode *inode); ++void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number); + + int dquot_disable(struct super_block *sb, int type, unsigned int flags); + /* Suspend quotas on remount RO */ +@@ -238,6 +240,13 @@ static inline int dquot_claim_space_nodi + return 0; + } + ++static inline int dquot_reclaim_space_nodirty(struct inode *inode, ++ qsize_t number) ++{ ++ inode_sub_bytes(inode, number); ++ return 0; ++} ++ + static inline int dquot_disable(struct super_block *sb, int type, + unsigned int flags) + { +@@ -336,6 +345,12 @@ static inline int dquot_claim_block(stru + return ret; + } + ++static inline void dquot_reclaim_block(struct inode *inode, qsize_t nr) ++{ ++ dquot_reclaim_space_nodirty(inode, nr << inode->i_blkbits); ++ mark_inode_dirty_sync(inode); ++} ++ + static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr) + { + __dquot_free_space(inode, nr, 0); diff --git a/queue-3.10/series b/queue-3.10/series index a91149a6266..f93d92e0dd0 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -27,3 +27,5 @@ drbd-merge_bvec_fn-properly-remap-bvm-bi_bdev.patch crypto-prefix-module-autoloading-with-crypto.patch crypto-include-crypto-module-prefix-in-template.patch crypto-add-missing-crypto-module-aliases.patch +quota-provide-interface-for-readding-allocated-space-into-reserved-space.patch +ext4-fix-warning-in-ext4_da_update_reserve_space.patch