From: Jie Liu <jeff.liu@xxxxxxxxxx> Introduce 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. Similar to the per allocation group inumbers, we could perform bulkstat in parallel with that. Refactor xfs_bulkstat() with it. Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx> --- fs/xfs/xfs_itable.c | 288 +++++++++++++++++++++++++++++----------------------- fs/xfs/xfs_itable.h | 20 ++++ 2 files changed, 180 insertions(+), 128 deletions(-) diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 56e1d5f..58dc182 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -337,86 +337,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; - - nirbuf = irbsize / sizeof(*irbuf); + 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; + + 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 stat; + 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 @@ -434,32 +392,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, &stat); + if (error) + break; + if (!stat) + 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, &stat); + if (error || !stat) + break; } - 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; + error = xfs_inobt_get_rec(cur, &r, &stat); + if (error) + break; + if (!stat) { + end_of_ag = true; break; } - /* - * 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; @@ -468,77 +428,149 @@ 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, &stat); + if (error) + break; + if (!stat) { + 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); + } + + 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 d3e004e..0488960 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 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs