Let zfs diff be more permissive

In the current world, `zfs diff` will die on certain kinds of errors
that come up on ordinary, not-mangled filesystems - like EINVAL,
which can come from a file with multiple hardlinks having the one
whose name is referenced deleted.

Since it should always be safe to continue, let's relax about all
error codes - still print something for most, but don't immediately
abort when we encounter them.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Signed-off-by: Rich Ercolani <rincebrain@gmail.com>
Closes #12072
This commit is contained in:
Rich Ercolani 2021-06-04 17:00:39 -04:00 committed by Tony Hutter
parent 439b4b134d
commit c64c17328b
1 changed files with 23 additions and 12 deletions

View File

@ -243,6 +243,7 @@ write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
struct zfs_stat fsb, tsb; struct zfs_stat fsb, tsb;
mode_t fmode, tmode; mode_t fmode, tmode;
char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN]; char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
boolean_t already_logged = B_FALSE;
int fobjerr, tobjerr; int fobjerr, tobjerr;
int change; int change;
@ -254,22 +255,35 @@ write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
* we get ENOENT, then the object just didn't exist in that * we get ENOENT, then the object just didn't exist in that
* snapshot. If we get ENOTSUP, then we tried to get * snapshot. If we get ENOTSUP, then we tried to get
* info on a non-ZPL object, which we don't care about anyway. * info on a non-ZPL object, which we don't care about anyway.
* For any other error we print a warning which includes the
* errno and continue.
*/ */
fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname, fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname,
MAXPATHLEN, &fsb); MAXPATHLEN, &fsb);
if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP) if (fobjerr && di->zerr != ENOTSUP && di->zerr != ENOENT) {
return (-1); zfs_error_aux(di->zhp->zfs_hdl, strerror(di->zerr));
zfs_error(di->zhp->zfs_hdl, di->zerr, di->errbuf);
/*
* Let's not print an error for the same object more than
* once if it happens in both snapshots
*/
already_logged = B_TRUE;
}
tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname, tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname,
MAXPATHLEN, &tsb); MAXPATHLEN, &tsb);
if (tobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
return (-1);
if (tobjerr && di->zerr != ENOTSUP && di->zerr != ENOENT) {
if (!already_logged) {
zfs_error_aux(di->zhp->zfs_hdl, strerror(di->zerr));
zfs_error(di->zhp->zfs_hdl, di->zerr, di->errbuf);
}
}
/* /*
* Unallocated object sharing the same meta dnode block * Unallocated object sharing the same meta dnode block
*/ */
if (fobjerr && tobjerr) { if (fobjerr && tobjerr) {
ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP);
di->zerr = 0; di->zerr = 0;
return (0); return (0);
} }
@ -344,12 +358,11 @@ describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf,
{ {
struct zfs_stat sb; struct zfs_stat sb;
if (get_stats_for_obj(di, di->fromsnap, object, namebuf, (void) get_stats_for_obj(di, di->fromsnap, object, namebuf,
maxlen, &sb) != 0) { maxlen, &sb);
return (-1);
}
/* Don't print if in the delete queue on from side */ /* Don't print if in the delete queue on from side */
if (di->zerr == ESTALE) { if (di->zerr == ESTALE || di->zerr == ENOENT) {
di->zerr = 0; di->zerr = 0;
return (0); return (0);
} }
@ -384,8 +397,6 @@ write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
} }
err = describe_free(fp, di, zc.zc_obj, fobjname, err = describe_free(fp, di, zc.zc_obj, fobjname,
MAXPATHLEN); MAXPATHLEN);
if (err)
break;
} else if (errno == ESRCH) { } else if (errno == ESRCH) {
break; break;
} else { } else {