On Tue, Nov 04, 2014 at 11:53:17PM +1100, Dave Chinner wrote: > From: Dave Chinner <dchinner@xxxxxxxxxx> > > The xfs_bulkstat_agichunk formatting cursor takes buffer values from > the main loop and passes them via the structure to the chunk > formatter, and the writes the chnged values back into the main loop > local variables. UNfortunately, this complex dance is full of corner > cases that aren't handled correctly. > > The biggest problem is that it is double handling the information in > both the main loop and the chunk formatting function, leading to > inconsistent updates and endless loops where progress is not made. > > To fix this, push the struct xfs_bulkstat_agichunk outwards to be > the primary holder of user buffer information. this removes the > double handling in the main loop. > > Also, pass the last inode processed by the chunk formatter as a > separate parameter as it purely an output variable and is not > related to the user buffer consumption cursor. > > Finally, the chunk formatting code is not shared by anyone, so make > it local to xfs_itable.c. > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> > --- The commit log suggests this patch is fixing some problem(s), but I see mostly a refactor to pull up the ac structure and eliminate the variable swapping between xfs_bulkstat() and xfs_bulkstat_ag_ichunk(). The lastino separation doesn't appear to change semantics that I can tell either. The refactor looks good to me: Reviewed-by: Brian Foster <bfoster@xxxxxxxxxx> ... but is there something subtle in here I'm missing about the problem being fixed? If not, could we update the commit title to suggest this is a clean up? Brian > fs/xfs/xfs_itable.c | 59 +++++++++++++++++++++++++---------------------------- > fs/xfs/xfs_itable.h | 16 --------------- > 2 files changed, 28 insertions(+), 47 deletions(-) > > diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c > index 16737cb..50a3e59 100644 > --- a/fs/xfs/xfs_itable.c > +++ b/fs/xfs/xfs_itable.c > @@ -262,20 +262,26 @@ xfs_bulkstat_grab_ichunk( > > #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) > > +struct xfs_bulkstat_agichunk { > + char __user **ac_ubuffer;/* pointer into user's buffer */ > + int ac_ubleft; /* bytes left in user's buffer */ > + int ac_ubelem; /* spaces used in user's buffer */ > +}; > + > /* > * Process inodes in chunk with a pointer to a formatter function > * that will iget the inode and fill in the appropriate structure. > */ > -int > +static int > xfs_bulkstat_ag_ichunk( > struct xfs_mount *mp, > xfs_agnumber_t agno, > struct xfs_inobt_rec_incore *irbp, > bulkstat_one_pf formatter, > size_t statstruct_size, > - struct xfs_bulkstat_agichunk *acp) > + struct xfs_bulkstat_agichunk *acp, > + xfs_ino_t *lastino) > { > - xfs_ino_t lastino = acp->ac_lastino; > char __user **ubufp = acp->ac_ubuffer; > int ubleft = acp->ac_ubleft; > int ubelem = acp->ac_ubelem; > @@ -295,7 +301,7 @@ xfs_bulkstat_ag_ichunk( > > /* Skip if this inode is free */ > if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { > - lastino = ino; > + *lastino = ino; > continue; > } > > @@ -313,7 +319,7 @@ xfs_bulkstat_ag_ichunk( > ubleft = 0; > break; > } > - lastino = ino; > + *lastino = ino; > continue; > } > if (fmterror == BULKSTAT_RV_GIVEUP) { > @@ -325,10 +331,9 @@ xfs_bulkstat_ag_ichunk( > *ubufp += ubused; > ubleft -= ubused; > ubelem++; > - lastino = ino; > + *lastino = ino; > } > > - acp->ac_lastino = lastino; > acp->ac_ubleft = ubleft; > acp->ac_ubelem = ubelem; > > @@ -355,7 +360,6 @@ xfs_bulkstat( > 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 icount; /* count of inodes good in irbuf */ > size_t irbsize; /* size of irec buffer in bytes */ > xfs_ino_t ino; /* inode number (filesystem) */ > @@ -366,10 +370,8 @@ xfs_bulkstat( > int nirbuf; /* size of irbuf */ > int rval; /* return value error code */ > 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 */ > int stat; > + struct xfs_bulkstat_agichunk ac; > > /* > * Get the last inode value, see if there's nothing to do. > @@ -386,11 +388,13 @@ xfs_bulkstat( > } > > ubcount = *ubcountp; /* statstruct's */ > - ubleft = ubcount * statstruct_size; /* bytes */ > - *ubcountp = ubelem = 0; > + ac.ac_ubuffer = &ubuffer; > + ac.ac_ubleft = ubcount * statstruct_size; /* bytes */; > + ac.ac_ubelem = 0; > + > + *ubcountp = 0; > *done = 0; > - fmterror = 0; > - ubufp = ubuffer; > + > irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); > if (!irbuf) > return -ENOMEM; > @@ -402,7 +406,7 @@ xfs_bulkstat( > * inode returned; 0 means start of the allocation group. > */ > rval = 0; > - while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { > + while (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft) && agno < mp->m_sb.sb_agcount) { > cond_resched(); > error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); > if (error) > @@ -497,28 +501,21 @@ del_cursor: > */ > irbufend = irbp; > for (irbp = irbuf; > - irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) { > - struct xfs_bulkstat_agichunk ac; > - > - ac.ac_lastino = lastino; > - ac.ac_ubuffer = &ubuffer; > - ac.ac_ubleft = ubleft; > - ac.ac_ubelem = ubelem; > + irbp < irbufend && XFS_BULKSTAT_UBLEFT(ac.ac_ubleft); > + irbp++) { > error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, > - formatter, statstruct_size, &ac); > + formatter, statstruct_size, &ac, > + &lastino); > if (error) > rval = error; > > - lastino = ac.ac_lastino; > - ubleft = ac.ac_ubleft; > - ubelem = ac.ac_ubelem; > - > cond_resched(); > } > + > /* > * Set up for the next loop iteration. > */ > - if (XFS_BULKSTAT_UBLEFT(ubleft)) { > + if (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft)) { > if (end_of_ag) { > agno++; > agino = 0; > @@ -531,11 +528,11 @@ del_cursor: > * Done, we're either out of filesystem or space to put the data. > */ > kmem_free(irbuf); > - *ubcountp = ubelem; > + *ubcountp = ac.ac_ubelem; > /* > * Found some inodes, return them now and return the error next time. > */ > - if (ubelem) > + if (ac.ac_ubelem) > rval = 0; > if (agno >= mp->m_sb.sb_agcount) { > /* > diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h > index aaed080..6ea8b39 100644 > --- a/fs/xfs/xfs_itable.h > +++ b/fs/xfs/xfs_itable.h > @@ -30,22 +30,6 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, > int *ubused, > int *stat); > > -struct xfs_bulkstat_agichunk { > - xfs_ino_t ac_lastino; /* last inode returned */ > - char __user **ac_ubuffer;/* pointer into user's buffer */ > - int ac_ubleft; /* bytes left in user's buffer */ > - int ac_ubelem; /* spaces used in user's buffer */ > -}; > - > -int > -xfs_bulkstat_ag_ichunk( > - struct xfs_mount *mp, > - xfs_agnumber_t agno, > - struct xfs_inobt_rec_incore *irbp, > - bulkstat_one_pf formatter, > - size_t statstruct_size, > - struct xfs_bulkstat_agichunk *acp); > - > /* > * Values for stat return value. > */ > -- > 2.0.0 > > _______________________________________________ > xfs mailing list > xfs@xxxxxxxxxxx > http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs