Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / fs / xfs / quota / xfs_trans_dquot.c
index 149b2a1..9168918 100644 (file)
@@ -1,39 +1,25 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.
+ * All Rights Reserved.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation.
  *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_inum.h"
+#include "xfs_bit.h"
 #include "xfs_log.h"
+#include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
-#include "xfs_alloc_btree.h"
 #include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_ialloc.h"
+#include "xfs_itable.h"
+#include "xfs_btree.h"
 #include "xfs_bmap.h"
-#include "xfs_bit.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_itable.h"
 #include "xfs_rw.h"
 #include "xfs_acl.h"
 #include "xfs_cap.h"
@@ -65,7 +50,6 @@
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
-
 #include "xfs_qm.h"
 
 STATIC void    xfs_trans_alloc_dqinfo(xfs_trans_t *);
@@ -187,7 +171,7 @@ xfs_trans_dup_dqinfo(
 /*
  * Wrap around mod_dquot to account for both user and group quotas.
  */
-void
+STATIC void
 xfs_trans_mod_dquot_byino(
        xfs_trans_t     *tp,
        xfs_inode_t     *ip,
@@ -207,12 +191,10 @@ xfs_trans_mod_dquot_byino(
        if (tp->t_dqinfo == NULL)
                xfs_trans_alloc_dqinfo(tp);
 
-       if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) {
+       if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
                (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
-       }
-       if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) {
+       if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot)
                (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
-       }
 }
 
 STATIC xfs_dqtrx_t *
@@ -368,7 +350,7 @@ xfs_trans_dqlockedjoin(
  * Unreserve just the reservations done by this transaction.
  * dquot is still left locked at exit.
  */
-void
+STATIC void
 xfs_trans_apply_dquot_deltas(
        xfs_trans_t             *tp)
 {
@@ -431,25 +413,25 @@ xfs_trans_apply_dquot_deltas(
                                qtrx->qt_delrtb_delta;
 #ifdef QUOTADEBUG
                        if (totalbdelta < 0)
-                               ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
+                               ASSERT(be64_to_cpu(d->d_bcount) >=
                                       (xfs_qcnt_t) -totalbdelta);
 
                        if (totalrtbdelta < 0)
-                               ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
+                               ASSERT(be64_to_cpu(d->d_rtbcount) >=
                                       (xfs_qcnt_t) -totalrtbdelta);
 
                        if (qtrx->qt_icount_delta < 0)
-                               ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
+                               ASSERT(be64_to_cpu(d->d_icount) >=
                                       (xfs_qcnt_t) -qtrx->qt_icount_delta);
 #endif
                        if (totalbdelta)
-                               INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
+                               be64_add(&d->d_bcount, (xfs_qcnt_t)totalbdelta);
 
                        if (qtrx->qt_icount_delta)
-                               INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
+                               be64_add(&d->d_icount, (xfs_qcnt_t)qtrx->qt_icount_delta);
 
                        if (totalrtbdelta)
-                               INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
+                               be64_add(&d->d_rtbcount, (xfs_qcnt_t)totalrtbdelta);
 
                        /*
                         * Get any default limits in use.
@@ -499,7 +481,7 @@ xfs_trans_apply_dquot_deltas(
                         * Adjust the RT reservation.
                         */
                        if (qtrx->qt_rtblk_res != 0) {
-                               if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+                               if (qtrx->qt_rtblk_res != qtrx->qt_rtblk_res_used) {
                                        if (qtrx->qt_rtblk_res >
                                            qtrx->qt_rtblk_res_used)
                                               dqp->q_res_rtbcount -= (xfs_qcnt_t)
@@ -532,18 +514,12 @@ xfs_trans_apply_dquot_deltas(
                                            (xfs_qcnt_t)qtrx->qt_icount_delta;
                        }
 
-
-#ifdef QUOTADEBUG
-                       if (qtrx->qt_rtblk_res != 0)
-                               cmn_err(CE_DEBUG, "RT res %d for 0x%p\n",
-                                       (int) qtrx->qt_rtblk_res, dqp);
-#endif
                        ASSERT(dqp->q_res_bcount >=
-                               INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+                               be64_to_cpu(dqp->q_core.d_bcount));
                        ASSERT(dqp->q_res_icount >=
-                               INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+                               be64_to_cpu(dqp->q_core.d_icount));
                        ASSERT(dqp->q_res_rtbcount >=
-                               INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
+                               be64_to_cpu(dqp->q_core.d_rtbcount));
                }
                /*
                 * Do the group quotas next
@@ -619,12 +595,19 @@ xfs_trans_unreserve_and_mod_dquots(
        }
 }
 
+STATIC int
+xfs_quota_error(uint flags)
+{
+       if (flags & XFS_QMOPT_ENOSPC)
+               return ENOSPC;
+       return EDQUOT;
+}
+
 /*
  * This reserves disk blocks and inodes against a dquot.
  * Flags indicate if the dquot is to be locked here and also
  * if the blk reservation is for RT or regular blocks.
  * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
- * Returns EDQUOT if quota is exceeded.
  */
 STATIC int
 xfs_trans_dqresv(
@@ -638,7 +621,10 @@ xfs_trans_dqresv(
        int             error;
        xfs_qcnt_t      hardlimit;
        xfs_qcnt_t      softlimit;
-       time_t          btimer;
+       time_t          timer;
+       xfs_qwarncnt_t  warns;
+       xfs_qwarncnt_t  warnlimit;
+       xfs_qcnt_t      count;
        xfs_qcnt_t      *resbcountp;
        xfs_quotainfo_t *q = mp->m_quotainfo;
 
@@ -647,23 +633,27 @@ xfs_trans_dqresv(
        }
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        if (flags & XFS_TRANS_DQ_RES_BLKS) {
-               hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
+               hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);
                if (!hardlimit)
                        hardlimit = q->qi_bhardlimit;
-               softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
+               softlimit = be64_to_cpu(dqp->q_core.d_blk_softlimit);
                if (!softlimit)
                        softlimit = q->qi_bsoftlimit;
-               btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
+               timer = be32_to_cpu(dqp->q_core.d_btimer);
+               warns = be16_to_cpu(dqp->q_core.d_bwarns);
+               warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount);
                resbcountp = &dqp->q_res_bcount;
        } else {
                ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
-               hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
+               hardlimit = be64_to_cpu(dqp->q_core.d_rtb_hardlimit);
                if (!hardlimit)
                        hardlimit = q->qi_rtbhardlimit;
-               softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
+               softlimit = be64_to_cpu(dqp->q_core.d_rtb_softlimit);
                if (!softlimit)
                        softlimit = q->qi_rtbsoftlimit;
-               btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
+               timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+               warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
+               warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount);
                resbcountp = &dqp->q_res_rtbcount;
        }
        error = 0;
@@ -683,48 +673,37 @@ xfs_trans_dqresv(
                         */
                        if (hardlimit > 0ULL &&
                             (hardlimit <= nblks + *resbcountp)) {
-                               error = EDQUOT;
+                               error = xfs_quota_error(flags);
                                goto error_return;
                        }
 
                        if (softlimit > 0ULL &&
                             (softlimit <= nblks + *resbcountp)) {
-                               /*
-                                * If timer or warnings has expired,
-                                * return EDQUOT
-                                */
-                               if ((btimer != 0 && get_seconds() > btimer) ||
-                                   (dqp->q_core.d_bwarns &&
-                                    INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
-                                    XFS_QI_BWARNLIMIT(dqp->q_mount))) {
-                                       error = EDQUOT;
+                               if ((timer != 0 && get_seconds() > timer) ||
+                                   (warns != 0 && warns >= warnlimit)) {
+                                       error = xfs_quota_error(flags);
                                        goto error_return;
                                }
                        }
                }
                if (ninos > 0) {
-                       hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT);
+                       count = be64_to_cpu(dqp->q_core.d_icount);
+                       timer = be32_to_cpu(dqp->q_core.d_itimer);
+                       warns = be16_to_cpu(dqp->q_core.d_iwarns);
+                       warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount);
+                       hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
                        if (!hardlimit)
                                hardlimit = q->qi_ihardlimit;
-                       softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT);
+                       softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
                        if (!softlimit)
                                softlimit = q->qi_isoftlimit;
-                       if (hardlimit > 0ULL &&
-                           INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) {
-                               error = EDQUOT;
+                       if (hardlimit > 0ULL && count >= hardlimit) {
+                               error = xfs_quota_error(flags);
                                goto error_return;
-                       } else if (softlimit > 0ULL &&
-                                  INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) {
-                               /*
-                                * If timer or warnings has expired,
-                                * return EDQUOT
-                                */
-                               if ((dqp->q_core.d_itimer &&
-                                    get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
-                                   (dqp->q_core.d_iwarns &&
-                                    INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
-                                    XFS_QI_IWARNLIMIT(dqp->q_mount))) {
-                                       error = EDQUOT;
+                       } else if (softlimit > 0ULL && count >= softlimit) {
+                               if ((timer != 0 && get_seconds() > timer) ||
+                                    (warns != 0 && warns >= warnlimit)) {
+                                       error = xfs_quota_error(flags);
                                        goto error_return;
                                }
                        }
@@ -758,9 +737,9 @@ xfs_trans_dqresv(
                                            XFS_TRANS_DQ_RES_INOS,
                                            ninos);
        }
-       ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-       ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
-       ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+       ASSERT(dqp->q_res_bcount >= be64_to_cpu(dqp->q_core.d_bcount));
+       ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount));
+       ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount));
 
 error_return:
        if (! (flags & XFS_QMOPT_DQLOCK)) {
@@ -771,13 +750,14 @@ error_return:
 
 
 /*
- * Given dquot(s), make disk block and/or inode reservations against them.
+ * Given dquot(s), make disk block and/or inode reservations against them.
  * The fact that this does the reservation against both the usr and
- * grp quotas is important, because this follows a both-or-nothing
+ * grp/prj quotas is important, because this follows a both-or-nothing
  * approach.
  *
  * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
  *        XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
+ *        XFS_QMOPT_ENOSPC returns ENOSPC not EDQUOT.  Used by pquota.
  *        XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
  *        XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
  * dquots are unlocked on return, if they were not locked by caller.
@@ -792,25 +772,27 @@ xfs_trans_reserve_quota_bydquots(
        long            ninos,
        uint            flags)
 {
-       int             resvd;
+       int             resvd = 0, error;
 
-       if (! XFS_IS_QUOTA_ON(mp))
-               return (0);
+       if (!XFS_IS_QUOTA_ON(mp))
+               return 0;
 
        if (tp && tp->t_dqinfo == NULL)
                xfs_trans_alloc_dqinfo(tp);
 
        ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-       resvd = 0;
 
        if (udqp) {
-               if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
-                       return (EDQUOT);
+               error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
+                                       (flags & ~XFS_QMOPT_ENOSPC));
+               if (error)
+                       return error;
                resvd = 1;
        }
 
        if (gdqp) {
-               if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) {
+               error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
+               if (error) {
                        /*
                         * can't do it, so backout previous reservation
                         */
@@ -819,14 +801,14 @@ xfs_trans_reserve_quota_bydquots(
                                xfs_trans_dqresv(tp, mp, udqp,
                                                 -nblks, -ninos, flags);
                        }
-                       return (EDQUOT);
+                       return error;
                }
        }
 
        /*
-        * Didnt change anything critical, so, no need to log
+        * Didn't change anything critical, so, no need to log
         */
