#include "xfs_iomap.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
 
 
 #define XFS_WRITEIO_ALIGN(mp,off)      (((off) >> mp->m_writeio_log) \
        return XFS_B_TO_FSB(mp, offset);
 }
 
+STATIC bool
+xfs_quota_need_throttle(
+       struct xfs_inode *ip,
+       int type,
+       xfs_fsblock_t alloc_blocks)
+{
+       struct xfs_dquot *dq = xfs_inode_dquot(ip, type);
+
+       if (!dq || !xfs_this_quota_on(ip->i_mount, type))
+               return false;
+
+       /* no hi watermark, no throttle */
+       if (!dq->q_prealloc_hi_wmark)
+               return false;
+
+       /* under the lo watermark, no throttle */
+       if (dq->q_res_bcount + alloc_blocks < dq->q_prealloc_lo_wmark)
+               return false;
+
+       return true;
+}
+
+STATIC void
+xfs_quota_calc_throttle(
+       struct xfs_inode *ip,
+       int type,
+       xfs_fsblock_t *qblocks,
+       int *qshift)
+{
+       int64_t freesp;
+       int shift = 0;
+       struct xfs_dquot *dq = xfs_inode_dquot(ip, type);
+
+       /* over hi wmark, squash the prealloc completely */
+       if (dq->q_res_bcount >= dq->q_prealloc_hi_wmark) {
+               *qblocks = 0;
+               return;
+       }
+
+       freesp = dq->q_prealloc_hi_wmark - dq->q_res_bcount;
+       if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) {
+               shift = 2;
+               if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT])
+                       shift += 2;
+               if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT])
+                       shift += 2;
+       }
+
+       /* only overwrite the throttle values if we are more aggressive */
+       if ((freesp >> shift) < (*qblocks >> *qshift)) {
+               *qblocks = freesp;
+               *qshift = shift;
+       }
+}
+
 /*
  * If we don't have a user specified preallocation size, dynamically increase
  * the preallocation size as the size of the file grows. Cap the maximum size
        xfs_fsblock_t           alloc_blocks = 0;
        int                     shift = 0;
        int64_t                 freesp;
+       xfs_fsblock_t           qblocks;
+       int                     qshift = 0;
 
        alloc_blocks = xfs_iomap_eof_prealloc_initial_size(mp, ip, offset,
                                                           imap, nimaps);
        if (!alloc_blocks)
                goto check_writeio;
+       qblocks = alloc_blocks;
 
        /*
         * MAXEXTLEN is not a power of two value but we round the prealloc down
                if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT])
                        shift++;
        }
+
+       /*
+        * Check each quota to cap the prealloc size and provide a shift
+        * value to throttle with.
+        */
+       if (xfs_quota_need_throttle(ip, XFS_DQ_USER, alloc_blocks))
+               xfs_quota_calc_throttle(ip, XFS_DQ_USER, &qblocks, &qshift);
+       if (xfs_quota_need_throttle(ip, XFS_DQ_GROUP, alloc_blocks))
+               xfs_quota_calc_throttle(ip, XFS_DQ_GROUP, &qblocks, &qshift);
+       if (xfs_quota_need_throttle(ip, XFS_DQ_PROJ, alloc_blocks))
+               xfs_quota_calc_throttle(ip, XFS_DQ_PROJ, &qblocks, &qshift);
+
+       /*
+        * The final prealloc size is set to the minimum of free space available
+        * in each of the quotas and the overall filesystem.
+        *
+        * The shift throttle value is set to the maximum value as determined by
+        * the global low free space values and per-quota low free space values.
+        */
+       alloc_blocks = MIN(alloc_blocks, qblocks);
+       shift = MAX(shift, qshift);
+
        if (shift)
                alloc_blocks >>= shift;
        /*