diff options
author | Rich Ercolani <214141+rincebrain@users.noreply.github.com> | 2021-06-04 17:00:39 -0400 |
---|---|---|
committer | Tony Hutter <hutter2@llnl.gov> | 2021-11-01 16:20:02 -0700 |
commit | 5089220de851ca50e2e5fdf17734247a9e9212d1 (patch) | |
tree | da4d57438fe4c5d9e3b134d9a5c8a4d2597f4238 | |
parent | 4c05c35f8b10027635acad5954fe3522ba678f06 (diff) |
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
-rw-r--r-- | lib/libzfs/libzfs_diff.c | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c index 7941a5883..688cadf3b 100644 --- a/lib/libzfs/libzfs_diff.c +++ b/lib/libzfs/libzfs_diff.c @@ -243,6 +243,7 @@ write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj) struct zfs_stat fsb, tsb; mode_t fmode, tmode; char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN]; + boolean_t already_logged = B_FALSE; int fobjerr, tobjerr; 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 * snapshot. If we get ENOTSUP, then we tried to get * 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, MAXPATHLEN, &fsb); - if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP) - return (-1); + if (fobjerr && di->zerr != ENOTSUP && di->zerr != ENOENT) { + 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, 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 */ if (fobjerr && tobjerr) { - ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP); di->zerr = 0; return (0); } @@ -344,12 +358,11 @@ describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf, { struct zfs_stat sb; - if (get_stats_for_obj(di, di->fromsnap, object, namebuf, - maxlen, &sb) != 0) { - return (-1); - } + (void) get_stats_for_obj(di, di->fromsnap, object, namebuf, + maxlen, &sb); + /* 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; 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, MAXPATHLEN); - if (err) - break; } else if (errno == ESRCH) { break; } else { |