Commit afa947cb52a8e73fe71915a0b0af6fcf98dfbe1a

Authored by Dave Chinner
Committed by Dave Chinner
1 parent 77783d0642

xfs: bulkstat btree walk doesn't terminate

The bulkstat code has several different ways of detecting the end of
an AG when doing a walk. They are not consistently detected, and the
code that checks for the end of AG conditions is not consistently
coded. Hence the are conditions where the walk code can get stuck in
an endless loop making no progress and not triggering any
termination conditions.

Convert all the "tmp/i" status return codes from btree operations
to a common name (stat) and apply end-of-ag detection to these
operations consistently.

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>

Showing 1 changed file with 10 additions and 9 deletions Side-by-side Diff

... ... @@ -356,7 +356,6 @@
356 356 int end_of_ag; /* set if we've seen the ag end */
357 357 int error; /* error code */
358 358 int fmterror;/* bulkstat formatter result */
359   - int i; /* loop index */
360 359 int icount; /* count of inodes good in irbuf */
361 360 size_t irbsize; /* size of irec buffer in bytes */
362 361 xfs_ino_t ino; /* inode number (filesystem) */
363 362  
... ... @@ -366,11 +365,11 @@
366 365 xfs_ino_t lastino; /* last inode number returned */
367 366 int nirbuf; /* size of irbuf */
368 367 int rval; /* return value error code */
369   - int tmp; /* result value from btree calls */
370 368 int ubcount; /* size of user's buffer */
371 369 int ubleft; /* bytes left in user's buffer */
372 370 char __user *ubufp; /* pointer into user's buffer */
373 371 int ubelem; /* spaces used in user's buffer */
  372 + int stat;
374 373  
375 374 /*
376 375 * Get the last inode value, see if there's nothing to do.
377 376  
378 377  
379 378  
... ... @@ -436,13 +435,15 @@
436 435 agino = r.ir_startino + XFS_INODES_PER_CHUNK;
437 436 }
438 437 /* Increment to the next record */
439   - error = xfs_btree_increment(cur, 0, &tmp);
  438 + error = xfs_btree_increment(cur, 0, &stat);
440 439 } else {
441 440 /* Start of ag. Lookup the first inode chunk */
442   - error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp);
  441 + error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat);
443 442 }
444   - if (error)
  443 + if (error || stat == 0) {
  444 + end_of_ag = 1;
445 445 goto del_cursor;
  446 + }
446 447  
447 448 /*
448 449 * Loop through inode btree records in this ag,
... ... @@ -451,8 +452,8 @@
451 452 while (irbp < irbufend && icount < ubcount) {
452 453 struct xfs_inobt_rec_incore r;
453 454  
454   - error = xfs_inobt_get_rec(cur, &r, &i);
455   - if (error || i == 0) {
  455 + error = xfs_inobt_get_rec(cur, &r, &stat);
  456 + if (error || stat == 0) {
456 457 end_of_ag = 1;
457 458 goto del_cursor;
458 459 }
... ... @@ -473,8 +474,8 @@
473 474 * Set agino to after this chunk and bump the cursor.
474 475 */
475 476 agino = r.ir_startino + XFS_INODES_PER_CHUNK;
476   - error = xfs_btree_increment(cur, 0, &tmp);
477   - if (error) {
  477 + error = xfs_btree_increment(cur, 0, &stat);
  478 + if (error || stat == 0) {
478 479 end_of_ag = 1;
479 480 goto del_cursor;
480 481 }