xfs
[Top] [All Lists]

[PATCH 9/10] xfs: implement bulkstat per allocation group

To: "xfs@xxxxxxxxxxx" <xfs@xxxxxxxxxxx>
Subject: [PATCH 9/10] xfs: implement bulkstat per allocation group
From: Jeff Liu <jeff.liu@xxxxxxxxxx>
Date: Sat, 28 Dec 2013 19:22:35 +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>

With xfs_perag_bulkstat(), we can return stat information in bulk by
inode as per the given allocation group number and start inode number
in it via a new ioctl(2) in the future.

Refactor xfs_bulkstat() with it.

Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx>
---
 fs/xfs/xfs_itable.c | 291 +++++++++++++++++++++++++++++-----------------------
 fs/xfs/xfs_itable.h |  20 ++++
 2 files changed, 183 insertions(+), 128 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 249b516..4d53f15 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -334,86 +334,44 @@ xfs_bulkstat_ag_ichunk(
 }
 
 /*
- * Return stat information in bulk (by-inode) for the filesystem.
+ * Return stat information in bulk (by-inode) in an allocation group until
+ * we run out of the AG or user buffers.
  */
-int                                    /* error status */
-xfs_bulkstat(
-       xfs_mount_t             *mp,    /* mount point for filesystem */
-       xfs_ino_t               *lastinop, /* last inode returned */
-       int                     *ubcountp, /* size of buffer/count returned */
-       bulkstat_one_pf         formatter, /* func that'd fill a single buf */
-       size_t                  statstruct_size, /* sizeof struct filling */
-       char                    __user *ubuffer, /* buffer with inode stats */
-       int                     *done)  /* 1 if there are more stats to get */
+int
+xfs_perag_bulkstat(
+       struct xfs_mount                *mp,
+       struct xfs_agbulkstat           *agbulkp,
+       struct xfs_inobt_rec_incore     *irbuf,
+       size_t                          nirbuf,
+       bulkstat_one_pf                 formatter,
+       size_t                          statstruct_size)
 {
-       xfs_buf_t               *agbp;  /* agi header buffer */
-       xfs_agi_t               *agi;   /* agi header data */
-       xfs_agino_t             agino;  /* inode # in allocation group */
-       xfs_agnumber_t          agno;   /* allocation group number */
-       xfs_btree_cur_t         *cur;   /* btree cursor for ialloc btree */
-       int                     end_of_ag; /* set if we've seen the ag end */
-       int                     error;  /* error code */
-       int                     fmterror;/* bulkstat formatter result */
-       int                     i;      /* loop index */
-       int                     icount; /* count of inodes good in irbuf */
-       size_t                  irbsize; /* size of irec buffer in bytes */
-       xfs_ino_t               ino;    /* inode number (filesystem) */
-       xfs_inobt_rec_incore_t  *irbp;  /* current irec buffer pointer */
-       xfs_inobt_rec_incore_t  *irbuf; /* start of irec buffer */
-       xfs_inobt_rec_incore_t  *irbufend; /* end of good irec buffer entries */
-       xfs_ino_t               lastino; /* last inode number returned */
-       int                     nirbuf; /* size of irbuf */
-       int                     rval;   /* return value error code */
-       int                     tmp;    /* result value from btree calls */
-       int                     ubcount; /* size of user's buffer */
-       int                     ubleft; /* bytes left in user's buffer */
-       char                    __user *ubufp;  /* pointer into user's buffer */
-       int                     ubelem; /* spaces used in user's buffer */
-
-       /*
-        * Get the last inode value, see if there's nothing to do.
-        */
-       ino = (xfs_ino_t)*lastinop;
-       lastino = ino;
-       agno = XFS_INO_TO_AGNO(mp, ino);
-       agino = XFS_INO_TO_AGINO(mp, ino);
-       if (agno >= mp->m_sb.sb_agcount ||
-           ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
-               *done = 1;
-               *ubcountp = 0;
-               return 0;
-       }
-       ubcount = *ubcountp; /* statstruct's */
-       ubleft = ubcount * statstruct_size; /* bytes */
-       *ubcountp = ubelem = 0;
-       *done = 0;
-       fmterror = 0;
-       ubufp = ubuffer;
-       irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
-       if (!irbuf)
-               return ENOMEM;
+       xfs_agnumber_t                  agno = agbulkp->ab_agno;
+       xfs_agino_t                     agino = *(agbulkp->ab_aginop);
+       xfs_ino_t                       lastino = XFS_AGINO_TO_INO(mp, agno,
+                                                                  agino);
+       char                            __user *ubuffer = agbulkp->ab_ubuffer;
+       int                             ubcount = agbulkp->ab_icount;
+       int                             ubelem = 0;/* # elements written */
+       struct xfs_btree_cur            *cur = NULL;
+       struct xfs_buf                  *agbp = NULL;
+       int                             ubleft_bytes;
+       int                             error;
 
-       nirbuf = irbsize / sizeof(*irbuf);
+       ubleft_bytes = ubcount * statstruct_size;
+       for (;;) {
+               struct xfs_inobt_rec_incore     *irbp = irbuf;
+               struct xfs_inobt_rec_incore     *irbufend = irbuf + nirbuf;
+               struct xfs_agi                  *agi;
+               int                             i;/* btree operation status */
+               int                             icount = 0;/* # inodes in irbuf 
*/
+               bool                            end_of_ag = false;
 
-       /*
-        * Loop over the allocation groups, starting from the last
-        * inode returned; 0 means start of the allocation group.
-        */
-       rval = 0;
-       while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
-               cond_resched();
                error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
                if (error)
                        break;
                agi = XFS_BUF_TO_AGI(agbp);
-               /*
-                * Allocate and initialize a btree cursor for ialloc btree.
-                */
                cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
-               irbp = irbuf;
-               irbufend = irbuf + nirbuf;
-               end_of_ag = 0;
-               icount = 0;
                if (agino > 0) {
                        /*
                         * In the middle of an allocation group, we need to get
@@ -421,7 +379,8 @@ xfs_bulkstat(
                         */
                        struct xfs_inobt_rec_incore     r;
 
-                       error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, 
&r);
+                       error = xfs_bulkstat_grab_ichunk(cur, agino, &icount,
+                                                        &r);
                        if (error)
                                break;
                        if (icount) {
@@ -431,32 +390,34 @@ xfs_bulkstat(
                                irbp++;
                                agino += r.ir_startino + XFS_INODES_PER_CHUNK;
                        }
-                       /* Increment to the next record */
-                       error = xfs_btree_increment(cur, 0, &tmp);
+                       error = xfs_btree_increment(cur, 0, &i);
+                       if (error)
+                               break;
+                       if (i == 0) {
+                               /* There are no rightward btree entries */
+                               end_of_ag = true;
+                       }
                } else {
                        /* Start of ag.  Lookup the first inode chunk */
-                       error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp);
+                       error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
+                       if (error)
+                               break;
+                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
                }
-               if (error)
-                       break;
 
                /*
-                * Loop through inode btree records in this ag,
-                * until we run out of inodes or space in the buffer.
+                * Loop over inode btree records in this AG until we run out of
+                * inodes or space in the buffer.
                 */
                while (irbp < irbufend && icount < ubcount) {
                        struct xfs_inobt_rec_incore     r;
 
                        error = xfs_inobt_get_rec(cur, &r, &i);
-                       if (error || i == 0) {
-                               end_of_ag = 1;
+                       if (error)
                                break;
-                       }
+                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0)
 
-                       /*
-                        * If this chunk has any allocated inodes, save it.
-                        * Also start read-ahead now for this chunk.
-                        */
+                       /* If this chunk has any allocated inodes, save it */
                        if (r.ir_freecount < XFS_INODES_PER_CHUNK) {
                                xfs_bulkstat_ichunk_ra(mp, agno, &r);
                                irbp->ir_startino = r.ir_startino;
@@ -465,77 +426,151 @@ xfs_bulkstat(
                                irbp++;
                                icount += XFS_INODES_PER_CHUNK - r.ir_freecount;
                        }
-                       /*
-                        * Set agino to after this chunk and bump the cursor.
-                        */
+
+                       /* Set agino to after this chunk and bump the cursor */
                        agino = r.ir_startino + XFS_INODES_PER_CHUNK;
-                       error = xfs_btree_increment(cur, 0, &tmp);
+                       error = xfs_btree_increment(cur, 0, &i);
+                       if (error)
+                               break;
+                       if (i == 0) {
+                               /* There are no rightward btree entries */
+                               end_of_ag = true;
+                               break;
+                       }
+
                        cond_resched();
                }
+
+               /* Break if previously there is any error has happened */
+               if (error)
+                       break;
                /*
-                * Drop the btree buffers and the agi buffer.
-                * We can't hold any of the locks these represent
-                * when calling iget.
+                * Drop the btree buffers and the agi buffer.  We can't hold
+                * any of the locks these represent when calling iget.
                 */
                xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+               cur = NULL;
                xfs_buf_relse(agbp);
-               /*
-                * Now format all the good inodes into the user's buffer.
-                */
+               agbp = NULL;
+
                irbufend = irbp;
                for (irbp = irbuf;
-                    irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) {
-                       struct xfs_bulkstat_agichunk ac;
+                    irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft_bytes);
+                    irbp++) {
+                       struct xfs_bulkstat_agichunk    ac;
 
                        ac.ac_lastino = lastino;
                        ac.ac_ubuffer = ubuffer;
-                       ac.ac_ubleft = ubleft;
+                       ac.ac_ubleft = ubleft_bytes;
                        ac.ac_ubelem = ubelem;
                        error = xfs_bulkstat_ag_ichunk(mp, agno, irbp,
                                        formatter, statstruct_size, &ac);
                        if (error)
-                               rval = error;
-
+                               break;
                        lastino = ac.ac_lastino;
-                       ubleft = ac.ac_ubleft;
+                       ubleft_bytes = ac.ac_ubleft;
                        ubelem = ac.ac_ubelem;
 
                        cond_resched();
                }
