xfs
[Top] [All Lists]

[PATCH v2 04/10] xfs: introduce per allocation group inumbers

To: "xfs@xxxxxxxxxxx" <xfs@xxxxxxxxxxx>
Subject: [PATCH v2 04/10] xfs: introduce per allocation group inumbers
From: Jeff Liu <jeff.liu@xxxxxxxxxx>
Date: Fri, 18 Apr 2014 08:58:29 +0800
Delivered-to: xfs@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0
From: Jie Liu <jeff.liu@xxxxxxxxxx>

Introduce xfs_perag_inumbers(), it could be used to fetch the inode number
tables per allocation group via a new ioctl(2) in the future.  Also, that
would be a net win considering the scalability for a file system with huge
number of inodes as multiple allocation groups can be scanned in parallel,
refactor xfs_inumbers() with it.

Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx>
---
 fs/xfs/xfs_itable.c | 179 ++++++++++++++++++++++++++++++++--------------------
 fs/xfs/xfs_itable.h |  13 +++-
 2 files changed, 123 insertions(+), 69 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 2025bd0..62cf2f8 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -570,105 +570,150 @@ xfs_inumbers_fmt(
 }
 
 /*
- * Return inode number table for the filesystem.
+ * Return inode number table in an allocation group.  Record how many elements
+ * have been written out and update the last allocation group inode number on
+ * success.  Otherwise, those values will remain the same and return error.
  */
-int                                    /* error status */
-xfs_inumbers(
-       struct xfs_mount        *mp,/* mount point for filesystem */
-       xfs_ino_t               *lastino,/* last inode returned */
-       int                     *count,/* size of buffer/count returned */
-       void                    __user *ubuffer,/* buffer with inode desc */
+static int
+xfs_perag_inumbers(
+       struct xfs_mount        *mp,
+       struct xfs_aginumbers   *aip,
+       struct xfs_inogrp       *buffer,
+       int                     bcount,
        inumbers_fmt_pf         formatter)
 {
-       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, *lastino);
-       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, *lastino);
-       struct xfs_btree_cur    *cur = NULL;
-       struct xfs_buf          *agbp = NULL;
-       struct xfs_inogrp       *buffer;
-       int                     left = *count;
-       int                     bcount;
-       int                     bufidx;
+       xfs_agnumber_t          agno = aip->ai_agno;
+       xfs_agino_t             agino = *(aip->ai_lastip);
+       char                    *ubuffer = aip->ai_ubuffer;
+       int                     ubleft = aip->ai_icount;
+       int                     bufidx = 0;
+       long                    count = 0;/* # elements written out */
+       struct xfs_agi          *agi;
+       struct xfs_buf          *agbp;
+       struct xfs_btree_cur    *cur;
+       int                     stat;
        int                     error;
 
-       *count = 0;
-       if (agno >= mp->m_sb.sb_agcount ||
-           *lastino != XFS_AGINO_TO_INO(mp, agno, agino))
-               return 0;
-
-       bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer)));
-       buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP);
-       bufidx = error = 0;
-       do {
+       error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
+       if (error)
+               return error;
+       agi = XFS_BUF_TO_AGI(agbp);
+       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
+       /* Done if failed to lookup or no inode chuck is found */
+       error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, &stat);
+       if (error || !stat)
+               goto error0;
+
+       for (;;) {
                struct xfs_inobt_rec_incore     r;
-               int                             stat;
-
-               if (!agbp) {
-                       error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
-                       if (error)
-                               break;
-                       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
-                       error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
-                                                &stat);
-                       if (error)
-                               break;
-                       if (!stat)
-                               goto next_ag;
-               }
 
                error = xfs_inobt_get_rec(cur, &r, &stat);
-               if (error || !stat)
+               if (error || !stat) {
+                       pr_info("xfs_inobt_get_rec: stat=%d\n", stat);
                        break;
+               }
 
                agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
-               buffer[bufidx].xi_startino =
-                       XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
-               buffer[bufidx].xi_alloccount =
-                       XFS_INODES_PER_CHUNK - r.ir_freecount;
+               buffer[bufidx].xi_startino = XFS_AGINO_TO_INO(mp, agno,
+                                                             r.ir_startino);
+               buffer[bufidx].xi_alloccount = XFS_INODES_PER_CHUNK -
+                                              r.ir_freecount;
                buffer[bufidx].xi_allocmask = ~r.ir_free;
