libertas: unify various CF-related defines
[safe/jmp/linux-2.6] / fs / xfs / xfs_ialloc.c
index 7e5ccfe..aad8c5d 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"
@@ -109,6 +107,16 @@ xfs_ialloc_log_di(
 /*
  * Allocation group level functions.
  */
+static inline int
+xfs_ialloc_cluster_alignment(
+       xfs_alloc_arg_t *args)
+{
+       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)))
+               return args->mp->m_sb.sb_inoalignmt;
+       return 1;
+}
 
 /*
  * Allocate new inodes in the allocation group specified by agbp.
@@ -125,6 +133,7 @@ xfs_ialloc_ag_alloc(
        int             blks_per_cluster;  /* fs blocks per inode cluster */
        xfs_btree_cur_t *cur;           /* inode btree cursor */
        xfs_daddr_t     d;              /* disk addr of buffer */
+       xfs_agnumber_t  agno;
        int             error;
        xfs_buf_t       *fbuf;          /* new free inodes' buffer */
        xfs_dinode_t    *free;          /* new free inode structure */
@@ -138,6 +147,7 @@ xfs_ialloc_ag_alloc(
        int             version;        /* inode version number to use */
        int             isaligned = 0;  /* inode allocation at stripe unit */
                                        /* boundary */
+       unsigned int    gen;
 
        args.tp = tp;
        args.mp = tp->t_mountp;
@@ -168,10 +178,24 @@ xfs_ialloc_ag_alloc(
                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.
+                * We need to take into account alignment here to ensure that
+                * we don't modify the free list if we fail to have an exact
+                * block. If we don't have an exact match, and every oher
+                * attempt allocation attempt fails, we'll end up cancelling
+                * a dirty transaction and shutting down.
+                *
+                * For an exact allocation, alignment must be 1,
+                * however we need to take cluster alignment into account when
+                * fixing up the freelist. Use the minalignslop field to
+                * indicate that extra blocks might be required for alignment,
+                * but not to use them in the actual exact allocation.
                 */
+               args.alignment = 1;
+               args.minalignslop = xfs_ialloc_cluster_alignment(&args) - 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;
@@ -192,13 +216,8 @@ xfs_ialloc_ag_alloc(
                        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;
+               } else
+                       args.alignment = xfs_ialloc_cluster_alignment(&args);
                /*
                 * Need to figure out where to allocate the inode blocks.
                 * Ideally they should be spaced out through the a.g.
@@ -231,12 +250,7 @@ xfs_ialloc_ag_alloc(
                args.agbno = be32_to_cpu(agi->agi_root);
                args.fsbno = XFS_AGB_TO_FSB(args.mp,
                                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)))
-                               args.alignment = args.mp->m_sb.sb_inoalignmt;
-               else
-                       args.alignment = 1;
+               args.alignment = xfs_ialloc_cluster_alignment(&args);
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
@@ -272,11 +286,19 @@ xfs_ialloc_ag_alloc(
         * use the old version so that old kernels will continue to be
         * able to use the file system.
         */
-       if (XFS_SB_VERSION_HASNLINK(&args.mp->m_sb))
+       if (xfs_sb_version_hasnlink(&args.mp->m_sb))
                version = XFS_DINODE_VERSION_2;
        else
                version = XFS_DINODE_VERSION_1;
 
+       /*
+        * Seed the new inode cluster with a random generation number. This
+        * prevents short-term reuse of generation numbers if a chunk is
+        * freed and then immediately reallocated. We use random numbers
+        * rather than a linear progression to prevent the next generation
+        * number from being easily guessable.
+        */
+       gen = random32();
        for (j = 0; j < nbufs; j++) {
                /*
                 * Get the block.
@@ -294,25 +316,26 @@ xfs_ialloc_ag_alloc(
                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);
-                       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);
+                       free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
+                       free->di_core.di_version = version;
+                       free->di_core.di_gen = cpu_to_be32(gen);
+                       free->di_next_unlinked = cpu_to_be32(NULLAGINO);
                        xfs_ialloc_log_di(tp, fbuf, i,
                                XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
                }
                xfs_trans_inode_alloc_buf(tp, fbuf);
        }
-       be32_add(&agi->agi_count, newlen);
-       be32_add(&agi->agi_freecount, newlen);
+       be32_add_cpu(&agi->agi_count, newlen);
+       be32_add_cpu(&agi->agi_freecount, newlen);
+       agno = be32_to_cpu(agi->agi_seqno);
        down_read(&args.mp->m_peraglock);
-       args.mp->m_perag[be32_to_cpu(agi->agi_seqno)].pagi_freecount += newlen;
+       args.mp->m_perag[agno].pagi_freecount += newlen;
        up_read(&args.mp->m_peraglock);
        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,
-                       be32_to_cpu(agi->agi_seqno),
+       cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno,
                        XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
        for (thisino = newino;
             thisino < newino + newlen;
@@ -344,7 +367,7 @@ xfs_ialloc_ag_alloc(
        return 0;
 }
 
-STATIC __inline xfs_agnumber_t
+STATIC_INLINE xfs_agnumber_t
 xfs_ialloc_next_ag(
        xfs_mount_t     *mp)
 {
@@ -460,7 +483,7 @@ nextag:
                 */
                if (XFS_FORCED_SHUTDOWN(mp)) {
                        up_read(&mp->m_peraglock);
-                       return (xfs_buf_t *)0;
+                       return NULL;
                }
                agno++;
                if (agno >= agcount)
@@ -468,7 +491,7 @@ nextag:
                if (agno == pagno) {
                        if (flags == 0) {
                                up_read(&mp->m_peraglock);
-                               return (xfs_buf_t *)0;
+                               return NULL;
                        }
                        flags = 0;
                }
@@ -531,10 +554,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) {
@@ -886,7 +909,7 @@ nextag:
        if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount,
                        rec.ir_free)))
                goto error0;
-       be32_add(&agi->agi_freecount, -1);
+       be32_add_cpu(&agi->agi_freecount, -1);
        xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
        down_read(&mp->m_peraglock);
        mp->m_perag[tagno].pagi_freecount--;
@@ -947,7 +970,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;
 
@@ -1054,7 +1077,7 @@ xfs_difree(
        /*
         * When an inode cluster is free, it becomes eligible for removal
         */
-       if ((mp->m_flags & XFS_MOUNT_IDELETE) &&
+       if (!(mp->m_flags & XFS_MOUNT_IKEEP) &&
            (rec.ir_freecount == XFS_IALLOC_INODES(mp))) {
 
                *delete = 1;
@@ -1066,8 +1089,8 @@ xfs_difree(
                 * to be freed when the transaction is committed.
                 */
                ilen = XFS_IALLOC_INODES(mp);
-               be32_add(&agi->agi_count, -ilen);
-               be32_add(&agi->agi_freecount, -(ilen - 1));
+               be32_add_cpu(&agi->agi_count, -ilen);
+               be32_add_cpu(&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;
@@ -1096,7 +1119,7 @@ xfs_difree(
                /* 
                 * Change the inode free counts and log the ag/sb changes.
                 */
-               be32_add(&agi->agi_freecount, 1);
+               be32_add_cpu(&agi->agi_freecount, 1);
                xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
                down_read(&mp->m_peraglock);
                mp->m_perag[agno].pagi_freecount++;
@@ -1197,6 +1220,7 @@ xfs_dilocate(
                                        "(0x%llx)",
                                        ino, XFS_AGINO_TO_INO(mp, agno, agino));
                }
+               xfs_stack_trace();
 #endif /* DEBUG */
                return XFS_ERROR(EINVAL);
        }
@@ -1388,6 +1412,7 @@ xfs_ialloc_read_agi(
        pag = &mp->m_perag[agno];
        if (!pag->pagi_init) {
                pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
+               pag->pagi_count = be32_to_cpu(agi->agi_count);
                pag->pagi_init = 1;
        } else {
                /*
@@ -1411,3 +1436,23 @@ xfs_ialloc_read_agi(
        *bpp = bp;
        return 0;
 }
+
+/*
+ * Read in the agi to initialise the per-ag data in the mount structure
+ */
+int
+xfs_ialloc_pagi_init(
+       xfs_mount_t     *mp,            /* file system mount structure */
+       xfs_trans_t     *tp,            /* transaction pointer */
+       xfs_agnumber_t  agno)           /* allocation group number */
+{
+       xfs_buf_t       *bp = NULL;
+       int             error;
+
+       error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
+       if (error)
+               return error;
+       if (bp)
+               xfs_trans_brelse(tp, bp);
+       return 0;
+}