Skip to content

fix(host_scanner): reduce syscalls during scans#1221

Open
Molter73 wants to merge 5 commits into
mainfrom
mauro/fix/miscellaneous-host-scanner-improvements
Open

fix(host_scanner): reduce syscalls during scans#1221
Molter73 wants to merge 5 commits into
mainfrom
mauro/fix/miscellaneous-host-scanner-improvements

Conversation

@Molter73

@Molter73 Molter73 commented Jul 21, 2026

Copy link
Copy Markdown
Member

Description

This PR makes some efforts to try and reduce the amount of syscalls that HostScanner does when scanning through the filesystem. This is achieved essentially with two changes:

  • Reduce the number of stat calls.
  • Reduce the number of BPF map update for inode tracking.

The first one is done by replacing individual calls to PathBuf::is_file, PathBuf::is_dir and PathBuf::metadata, all of which call stat under the hood, with a single PathBuf::metadata call and using it where needed.

The second one is done by first checking if the userspace inode map has the found inode and if it is already there, we simply skip inserting it kernel side, since it should've been put there in a previous scan.

Checklist

  • Patch has a change log entry OR does not need one.
  • Investigated and inspected CI test results
  • Updated documentation accordingly

Automated testing

  • Added unit tests
  • Added integration tests
  • Added regression tests

If any of these don't apply, please comment below.

Testing Performed

Reduced number of syscalls

Running fact with the following command: FACT_LOGLEVEL=info RUST_BACKTRACE=1 cargo srun --bin fact --all-features -- -p '/etc/**/*:/etc/' --inodes-max=2097152 --expose-metrics --scan-interval 30, then using perf stat -e 'syscalls:sys_enter_statx,syscalls:sys_enter_bpf' -p "$(pgrep fact)" -- sleep 30 capturing a single scan. No events generated during the run, no modifications to the /etc directory, 25966 inodes tracked for all the scans.

Before changes:

 Performance counter stats for process id '1050929':

           114,514      syscalls:sys_enter_statx
            28,447      syscalls:sys_enter_bpf

      30.002484040 seconds time elapsed

After all changes:

 Performance counter stats for process id '1067511':

            56,597      syscalls:sys_enter_statx
                 0      syscalls:sys_enter_bpf

      30.002870566 seconds time elapsed

Average scan time

Run fact with the following command in each commit in this PR: FACT_LOGLEVEL=info RUST_BACKTRACE=1 cargo srun --bin fact --all-features -- -p '/etc/**/*:/etc/' --inodes-max=2097152 --expose-metrics --scan-interval 1. No events generated during the run, no modifications to the /etc directory, 25966 inodes tracked for all the scans.

