xfs
[Top] [All Lists]

[PATCH 09/18] xfs: allocate sparse inode chunks on full chunk allocation

To: xfs@xxxxxxxxxxx
Subject: [PATCH 09/18] xfs: allocate sparse inode chunks on full chunk allocation failure
From: Brian Foster <bfoster@xxxxxxxxxx>
Date: Thu, 24 Jul 2014 10:22:59 -0400
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1406211788-63206-1-git-send-email-bfoster@xxxxxxxxxx>
References: <1406211788-63206-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 inode cluster size
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. Convert xfs_inobt_insert() to
xfs_inobt_update_insert() to handle record insertion or update in a
generic fashion. This facilitates the continued use of the same function
for the inobt and finobt.

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

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index be57b51..4226b1b 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -121,28 +121,28 @@ xfs_inobt_get_rec(
 STATIC int
 xfs_inobt_insert_rec(
        struct xfs_btree_cur    *cur,
+       __uint16_t              holemask,
        __int32_t               freecount,
        xfs_inofree_t           free,
        int                     *stat)
 {
-       cur->bc_rec.i.ir_holemask = 0;
+       cur->bc_rec.i.ir_holemask = holemask;
        cur->bc_rec.i.ir_freecount = freecount;
        cur->bc_rec.i.ir_free = free;
        return xfs_btree_insert(cur, stat);
 }
 
 /*
- * Insert records describing a newly allocated inode chunk into the inobt.
+ * Update or insert records describing a newly allocated inode chunk into the
+ * specified inobt.
  */
 STATIC int
-xfs_inobt_insert(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       struct xfs_buf          *agbp,
-       xfs_agino_t             newino, /* start inode of record */
-       xfs_agino_t             count,  /* inode count */
-       xfs_inofree_t           free,   /* free mask */
-       xfs_btnum_t             btnum)
+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);
@@ -152,23 +152,25 @@ xfs_inobt_insert(
 
        cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
 
-       error = xfs_inobt_lookup(cur, newino, XFS_LOOKUP_EQ, &i);
-       if (error) {
-               xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
-               return error;
-       }
-       ASSERT(i == 0);
-
-       error = xfs_inobt_insert_rec(cur, count, free, &i);
-       if (error) {
-               xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
-               return error;
+       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_freecount, rec->ir_free, &i);
+               if (error)
+                       goto error;
+               ASSERT(i == 1);
        }
-       ASSERT(i == 1);
 
        xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
-
        return 0;
+
+error:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       return error;
 }
 
 /*
@@ -423,6 +425,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));
@@ -538,6 +544,28 @@ 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 = xfs_ialloc_cluster_alignment(args.mp);
+
+               /* allocate sparse regions in cluster granularity */
+               args.minlen = xfs_ialloc_cluster_alignment(args.mp);
+               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_SPCHUNK)) - 1;
+       }
+
        if (args.fsbno == NULLFSBLOCK) {
                *alloc = 0;
                return 0;
@@ -572,14 +600,34 @@ xfs_ialloc_ag_alloc(
        /*
         * Insert records describing the new inode chunk into the btrees.
         */
-       error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
-                                XFS_INOBT_ALL_FREE, XFS_BTNUM_INO);
+       error = xfs_spchunk_has_record(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_freecount = newlen;
+               rec.ir_free = XFS_INOBT_ALL_FREE;
+       } else {
+               /* we already have a record, update it */
+               offset = newino - rec.ir_startino;
+               ASSERT(offset % XFS_INODES_PER_SPCHUNK == 0);
+
+               allocmask <<= offset / XFS_INODES_PER_SPCHUNK;
+
+               rec.ir_freecount += newlen;
+               rec.ir_holemask &= ~allocmask;
+       }
+
+       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_insert(args.mp, tp, agbp, newino, newlen,
-                                        XFS_INOBT_ALL_FREE, XFS_BTNUM_FINO);
+               error = xfs_inobt_update_insert(args.mp, tp, agbp, &rec,
+                                               XFS_BTNUM_FINO);
                if (error)
                        return error;
        }
@@ -1644,7 +1692,8 @@ 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_freecount,
                                             ibtrec->ir_free, &i);
                if (error)
                        goto error;
-- 
1.8.3.1

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