From: Darrick J. Wong <djwong@xxxxxxxxxx> Make the xfs_scrubbed background service query the autofsck filesystem property to figure out which operating mode it should use. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- scrub/xfs_scrubbed.in | 62 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 90602481f64c88..2b34603cb361e2 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -573,6 +573,21 @@ def fgetpath(fd, fh = None, mountpoint = None): break return ret +# Filesystem properties + +FSPROP_NAMESPACE = "trusted." +FSPROP_NAME_PREFIX = "xfs:" +FSPROP_AUTOFSCK_NAME = "autofsck" + +def fsprop_attrname(n): + '''Construct the xattr name for a filesystem property.''' + return f"{FSPROP_NAMESPACE}{FSPROP_NAME_PREFIX}{n}" + +def fsprop_getstr(fd, n): + '''Return the value of a filesystem property as a string.''' + attrname = fsprop_attrname(n) + return os.getxattr(fd, attrname).decode('utf-8') + # main program def health_reports(mon_fp, fh): @@ -731,6 +746,31 @@ def handle_event(e): elif want_repair and event['type'] == 'sick': repair_queue.submit(repair_metadata, event, fh) +def want_repair_from_autofsck(fd): + '''Determine want_repair from the autofsck filesystem property.''' + global has_parent + global has_rmapbt + + try: + advice = fsprop_getstr(fd, FSPROP_AUTOFSCK_NAME) + if advice == "repair": + return True + if advice == "check" or advice == "optimize": + return False + if advice == "none": + return None + except: + # Any OS error (including ENODATA) or string parsing error is + # treated the same as an unrecognized value. + pass + + # For an unrecognized value, log but do not fix runtime corruption if + # backref metadata are enabled. If no backref metadata are available, + # the fs is too old so don't run at all. + if has_rmapbt or has_parent: + return False + return None + def monitor(mountpoint, event_queue, **kwargs): '''Monitor the given mountpoint for health events.''' global everything @@ -749,6 +789,20 @@ def monitor(mountpoint, event_queue, **kwargs): # Don't care if we can't detect parent pointers or rmap print(f'{printf_prefix}: detecting fs features: {e}', file = sys.stderr) + # Does the sysadmin have any advice for us about whether or not to + # background scrub? + if want_repair is None: + want_repair = want_repair_from_autofsck(fd) + if want_repair is None: + print(f"{mountpoint}: Disabling daemon per autofsck directive.") + os.close(fd) + return 0 + elif want_repair: + print(f"{mountpoint}: Automatically repairing per autofsck directive.") + else: + print(f"{mountpoint}: Only logging errors per autofsck directive.") + + # Check for the backref metadata that makes repair effective. if want_repair: if not has_rmapbt: @@ -963,7 +1017,11 @@ def main(): action = "store_true") parser.add_argument("--everything", help = "Capture all events.", \ action = "store_true") - parser.add_argument("--repair", help = "Automatically repair corrupt metadata.", \ + action_group = parser.add_mutually_exclusive_group() + action_group.add_argument("--repair", \ + help = "Automatically repair corrupt metadata.", \ + action = "store_true") + action_group.add_argument("--autofsck", help = argparse.SUPPRESS, \ action = "store_true") parser.add_argument("-V", help = "Report version and exit.", \ action = "store_true") @@ -1004,6 +1062,8 @@ def main(): everything = True if args.debug_fast: debug_fast = True + if args.autofsck: + want_repair = None if args.repair: want_repair = True