]> err.no Git - linux-2.6/blobdiff - fs/xfs/xfs_alloc.c
Use ilog2() in fs/namespace.c
[linux-2.6] / fs / xfs / xfs_alloc.c
index 22af489d3f346c7bb4488cdcf1ee91e59e48ddf3..012a649a19c35c2fc68e0b953557b92f42df83b7 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"
@@ -57,17 +55,17 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
 ktrace_t *xfs_alloc_trace_buf;
 
 #define        TRACE_ALLOC(s,a)        \
-       xfs_alloc_trace_alloc(fname, s, a, __LINE__)
+       xfs_alloc_trace_alloc(__FUNCTION__, s, a, __LINE__)
 #define        TRACE_FREE(s,a,b,x,f)   \
-       xfs_alloc_trace_free(fname, s, mp, a, b, x, f, __LINE__)
+       xfs_alloc_trace_free(__FUNCTION__, s, mp, a, b, x, f, __LINE__)
 #define        TRACE_MODAGF(s,a,f)     \
-       xfs_alloc_trace_modagf(fname, s, mp, a, f, __LINE__)
-#define        TRACE_BUSY(fname,s,ag,agb,l,sl,tp)      \
-       xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
-#define        TRACE_UNBUSY(fname,s,ag,sl,tp)  \
-       xfs_alloc_trace_busy(fname, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
-#define        TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp)        \
-       xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
+       xfs_alloc_trace_modagf(__FUNCTION__, s, mp, a, f, __LINE__)
+#define        TRACE_BUSY(__FUNCTION__,s,ag,agb,l,sl,tp)       \
+       xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
+#define        TRACE_UNBUSY(__FUNCTION__,s,ag,sl,tp)   \
+       xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
+#define        TRACE_BUSYSEARCH(__FUNCTION__,s,ag,agb,l,sl,tp) \
+       xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
 #else
 #define        TRACE_ALLOC(s,a)
 #define        TRACE_FREE(s,a,b,x,f)
@@ -422,7 +420,7 @@ xfs_alloc_read_agfl(
  */
 STATIC void
 xfs_alloc_trace_alloc(
-       char            *name,          /* function tag string */
+       const char      *name,          /* function tag string */
        char            *str,           /* additional string */
        xfs_alloc_arg_t *args,          /* allocation argument structure */
        int             line)           /* source line number */
@@ -455,7 +453,7 @@ xfs_alloc_trace_alloc(
  */
 STATIC void
 xfs_alloc_trace_free(
-       char            *name,          /* function tag string */
+       const char      *name,          /* function tag string */
        char            *str,           /* additional string */
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_agnumber_t  agno,           /* allocation group number */
@@ -481,7 +479,7 @@ xfs_alloc_trace_free(
  */
 STATIC void
 xfs_alloc_trace_modagf(
-       char            *name,          /* function tag string */
+       const char      *name,          /* function tag string */
        char            *str,           /* additional string */
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_agf_t       *agf,           /* new agf value */
@@ -509,7 +507,7 @@ xfs_alloc_trace_modagf(
 
 STATIC void
 xfs_alloc_trace_busy(
-       char            *name,          /* function tag string */
+       const char      *name,          /* function tag string */
        char            *str,           /* additional string */
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_agnumber_t  agno,           /* allocation group number */
@@ -551,9 +549,6 @@ xfs_alloc_ag_vextent(
        xfs_alloc_arg_t *args)  /* argument structure for allocation */
 {
        int             error=0;
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_ag_vextent";
-#endif
 
        ASSERT(args->minlen > 0);
        ASSERT(args->maxlen > 0);
@@ -637,9 +632,6 @@ xfs_alloc_ag_vextent_exact(
        xfs_agblock_t   fbno;   /* start block of found extent */
        xfs_agblock_t   fend;   /* end block of found extent */
        xfs_extlen_t    flen;   /* length of found extent */
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_ag_vextent_exact";
-#endif
        int             i;      /* success/failure of operation */
        xfs_agblock_t   maxend; /* end of maximal extent */
        xfs_agblock_t   minend; /* end of minimal extent */
@@ -739,9 +731,6 @@ xfs_alloc_ag_vextent_near(
        xfs_btree_cur_t *bno_cur_gt;    /* cursor for bno btree, right side */
        xfs_btree_cur_t *bno_cur_lt;    /* cursor for bno btree, left side */
        xfs_btree_cur_t *cnt_cur;       /* cursor for count btree */
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_ag_vextent_near";
-#endif
        xfs_agblock_t   gtbno;          /* start bno of right side entry */
        xfs_agblock_t   gtbnoa;         /* aligned ... */
        xfs_extlen_t    gtdiff;         /* difference to right side entry */
@@ -766,7 +755,7 @@ xfs_alloc_ag_vextent_near(
         */
        int             dofirst;        /* set to do first algorithm */
 
-       dofirst = random() & 1;
+       dofirst = random32() & 1;
 #endif
        /*
         * Get a cursor for the by-size btree.
@@ -1272,9 +1261,6 @@ xfs_alloc_ag_vextent_size(
        int             error;          /* error result */
        xfs_agblock_t   fbno;           /* start of found freespace */
        xfs_extlen_t    flen;           /* length of found freespace */
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_ag_vextent_size";
-#endif
        int             i;              /* temp status variable */
        xfs_agblock_t   rbno;           /* returned block number */
        xfs_extlen_t    rlen;           /* length of returned extent */
@@ -1429,9 +1415,6 @@ xfs_alloc_ag_vextent_small(
        int             error;
        xfs_agblock_t   fbno;
        xfs_extlen_t    flen;
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_ag_vextent_small";
-#endif
        int             i;
 
        if ((error = xfs_alloc_decrement(ccur, 0, &i)))
@@ -1449,7 +1432,8 @@ xfs_alloc_ag_vextent_small(
        else if (args->minlen == 1 && args->alignment == 1 && !args->isfl &&
                 (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount)
                  > args->minleft)) {
-               if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno)))
+               error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
+               if (error)
                        goto error0;
                if (fbno != NULLAGBLOCK) {
                        if (args->userdata) {
@@ -1479,8 +1463,10 @@ xfs_alloc_ag_vextent_small(
        /*
         * Can't allocate from the freelist for some reason.
         */
-       else
+       else {
+               fbno = NULLAGBLOCK;
                flen = 0;
+       }
        /*
         * Can't do the allocation, give up.
         */
@@ -1515,9 +1501,6 @@ xfs_free_ag_extent(
        xfs_btree_cur_t *bno_cur;       /* cursor for by-block btree */
        xfs_btree_cur_t *cnt_cur;       /* cursor for by-size btree */
        int             error;          /* error return value */
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_free_ag_extent";
-#endif
        xfs_agblock_t   gtbno;          /* start of right neighbor block */
        xfs_extlen_t    gtlen;          /* length of right neighbor block */
        int             haveleft;       /* have a left neighbor block */
@@ -1837,40 +1820,47 @@ xfs_alloc_fix_freelist(
                                &agbp)))
                        return error;
                if (!pag->pagf_init) {
+                       ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);
+                       ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
                        args->agbp = NULL;
                        return 0;
                }
        } else
                agbp = NULL;
 
-       /* If this is a metadata preferred pag and we are user data
+       /*
+        * If this is a metadata preferred pag and we are user data
         * then try somewhere else if we are not being asked to
         * try harder at this point
         */
-       if (pag->pagf_metadata && args->userdata && flags) {
+       if (pag->pagf_metadata && args->userdata &&
+           (flags & XFS_ALLOC_FLAG_TRYLOCK)) {
+               ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
                args->agbp = NULL;
                return 0;
        }
 
-       need = XFS_MIN_FREELIST_PAG(pag, mp);
-       delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
-       /*
-        * If it looks like there isn't a long enough extent, or enough
-        * total blocks, reject it.
-        */
-       longest = (pag->pagf_longest > delta) ?
-               (pag->pagf_longest - delta) :
-               (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
-       if (args->minlen + args->alignment + args->minalignslop - 1 > longest ||
-           (!(flags & XFS_ALLOC_FLAG_FREEING) &&
-            (int)(pag->pagf_freeblks + pag->pagf_flcount -
-                  need - args->total) <
-            (int)args->minleft)) {
-               if (agbp)
-                       xfs_trans_brelse(tp, agbp);
-               args->agbp = NULL;
-               return 0;
+       if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
+               need = XFS_MIN_FREELIST_PAG(pag, mp);
+               delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
+               /*
+                * If it looks like there isn't a long enough extent, or enough
+                * total blocks, reject it.
+                */
+               longest = (pag->pagf_longest > delta) ?
+                       (pag->pagf_longest - delta) :
+                       (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
+               if ((args->minlen + args->alignment + args->minalignslop - 1) >
+                               longest ||
+                   ((int)(pag->pagf_freeblks + pag->pagf_flcount -
+                          need - args->total) < (int)args->minleft)) {
+                       if (agbp)
+                               xfs_trans_brelse(tp, agbp);
+                       args->agbp = NULL;
+                       return 0;
+               }
        }
+
        /*
         * Get the a.g. freespace buffer.
         * Can fail if we're not blocking on locks, and it's held.
@@ -1880,6 +1870,8 @@ xfs_alloc_fix_freelist(
                                &agbp)))
                        return error;
                if (agbp == NULL) {
+                       ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);
+                       ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
                        args->agbp = NULL;
                        return 0;
                }
@@ -1889,22 +1881,24 @@ xfs_alloc_fix_freelist(
         */
        agf = XFS_BUF_TO_AGF(agbp);
        need = XFS_MIN_FREELIST(agf, mp);
-       delta = need > be32_to_cpu(agf->agf_flcount) ?
-               (need - be32_to_cpu(agf->agf_flcount)) : 0;
        /*
         * If there isn't enough total or single-extent, reject it.
         */
-       longest = be32_to_cpu(agf->agf_longest);
-       longest = (longest > delta) ? (longest - delta) :
-               (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);
-       if (args->minlen + args->alignment + args->minalignslop - 1 > longest ||
-            (!(flags & XFS_ALLOC_FLAG_FREEING) &&
-               (int)(be32_to_cpu(agf->agf_freeblks) +
-                  be32_to_cpu(agf->agf_flcount) - need - args->total) <
-            (int)args->minleft)) {
-               xfs_trans_brelse(tp, agbp);
-               args->agbp = NULL;
-               return 0;
+       if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
+               delta = need > be32_to_cpu(agf->agf_flcount) ?
+                       (need - be32_to_cpu(agf->agf_flcount)) : 0;
+               longest = be32_to_cpu(agf->agf_longest);
+               longest = (longest > delta) ? (longest - delta) :
+                       (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);
+               if ((args->minlen + args->alignment + args->minalignslop - 1) >
+                               longest ||
+                   ((int)(be32_to_cpu(agf->agf_freeblks) +
+                    be32_to_cpu(agf->agf_flcount) - need - args->total) <
+                               (int)args->minleft)) {
+                       xfs_trans_brelse(tp, agbp);
+                       args->agbp = NULL;
+                       return 0;
+               }
        }
        /*
         * Make the freelist shorter if it's too long.
@@ -1912,7 +1906,8 @@ xfs_alloc_fix_freelist(
        while (be32_to_cpu(agf->agf_flcount) > need) {
                xfs_buf_t       *bp;
 
-               if ((error = xfs_alloc_get_freelist(tp, agbp, &bno)))
+               error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
+               if (error)
                        return error;
                if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))
                        return error;
@@ -1952,19 +1947,19 @@ xfs_alloc_fix_freelist(
                 * on a completely full ag.
                 */
                if (targs.agbno == NULLAGBLOCK) {
-                       if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
-                               xfs_trans_brelse(tp, agflbp);
-                               args->agbp = NULL;
-                               return 0;
-                       }
-                       break;
+                       if (flags & XFS_ALLOC_FLAG_FREEING)
+                               break;
+                       xfs_trans_brelse(tp, agflbp);
+                       args->agbp = NULL;
+                       return 0;
                }
                /*
                 * Put each allocated block on the list.
                 */
                for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) {
-                       if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp,
-                                       bno)))
+                       error = xfs_alloc_put_freelist(tp, agbp,
+                                                       agflbp, bno, 0);
+                       if (error)
                                return error;
                }
        }
@@ -1981,16 +1976,15 @@ int                             /* error */
 xfs_alloc_get_freelist(
        xfs_trans_t     *tp,    /* transaction pointer */
        xfs_buf_t       *agbp,  /* buffer containing the agf structure */
-       xfs_agblock_t   *bnop)  /* block address retrieved from freelist */
+       xfs_agblock_t   *bnop,  /* block address retrieved from freelist */
+       int             btreeblk) /* destination is a AGF btree */
 {
        xfs_agf_t       *agf;   /* a.g. freespace structure */
        xfs_agfl_t      *agfl;  /* a.g. freelist structure */
        xfs_buf_t       *agflbp;/* buffer for a.g. freelist structure */
        xfs_agblock_t   bno;    /* block number returned */
        int             error;
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_get_freelist";
-#endif
+       int             logflags;
        xfs_mount_t     *mp;    /* mount structure */
        xfs_perag_t     *pag;   /* per allocation group data */
 
@@ -2013,7 +2007,7 @@ xfs_alloc_get_freelist(
        /*
         * Get the block number and update the data structures.
         */
-       bno = INT_GET(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)], ARCH_CONVERT);
+       bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
        be32_add(&agf->agf_flfirst, 1);
        xfs_trans_brelse(tp, agflbp);
        if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
@@ -2022,8 +2016,16 @@ xfs_alloc_get_freelist(
        be32_add(&agf->agf_flcount, -1);
        xfs_trans_agflist_delta(tp, -1);
        pag->pagf_flcount--;
-       TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
-       xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
+
+       logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT;
+       if (btreeblk) {
+               be32_add(&agf->agf_btreeblks, 1);
+               pag->pagf_btreeblks++;
+               logflags |= XFS_AGF_BTREEBLKS;
+       }
+
+       TRACE_MODAGF(NULL, agf, logflags);
+       xfs_alloc_log_agf(tp, agbp, logflags);
        *bnop = bno;
 
        /*
@@ -2061,6 +2063,7 @@ xfs_alloc_log_agf(
                offsetof(xfs_agf_t, agf_flcount),
                offsetof(xfs_agf_t, agf_freeblks),
                offsetof(xfs_agf_t, agf_longest),
+               offsetof(xfs_agf_t, agf_btreeblks),
                sizeof(xfs_agf_t)
        };
 
@@ -2096,15 +2099,14 @@ xfs_alloc_put_freelist(
        xfs_trans_t             *tp,    /* transaction pointer */
        xfs_buf_t               *agbp,  /* buffer for a.g. freelist header */
        xfs_buf_t               *agflbp,/* buffer for a.g. free block array */
-       xfs_agblock_t           bno)    /* block being freed */
+       xfs_agblock_t           bno,    /* block being freed */
+       int                     btreeblk) /* block came from a AGF btree */
 {
        xfs_agf_t               *agf;   /* a.g. freespace structure */
        xfs_agfl_t              *agfl;  /* a.g. free block array */
-       xfs_agblock_t           *blockp;/* pointer to array entry */
+       __be32                  *blockp;/* pointer to array entry */
        int                     error;
-#ifdef XFS_ALLOC_TRACE
-       static char             fname[] = "xfs_alloc_put_freelist";
-#endif
+       int                     logflags;
        xfs_mount_t             *mp;    /* mount structure */
        xfs_perag_t             *pag;   /* per allocation group data */
 
@@ -2122,11 +2124,22 @@ xfs_alloc_put_freelist(
        be32_add(&agf->agf_flcount, 1);
        xfs_trans_agflist_delta(tp, 1);
        pag->pagf_flcount++;
+
+       logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT;
+       if (btreeblk) {
+               be32_add(&agf->agf_btreeblks, -1);
+               pag->pagf_btreeblks--;
+               logflags |= XFS_AGF_BTREEBLKS;
+       }
+
+       TRACE_MODAGF(NULL, agf, logflags);
+       xfs_alloc_log_agf(tp, agbp, logflags);
+
        ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
        blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
-       INT_SET(*blockp, ARCH_CONVERT, bno);
-       TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
-       xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
+       *blockp = cpu_to_be32(bno);
+       TRACE_MODAGF(NULL, agf, logflags);
+       xfs_alloc_log_agf(tp, agbp, logflags);
        xfs_trans_log_buf(tp, agflbp,
                (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
                (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
@@ -2186,6 +2199,7 @@ xfs_alloc_read_agf(
        pag = &mp->m_perag[agno];
        if (!pag->pagf_init) {
                pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
+               pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
                pag->pagf_flcount = be32_to_cpu(agf->agf_flcount);
                pag->pagf_longest = be32_to_cpu(agf->agf_longest);
                pag->pagf_levels[XFS_BTNUM_BNOi] =
@@ -2225,9 +2239,6 @@ xfs_alloc_vextent(
        xfs_agblock_t   agsize; /* allocation group size */
        int             error;
        int             flags;  /* XFS_ALLOC_FLAG_... locking flags */
-#ifdef XFS_ALLOC_TRACE
-       static char     fname[] = "xfs_alloc_vextent";
-#endif
        xfs_extlen_t    minleft;/* minimum left value, temp copy */
        xfs_mount_t     *mp;    /* mount structure pointer */
        xfs_agnumber_t  sagno;  /* starting allocation group number */
@@ -2444,31 +2455,26 @@ xfs_free_extent(
        xfs_fsblock_t   bno,    /* starting block number of extent */
        xfs_extlen_t    len)    /* length of extent */
 {
-#ifdef DEBUG
-       xfs_agf_t       *agf;   /* a.g. freespace header */
-#endif
-       xfs_alloc_arg_t args;   /* allocation argument structure */
+       xfs_alloc_arg_t args;
        int             error;
 
        ASSERT(len != 0);
+       memset(&args, 0, sizeof(xfs_alloc_arg_t));
        args.tp = tp;
        args.mp = tp->t_mountp;
        args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
        ASSERT(args.agno < args.mp->m_sb.sb_agcount);
        args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
-       args.alignment = 1;
-       args.minlen = args.minleft = args.minalignslop = 0;
        down_read(&args.mp->m_peraglock);
        args.pag = &args.mp->m_perag[args.agno];
        if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
                goto error0;
 #ifdef DEBUG
        ASSERT(args.agbp != NULL);
-       agf = XFS_BUF_TO_AGF(args.agbp);
-       ASSERT(args.agbno + len <= be32_to_cpu(agf->agf_length));
+       ASSERT((args.agbno + len) <=
+               be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length));
 #endif
-       error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno,
-               len, 0);
+       error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
 error0:
        up_read(&args.mp->m_peraglock);
        return error;