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 / xfs_ialloc.c
index ce5fee9..deddbd0 100644 (file)
@@ -1,41 +1,26 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2002,2005 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_macros.h"
+#include "xfs_fs.h"
 #include "xfs_types.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_dir2.h"
 #include "xfs_dmapi.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_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
 #include "xfs_alloc.h"
-#include "xfs_bit.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_bmap.h"
@@ -152,10 +136,8 @@ xfs_ialloc_ag_alloc(
        int             ninodes;        /* num inodes per buf */
        xfs_agino_t     thisino;        /* current inode number, for loop */
        int             version;        /* inode version number to use */
-       int             isaligned;      /* inode allocation at stripe unit */
+       int             isaligned = 0;  /* inode allocation at stripe unit */
                                        /* boundary */
-       xfs_dinode_core_t dic;          /* a dinode_core to copy to new */
-                                       /* inodes */
 
        args.tp = tp;
        args.mp = tp->t_mountp;
@@ -170,46 +152,75 @@ xfs_ialloc_ag_alloc(
                return XFS_ERROR(ENOSPC);
        args.minlen = args.maxlen = XFS_IALLOC_BLOCKS(args.mp);
        /*
-        * Set the alignment for the allocation.
-        * If stripe alignment is turned on then align at stripe unit
-        * boundary.
-        * If the cluster size is smaller than a filesystem block
-        * then we're doing I/O for inodes in filesystem block size pieces,
-        * so don't need alignment anyway.
-        */
-       isaligned = 0;
-       if (args.mp->m_sinoalign) {
-               ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN));
-               args.alignment = args.mp->m_dalign;
-               isaligned = 1;
-       } else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) &&
-           args.mp->m_sb.sb_inoalignmt >=
-           XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp)))
-               args.alignment = args.mp->m_sb.sb_inoalignmt;
-       else
-               args.alignment = 1;
+        * First try to allocate inodes contiguous with the last-allocated
+        * chunk of inodes.  If the filesystem is striped, this will fill
+        * an entire stripe unit with inodes.
+        */
        agi = XFS_BUF_TO_AGI(agbp);
-       /*
-        * Need to figure out where to allocate the inode blocks.
-        * Ideally they should be spaced out through the a.g.
-        * For now, just allocate blocks up front.
-        */
-       args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT);
-       args.fsbno = XFS_AGB_TO_FSB(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT),
-                                   args.agbno);
-       /*
-        * Allocate a fixed-size extent of inodes.
-        */
-       args.type = XFS_ALLOCTYPE_NEAR_BNO;
-       args.mod = args.total = args.wasdel = args.isfl = args.userdata =
-               args.minalignslop = 0;
-       args.prod = 1;
-       /*
-        * Allow space for the inode btree to split.
-        */
-       args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
-       if ((error = xfs_alloc_vextent(&args)))
-               return error;
+       newino = be32_to_cpu(agi->agi_newino);
+       args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
+                       XFS_IALLOC_BLOCKS(args.mp);
+       if (likely(newino != NULLAGINO &&
+                 (args.agbno < be32_to_cpu(agi->agi_length)))) {
+               args.fsbno = XFS_AGB_TO_FSB(args.mp,
+                               be32_to_cpu(agi->agi_seqno), args.agbno);
+               args.type = XFS_ALLOCTYPE_THIS_BNO;
+               args.mod = args.total = args.wasdel = args.isfl =
+                       args.userdata = args.minalignslop = 0;
+               args.prod = 1;
+               args.alignment = 1;
+               /*
+                * Allow space for the inode btree to split.
+                */
+               args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+               if ((error = xfs_alloc_vextent(&args)))
+                       return error;
+       } else
+               args.fsbno = NULLFSBLOCK;
+
+       if (unlikely(args.fsbno == NULLFSBLOCK)) {
+               /*
+                * Set the alignment for the allocation.
+                * If stripe alignment is turned on then align at stripe unit
+                * boundary.
+                * If the cluster size is smaller than a filesystem block
+                * then we're doing I/O for inodes in filesystem block size
+                * pieces, so don't need alignment anyway.
+                */
+               isaligned = 0;
+               if (args.mp->m_sinoalign) {
+                       ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN));
+                       args.alignment = args.mp->m_dalign;
+                       isaligned = 1;
+               } else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) &&
+                          args.mp->m_sb.sb_inoalignmt >=
+                          XFS_B_TO_FSBT(args.mp,
+                               XFS_INODE_CLUSTER_SIZE(args.mp)))
+                               args.alignment = args.mp->m_sb.sb_inoalignmt;
+               else
+                       args.alignment = 1;
+               /*
+                * Need to figure out where to allocate the inode blocks.
+                * Ideally they should be spaced out through the a.g.
+                * For now, just allocate blocks up front.
+                */
+               args.agbno = be32_to_cpu(agi->agi_root);
+               args.fsbno = XFS_AGB_TO_FSB(args.mp,
+                               be32_to_cpu(agi->agi_seqno), args.agbno);
+               /*
+                * Allocate a fixed-size extent of inodes.
+                */
+               args.type = XFS_ALLOCTYPE_NEAR_BNO;
+               args.mod = args.total = args.wasdel = args.isfl =
+                       args.userdata = args.minalignslop = 0;
+               args.prod = 1;
+               /*
+                * Allow space for the inode btree to split.
+                */
+               args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+               if ((error = xfs_alloc_vextent(&args)))
+                       return error;
+       }
 
        /*
         * If stripe alignment is turned on, then try again with cluster
@@ -217,9 +228,9 @@ xfs_ialloc_ag_alloc(
         */
        if (isaligned && args.fsbno == NULLFSBLOCK) {
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
-               args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT);
+               args.agbno = be32_to_cpu(agi->agi_root);
                args.fsbno = XFS_AGB_TO_FSB(args.mp,
-                               INT_GET(agi->agi_seqno, ARCH_CONVERT), args.agbno);
+                               be32_to_cpu(agi->agi_seqno), args.agbno);
                if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) &&
                        args.mp->m_sb.sb_inoalignmt >=
                        XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp)))
@@ -266,15 +277,11 @@ xfs_ialloc_ag_alloc(
        else
                version = XFS_DINODE_VERSION_1;
 
-       memset(&dic, 0, sizeof(xfs_dinode_core_t));
-       INT_SET(dic.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC);
-       INT_SET(dic.di_version, ARCH_CONVERT, version);
-
        for (j = 0; j < nbufs; j++) {
                /*
                 * Get the block.
                 */
-               d = XFS_AGB_TO_DADDR(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT),
+               d = XFS_AGB_TO_DADDR(args.mp, be32_to_cpu(agi->agi_seqno),
                                     args.agbno + (j * blks_per_cluster));
                fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d,
                                         args.mp->m_bsize * blks_per_cluster,
@@ -282,29 +289,30 @@ xfs_ialloc_ag_alloc(
                ASSERT(fbuf);
                ASSERT(!XFS_BUF_GETERROR(fbuf));
                /*
-                * Loop over the inodes in this buffer.
+                * Set initial values for the inodes in this buffer.
                 */
-
+               xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog);
                for (i = 0; i < ninodes; i++) {
                        free = XFS_MAKE_IPTR(args.mp, fbuf, i);
-                       memcpy(&(free->di_core), &dic, sizeof(xfs_dinode_core_t));
+                       INT_SET(free->di_core.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC);
+                       INT_SET(free->di_core.di_version, ARCH_CONVERT, version);
                        INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO);
                        xfs_ialloc_log_di(tp, fbuf, i,
                                XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
                }
                xfs_trans_inode_alloc_buf(tp, fbuf);
        }
-       INT_MOD(agi->agi_count, ARCH_CONVERT, newlen);
-       INT_MOD(agi->agi_freecount, ARCH_CONVERT, newlen);
+       be32_add(&agi->agi_count, newlen);
+       be32_add(&agi->agi_freecount, newlen);
        down_read(&args.mp->m_peraglock);
-       args.mp->m_perag[INT_GET(agi->agi_seqno, ARCH_CONVERT)].pagi_freecount += newlen;
+       args.mp->m_perag[be32_to_cpu(agi->agi_seqno)].pagi_freecount += newlen;
        up_read(&args.mp->m_peraglock);
-       INT_SET(agi->agi_newino, ARCH_CONVERT, newino);
+       agi->agi_newino = cpu_to_be32(newino);
        /*
         * Insert records describing the new inode chunk into the btree.
         */
        cur = xfs_btree_init_cursor(args.mp, tp, agbp,
-                       INT_GET(agi->agi_seqno, ARCH_CONVERT),
+                       be32_to_cpu(agi->agi_seqno),
                        XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
        for (thisino = newino;
             thisino < newino + newlen;
@@ -544,7 +552,7 @@ xfs_dialloc(
                        return 0;
                }
                agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC);
+               ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);
        } else {
                /*
                 * Continue where we left off before.  In this case, we
@@ -552,12 +560,12 @@ xfs_dialloc(
                 */
                agbp = *IO_agbp;
                agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC);
