[XFS] Use do_div() on 64 bit types.
[safe/jmp/linux-2.6] / fs / xfs / xfs_fsops.c
index 56caa88..2251a49 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -96,6 +94,8 @@ xfs_fs_geometry(
                                XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
                        (XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
                                XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
+                       (xfs_sb_version_haslazysbcount(&mp->m_sb) ?
+                               XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
                        (XFS_SB_VERSION_HASATTR2(&mp->m_sb) ?
                                XFS_FSOP_GEOM_FLAGS_ATTR2 : 0);
                geo->logsectsize = XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
@@ -142,6 +142,8 @@ xfs_growfs_data_private(
        pct = in->imaxpct;
        if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
                return XFS_ERROR(EINVAL);
+       if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
+               return error;
        dpct = pct - mp->m_sb.sb_imax_pct;
        error = xfs_read_buf(mp, mp->m_ddev_targp,
                        XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
@@ -175,6 +177,7 @@ xfs_growfs_data_private(
                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);
@@ -252,8 +255,7 @@ xfs_growfs_data_private(
                block->bb_numrecs = cpu_to_be16(1);
                block->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
-               arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc,
-                       block, 1, mp->m_alloc_mxr[0]);
+               arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1);
                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
@@ -274,8 +276,7 @@ xfs_growfs_data_private(
                block->bb_numrecs = cpu_to_be16(1);
                block->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
-               arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc,
-                       block, 1, mp->m_alloc_mxr[0]);
+               arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1);
                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
@@ -332,6 +333,7 @@ xfs_growfs_data_private(
                be32_add(&agf->agf_length, new);
                ASSERT(be32_to_cpu(agf->agf_length) ==
                       be32_to_cpu(agi->agi_length));
+               xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
                /*
                 * Free the new space.
                 */
@@ -350,7 +352,7 @@ xfs_growfs_data_private(
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
        if (dpct)
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
-       error = xfs_trans_commit(tp, 0, NULL);
+       error = xfs_trans_commit(tp, 0);
        if (error) {
                return error;
        }
@@ -462,9 +464,9 @@ xfs_fs_counts(
 {
        unsigned long   s;
 
-       xfs_icsb_sync_counters_lazy(mp);
+       xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT);
        s = XFS_SB_LOCK(mp);
-       cnt->freedata = mp->m_sb.sb_fdblocks;
+       cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
        cnt->freertx = mp->m_sb.sb_frextents;
        cnt->freeino = mp->m_sb.sb_ifree;
        cnt->allocino = mp->m_sb.sb_icount;
@@ -477,7 +479,7 @@ xfs_fs_counts(
  *
  * xfs_reserve_blocks is called to set m_resblks
  * in the in-core mount table. The number of unused reserved blocks
- * is kept in m_resbls_avail.
+ * is kept in m_resblks_avail.
  *
  * Reserve the requested number of blocks if available. Otherwise return
  * as many as possible to satisfy the request. The actual number
@@ -493,63 +495,113 @@ xfs_reserve_blocks(
        __uint64_t              *inval,
        xfs_fsop_resblks_t      *outval)
 {
-       __int64_t               lcounter, delta;
+       __int64_t               lcounter, delta, fdblks_delta;
        __uint64_t              request;
        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;
        }
 
        request = *inval;
+
+       /*
+        * With per-cpu counters, this becomes an interesting
+        * problem. we needto work out if we are freeing or allocation
+        * blocks first, then we can do the modification as necessary.
+        *
+        * We do this under the XFS_SB_LOCK so that if we are near
+        * ENOSPC, we will hold out any changes while we work out
+        * what to do. This means that the amount of free space can
+        * change while we do this, so we need to retry if we end up
+        * trying to reserve more space than is available.
+        *
+        * We also use the xfs_mod_incore_sb() interface so that we
+        * don't have to care about whether per cpu counter are
+        * enabled, disabled or even compiled in....
+        */
+retry:
        s = XFS_SB_LOCK(mp);
+       xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED);
 
        /*
         * If our previous reservation was larger than the current value,
         * then move any unused blocks back to the free pool.
         */
-
+       fdblks_delta = 0;
        if (mp->m_resblks > request) {
                lcounter = mp->m_resblks_avail - request;
                if (lcounter  > 0) {            /* release unused blocks */
-                       mp->m_sb.sb_fdblocks += lcounter;
+                       fdblks_delta = lcounter;
                        mp->m_resblks_avail -= lcounter;
                }
                mp->m_resblks = request;
        } else {
+               __int64_t       free;
+
+               free =  mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
+               if (!free)
+                       goto out; /* ENOSPC and fdblks_delta = 0 */
+
                delta = request - mp->m_resblks;
-               lcounter = mp->m_sb.sb_fdblocks - delta;
+               lcounter = free - delta;
                if (lcounter < 0) {
                        /* We can't satisfy the request, just get what we can */
-                       mp->m_resblks += mp->m_sb.sb_fdblocks;
-                       mp->m_resblks_avail += mp->m_sb.sb_fdblocks;
-                       mp->m_sb.sb_fdblocks = 0;
+                       mp->m_resblks += free;
+                       mp->m_resblks_avail += free;
+                       fdblks_delta = -free;
+                       mp->m_sb.sb_fdblocks = XFS_ALLOC_SET_ASIDE(mp);
                } else {
-                       mp->m_sb.sb_fdblocks = lcounter;
+                       fdblks_delta = -delta;
+                       mp->m_sb.sb_fdblocks =
+                               lcounter + XFS_ALLOC_SET_ASIDE(mp);
                        mp->m_resblks = request;
                        mp->m_resblks_avail += delta;
                }
        }
-
-       outval->resblks = mp->m_resblks;
-       outval->resblks_avail = mp->m_resblks_avail;
+out:
+       if (outval) {
+               outval->resblks = mp->m_resblks;
+               outval->resblks_avail = mp->m_resblks_avail;
+       }
        XFS_SB_UNLOCK(mp, s);
+
+       if (fdblks_delta) {
+               /*
+                * If we are putting blocks back here, m_resblks_avail is
+                * already at it's max so this will put it in the free pool.
+                *
+                * If we need space, we'll either succeed in getting it
+                * from the free block count or we'll get an enospc. If
+                * we get a ENOSPC, it means things changed while we were
+                * calculating fdblks_delta and so we should try again to
+                * see if there is anything left to reserve.
+                *
+                * Don't set the reserved flag here - we don't want to reserve
+                * the extra reserve blocks from the reserve.....
+                */
+               int error;
+               error = xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, fdblks_delta, 0);
+               if (error == ENOSPC)
+                       goto retry;
+       }
+
        return 0;
 }
 
 void
-xfs_fs_log_dummy(xfs_mount_t *mp)
+xfs_fs_log_dummy(
+       xfs_mount_t     *mp)
 {
-       xfs_trans_t *tp;
-       xfs_inode_t *ip;
-
+       xfs_trans_t     *tp;
+       xfs_inode_t     *ip;
 
        tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1);
-       atomic_inc(&mp->m_active_trans);
        if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) {
                xfs_trans_cancel(tp, 0);
                return;
@@ -562,7 +614,7 @@ xfs_fs_log_dummy(xfs_mount_t *mp)
        xfs_trans_ihold(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        xfs_trans_set_sync(tp);
-       xfs_trans_commit(tp, 0, NULL);
+       xfs_trans_commit(tp, 0);
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
 }
@@ -574,21 +626,22 @@ xfs_fs_goingdown(
 {
        switch (inflags) {
        case XFS_FSOP_GOING_FLAGS_DEFAULT: {
-               struct vfs *vfsp = XFS_MTOVFS(mp);
+               struct bhv_vfs *vfsp = XFS_MTOVFS(mp);
                struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev);
 
                if (sb && !IS_ERR(sb)) {
-                       xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+                       xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                        thaw_bdev(sb->s_bdev, sb);
                }
        
                break;
        }
        case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+               xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                break;
        case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp,
+                               SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
                break;
        default:
                return XFS_ERROR(EINVAL);