up_write(&mp->m_peraglock);
        }
        tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
+       tp->t_flags |= XFS_TRANS_RESERVE;
        if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
                        XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
                xfs_trans_cancel(tp, 0);
        unsigned long           s;
 
        /* If inval is null, report current values and return */
-
        if (inval == (__uint64_t *)NULL) {
+               if (!outval)
+                       return EINVAL;
                outval->resblks = mp->m_resblks;
                outval->resblks_avail = mp->m_resblks_avail;
                return 0;
                }
        }
 out:
-       outval->resblks = mp->m_resblks;
-       outval->resblks_avail = mp->m_resblks_avail;
+       if (outval) {
+               outval->resblks = mp->m_resblks;
+               outval->resblks_avail = mp->m_resblks_avail;
+       }
        XFS_SB_UNLOCK(mp, s);
 
        if (fdblks_delta) {
 
        if (unlikely(rt)) {
                resrtextents = qblocks = resaligned;
                resrtextents /= mp->m_sb.sb_rextsize;
-               resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
-               quota_flag = XFS_QMOPT_RES_RTBLKS;
-       } else {
-               resrtextents = 0;
+               resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+               quota_flag = XFS_QMOPT_RES_RTBLKS;
+       } else {
+               resrtextents = 0;
                resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
-               quota_flag = XFS_QMOPT_RES_REGBLKS;
-       }
+               quota_flag = XFS_QMOPT_RES_REGBLKS;
+       }
 
        /*
         * Allocate and setup the transaction
                nimaps = 0;
                while (nimaps == 0) {
                        tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+                       tp->t_flags |= XFS_TRANS_RESERVE;
                        nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
                        error = xfs_trans_reserve(tp, nres,
                                        XFS_WRITE_LOG_RES(mp),
                                        0, XFS_TRANS_PERM_LOG_RES,
                                        XFS_WRITE_LOG_COUNT);
-                       if (error == ENOSPC) {
-                               error = xfs_trans_reserve(tp, 0,
-                                               XFS_WRITE_LOG_RES(mp),
-                                               0,
-                                               XFS_TRANS_PERM_LOG_RES,
-                                               XFS_WRITE_LOG_COUNT);
-                       }
                        if (error) {
                                xfs_trans_cancel(tp, 0);
                                return XFS_ERROR(error);
                 * from unwritten to real. Do allocations in a loop until
                 * we have covered the range passed in.
                 */
-
                tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+               tp->t_flags |= XFS_TRANS_RESERVE;
                error = xfs_trans_reserve(tp, resblks,
                                XFS_WRITE_LOG_RES(mp), 0,
                                XFS_TRANS_PERM_LOG_RES,
 
        bhv_vnode_t     *rvp = NULL;
        int             readio_log, writeio_log;
        xfs_daddr_t     d;
-       __uint64_t      ret64;
+       __uint64_t      resblks;
        __int64_t       update_flags;
        uint            quotamount, quotaflags;
        int             agno;
         */
        if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&
            (mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
+               __uint64_t      ret64;
                if (xfs_uuid_mount(mp)) {
                        error = XFS_ERROR(EINVAL);
                        goto error1;
                goto error4;
        }
 
-
        /*
         * Complete the quota initialisation, post-log-replay component.
         */
        if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags)))
                goto error4;
 
+       /*
+        * Now we are mounted, reserve a small amount of unused space for
+        * privileged transactions. This is needed so that transaction
+        * space required for critical operations can dip into this pool
+        * when at ENOSPC. This is needed for operations like create with
+        * attr, unwritten extent conversion at ENOSPC, etc. Data allocations
+        * are not allowed to use this reserved space.
+        *
+        * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
+        * This may drive us straight to ENOSPC on mount, but that implies
+        * we were already there on the last unmount.
+        */
+       resblks = min_t(__uint64_t, mp->m_sb.sb_dblocks / 20, 1024);
+       xfs_reserve_blocks(mp, &resblks, NULL);
+
        return 0;
 
  error4:
 #if defined(DEBUG) || defined(INDUCE_IO_ERROR)
        int64_t         fsid;
 #endif
+       __uint64_t      resblks;
 
        /*
         * We can potentially deadlock here if we have an inode cluster
                xfs_binval(mp->m_rtdev_targp);
        }
 
+       /*
+        * Unreserve any blocks we have so that when we unmount we don't account
+        * the reserved free space as used. This is really only necessary for
+        * lazy superblock counting because it trusts the incore superblock
+        * counters to be aboslutely correct on clean unmount.
+        *
+        * We don't bother correcting this elsewhere for lazy superblock
+        * counting because on mount of an unclean filesystem we reconstruct the
+        * correct counter value and this is irrelevant.
+        *
+        * For non-lazy counter filesystems, this doesn't matter at all because
+        * we only every apply deltas to the superblock and hence the incore
+        * value does not matter....
+        */
+       resblks = 0;
+       xfs_reserve_blocks(mp, &resblks, NULL);
+
        xfs_log_sbcount(mp, 1);
        xfs_unmountfs_writesb(mp);
        xfs_unmountfs_wait(mp);                 /* wait for async bufs */