-               ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0);
+               ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);
+               ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
        }
        mp = tp->t_mountp;
        agcount = mp->m_sb.sb_agcount;
-       agno = INT_GET(agi->agi_seqno, ARCH_CONVERT);
+       agno = be32_to_cpu(agi->agi_seqno);
        tagno = agno;
        pagno = XFS_INO_TO_AGNO(mp, parent);
        pagino = XFS_INO_TO_AGINO(mp, parent);
@@ -605,7 +613,7 @@ xfs_dialloc(
                                 * can commit the current transaction and call
                                 * us again where we left off.
                                 */
-                               ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0);
+                               ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
                                *alloc_done = B_TRUE;
                                *IO_agbp = agbp;
                                *inop = NULLFSINO;
@@ -636,7 +644,7 @@ nextag:
                if (error)
                        goto nextag;
                agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC);
+               ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);
        }
        /*
         * Here with an allocation group that has a free inode.
@@ -645,14 +653,14 @@ nextag:
         */
        agno = tagno;
        *IO_agbp = NULL;
-       cur = xfs_btree_init_cursor(mp, tp, agbp, INT_GET(agi->agi_seqno, ARCH_CONVERT),
+       cur = xfs_btree_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno),
                                    XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
        /*
         * If pagino is 0 (this is the root inode allocation) use newino.
         * This must work because we've just allocated some.
         */
        if (!pagino)
-               pagino = INT_GET(agi->agi_newino, ARCH_CONVERT);
+               pagino = be32_to_cpu(agi->agi_newino);
 #ifdef DEBUG
        if (cur->bc_nlevels == 1) {
                int     freecount = 0;
@@ -670,7 +678,7 @@ nextag:
                                goto error0;
                } while (i == 1);
 
-               ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
+               ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||
                       XFS_FORCED_SHUTDOWN(mp));
        }
 #endif
@@ -829,9 +837,9 @@ nextag:
         * In a different a.g. from the parent.
         * See if the most recently allocated block has any free.
         */
-       else if (INT_GET(agi->agi_newino, ARCH_CONVERT) != NULLAGINO) {
+       else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {
                if ((error = xfs_inobt_lookup_eq(cur,
-                               INT_GET(agi->agi_newino, ARCH_CONVERT), 0, 0, &i)))
+                               be32_to_cpu(agi->agi_newino), 0, 0, &i)))
                        goto error0;
                if (i == 1 &&
                    (error = xfs_inobt_get_rec(cur, &rec.ir_startino,
@@ -878,7 +886,7 @@ nextag:
        if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount,
                        rec.ir_free)))
                goto error0;
-       INT_MOD(agi->agi_freecount, ARCH_CONVERT, -1);
+       be32_add(&agi->agi_freecount, -1);
        xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
        down_read(&mp->m_peraglock);
        mp->m_perag[tagno].pagi_freecount--;
@@ -898,7 +906,7 @@ nextag:
                        if ((error = xfs_inobt_increment(cur, 0, &i)))
                                goto error0;
                } while (i == 1);
-               ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
+               ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||
                       XFS_FORCED_SHUTDOWN(mp));
        }
 #endif
@@ -957,8 +965,11 @@ xfs_difree(
        agino = XFS_INO_TO_AGINO(mp, inode);
        if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
                cmn_err(CE_WARN,
-                       "xfs_difree: inode != XFS_AGINO_TO_INO() (%d != %d) on %s.  Returning EINVAL.",
-                       inode, XFS_AGINO_TO_INO(mp, agno, agino), mp->m_fsname);
+                       "xfs_difree: inode != XFS_AGINO_TO_INO() "
+                       "(%llu != %llu) on %s.  Returning EINVAL.",
+                       (unsigned long long)inode,
+                       (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino),
+                       mp->m_fsname);
                ASSERT(0);
                return XFS_ERROR(EINVAL);
        }
