xfs
[Top] [All Lists]

[PATCH v2 09/17] xfs: allocate sparse inode chunks on full chunk allocat

To: xfs@xxxxxxxxxxx
Subject: [PATCH v2 09/17] xfs: allocate sparse inode chunks on full chunk allocation failure
From: Brian Foster <bfoster@xxxxxxxxxx>
Date: Mon, 3 Nov 2014 11:12:18 -0500
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1415031146-9107-1-git-send-email-bfoster@xxxxxxxxxx>
References: <1415031146-9107-1-git-send-email-bfoster@xxxxxxxxxx>
xfs_ialloc_ag_alloc() makes several attempts to allocate a full inode
chunk. If all else fails, reduce the allocation to the minimum sparse
granularity and attempt to allocate a sparse inode chunk.

If sparse chunk allocation succeeds, check whether an inobt record
already exists that can track the chunk. If so, inherit and update the
existing record. Otherwise, insert a new record for the sparse chunk.

Update xfs_inobt_insert_rec() to take the holemask as a parameter and
set the associated field on disk. Create the xfs_inobt_update_insert()
helper to handle the sparse chunk allocation case - insert or update an
existing record depending on whether it already exists.

Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx>
---
 fs/xfs/libxfs/xfs_ialloc.c | 149 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 136 insertions(+), 13 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 6879213..d22dd8a 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -123,12 +123,16 @@ xfs_inobt_get_rec(
 STATIC int
 xfs_inobt_insert_rec(
        struct xfs_btree_cur    *cur,
+       __uint16_t              holemask,
+       __uint8_t               count,
        __int32_t               freecount,
        xfs_inofree_t           free,
        int                     *stat)
 {
-       cur->bc_rec.i.ir_holemask = 0;
-       cur->bc_rec.i.ir_count = 0; /* zero for backwards compatibility */
+       ASSERT(count == 0 || xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb));
+
+       cur->bc_rec.i.ir_holemask = holemask;
+       cur->bc_rec.i.ir_count = count;
        cur->bc_rec.i.ir_freecount = freecount;
        cur->bc_rec.i.ir_free = free;
        return xfs_btree_insert(cur, stat);
@@ -152,6 +156,19 @@ xfs_inobt_insert(
        xfs_agino_t             thisino;
        int                     i;
        int                     error;
+       uint8_t                 count;
+
+       /*
+        * Only set ir_count in the inobt record if the sparse inodes feature is
+        * enabled. If disabled, we must maintain backwards compatibility with
+        * the older inobt record format where the current count and holemask
+        * fields map to the higher order bytes of freecount and thus must be
+        * zeroed.
+        */
+       if (xfs_sb_version_hassparseinodes(&mp->m_sb))
+               count = XFS_INODES_PER_CHUNK;
+       else
+               count = 0;
 
        cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
 
@@ -165,7 +182,7 @@ xfs_inobt_insert(
                }
                ASSERT(i == 0);
 
-               error = xfs_inobt_insert_rec(cur, XFS_INODES_PER_CHUNK,
+               error = xfs_inobt_insert_rec(cur, 0, count, 
XFS_INODES_PER_CHUNK,
                                             XFS_INOBT_ALL_FREE, &i);
                if (error) {
                        xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
@@ -175,8 +192,45 @@ xfs_inobt_insert(
        }
 
        xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+       return 0;
+}
+
+STATIC int
+xfs_inobt_update_insert(
+       struct xfs_mount                *mp,
+       struct xfs_trans                *tp,
+       struct xfs_buf                  *agbp,
+       struct xfs_inobt_rec_incore     *rec,   /* record to update/insert */
+       xfs_btnum_t                     btnum)
+{
+       struct xfs_btree_cur            *cur;
+       struct xfs_agi                  *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t                  agno = be32_to_cpu(agi->agi_seqno);
+       int                             i;
+       int                             error;
+
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
+
+       error = xfs_inobt_lookup(cur, rec->ir_startino, XFS_LOOKUP_EQ, &i);
+       if (i == 1) {
+               error = xfs_inobt_update(cur, rec);
+               if (error)
+                       goto error;
+       } else {
+               error = xfs_inobt_insert_rec(cur, rec->ir_holemask,
+                               rec->ir_count, rec->ir_freecount, rec->ir_free,
+                               &i);
+               if (error)
+                       goto error;
+               ASSERT(i == 1);
+       }
 
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
        return 0;
+
+error:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       return error;
 }
 
 /*
@@ -437,6 +491,10 @@ xfs_ialloc_ag_alloc(
        xfs_agino_t     newlen;         /* new number of inodes */
        int             isaligned = 0;  /* inode allocation at stripe unit */
                                        /* boundary */
+       uint16_t        allocmask = (uint16_t) -1; /* init. to full chunk */
+       struct xfs_inobt_rec_incore rec;
+       int             offset;
+
        struct xfs_perag *pag;
 
        memset(&args, 0, sizeof(args));
@@ -552,6 +610,27 @@ xfs_ialloc_ag_alloc(
                        return error;
        }
 
+       /*
+        * Finally, try a sparse allocation if the filesystem supports it.
+        */
+       if (xfs_sb_version_hassparseinodes(&args.mp->m_sb) &&
+           args.fsbno == NULLFSBLOCK) {
+               args.type = XFS_ALLOCTYPE_NEAR_BNO;
+               args.agbno = be32_to_cpu(agi->agi_root);
+               args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
+               args.alignment = args.mp->m_sb.sb_inoalignmt;
+
+               args.minlen = args.mp->m_ialloc_min_blks;
+               args.maxlen = args.minlen;
+
+               error = xfs_alloc_vextent(&args);
+               if (error)
+                       return error;
+
+               newlen = args.len << args.mp->m_sb.sb_inopblog;
+               allocmask = (1 << (newlen / XFS_INODES_PER_HOLEMASK_BIT)) - 1;
+       }
+
        if (args.fsbno == NULLFSBLOCK) {
                *alloc = 0;
                return 0;
@@ -583,20 +662,62 @@ xfs_ialloc_ag_alloc(
        xfs_perag_put(pag);
        agi->agi_newino = cpu_to_be32(newino);
 
-       /*
-        * Insert records describing the new inode chunk into the btrees.
-        */
-       error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
-                                XFS_BTNUM_INO);
-       if (error)
-               return error;
+       if (xfs_inobt_issparse(~allocmask)) {
+               /*
+                * We've allocated a sparse chunk...
+                */
+               error = xfs_inobt_rec_exists(args.mp, tp, agbp, newino,
+                                            newlen, XFS_BTNUM_INO, &rec);
+               if (error)
+                       return error;
+               if (rec.ir_startino == NULLAGINO) {
+                       /* no existing record, set all fields */
+                       rec.ir_startino = newino;
+                       rec.ir_holemask = ~allocmask;
+                       rec.ir_count = newlen;
+                       rec.ir_freecount = newlen;
+                       rec.ir_free = XFS_INOBT_ALL_FREE;
+               } else {
+                       /* we already have a record, update it */
+                       offset = newino - rec.ir_startino;
+                       allocmask <<= offset / XFS_INODES_PER_HOLEMASK_BIT;
+
+                       ASSERT(offset % XFS_INODES_PER_HOLEMASK_BIT == 0);
+                       ASSERT(rec.ir_count + newlen <= XFS_INODES_PER_CHUNK);
+                       ASSERT(rec.ir_freecount + newlen <=
+                               XFS_INODES_PER_CHUNK);
+
+                       rec.ir_count += newlen;
+                       rec.ir_freecount += newlen;
+                       rec.ir_holemask &= ~allocmask;
+               }
 
-       if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
+               error = xfs_inobt_update_insert(args.mp, tp, agbp, &rec,
+                                               XFS_BTNUM_INO);
+               if (error)
+                       return error;
+
+               if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
+                       error = xfs_inobt_update_insert(args.mp, tp, agbp, &rec,
+                                                       XFS_BTNUM_FINO);
+                       if (error)
+                               return error;
+               }
+       } else {
+               /* full chunk - insert new records to both btrees */
                error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
-                                        XFS_BTNUM_FINO);
+                                        XFS_BTNUM_INO);
                if (error)
                        return error;
+
+               if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
+                       error = xfs_inobt_insert(args.mp, tp, agbp, newino,
+                                                newlen, XFS_BTNUM_FINO);
+                       if (error)
+                               return error;
+               }
        }
+
        /*
         * Log allocation group header fields
         */
@@ -1657,7 +1778,9 @@ xfs_difree_finobt(
                 */
                XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
 
-               error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
+               error = xfs_inobt_insert_rec(cur, ibtrec->ir_holemask,
+                                            ibtrec->ir_count,
+                                            ibtrec->ir_freecount,
                                             ibtrec->ir_free, &i);
                if (error)
                        goto error;
-- 
1.8.3.1

<Prev in Thread] Current Thread [Next in Thread>