aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2014-11-06 16:31:15 -0500
committerDave Chinner <david@fromorbit.com>2014-11-06 16:31:15 -0500
commitfebe3cbe38b0bc0a925906dc90e8d59048851f87 (patch)
tree34a2cca7bbb1c14f19032eb9cfa693f5a3146b4a /fs
parent6e57c542cb7e0e580eb53ae76a77875c7d92b4b1 (diff)
xfs: bulkstat error handling is broken
The error propagation is a horror - xfs_bulkstat() returns a rval variable which is only set if there are formatter errors. Any sort of btree walk error or corruption will cause the bulkstat walk to terminate but will not pass an error back to userspace. Worse is the fact that formatter errors will also be ignored if any inodes were correctly formatted into the user buffer. Hence bulkstat can fail badly yet still report success to userspace. This causes significant issues with xfsdump not dumping everything in the filesystem yet reporting success. It's not until a restore fails that there is any indication that the dump was bad and tha bulkstat failed. This patch now triggers xfsdump to fail with bulkstat errors rather than silently missing files in the dump. This now causes bulkstat to fail when the lastino cookie does not fall inside an existing inode chunk. The pre-3.17 code tolerated that error by allowing the code to move to the next inode chunk as the agino target is guaranteed to fall into the next btree record. With the fixes up to this point in the series, xfsdump now passes on the troublesome filesystem image that exposes all these bugs. cc: <stable@vger.kernel.org> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_itable.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index acae3355ab22..ff3f431671b9 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -236,8 +236,10 @@ xfs_bulkstat_grab_ichunk(
236 XFS_WANT_CORRUPTED_RETURN(stat == 1); 236 XFS_WANT_CORRUPTED_RETURN(stat == 1);
237 237
238 /* Check if the record contains the inode in request */ 238 /* Check if the record contains the inode in request */
239 if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) 239 if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) {
240 return -EINVAL; 240 *icount = 0;
241 return 0;
242 }
241 243
242 idx = agino - irec->ir_startino + 1; 244 idx = agino - irec->ir_startino + 1;
243 if (idx < XFS_INODES_PER_CHUNK && 245 if (idx < XFS_INODES_PER_CHUNK &&
@@ -352,7 +354,6 @@ xfs_bulkstat(
352 xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ 354 xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */
353 xfs_ino_t lastino; /* last inode number returned */ 355 xfs_ino_t lastino; /* last inode number returned */
354 int nirbuf; /* size of irbuf */ 356 int nirbuf; /* size of irbuf */
355 int rval; /* return value error code */
356 int ubcount; /* size of user's buffer */ 357 int ubcount; /* size of user's buffer */
357 struct xfs_bulkstat_agichunk ac; 358 struct xfs_bulkstat_agichunk ac;
358 int error = 0; 359 int error = 0;
@@ -388,7 +389,6 @@ xfs_bulkstat(
388 * Loop over the allocation groups, starting from the last 389 * Loop over the allocation groups, starting from the last
389 * inode returned; 0 means start of the allocation group. 390 * inode returned; 0 means start of the allocation group.
390 */ 391 */
391 rval = 0;
392 while (agno < mp->m_sb.sb_agcount) { 392 while (agno < mp->m_sb.sb_agcount) {
393 struct xfs_inobt_rec_incore *irbp = irbuf; 393 struct xfs_inobt_rec_incore *irbp = irbuf;
394 struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf; 394 struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf;
@@ -491,13 +491,16 @@ del_cursor:
491 formatter, statstruct_size, &ac, 491 formatter, statstruct_size, &ac,
492 &lastino); 492 &lastino);
493 if (error) 493 if (error)
494 rval = error; 494 break;
495 495
496 cond_resched(); 496 cond_resched();
497 } 497 }
498 498
499 /* If we've run out of space, we are done */ 499 /*
500 if (ac.ac_ubleft < statstruct_size) 500 * If we've run out of space or had a formatting error, we
501 * are now done
502 */
503 if (ac.ac_ubleft < statstruct_size || error)
501 break; 504 break;
502 505
503 if (end_of_ag) { 506 if (end_of_ag) {
@@ -511,11 +514,17 @@ del_cursor:
511 */ 514 */
512 kmem_free(irbuf); 515 kmem_free(irbuf);
513 *ubcountp = ac.ac_ubelem; 516 *ubcountp = ac.ac_ubelem;
517
514 /* 518 /*
515 * Found some inodes, return them now and return the error next time. 519 * We found some inodes, so clear the error status and return them.
520 * The lastino pointer will point directly at the inode that triggered
521 * any error that occurred, so on the next call the error will be
522 * triggered again and propagated to userspace as there will be no
523 * formatted inodes in the buffer.
516 */ 524 */
517 if (ac.ac_ubelem) 525 if (ac.ac_ubelem)
518 rval = 0; 526 error = 0;
527
519 if (agno >= mp->m_sb.sb_agcount) { 528 if (agno >= mp->m_sb.sb_agcount) {
520 /* 529 /*
521 * If we ran out of filesystem, mark lastino as off 530 * If we ran out of filesystem, mark lastino as off
@@ -527,7 +536,7 @@ del_cursor:
527 } else 536 } else
528 *lastinop = (xfs_ino_t)lastino; 537 *lastinop = (xfs_ino_t)lastino;
529 538
530 return rval; 539 return error;
531} 540}
532 541
533int 542int