@@ -983,8 +994,8 @@ xfs_difree(
                return error;
        }
        agi = XFS_BUF_TO_AGI(agbp);
-       ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC);
-       ASSERT(agbno < INT_GET(agi->agi_length, ARCH_CONVERT));
+       ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);
+       ASSERT(agbno < be32_to_cpu(agi->agi_length));
        /*
         * Initialize the cursor.
         */
@@ -1006,7 +1017,7 @@ xfs_difree(
                                        goto error0;
                        }
                } while (i == 1);
-               ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
+               ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||
                       XFS_FORCED_SHUTDOWN(mp));
        }
 #endif
@@ -1041,7 +1052,7 @@ xfs_difree(
        rec.ir_freecount++;
 
        /*
-        * When an inode cluster is free, it becomes elgible for removal
+        * When an inode cluster is free, it becomes eligible for removal
         */
        if ((mp->m_flags & XFS_MOUNT_IDELETE) &&
            (rec.ir_freecount == XFS_IALLOC_INODES(mp))) {
@@ -1055,8 +1066,8 @@ xfs_difree(
                 * to be freed when the transaction is committed.
                 */
                ilen = XFS_IALLOC_INODES(mp);
-               INT_MOD(agi->agi_count, ARCH_CONVERT, -ilen);
-               INT_MOD(agi->agi_freecount, ARCH_CONVERT, -(ilen - 1));
+               be32_add(&agi->agi_count, -ilen);
+               be32_add(&agi->agi_freecount, -(ilen - 1));
                xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT);
                down_read(&mp->m_peraglock);
                mp->m_perag[agno].pagi_freecount -= ilen - 1;
@@ -1085,7 +1096,7 @@ xfs_difree(
                /* 
                 * Change the inode free counts and log the ag/sb changes.
                 */
-               INT_MOD(agi->agi_freecount, ARCH_CONVERT, 1);
+               be32_add(&agi->agi_freecount, 1);
                xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
                down_read(&mp->m_peraglock);
                mp->m_perag[agno].pagi_freecount++;
@@ -1111,7 +1122,7 @@ xfs_difree(
                                        goto error0;
                        }
                } while (i == 1);
-               ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
+               ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||
                       XFS_FORCED_SHUTDOWN(mp));
        }
 #endif
@@ -1320,7 +1331,7 @@ xfs_ialloc_log_agi(
        xfs_agi_t               *agi;   /* allocation group header */
 
        agi = XFS_BUF_TO_AGI(bp);
-       ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC);
+       ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);
 #endif
        /*
         * Compute byte offsets for the first and last fields.
@@ -1362,9 +1373,8 @@ xfs_ialloc_read_agi(
         */
        agi = XFS_BUF_TO_AGI(bp);
        agi_ok =
-               INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC &&
-               XFS_AGI_GOOD_VERSION(
-                       INT_GET(agi->agi_versionnum, ARCH_CONVERT));
+               be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&
+               XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
        if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI,
                        XFS_RANDOM_IALLOC_READ_AGI))) {
                XFS_CORRUPTION_ERROR("xfs_ialloc_read_agi", XFS_ERRLEVEL_LOW,
@@ -1374,16 +1384,15 @@ xfs_ialloc_read_agi(
        }
        pag = &mp->m_perag[agno];
        if (!pag->pagi_init) {
-               pag->pagi_freecount = INT_GET(agi->agi_freecount, ARCH_CONVERT);
+               pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
                pag->pagi_init = 1;
        } else {
                /*
                 * It's possible for these to be out of sync if
                 * we are in the middle of a forced shutdown.
                 */
-               ASSERT(pag->pagi_freecount ==
-                               INT_GET(agi->agi_freecount, ARCH_CONVERT)
-                       || XFS_FORCED_SHUTDOWN(mp));
+               ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) ||
+                       XFS_FORCED_SHUTDOWN(mp));
        }
 
 #ifdef DEBUG