fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / xfs / xfs_ialloc.c
index 8f3fae1..a446e5a 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"
@@ -136,10 +134,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;
@@ -154,46 +150,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 = 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;
+       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
@@ -250,10 +275,6 @@ 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.
@@ -266,12 +287,13 @@ 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);
@@ -436,7 +458,7 @@ nextag:
                 */
                if (XFS_FORCED_SHUTDOWN(mp)) {
                        up_read(&mp->m_peraglock);
-                       return (xfs_buf_t *)0;
+                       return NULL;
                }
                agno++;
                if (agno >= agcount)
@@ -444,7 +466,7 @@ nextag:
                if (agno == pagno) {
                        if (flags == 0) {
                                up_read(&mp->m_peraglock);
-                               return (xfs_buf_t *)0;
+                               return NULL;
                        }
                        flags = 0;
                }
@@ -507,10 +529,10 @@ xfs_dialloc(
        int             offset;         /* index of inode in chunk */
        xfs_agino_t     pagino;         /* parent's a.g. relative inode # */
        xfs_agnumber_t  pagno;          /* parent's allocation group number */
-       xfs_inobt_rec_t rec;            /* inode allocation record */
+       xfs_inobt_rec_incore_t rec;     /* inode allocation record */
        xfs_agnumber_t  tagno;          /* testing allocation group number */
        xfs_btree_cur_t *tcur;          /* temp cursor */
-       xfs_inobt_rec_t trec;           /* temp inode allocation record */
+       xfs_inobt_rec_incore_t trec;    /* temp inode allocation record */
 
 
        if (*IO_agbp == NULL) {
@@ -923,7 +945,7 @@ xfs_difree(
        int             ilen;   /* inodes in an inode cluster */
        xfs_mount_t     *mp;    /* mount structure for filesystem */
        int             off;    /* offset of inode in inode chunk */
-       xfs_inobt_rec_t rec;    /* btree record */
+       xfs_inobt_rec_incore_t rec;     /* btree record */
 
        mp = tp->t_mountp;
 
@@ -1028,7 +1050,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))) {
@@ -1150,6 +1172,9 @@ xfs_dilocate(
        if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
            ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
 #ifdef DEBUG
+               /* no diagnostics for bulkstat, ino comes from userspace */
+               if (flags & XFS_IMAP_BULKSTAT)
+                       return XFS_ERROR(EINVAL);
                if (agno >= mp->m_sb.sb_agcount) {
                        xfs_fs_cmn_err(CE_ALERT, mp,
                                        "xfs_dilocate: agno (%d) >= "
@@ -1170,6 +1195,7 @@ xfs_dilocate(
                                        "(0x%llx)",
                                        ino, XFS_AGINO_TO_INO(mp, agno, agino));
                }
+               xfs_stack_trace();
 #endif /* DEBUG */
                return XFS_ERROR(EINVAL);
        }