summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRich Ercolani <214141+rincebrain@users.noreply.github.com>2021-06-04 17:00:39 -0400
committerTony Hutter <hutter2@llnl.gov>2021-11-01 16:20:02 -0700
commit5089220de851ca50e2e5fdf17734247a9e9212d1 (patch)
treeda4d57438fe4c5d9e3b134d9a5c8a4d2597f4238
parent4c05c35f8b10027635acad5954fe3522ba678f06 (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.c35
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 {