-               if (++bufidx == bcount) {
+               /* Run out of the given buffer range, it's time to write out */
+               if (++bufidx == ubleft) {
                        long    written;
 
                        error = formatter(ubuffer, buffer, bufidx, &written);
                        if (error)
                                break;
-                       ubuffer += written;
-                       *count += bufidx;
+                       count += bufidx;
                        bufidx = 0;
+                       break;
                }
-               if (!--left)
+               if (!--ubleft)
                        break;
 
+               /* Done if failed or there are no rightward entries */
                error = xfs_btree_increment(cur, 0, &stat);
-               if (error)
+               if (error || !stat)
                        break;
-               if (stat)
-                       continue;
-
-next_ag:
-               xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
-               cur = NULL;
-               xfs_buf_relse(agbp);
-               agbp = NULL;
-               agino = 0;
-       } while (++agno < mp->m_sb.sb_agcount);
+       }
 
        if (!error) {
+               /*
+                * There might have remaining inode number tables reside in
+                * buffer which have not yet been written out if we iterate
+                * beyond inode btree.  We need to handle them separately.
+                */
                if (bufidx) {
                        long    written;
 
                        error = formatter(ubuffer, buffer, bufidx, &written);
-                       if (!error)
-                               *count += bufidx;
+                       if (error)
+                               goto error0;
+                       count += bufidx;
                }
-               *lastino = XFS_AGINO_TO_INO(mp, agno, agino);
+               /* Update the last AG inode number */
+               *(aip->ai_lastip) = agino;
+               /* Record how many elements have been written out */
+               aip->ai_ocount = count;
        }
 
-       kmem_free(buffer);
-       if (cur)
-               xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR :
-                                          XFS_BTREE_NOERROR));
-       if (agbp)
-               xfs_buf_relse(agbp);
+error0:
+       xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+       xfs_buf_relse(agbp);
+
+       return error;
+}
+
+/* Return inode number table for the filesystem */
+int
+xfs_inumbers(
+       struct xfs_mount        *mp,/* mount point for filesystem */
+       xfs_ino_t               *lastinop,/* last inode returned */
+       int                     *ubcountp,/* size of buffer/count returned */
+       void                    __user *ubuffer,/* buffer with inode desc */
+       inumbers_fmt_pf         formatter)
+{
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, *lastinop);
+       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, *lastinop);
+       int                     ubleft = *ubcountp;
+       struct xfs_inogrp       *buffer;
+       int                     count;
+       int                     error;
 
+       *ubcountp = 0;
+       if (agno >= mp->m_sb.sb_agcount ||
+           *lastinop != XFS_AGINO_TO_INO(mp, agno, agino))
+               return 0;
+
+       count = MIN(ubleft, (int)(PAGE_SIZE / sizeof(*buffer)));
+       buffer = kmem_alloc(count * sizeof(*buffer), KM_SLEEP);
+       do {
+               struct xfs_aginumbers   ai;
+
+               ai.ai_agno = agno;
+               ai.ai_lastip = &agino;
+               ai.ai_icount = ubleft;
+               ai.ai_ubuffer = ubuffer;
+               ai.ai_ocount = 0;
+               error = xfs_perag_inumbers(mp, &ai, buffer, count, formatter);
+               if (error)
+                       break;
+
+               *ubcountp += ai.ai_ocount;
+               ubleft -= ai.ai_ocount;
+               ASSERT(ubleft >= 0);
+               if (!ubleft)
+                       break;
+
+               ubuffer = ai.ai_ubuffer;
+               agino = 0;
+       } while (++agno < mp->m_sb.sb_agcount);
+
+       if (!error)
+               *lastinop = XFS_AGINO_TO_INO(mp, agno, agino);
+
+       kmem_free(buffer);
        return error;
 }
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index 21dbbd7..9c3e535 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -83,17 +83,26 @@ xfs_bulkstat_one(
 
 typedef int (*inumbers_fmt_pf)(
        void                    __user *ubuffer, /* buffer to write to */
-       const xfs_inogrp_t      *buffer,        /* buffer to read from */
+       const struct xfs_inogrp *buffer,        /* buffer to read from */
        long                    count,          /* # of elements to read */
        long                    *written);      /* # of bytes written */
 
 int
 xfs_inumbers_fmt(
        void                    __user *ubuffer, /* buffer to write to */
-       const xfs_inogrp_t      *buffer,        /* buffer to read from */
+       const struct xfs_inogrp *buffer,        /* buffer to read from */
        long                    count,          /* # of elements to read */
        long                    *written);      /* # of bytes written */
 
+/* This structure is used for xfs_inumbers per allocation group */
+struct xfs_aginumbers {
+       xfs_agnumber_t          ai_agno;/* AG number */
+       xfs_agino_t             *ai_lastip;/* last AG inode number */
+       char                    __user *ai_ubuffer;/* user buffer to write to */
+       __uint32_t              ai_icount;/* # of elements to read */
+       __uint32_t              ai_ocount;/* # of elements written */
+};
+
 int                                    /* error status */
 xfs_inumbers(
        xfs_mount_t             *mp,    /* mount point for filesystem */
-- 
1.8.3.2

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