-               /*
-                * Set up for the next loop iteration.
-                */
-               if (XFS_BULKSTAT_UBLEFT(ubleft)) {
-                       if (end_of_ag) {
-                               agno++;
-                               agino = 0;
-                       } else
-                               agino = XFS_INO_TO_AGINO(mp, lastino);
-               } else
+
+               if (error || end_of_ag || !XFS_BULKSTAT_UBLEFT(ubleft_bytes))
                        break;
+
+               /* Set up for the next loop iteration */
+               agino = XFS_INO_TO_AGINO(mp, lastino);
        }
+
+       if (!error) {
+               agbulkp->ab_ocount = ubelem;
+               *(agbulkp->ab_aginop) = XFS_INO_TO_AGINO(mp, lastino);
+       }
+
+error0:
+       if (cur) {
+               xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR :
+                                                 XFS_BTREE_NOERROR);
+       }
+       if (agbp)
+               xfs_buf_relse(agbp);
+
+       return error;
+}
+
+/*
+ * Return stat information in bulk (by-inode) for the filesystem.
+ */
+int
+xfs_bulkstat(
+       struct xfs_mount        *mp,    /* mount point for filesystem */
+       xfs_ino_t               *lastinop, /* last inode returned */
+       int                     *ubcountp, /* size of buffer/count returned */
+       bulkstat_one_pf         formatter, /* func that'd fill a single buf */
+       size_t                  statstruct_size, /* sizeof struct filling */
+       char                    __user *ubuffer, /* buffer with inode stats */
+       int                     *done)  /* 1 if there are more stats to get */
+{
+       xfs_ino_t               lastino = *lastinop;/* last inode number */
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, lastino);
+       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, lastino);
+       int                     ubleft = *ubcountp;/* size of user's buffer */
+       size_t                  irbsize;/* size of irec buffer in bytes */
+       int                     nirbuf; /* size of irbuf */
+       int                     error;  /* error code */
+       struct xfs_inobt_rec_incore *irbuf;/* start of irec buffer */
+
+       /* The given last inode number is beyond file system range, done */
+       if (agno >= mp->m_sb.sb_agcount ||
+           lastino != XFS_AGINO_TO_INO(mp, agno, agino)) {
+               *ubcountp = 0;
+               *done = 1;
+               return 0;
+       }
+
+       irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
+       if (!irbuf)
+               return ENOMEM;
+       nirbuf = irbsize / sizeof(*irbuf);
+
+       *done = 0;
        /*
-        * Done, we're either out of filesystem or space to put the data.
-        */
-       kmem_free(irbuf);
-       *ubcountp = ubelem;
-       /*
-        * Found some inodes, return them now and return the error next time.
+        * Loop over the allocation groups, starting from the last inode
+        * returned; 0 means start of the allocation group.
         */