-       return (0);
+       return 0;
 }
 
 
@@ -834,8 +816,6 @@ xfs_trans_reserve_quota_bydquots(
  * Lock the dquot and change the reservation if we can.
  * This doesn't change the actual usage, just the reservation.
  * The inode sent in is locked.
- *
- * Returns 0 on success, EDQUOT or other errors otherwise
  */
 STATIC int
 xfs_trans_reserve_quota_nblks(
@@ -844,20 +824,24 @@ xfs_trans_reserve_quota_nblks(
        xfs_inode_t     *ip,
        long            nblks,
        long            ninos,
-       uint            type)
+       uint            flags)
 {
        int             error;
 
        if (!XFS_IS_QUOTA_ON(mp))
-               return (0);
+               return 0;
+       if (XFS_IS_PQUOTA_ON(mp))
+               flags |= XFS_QMOPT_ENOSPC;
 
        ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
        ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
 
        ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
        ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-       ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
-              (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
+       ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
+                               XFS_TRANS_DQ_RES_RTBLKS ||
+              (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
+                               XFS_TRANS_DQ_RES_BLKS);
 
        /*
         * Reserve nblks against these dquots, with trans as the mediator.
@@ -865,8 +849,8 @@ xfs_trans_reserve_quota_nblks(
        error = xfs_trans_reserve_quota_bydquots(tp, mp,
                                                 ip->i_udquot, ip->i_gdquot,
                                                 nblks, ninos,
-                                                type);
-       return (error);
+                                                flags);
+       return error;
 }
 
 /*