Skip to content

Switch to JSON-based output parsing for LVM commands #1182

Merged
vojtechtrefny merged 3 commits intostoraged-project:masterfrom
vojtechtrefny:master_lvm-json
Mar 19, 2026
Merged

Switch to JSON-based output parsing for LVM commands #1182
vojtechtrefny merged 3 commits intostoraged-project:masterfrom
vojtechtrefny:master_lvm-json

Conversation

@vojtechtrefny
Copy link
Member

@vojtechtrefny vojtechtrefny commented Mar 13, 2026

Fixes: #729

Summary by CodeRabbit

  • Bug Fixes

    • Clear cached dependency state on many plugin unloads for more reliable cleanup and re-evaluation.
  • Improvements

    • LVM handling rewritten to consume JSON reports for more consistent, tolerant parsing and clearer error handling.
    • Added JSON parsing support to the build to enable the new LVM flow.
  • Updated Support

    • Minimum required LVM version raised to 2.03.17.
  • Tests

    • Expanded LVM tests for fields, segments, and hierarchical relationships; removed a plugin-reload-specific test.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 44a657a2-5e58-49aa-a8df-179f92261341

📥 Commits

Reviewing files that changed from the base of the PR and between ed0303f and 9663e3d.

📒 Files selected for processing (26)
  • scripts/boilerplate_generator.py
  • src/plugins/btrfs.c
  • src/plugins/dm.c
  • src/plugins/fs.c
  • src/plugins/fs/btrfs.c
  • src/plugins/fs/common.h
  • src/plugins/fs/exfat.c
  • src/plugins/fs/ext.c
  • src/plugins/fs/f2fs.c
  • src/plugins/fs/nilfs.c
  • src/plugins/fs/ntfs.c
  • src/plugins/fs/udf.c
  • src/plugins/fs/vfat.c
  • src/plugins/fs/xfs.c
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/lvm/lvm.c
  • src/plugins/mdraid.c
  • src/plugins/mpath.c
  • src/plugins/nvdimm.c
  • src/plugins/s390.c
  • src/plugins/smart/libatasmart.c
  • src/plugins/smart/smart-common.c
  • src/plugins/smart/smart-private.h
  • src/plugins/smart/smartmontools.c
  • src/plugins/swap.c
  • tests/library_test.py
💤 Files with no reviewable changes (1)
  • tests/library_test.py
✅ Files skipped from review due to trivial changes (2)
  • src/plugins/fs/common.h
  • src/plugins/lvm/lvm.c
🚧 Files skipped from review as they are similar to previous changes (20)
  • src/plugins/s390.c
  • src/plugins/smart/smart-common.c
  • src/plugins/fs.c
  • src/plugins/swap.c
  • src/plugins/btrfs.c
  • src/plugins/mdraid.c
  • scripts/boilerplate_generator.py
  • src/plugins/smart/smart-private.h
  • src/plugins/fs/xfs.c
  • src/plugins/fs/ext.c
  • src/plugins/fs/f2fs.c
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/smart/smartmontools.c
  • src/plugins/fs/udf.c
  • src/plugins/nvdimm.c
  • src/plugins/fs/exfat.c
  • src/plugins/fs/vfat.c
  • src/plugins/fs/nilfs.c
  • src/plugins/smart/libatasmart.c
  • src/plugins/dm.c

📝 Walkthrough

Walkthrough

LVM plugin rewritten to parse JSON reports via json-glib and new tree APIs; build checks/flags for json-glib added. Many plugins now clear cached runtime dependency availability on close; per-filesystem reset hooks added. Dynamic loader uses RTLD_NODELETE. Expanded LVM tests; a plugin-reload test removed.

Changes

Cohort / File(s) Summary
Build/config
configure.ac, src/plugins/lvm/Makefile.am
configure.ac: when enabling LVM, add a json-glib-1.0 pkg-config check alongside YAML. LVM Makefile: add $(JSON_GLIB_CFLAGS) to CFLAGS and $(JSON_GLIB_LIBS) to LIBADD.
LVM plugin (major refactor)
src/plugins/lvm/lvm.c, src/plugins/lvm/lvm-private.h, src/plugins/lvm/lvm-dbus.c
Replace line-based parsing with json-glib JSON report parsing, new JSON helpers, tolerate missing fields, add bd_lvm_lvinfo_tree and bd_lvm_lvs_tree, bump LVM_MIN_VERSION, and reset dependency/feature atomics on close.
Filesystem reset hooks
src/plugins/fs.c, src/plugins/fs/common.h, src/plugins/fs/.../*.c
Declare and implement _fs_*_reset_avail_deps() for ext, xfs, vfat, ntfs, exfat, btrfs, udf, f2fs, nilfs; bd_fs_close() now calls these reset helpers.
Plugin dependency state cleanup
src/plugins/btrfs.c, src/plugins/dm.c, src/plugins/mdraid.c, src/plugins/mpath.c, src/plugins/nvdimm.c, src/plugins/s390.c, src/plugins/swap.c
Multiple bd_*_close() functions changed from no-ops to atomically resetting avail_deps (and related counters) to 0 during plugin unload.
SMART plugin changes
src/plugins/smart/libatasmart.c, src/plugins/smart/smartmontools.c, src/plugins/smart/smart-common.c, src/plugins/smart/smart-private.h
Add internal _smart_close_plugin() and declaration; smart-common invokes it; smartmontools implementation clears avail_deps.
Dynamic loader behavior
scripts/boilerplate_generator.py
Generated loader code now calls `dlopen(so_name, RTLD_LAZY
LVM tests
tests/_lvm_cases.py
Expand PV/VG/LV assertions, add tree-based LV tests, validate segtype, per-segment sizing and VG/PV/LV relations across thin/thin-pool scenarios.
Test adjustments
tests/library_test.py
Removed PluginsTestCase.test_reload() which exercised plugin rebuild/reload behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes several changes beyond the core JSON parsing objective: adding dependency reset functions across multiple filesystem plugins, updating minimum LVM version, and test removals that appear tangential to JSON parsing implementation. Review and separate the dependency reset changes (fs plugins, dm, btrfs, mdraid, mpath, nvdimm, s390, swap, smart) and LVM minimum version bump into separate PRs to keep this focused on JSON parsing migration.
Docstring Coverage ⚠️ Warning Docstring coverage is 64.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: switching LVM command parsing from text-based output to JSON-based output, which directly addresses the linked issue #729.
Linked Issues check ✅ Passed The PR successfully implements JSON-based parsing for LVM commands (issue #729) by replacing text parsing with json-glib library integration, updated LVM CLI calls to use --reportformat json, and added JSON extraction helpers throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@vojtechtrefny
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
src/plugins/lvm/lvm-dbus.c (1)

198-220: ⚠️ Potential issue | 🟠 Major

Add NULL safety check to bd_lvm_close and properly release the DBus connection object.

The function calls g_dbus_connection_flush_sync() and g_dbus_connection_close_sync() on bus without checking if it's NULL, contradicting the comment that acknowledges bus may not be initialized. Additionally, bus = NULL leaks the GObject reference—use g_clear_object(&bus) instead to properly release and NULL the pointer.

🔧 Proposed fix
 void bd_lvm_close (void) {
     GError *error = NULL;
 
-    /* the check() call should create the DBus connection for us, but let's not
-       completely rely on it */
-    if (!g_dbus_connection_flush_sync (bus, NULL, &error)) {
-        bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to flush DBus connection: %s", error->message);
-        g_clear_error (&error);
-    }
-    if (!g_dbus_connection_close_sync (bus, NULL, &error)) {
-        bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to close DBus connection: %s", error->message);
-        g_clear_error (&error);
+    if (bus) {
+        if (!g_dbus_connection_flush_sync (bus, NULL, &error)) {
+            bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to flush DBus connection: %s", error->message);
+            g_clear_error (&error);
+        }
+        if (!g_dbus_connection_close_sync (bus, NULL, &error)) {
+            bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to close DBus connection: %s", error->message);
+            g_clear_error (&error);
+        }
+        g_clear_object (&bus);
     }
-
-    bus = NULL;
 
     dm_log_with_errno_init (NULL);
     dm_log_init_verbose (0);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/lvm/lvm-dbus.c` around lines 198 - 220, bd_lvm_close calls
g_dbus_connection_flush_sync and g_dbus_connection_close_sync on bus without
checking for NULL and then sets bus = NULL which leaks the GObject; update
bd_lvm_close to first check if (bus != NULL) before calling
g_dbus_connection_flush_sync and g_dbus_connection_close_sync, handle and clear
GError as already done, and replace the manual bus = NULL with
g_clear_object(&bus) to properly unref and NULL the DBus connection object; keep
the rest of the cleanup (dm_log_* and avail_* resets) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/plugins/btrfs.c`:
- Around line 152-154: bd_btrfs_close currently resets avail_deps and
avail_module_deps with plain assignments which can race with
check_deps()/check_module_deps that use g_atomic_int_get()/g_atomic_int_or();
replace the direct assignments in bd_btrfs_close() with atomic resets using
g_atomic_int_set(&avail_deps, 0) and g_atomic_int_set(&avail_module_deps, 0) so
the cache variables are cleared atomically and avoid race conditions with the
existing atomic readers/updaters.

In `@src/plugins/fs/f2fs.c`:
- Around line 31-35: The current _fs_f2fs_reset_avail_deps function resets
shared flags with plain stores (avail_deps and avail_shrink_deps) which races
with atomic readers/writers in check_deps(); replace the plain assignments with
atomic stores by calling g_atomic_int_set(&avail_deps, 0) and
g_atomic_int_set(&avail_shrink_deps, 0) so the updates are atomic; apply the
same change pattern to the other helper functions named _fs_*_reset_avail_deps
(ext, xfs, vfat, ntfs, exfat, btrfs, udf, nilfs) to ensure all access to those
variables uses g_atomic_* consistently.

In `@src/plugins/lvm/lvm.c`:
- Around line 560-565: The code parses a PE offset into
data->segs[0]->pv_start_pe using atoi(), which is 32-bit and can truncate;
replace the atoi() call with g_ascii_strtoull() to parse a 64-bit value (use
g_ascii_strtoull(paren + 1, NULL, 10)) so the result matches the guint64
pv_start_pe type; keep the existing dev/paren logic
(g_strdup(json_array_get_string_element(...)) and the null-termination of
*paren) unchanged.
- Around line 1799-1817: The dedupe/merge of LV rows currently compares lv_name
which is only unique per VG; update both bd_lvm_lvs and bd_lvm_lvs_tree to use
lv_uuid (the existing UUID field) for duplicate detection/merge instead of
lv_name (replace comparisons and log messages to reference lv_uuid), and ensure
g_ptr_array_index handling uses the lv_uuid member of BDLVMLVdata; additionally
change pv_start_pe parsing (where atoi() is used) to use g_ascii_strtoull() and
proper endptr/base handling to populate the guint64 pv_start_pe safely; finally
add a regression test that queries lvs with identical LV names in different VGs
to confirm de-duplication is by UUID not name.

In `@src/plugins/smart/smartmontools.c`:
- Around line 40-43: The close hook _smart_close_plugin currently writes to
avail_deps with a plain assignment causing a data race; replace the direct write
with an atomic reset by calling g_atomic_int_set(&avail_deps, 0) so the state is
updated atomically and is consistent with other accesses (g_atomic_int_get,
g_atomic_int_or) used in check_deps() and related functions.

---

Outside diff comments:
In `@src/plugins/lvm/lvm-dbus.c`:
- Around line 198-220: bd_lvm_close calls g_dbus_connection_flush_sync and
g_dbus_connection_close_sync on bus without checking for NULL and then sets bus
= NULL which leaks the GObject; update bd_lvm_close to first check if (bus !=
NULL) before calling g_dbus_connection_flush_sync and
g_dbus_connection_close_sync, handle and clear GError as already done, and
replace the manual bus = NULL with g_clear_object(&bus) to properly unref and
NULL the DBus connection object; keep the rest of the cleanup (dm_log_* and
avail_* resets) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ee2b2e2c-1edc-4f1b-8655-4c689f35de94

📥 Commits

Reviewing files that changed from the base of the PR and between fbd0cee and 0c46a31.

📒 Files selected for processing (30)
  • configure.ac
  • scripts/boilerplate_generator.py
  • src/plugins/btrfs.c
  • src/plugins/dm.c
  • src/plugins/fs.c
  • src/plugins/fs/btrfs.c
  • src/plugins/fs/common.h
  • src/plugins/fs/exfat.c
  • src/plugins/fs/ext.c
  • src/plugins/fs/f2fs.c
  • src/plugins/fs/nilfs.c
  • src/plugins/fs/ntfs.c
  • src/plugins/fs/udf.c
  • src/plugins/fs/vfat.c
  • src/plugins/fs/xfs.c
  • src/plugins/lvm/Makefile.am
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/lvm/lvm-private.h
  • src/plugins/lvm/lvm.c
  • src/plugins/mdraid.c
  • src/plugins/mpath.c
  • src/plugins/nvdimm.c
  • src/plugins/s390.c
  • src/plugins/smart/libatasmart.c
  • src/plugins/smart/smart-common.c
  • src/plugins/smart/smart-private.h
  • src/plugins/smart/smartmontools.c
  • src/plugins/swap.c
  • tests/_lvm_cases.py
  • tests/library_test.py
💤 Files with no reviewable changes (1)
  • tests/library_test.py

@vojtechtrefny vojtechtrefny force-pushed the master_lvm-json branch 2 times, most recently from 46a84eb to 3bdaf7a Compare March 13, 2026 11:21
@vojtechtrefny
Copy link
Member Author

@coderabbitai reviewv

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

@vojtechtrefny Sure, I'll go ahead and review the changes in this PR!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/plugins/lvm/lvm.c (1)

1791-1798: ⚠️ Potential issue | 🔴 Critical

Use uuid for LV dedupe/merge.

Line 1792 and Line 1860 compare rows by lv_name. That is only unique within a VG, so bd_lvm_lvs(NULL) can drop one LV and bd_lvm_lvs_tree(NULL) can merge segments from different VGs when they reuse the same name. lv_uuid is already in the report and globally unique, so these comparisons should use uuid instead, with a regression test that creates identical LV names in two VGs.

🔧 Suggested fix
-                if (g_strcmp0 (((BDLVMLVdata *) g_ptr_array_index (lvs, j))->lv_name, lvdata->lv_name) == 0) {
+                if (g_strcmp0 (((BDLVMLVdata *) g_ptr_array_index (lvs, j))->uuid, lvdata->uuid) == 0) {
@@
-                if (g_strcmp0 (other->lv_name, lvdata->lv_name) == 0) {
+                if (g_strcmp0 (other->uuid, lvdata->uuid) == 0) {

Also applies to: 1858-1864

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/lvm/lvm.c` around lines 1791 - 1798, The dedup/merge logic is
comparing LV rows by lv_name which is only VG-unique; change those comparisons
to use the LV UUID field (lv_uuid) instead: locate the comparison in the loop
that inspects g_ptr_array_index(lvs, j) against lvdata (the block that logs
"Duplicate LV entry..." and sets duplicate/ calls bd_lvm_lvdata_free) and the
similar comparison later around the bd_lvm_lvs_tree handling (the other
comparison at ~1858-1864), and replace g_strcmp0(...->lv_name, lvdata->lv_name)
checks with comparisons against the uuid field (e.g., ->lv_uuid) so dedupe/merge
is done by globally-unique uuid; ensure you still free and mark duplicate
exactly as before and add/adjust a regression test that creates identical
lv_name in two VGs to verify behavior.
🧹 Nitpick comments (1)
scripts/boilerplate_generator.py (1)

201-201: Adding RTLD_NODELETE is the key change that necessitates all the avail_deps reset changes.

With RTLD_NODELETE, the plugin shared library remains mapped in memory even after dlclose() succeeds. This means static variables like avail_deps persist across plugin unload/reload cycles. The coordinated changes to reset these counters in each plugin's close function ensure fresh dependency checks on reload.

Consider adding a brief comment in the generated code explaining why RTLD_NODELETE is used:

-    ret += '    handle = dlopen(so_name, RTLD_LAZY | RTLD_NODELETE);\n'
+    ret += '    /* RTLD_NODELETE keeps the library loaded to preserve symbols; close_fn resets state */\n'
+    ret += '    handle = dlopen(so_name, RTLD_LAZY | RTLD_NODELETE);\n'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/boilerplate_generator.py` at line 201, The generated code now uses
RTLD_NODELETE when calling dlopen which causes plugin static state (e.g.,
avail_deps) to persist across dlclose/reload; update
scripts/boilerplate_generator.py so the string built around the dlopen call (the
line containing "handle = dlopen(so_name, RTLD_LAZY | RTLD_NODELETE);") includes
a brief inline comment explaining why RTLD_NODELETE is used and that static
variables persist across unloads and therefore plugins must reset avail_deps in
their close functions; place the comment immediately adjacent to that dlopen
line in the generated output so maintainers see the rationale.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/plugins/lvm/lvm.c`:
- Around line 1791-1798: The dedup/merge logic is comparing LV rows by lv_name
which is only VG-unique; change those comparisons to use the LV UUID field
(lv_uuid) instead: locate the comparison in the loop that inspects
g_ptr_array_index(lvs, j) against lvdata (the block that logs "Duplicate LV
entry..." and sets duplicate/ calls bd_lvm_lvdata_free) and the similar
comparison later around the bd_lvm_lvs_tree handling (the other comparison at
~1858-1864), and replace g_strcmp0(...->lv_name, lvdata->lv_name) checks with
comparisons against the uuid field (e.g., ->lv_uuid) so dedupe/merge is done by
globally-unique uuid; ensure you still free and mark duplicate exactly as before
and add/adjust a regression test that creates identical lv_name in two VGs to
verify behavior.

---

Nitpick comments:
In `@scripts/boilerplate_generator.py`:
- Line 201: The generated code now uses RTLD_NODELETE when calling dlopen which
causes plugin static state (e.g., avail_deps) to persist across dlclose/reload;
update scripts/boilerplate_generator.py so the string built around the dlopen
call (the line containing "handle = dlopen(so_name, RTLD_LAZY |
RTLD_NODELETE);") includes a brief inline comment explaining why RTLD_NODELETE
is used and that static variables persist across unloads and therefore plugins
must reset avail_deps in their close functions; place the comment immediately
adjacent to that dlopen line in the generated output so maintainers see the
rationale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a8dfde8-d6ea-4151-831b-d4d5736b6074

📥 Commits

Reviewing files that changed from the base of the PR and between 0c46a31 and 3bdaf7a.

📒 Files selected for processing (30)
  • configure.ac
  • scripts/boilerplate_generator.py
  • src/plugins/btrfs.c
  • src/plugins/dm.c
  • src/plugins/fs.c
  • src/plugins/fs/btrfs.c
  • src/plugins/fs/common.h
  • src/plugins/fs/exfat.c
  • src/plugins/fs/ext.c
  • src/plugins/fs/f2fs.c
  • src/plugins/fs/nilfs.c
  • src/plugins/fs/ntfs.c
  • src/plugins/fs/udf.c
  • src/plugins/fs/vfat.c
  • src/plugins/fs/xfs.c
  • src/plugins/lvm/Makefile.am
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/lvm/lvm-private.h
  • src/plugins/lvm/lvm.c
  • src/plugins/mdraid.c
  • src/plugins/mpath.c
  • src/plugins/nvdimm.c
  • src/plugins/s390.c
  • src/plugins/smart/libatasmart.c
  • src/plugins/smart/smart-common.c
  • src/plugins/smart/smart-private.h
  • src/plugins/smart/smartmontools.c
  • src/plugins/swap.c
  • tests/_lvm_cases.py
  • tests/library_test.py
💤 Files with no reviewable changes (1)
  • tests/library_test.py
🚧 Files skipped from review as they are similar to previous changes (16)
  • configure.ac
  • src/plugins/lvm/Makefile.am
  • src/plugins/mpath.c
  • src/plugins/fs/common.h
  • src/plugins/fs/btrfs.c
  • src/plugins/fs/f2fs.c
  • src/plugins/fs.c
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/fs/ntfs.c
  • src/plugins/lvm/lvm-private.h
  • src/plugins/fs/udf.c
  • src/plugins/btrfs.c
  • src/plugins/dm.c
  • src/plugins/fs/vfat.c
  • src/plugins/smart/smart-common.c
  • src/plugins/smart/libatasmart.c

Switch pvs, pvinfo, vgs, vginfo, lvs, lvinfo, lvs_tree and lvinfo_tree
functions to use --reportformat json_std for parsing LVM command output
instead of the text-based --nameprefixes format.

This also bumps the minimum required LVM version to 2.03.17 which is
the version that introduced the json_std report format.

Tests for pvinfo, vginfo, lvinfo and lvinfo_tree have been extended
to cover more fields and a new test_lvs_tree test case has been added.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vojtechtrefny vojtechtrefny marked this pull request as ready for review March 16, 2026 15:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/plugins/lvm/lvm.c (1)

1787-1794: ⚠️ Potential issue | 🔴 Critical

Deduplicate/merge LVs by UUID, not lv_name.

At Line 1790 and Line 1858, matching on lv_name can incorrectly collapse distinct LVs from different VGs when vg_name == NULL. This can silently drop or merge unrelated entries.

Suggested fix
-                if (g_strcmp0 (((BDLVMLVdata *) g_ptr_array_index (lvs, j))->lv_name, lvdata->lv_name) == 0) {
+                if (g_strcmp0 (((BDLVMLVdata *) g_ptr_array_index (lvs, j))->uuid, lvdata->uuid) == 0) {
                     bd_utils_log_format (BD_UTILS_LOG_DEBUG,
-                                         "Duplicate LV entry for '%s' found in lvs output",
-                                         lvdata->lv_name);
+                                         "Duplicate LV entry for UUID '%s' found in lvs output",
+                                         lvdata->uuid);
                     bd_lvm_lvdata_free (lvdata);
                     duplicate = TRUE;
                     break;
                 }
@@
-                if (g_strcmp0 (other->lv_name, lvdata->lv_name) == 0) {
+                if (g_strcmp0 (other->uuid, lvdata->uuid) == 0) {
                     merge_lv_data (other, lvdata);
                     bd_lvm_lvdata_free (lvdata);
                     merged = TRUE;
                     break;
                 }

Also applies to: 1856-1859

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/lvm/lvm.c` around lines 1787 - 1794, The duplicate-detection
currently compares lv_name (see comparisons using ((BDLVMLVdata *)
g_ptr_array_index (lvs, j))->lv_name and lvdata->lv_name) which can collapse
distinct LVs across VGs when vg_name is NULL; change the check to compare the LV
UUID field (e.g., lv_uuid or whichever UUID member exists on BDLVMLVdata)
instead of lv_name in both places (the loop at the shown block and the similar
comparison around lines 1856–1859), and ensure bd_lvm_lvdata_free is called only
when the UUIDs match to avoid dropping unrelated entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/plugins/lvm/lvm.c`:
- Around line 1787-1794: The duplicate-detection currently compares lv_name (see
comparisons using ((BDLVMLVdata *) g_ptr_array_index (lvs, j))->lv_name and
lvdata->lv_name) which can collapse distinct LVs across VGs when vg_name is
NULL; change the check to compare the LV UUID field (e.g., lv_uuid or whichever
UUID member exists on BDLVMLVdata) instead of lv_name in both places (the loop
at the shown block and the similar comparison around lines 1856–1859), and
ensure bd_lvm_lvdata_free is called only when the UUIDs match to avoid dropping
unrelated entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 692600b6-98e3-4c36-a5a7-b4dd04a63623

📥 Commits

Reviewing files that changed from the base of the PR and between 3bdaf7a and ed0303f.

📒 Files selected for processing (30)
  • configure.ac
  • scripts/boilerplate_generator.py
  • src/plugins/btrfs.c
  • src/plugins/dm.c
  • src/plugins/fs.c
  • src/plugins/fs/btrfs.c
  • src/plugins/fs/common.h
  • src/plugins/fs/exfat.c
  • src/plugins/fs/ext.c
  • src/plugins/fs/f2fs.c
  • src/plugins/fs/nilfs.c
  • src/plugins/fs/ntfs.c
  • src/plugins/fs/udf.c
  • src/plugins/fs/vfat.c
  • src/plugins/fs/xfs.c
  • src/plugins/lvm/Makefile.am
  • src/plugins/lvm/lvm-dbus.c
  • src/plugins/lvm/lvm-private.h
  • src/plugins/lvm/lvm.c
  • src/plugins/mdraid.c
  • src/plugins/mpath.c
  • src/plugins/nvdimm.c
  • src/plugins/s390.c
  • src/plugins/smart/libatasmart.c
  • src/plugins/smart/smart-common.c
  • src/plugins/smart/smart-private.h
  • src/plugins/smart/smartmontools.c
  • src/plugins/swap.c
  • tests/_lvm_cases.py
  • tests/library_test.py
💤 Files with no reviewable changes (1)
  • tests/library_test.py
🚧 Files skipped from review as they are similar to previous changes (17)
  • src/plugins/swap.c
  • src/plugins/fs/ext.c
  • src/plugins/s390.c
  • src/plugins/fs/btrfs.c
  • src/plugins/fs.c
  • src/plugins/fs/common.h
  • scripts/boilerplate_generator.py
  • src/plugins/nvdimm.c
  • src/plugins/fs/xfs.c
  • src/plugins/lvm/lvm-dbus.c
  • configure.ac
  • src/plugins/dm.c
  • src/plugins/smart/smart-common.c
  • src/plugins/lvm/lvm-private.h
  • src/plugins/smart/libatasmart.c
  • src/plugins/smart/smart-private.h
  • src/plugins/fs/nilfs.c

@vojtechtrefny
Copy link
Member Author

/packit test

@vojtechtrefny vojtechtrefny requested a review from tbzatek March 17, 2026 08:40
tbzatek
tbzatek previously approved these changes Mar 18, 2026
Copy link
Member

@tbzatek tbzatek left a comment

Choose a reason for hiding this comment

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

Quite heavy, but makes sense. The plugin unloading/deinitialization makes sense, though limiting and suboptimal, but given the requirements I don't have any better idea.

vojtechtrefny and others added 2 commits March 19, 2026 09:27
…close

Use RTLD_NODELETE flag with dlopen when loading plugins to prevent
shared libraries (like json-glib) from being unmapped on dlclose.
This avoids GType re-registration failures when a plugin is reloaded
via reinit, since GTypes are permanent but the static variables
guarding their registration would be lost if the library is unmapped.

As a consequence of RTLD_NODELETE keeping libraries mapped, static
variables caching dependency check results (avail_deps, avail_features,
etc.) now persist across plugin reload cycles. Reset these caches in
each plugin's close function so that dependency availability is
properly re-evaluated on the next load.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test_reload test recompiled the LVM plugin and verified that
reinit picked up the new code. This no longer works because plugins
are loaded with RTLD_NODELETE, which prevents the shared library
from being unmapped on dlclose -- dlopen of the same path returns
the already-loaded library. The test_force_plugin test already
covers reloading with a different .so name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vojtechtrefny vojtechtrefny merged commit ef1c698 into storaged-project:master Mar 19, 2026
44 of 48 checks passed
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.

lvm plugin could use --reportformat json

2 participants