#include <linux/blkdev.h>
 #include <linux/magic.h>
 #include <linux/jbd2.h>
+#include <linux/quota.h>
 #include "ext4_i.h"
 
 /*
 extern int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+extern qsize_t ext4_get_reserved_space(struct inode *inode);
 
 /* ioctl.c */
 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
 
        return err;
 }
 
+qsize_t ext4_get_reserved_space(struct inode *inode)
+{
+       unsigned long long total;
+
+       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
+       total = EXT4_I(inode)->i_reserved_data_blocks +
+               EXT4_I(inode)->i_reserved_meta_blocks;
+       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+
+       return total;
+}
 /*
  * Calculate the number of metadata blocks need to reserve
  * to allocate @blocks for non extent file based file
        /* update per-inode reservations */
        BUG_ON(used  > EXT4_I(inode)->i_reserved_data_blocks);
        EXT4_I(inode)->i_reserved_data_blocks -= used;
-
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+
+       /*
+        * free those over-booking quota for metadata blocks
+        */
+
+       if (mdb_free)
+               vfs_dq_release_reservation_block(inode, mdb_free);
 }
 
 /*
 static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
 {
        int retries = 0;
-       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-       unsigned long md_needed, mdblocks, total = 0;
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       unsigned long md_needed, mdblocks, total = 0;
 
        /*
         * recalculate the amount of metadata blocks to reserve
        md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
        total = md_needed + nrblocks;
 
+       /*
+        * Make quota reservation here to prevent quota overflow
+        * later. Real quota accounting is done at pages writeout
+        * time.
+        */
+       if (vfs_dq_reserve_block(inode, total)) {
+               spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+               return -EDQUOT;
+       }
+
        if (ext4_claim_free_blocks(sbi, total)) {
                spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
                if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
                        yield();
                        goto repeat;
                }
+               vfs_dq_release_reservation_block(inode, total);
                return -ENOSPC;
        }
        EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
        BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
        EXT4_I(inode)->i_reserved_meta_blocks = mdb;
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+
+       vfs_dq_release_reservation_block(inode, release);
 }
 
 static void ext4_da_page_release_reservation(struct page *page,
 
        if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
                /* release all the reserved blocks if non delalloc */
                percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
-       else
+       else {
                percpu_counter_sub(&sbi->s_dirtyblocks_counter,
                                                ac->ac_b_ex.fe_len);
+               /* convert reserved quota blocks to real quota blocks */
+               vfs_dq_claim_block(ac->ac_inode, ac->ac_b_ex.fe_len);
+       }
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi,
        struct ext4_sb_info *sbi;
        struct super_block *sb;
        ext4_fsblk_t block = 0;
-       unsigned int inquota;
+       unsigned int inquota = 0;
        unsigned int reserv_blks = 0;
 
        sb = ar->inode->i_sb;
                   (unsigned long long) ar->pleft,
                   (unsigned long long) ar->pright);
 
-       if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
-               /*
-                * With delalloc we already reserved the blocks
+       /*
+        * For delayed allocation, we could skip the ENOSPC and
+        * EDQUOT check, as blocks and quotas have been already
+        * reserved when data being copied into pagecache.
+        */
+       if (EXT4_I(ar->inode)->i_delalloc_reserved_flag)
+               ar->flags |= EXT4_MB_DELALLOC_RESERVED;
+       else {
+               /* Without delayed allocation we need to verify
+                * there is enough free blocks to do block allocation
+                * and verify allocation doesn't exceed the quota limits.
                 */
                while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
                        /* let others to free the space */
                        return 0;
                }
                reserv_blks = ar->len;
+               while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
+                       ar->flags |= EXT4_MB_HINT_NOPREALLOC;
+                       ar->len--;
+               }
+               inquota = ar->len;
+               if (ar->len == 0) {
+                       *errp = -EDQUOT;
+                       goto out3;
+               }
        }
-       while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
-               ar->flags |= EXT4_MB_HINT_NOPREALLOC;
-               ar->len--;
-       }
-       if (ar->len == 0) {
-               *errp = -EDQUOT;
-               goto out3;
-       }
-       inquota = ar->len;
-
-       if (EXT4_I(ar->inode)->i_delalloc_reserved_flag)
-               ar->flags |= EXT4_MB_DELALLOC_RESERVED;
 
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
        if (!ac) {
 out2:
        kmem_cache_free(ext4_ac_cachep, ac);
 out1:
-       if (ar->len < inquota)
+       if (inquota && ar->len < inquota)
                DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len);
 out3:
        if (!ar->len) {
 
        .initialize     = dquot_initialize,
        .drop           = dquot_drop,
        .alloc_space    = dquot_alloc_space,
+       .reserve_space  = dquot_reserve_space,
+       .claim_space    = dquot_claim_space,
+       .release_rsv    = dquot_release_reserved_space,
+       .get_reserved_space = ext4_get_reserved_space,
        .alloc_inode    = dquot_alloc_inode,
        .free_space     = dquot_free_space,
        .free_inode     = dquot_free_inode,