--- /dev/null
+From 7d7345322d60edb0fa49a64a89b31360f01d09cb Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Sat, 17 Aug 2013 09:36:54 -0400
+Subject: ext4: fix warning in ext4_da_update_reserve_space()
+
+From: Jan Kara <jack@suse.cz>
+
+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 <jack@suse.cz>
+Cc: Josh Hunt <johunt@akamai.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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");
--- /dev/null
+From 1c8924eb106c1ac755d5d35ce9b3ff42e89e2511 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Sat, 17 Aug 2013 09:32:32 -0400
+Subject: quota: provide interface for readding allocated space into reserved space
+
+From: Jan Kara <jack@suse.cz>
+
+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 <jack@suse.cz>
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Cc: Josh Hunt <johunt@akamai.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);