aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_itable.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2014-11-06 16:30:58 -0500
committerDave Chinner <david@fromorbit.com>2014-11-06 16:30:58 -0500
commit2b831ac6bc87d3cbcbb1a8816827b6923403e461 (patch)
treee1c5fb18fa99b4a6b025d716e29793df06861119 /fs/xfs/xfs_itable.c
parentbf4a5af20d25ecc8876978ad34b8db83b4235f3c (diff)
xfs: bulkstat chunk-formatter has issues
The loop construct has issues: - clustidx is completely unused, so remove it. - the loop tries to be smart by terminating when the "freecount" tells it that all inodes are free. Just drop it as in most cases we have to scan all inodes in the chunk anyway. - move the "user buffer left" condition check to the only point where we consume space int eh user buffer. - move the initialisation of agino out of the loop, leaving just a simple loop control logic using the clusteridx. Also, double handling of the user buffer variables leads to problems tracking the current state - use the cursor variables directly rather than keeping local copies and then having to update the cursor before returning. cc: <stable@vger.kernel.org> # 3.17 Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_itable.c')
-rw-r--r--fs/xfs/xfs_itable.c58
1 files changed, 24 insertions, 34 deletions
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 50a3e5995dd9..7ea2b113db1b 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -283,59 +283,49 @@ xfs_bulkstat_ag_ichunk(
283 xfs_ino_t *lastino) 283 xfs_ino_t *lastino)
284{ 284{
285 char __user **ubufp = acp->ac_ubuffer; 285 char __user **ubufp = acp->ac_ubuffer;
286 int ubleft = acp->ac_ubleft; 286 int chunkidx;
287 int ubelem = acp->ac_ubelem;
288 int chunkidx, clustidx;
289 int error = 0; 287 int error = 0;
290 xfs_agino_t agino; 288 xfs_agino_t agino;
291 289
292 for (agino = irbp->ir_startino, chunkidx = clustidx = 0; 290 agino = irbp->ir_startino;
293 XFS_BULKSTAT_UBLEFT(ubleft) && 291 for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK;
294 irbp->ir_freecount < XFS_INODES_PER_CHUNK; 292 chunkidx++, agino++) {
295 chunkidx++, clustidx++, agino++) { 293 int fmterror;
296 int fmterror; /* bulkstat formatter result */
297 int ubused; 294 int ubused;
298 xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino); 295 xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino);
299 296
300 ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
301
302 /* Skip if this inode is free */ 297 /* Skip if this inode is free */
303 if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { 298 if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) {
304 *lastino = ino; 299 *lastino = ino;
305 continue; 300 continue;
306 } 301 }
307 302
308 /*
309 * Count used inodes as free so we can tell when the
310 * chunk is used up.
311 */
312 irbp->ir_freecount++;
313
314 /* Get the inode and fill in a single buffer */ 303 /* Get the inode and fill in a single buffer */
315 ubused = statstruct_size; 304 ubused = statstruct_size;
316 error = formatter(mp, ino, *ubufp, ubleft, &ubused, &fmterror); 305 error = formatter(mp, ino, *ubufp, acp->ac_ubleft,
317 if (fmterror == BULKSTAT_RV_NOTHING) { 306 &ubused, &fmterror);
318 if (error && error != -ENOENT && error != -EINVAL) { 307 if (fmterror == BULKSTAT_RV_GIVEUP ||
319 ubleft = 0; 308 (error && error != -ENOENT && error != -EINVAL)) {
320 break; 309 acp->ac_ubleft = 0;
321 }
322 *lastino = ino;
323 continue;
324 }
325 if (fmterror == BULKSTAT_RV_GIVEUP) {
326 ubleft = 0;
327 ASSERT(error); 310 ASSERT(error);
328 break; 311 break;
329 } 312 }
330 if (*ubufp) 313
331 *ubufp += ubused; 314 /* be careful not to leak error if at end of chunk */
332 ubleft -= ubused; 315 if (fmterror == BULKSTAT_RV_NOTHING || error) {
333 ubelem++; 316 *lastino = ino;
317 error = 0;
318 continue;
319 }
320
321 *ubufp += ubused;
322 acp->ac_ubleft -= ubused;
323 acp->ac_ubelem++;
334 *lastino = ino; 324 *lastino = ino;
335 }
336 325
337 acp->ac_ubleft = ubleft; 326 if (acp->ac_ubleft < statstruct_size)
338 acp->ac_ubelem = ubelem; 327 break;
328 }
339 329
340 return error; 330 return error;
341} 331}