Skip to content

NPU plugin test /dev - #1

Draft
wangixt wants to merge 5 commits into
mainfrom
cursor/npu-plugin-test-dev-4382
Draft

NPU plugin test /dev#1
wangixt wants to merge 5 commits into
mainfrom
cursor/npu-plugin-test-dev-4382

Conversation

@wangixt

@wangixt wangixt commented Mar 11, 2026

Copy link
Copy Markdown
Owner
<!--
Please make sure you've read and understood our contributing guidelines:
https://github.com/checkpoint-restore/criu/blob/criu-dev/CONTRIBUTING.md

In short you need to:

- Describe What you do and How you do it;
- Separate each logical change into a separate commit;
- Add a "Signed-off-by:" line identifying that you certify your work with DCO;
- If you fix some specific bug or commit, please add "Fixes: ..." line;
- Review fixes should be made by amending the original commits. For example:
  a) fix the code (e.g. this fixes commit with hash aaa1111)
  b) git commit -a --fixup aaa1111
  c) git rebase --interactive --autosquash aaa1111^
- Pull request integration tests should generally be passing;
- If you change something non-obvious, please consider adding a ZDTM test for it;

-->
**What you do:**
Implement chroot-based isolation for the NPU plugin unit tests to prevent host `/dev` directory corruption.

**How you do it:**
The unit tests previously used mount namespaces, which do not isolate filesystem data operations, leading to modifications of the host `/dev`. This change introduces `setup_chroot_env()` within `npu_plugin_ut.c` to:
1. Create a new mount namespace.
2. Mount a temporary filesystem (tmpfs) as the new root directory.
3. Create essential directories (`/dev`, `/tmp`, `/run`, `/proc`).
4. Mount a separate tmpfs specifically for `/dev` within the chroot.
5. Recreate necessary character device nodes (`/dev/null`, `/dev/zero`, `/dev/full`).
6. Mount `procfs` for `/proc/self/fd/` resolution.
7. Bind-mount the build directory at its original absolute path to allow `gcov` to write coverage data to the host filesystem.
8. Perform a `chroot()` into this isolated tmpfs root and `chdir("/")`.

This ensures that all file system operations during the unit tests occur within a completely isolated environment, preventing any unintended side effects on the host system. Additionally, `npu_plugin_ut_stubs.c` is updated with necessary stubs for `print_on_level`, `log_get_loglevel`, `criu_get_image_dir`, `cr_system`, and `npu_ut_set_img_dirfd` to enable standalone compilation of the unit test binary. The `npu_plugin.c` source code remains unchanged.
Open in Web Open in Cursor 

Mount namespaces alone do NOT isolate filesystem data operations on the
underlying storage -- they only isolate mount/unmount event propagation.
When the unit test unmounted the tmpfs overlay on /dev and then continued
to create/delete files, those operations hit the real host /dev directory,
corrupting it (leaving only a regular file 'null' instead of the expected
device nodes).

Replace the mount-namespace-only approach with a chroot-based isolated
test environment:
  1. Create a new mount namespace with private propagation.
  2. Mount a tmpfs as the new root directory.
  3. Mount a separate tmpfs on /dev within the new root (so tests can
     safely umount+rmdir /dev without exposing the host filesystem).
  4. Create basic device nodes (null, zero, full).
  5. Mount procfs for /proc/self/fd/ resolution.
  6. Bind-mount the build directory for gcov data persistence.
  7. chroot() into the new root.

After chroot, ALL path-based operations resolve within the tmpfs tree,
making it impossible to corrupt the host /dev regardless of what the
tests do with mount/umount/rmdir/mknod inside the chroot.

Also add comprehensive stubs (print_on_level, log_get_loglevel,
criu_get_image_dir, cr_system, npu_ut_set_img_dirfd) to the stubs
file so the test binary can link standalone without the full CRIU
library.

Co-authored-by: wangixt <wangixt@users.noreply.github.com>
@cursor

cursor Bot commented Mar 11, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

cursoragent and others added 4 commits March 11, 2026 13:32
npu_ut_set_img_dirfd(), criu_get_image_dir(), cr_system(),
print_on_level(), and log_get_loglevel() are already provided by
npu_plugin.c under #ifdef NPU_PLUGIN_UT.  Having them in the stubs
file as well causes 'multiple definition' linker errors.

Revert the stubs file to only contain the symbols that are NOT
provided by npu_plugin.c: xmalloc/xfree family, strdup/getpwnam_r
wrappers, and img_streamer_open.

Co-authored-by: wangixt <wangixt@users.noreply.github.com>
Remove the #ifdef NPU_PLUGIN_UT block from npu_plugin.c entirely.
The standard pr_* macros from log.h (which call print_on_level())
are now used in UT mode as well.

All UT-specific symbols are provided by npu_plugin_ut_stubs.c:
  - print_on_level() / log_get_loglevel(): logging backend
  - criu_get_image_dir() / npu_ut_set_img_dirfd(): image dir control
  - cr_system(): command execution stub
  - xmalloc/xfree family, strdup/getpwnam_r wrappers, img_streamer_open

Also update npu_plugin.c to the latest version with:
  - cached_npu_memfd / init_cached_memfd / close_cached_memfd
  - npu_plugin_update_inetsk with id parameter
  - #ifndef NPU_DEVICE guard

Co-authored-by: wangixt <wangixt@users.noreply.github.com>
Move the chroot environment setup from C (setup_chroot_env()) to a
shell script (unit/run_ut_chroot.sh).  This is simpler and cleaner:

  run_ut_chroot.sh:
    1. Re-execs inside unshare --mount --propagation private
    2. Creates tmpfs root + /dev (separate tmpfs) + /tmp + /run + /proc
    3. Creates device nodes: null, zero, full
    4. Bind-mounts shared library dirs (auto-detected via ldd)
    5. Bind-mounts build directory for gcov .gcda persistence
    6. chroot + exec test binary

  npu_plugin_ut.c:
    - Removed ~120 lines of setup_chroot_env() / mkdirs_for_path()
    - main() just sets devns_entered=1 (already inside chroot)
    - enter_private_dev_namespace() is a no-op when devns_entered=1

  Makefile:
    - unit-run calls: bash unit/run_ut_chroot.sh ./unit/npu_plugin_ut

Co-authored-by: wangixt <wangixt@users.noreply.github.com>
The plugin's npu_plugin_update_vmamap() calls memfd_create() on every
invocation (no caching).  Under FD pressure memfd_create() fails and
returns -ENOTSUP, not -1 (which would come from fcntl F_DUPFD_CLOEXEC
in a cached-memfd design).  Update the assertion accordingly.

Co-authored-by: wangixt <wangixt@users.noreply.github.com>
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.

2 participants