-       if (ubelem)
-               rval = 0;
-       if (agno >= mp->m_sb.sb_agcount) {
+       do {
+               struct xfs_agbulkstat   agbulk;
+
+               agbulk.ab_agno = agno;
+               agbulk.ab_aginop = &agino;
+               agbulk.ab_ubuffer = ubuffer;
+               agbulk.ab_icount = ubleft;
+               agbulk.ab_ocount = 0;
+               error = xfs_perag_bulkstat(mp, &agbulk, irbuf, nirbuf,
+                                          formatter, statstruct_size);
+               if (error)
+                       break;
+
+               ubleft -= agbulk.ab_ocount;
+               ASSERT(ubleft >= 0);
+               if (!ubleft)
+                       break;
+
                /*
-                * If we ran out of filesystem, mark lastino as off
-                * the end of the filesystem, so the next call
-                * will return immediately.
+                * No more inodes in current allocation group, however the user
+                * requires more.  Proceed to loop over the next one.
                 */
-               *lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0);
+               agino = 0;
+       } while (++agno < mp->m_sb.sb_agcount);
+
+       kmem_free(irbuf);
+
+       if (!error) {
+               *ubcountp -= ubleft;
+               *lastinop = XFS_AGINO_TO_INO(mp, agno, agino);
                *done = 1;
-       } else
-               *lastinop = (xfs_ino_t)lastino;
+       }
 
-       return rval;
+       return error;
 }
 
 /*
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index e33ec46..16536b1 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -47,6 +47,26 @@ xfs_bulkstat_ag_ichunk(
        struct xfs_bulkstat_agichunk    *acp);
 
 /*
+ * Structures returned stat information in bulk (by-inode) per AG.
+ */
+struct xfs_agbulkstat {
+       xfs_agnumber_t  ab_agno;        /* AG number */
+       xfs_agino_t     *ab_aginop;     /* last agino returned */
+       char            __user *ab_ubuffer; /* pointer into user's buffer */
+       __uint32_t      ab_icount;      /* count of entries in buffer */
+       __uint32_t      ab_ocount;      /* output counter */
+};
+
+int
+xfs_perag_bulkstat(
+       struct xfs_mount                *mp,
+       struct xfs_agbulkstat           *agbulkp,
+       struct xfs_inobt_rec_incore     *irbuf,
+       size_t                          nirbuf,
+       bulkstat_one_pf                 formatter,
+       size_t                          statstruct_size);
+
+/*
  * Values for stat return value.
  */
 #define BULKSTAT_RV_NOTHING    0
-- 
1.8.3.2

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