xfs: introduce per allocation group bulkstat
PATCH v2 9/10 xfs: introduce per allocation group bulkstat
From: Jie Liu <[email protected]>
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 <[email protected]>
--- fs/xfs/xfs_itable.c | 288 +++++++++++++++++++++++++++++----------------------- fs/xfs/xfs_itable.h | 20 ++++ 2 files changed, 180 insertions(+), 128 deletions(-)
fs/xfs/xfs_itable.c +160 -128
@@ -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; }/*
fs/xfs/xfs_itable.h +20 -0
@@ -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
Signature · 6 lines
1.8.3.2 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs