diff options
author | Dave Chinner <dchinner@redhat.com> | 2014-10-28 17:22:18 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2014-10-28 17:22:18 -0400 |
commit | a6bbce54efa9145dbcf3029c885549f7ebc40a3b (patch) | |
tree | ad8cac74e9ad13827614de3bd368d3cdaff4b22e /fs/xfs | |
parent | cac7f2429872d3733dc3f9915857b1691da2eb2f (diff) |
xfs: bulkstat doesn't release AGI buffer on error
The recent refactoring of the bulkstat code left a small landmine in
the code. If a inobt read fails, then the tree walk is aborted and
returns without releasing the AGI buffer or freeing the cursor. This
can lead to a subsequent bulkstat call hanging trying to grab the
AGI buffer again.
cc: <stable@vger.kernel.org>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_itable.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index f1deb961a296..ef8ea0589780 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -427,7 +427,7 @@ xfs_bulkstat( | |||
427 | 427 | ||
428 | error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); | 428 | error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); |
429 | if (error) | 429 | if (error) |
430 | break; | 430 | goto del_cursor; |
431 | if (icount) { | 431 | if (icount) { |
432 | irbp->ir_startino = r.ir_startino; | 432 | irbp->ir_startino = r.ir_startino; |
433 | irbp->ir_freecount = r.ir_freecount; | 433 | irbp->ir_freecount = r.ir_freecount; |
@@ -442,7 +442,7 @@ xfs_bulkstat( | |||
442 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); | 442 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); |
443 | } | 443 | } |
444 | if (error) | 444 | if (error) |
445 | break; | 445 | goto del_cursor; |
446 | 446 | ||
447 | /* | 447 | /* |
448 | * Loop through inode btree records in this ag, | 448 | * Loop through inode btree records in this ag, |
@@ -454,7 +454,7 @@ xfs_bulkstat( | |||
454 | error = xfs_inobt_get_rec(cur, &r, &i); | 454 | error = xfs_inobt_get_rec(cur, &r, &i); |
455 | if (error || i == 0) { | 455 | if (error || i == 0) { |
456 | end_of_ag = 1; | 456 | end_of_ag = 1; |
457 | break; | 457 | goto del_cursor; |
458 | } | 458 | } |
459 | 459 | ||
460 | /* | 460 | /* |
@@ -476,13 +476,17 @@ xfs_bulkstat( | |||
476 | error = xfs_btree_increment(cur, 0, &tmp); | 476 | error = xfs_btree_increment(cur, 0, &tmp); |
477 | cond_resched(); | 477 | cond_resched(); |
478 | } | 478 | } |
479 | |||
479 | /* | 480 | /* |
480 | * Drop the btree buffers and the agi buffer. | 481 | * Drop the btree buffers and the agi buffer as we can't hold any |
481 | * We can't hold any of the locks these represent | 482 | * of the locks these represent when calling iget. If there is a |
482 | * when calling iget. | 483 | * pending error, then we are done. |
483 | */ | 484 | */ |
485 | del_cursor: | ||
484 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 486 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
485 | xfs_buf_relse(agbp); | 487 | xfs_buf_relse(agbp); |
488 | if (error) | ||
489 | break; | ||
486 | /* | 490 | /* |
487 | * Now format all the good inodes into the user's buffer. | 491 | * Now format all the good inodes into the user's buffer. |
488 | */ | 492 | */ |