Average scan time adding scan duration to log and metric: 162.48ms
# HELP stackrox_fact_host_scanner_scan_duration Histogram of scan durations from the host scanner component.
# TYPE stackrox_fact_host_scanner_scan_duration histogram
stackrox_fact_host_scanner_scan_duration_sum 19.660724177999989
stackrox_fact_host_scanner_scan_duration_count 121
stackrox_fact_host_scanner_scan_duration_bucket{le="0.01"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.05"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.1"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.25"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="0.5"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="1.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="5.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="10.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="30.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="60.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="120.0"} 121
stackrox_fact_host_scanner_scan_duration_bucket{le="+Inf"} 121
Average scan time using a single metadata call: 136.44ms
# HELP stackrox_fact_host_scanner_scan_duration Histogram of scan durations from the host scanner component.
# TYPE stackrox_fact_host_scanner_scan_duration histogram
stackrox_fact_host_scanner_scan_duration_sum 14.190043638000005
stackrox_fact_host_scanner_scan_duration_count 104
stackrox_fact_host_scanner_scan_duration_bucket{le="0.01"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.05"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.1"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.25"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="0.5"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="1.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="5.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="10.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="30.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="60.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="120.0"} 104
stackrox_fact_host_scanner_scan_duration_bucket{le="+Inf"} 104
Average scan time skipping re-insertion of inodes in BPF map: 114.19ms
# HELP stackrox_fact_host_scanner_scan_duration Histogram of scan durations from the host scanner component.
# TYPE stackrox_fact_host_scanner_scan_duration histogram
stackrox_fact_host_scanner_scan_duration_sum 13.245613742999997
stackrox_fact_host_scanner_scan_duration_count 116
stackrox_fact_host_scanner_scan_duration_bucket{le="0.01"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.05"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.1"} 0
stackrox_fact_host_scanner_scan_duration_bucket{le="0.25"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="0.5"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="1.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="5.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="10.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="30.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="60.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="120.0"} 116
stackrox_fact_host_scanner_scan_duration_bucket{le="+Inf"} 116

Summary by CodeRabbit

  • Improvements

    • Host scanning now reports completion time and tracked inode counts for improved visibility.
    • Scanning handles filesystem and path-reading errors more gracefully, allowing valid entries to continue processing.
    • File updates are processed more efficiently, reducing unnecessary work when paths have not changed.
  • Monitoring

    • Added scan-duration metrics.
    • Added metrics for filesystem metadata and directory traversal failures.

Molter73 added 4 commits July 21, 2026 11:18
Add a histogram capturing the duration of a host_scanner scan.
Instead of using `PathBuf::is_file`, `PathBuf::is_dir` and
`PathBuf::metadata` individually, each of which produce independent
calls to `stat` under the hood, use a single call to `PathBuf::metadata`
and propagate it down to the places it is needed.
Avoid additional syscalls to insert inodes into the kernel BPF inode map
if the userspace already has said inode.
@Molter73
Molter73 requested a review from a team as a code owner July 21, 2026 10:48
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Host scanning now records scan durations, logs lifecycle events at info level, skips glob and metadata lookup failures, passes fetched metadata through updates, and avoids redundant inode tracking work.

Changes

Host scanner observability and resilient inode tracking

Layer / File(s) Summary
Scan duration metrics
fact/src/metrics/host_scanner.rs
Adds and registers a histogram with fixed buckets for host scanner scan durations, plus labels for glob and metadata lookup failures.
Scan timing instrumentation
fact/src/host_scanner.rs
Measures scan elapsed time, records it in the histogram, and logs scan start and completion details.
Defensive traversal and inode tracking
fact/src/host_scanner.rs
Logs and skips glob or metadata failures, passes fetched metadata into inode updates, avoids repeated updates for unchanged inode paths, and consolidates kernel insertion error handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main host scanner syscall reduction work.
Description check ✅ Passed The description covers the change, checklist, and testing performed, with only minor checklist items left incomplete.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mauro/fix/miscellaneous-host-scanner-improvements

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 49 lines in your changes missing coverage. Please review.
✅ Project coverage is 32.94%. Comparing base (64ed5ae) to head (0a1d04e).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
fact/src/host_scanner.rs 0.00% 37 Missing ⚠️
fact/src/metrics/host_scanner.rs 0.00% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1221      +/-   ##
==========================================
- Coverage   33.22%   32.94%   -0.28%     
==========================================
  Files          21       21              
  Lines        2971     2996      +25     
  Branches     2971     2996      +25     
==========================================
  Hits          987      987              
- Misses       1981     2006      +25     
  Partials        3        3              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
fact/src/host_scanner.rs (1)

205-234: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not retain a userspace inode when kernel insertion fails.

Line 217 inserts into inode_map before the BPF insertion at Line 221. On a full or failed kernel map insertion, later scans hit Lines 207-213 and never retry BPF tracking, leaving the inode falsely marked as monitored. Insert into inode_map only after kernel insertion succeeds, or roll back the userspace entry on every error path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fact/src/host_scanner.rs` around lines 205 - 234, The inode_map entry must
not remain when kernel_inode_map insertion fails. Update the new-inode path
around inode_map and kernel_inode_map so the userspace inode is inserted only
after the kernel insertion succeeds, or remove it on every error path, while
preserving the existing already-tracked path and error reporting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@fact/src/host_scanner.rs`:
- Around line 205-234: The inode_map entry must not remain when kernel_inode_map
insertion fails. Update the new-inode path around inode_map and kernel_inode_map
so the userspace inode is inserted only after the kernel insertion succeeds, or
remove it on every error path, while preserving the existing already-tracked
path and error reporting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 5edde49b-9885-47e7-a91d-25e6873b308f

📥 Commits

Reviewing files that changed from the base of the PR and between a47086e and e7a0da4.

📒 Files selected for processing (2)
  • fact/src/host_scanner.rs
  • fact/src/metrics/host_scanner.rs

@Molter73 Molter73 linked an issue Jul 21, 2026 that may be closed by this pull request
@Molter73

Copy link
Copy Markdown
Member Author

/retest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use tokio::fs in HostScanner

2 participants