]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add listmount() sample
authorKarel Zak <kzak@redhat.com>
Thu, 15 Aug 2024 09:08:52 +0000 (11:08 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 8 Jan 2025 12:57:42 +0000 (13:57 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/samples/Makemodule.am
libmount/samples/listmount.c [new file with mode: 0644]

index dc9f641f4e1d480114782627d60e4ee41a578b27..39c3e81669d07fa5fe6ea6265568246ecf809044 100644 (file)
@@ -2,7 +2,8 @@
 if LINUX
 check_PROGRAMS += \
        sample-mount-overwrite \
-       sample-mount-statmount
+       sample-mount-statmount \
+       sample-mount-listmount
 endif
 
 sample_mount_overwrite_SOURCES = libmount/samples/overwrite.c
@@ -12,3 +13,7 @@ sample_mount_overwrite_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
 sample_mount_statmount_SOURCES = libmount/samples/statmount.c
 sample_mount_statmount_LDADD =  libmount.la $(LDADD) libcommon.la
 sample_mount_statmount_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
+
+sample_mount_listmount_SOURCES = libmount/samples/listmount.c
+sample_mount_listmount_LDADD =  libmount.la $(LDADD) libcommon.la
+sample_mount_listmount_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
diff --git a/libmount/samples/listmount.c b/libmount/samples/listmount.c
new file mode 100644 (file)
index 0000000..aeca96d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdlib.h>
+
+#include "c.h"
+#include "strutils.h"
+#include "timeutils.h"
+#include "pathnames.h"
+
+#include "libmount.h"
+
+#include "mount-api-utils.h"   /* fallback for old linux/mount.h */
+
+static void __iter_table(      struct libmnt_table *tb,
+                       struct libmnt_iter *itr, int output, int reverse)
+{
+       struct libmnt_fs *fs = NULL;
+       int rc;
+
+       mnt_reset_iter(itr, reverse ? MNT_ITER_BACKWARD : MNT_ITER_FORWARD);
+       while ((rc = mnt_table_next_fs(tb, itr, &fs)) == 0) {
+               const char *tgt = mnt_fs_get_target(fs);
+               const char *type = mnt_fs_get_fstype(fs);
+
+               if (output)
+                       printf (" %15s %s\n", type, tgt);
+       }
+       if (rc < 0)
+               warn("cannot iterate on filesystems");
+}
+
+#define fetch_data(t, i)               __iter_table(t, i, 0, 0)
+#define print_table(t, i)              __iter_table(t, i, 1, 0)
+#define print_table_reverse(t, i)      __iter_table(t, i, 1, 1)
+
+
+int main(int argc, char *argv[])
+{
+       struct libmnt_table *tb;
+       struct libmnt_statmnt *sm;
+       struct libmnt_iter *itr;
+       struct timeval start, end;
+       uint64_t id = 0;
+       double sec_lsmnt, sec_lsstmnt, sec_mountinfo;
+
+       mnt_init_debug(0);
+
+
+       if (argc == 2) {
+               const char *arg = argv[1];
+               if (!isdigit_string(arg))
+                       mnt_id_from_path(arg, &id, NULL);
+               else
+                       id = strtou64_or_err(arg, "cannot ID");
+       }
+
+       itr = mnt_new_iter(MNT_ITER_FORWARD);
+       if (!itr)
+               err(MNT_EX_SYSERR, "failed to initialize libmount iterator");
+
+       tb = mnt_new_table();
+       if (!tb)
+               err(EXIT_FAILURE, "failed to allocate table handler");
+       if (id)
+               mnt_table_listmount_set_id(tb, id);
+
+       /*
+        * A) listmount() and statmount() based table
+        */
+       sm = mnt_new_statmnt();
+       if (!sm)
+               err(EXIT_FAILURE, "failed to allocate statmnt handler");
+
+       /* Without this mask setting, the library will make two statmount() calls
+        * for each node. */
+       mnt_statmnt_set_mask(sm, STATMOUNT_MNT_POINT | STATMOUNT_FS_TYPE);
+
+       /* force fetch all data
+       mnt_statmnt_set_mask(sm,
+                       STATMOUNT_SB_BASIC |
+                       STATMOUNT_MNT_BASIC |
+                       STATMOUNT_PROPAGATE_FROM |
+                       STATMOUNT_MNT_ROOT |
+                       STATMOUNT_MNT_POINT |
+                       STATMOUNT_FS_TYPE
+                       STATMOUNT_MNT_OPTS);
+       */
+
+       /* enable don-demand statmount() call for all filesystems in the table */
+       mnt_table_refer_statmnt(tb, sm);
+
+       /* listmount() only */
+       gettimeofday(&start, NULL);
+       if (mnt_table_fetch_listmount(tb) != 0)
+               warn("failed to read mount table by listmount()");
+       gettimeofday(&end, NULL);
+       sec_lsmnt = time_diff(&end, &start);
+
+       /* force statmount() for all nodes */
+       fetch_data(tb, itr);
+       gettimeofday(&end, NULL);
+       sec_lsstmnt = time_diff(&end, &start);
+
+       fprintf(stdout, "listmount() based table:\n");
+       print_table(tb, itr);
+
+
+       /* disable statmount() and listmount(); reset table */
+       mnt_statmnt_disable_fetching(sm, 1);
+       mnt_table_enable_listmount(tb, 0);
+       mnt_reset_table(tb);
+
+       /*
+        * B) /proc/self/mountinfo based table
+        */
+       gettimeofday(&start, NULL);
+       mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO);
+       gettimeofday(&end, NULL);
+       sec_mountinfo = time_diff(&end, &start);
+
+       fprintf(stdout, "\nprocfs based table:\n");
+       print_table(tb, itr);
+
+       fprintf(stdout, "\n"
+                       "%f sec listmount()\n"
+                       "%f sec listmount()+statmount()\n"
+                       "%f sec /proc/sef/mountinfo"
+                       "\n\n",
+                       sec_lsmnt, sec_lsstmnt, sec_mountinfo);
+
+
+       mnt_reset_table(tb);
+
+       /*
+        * C) Instead of reading the entire mount table with one listmount() call, read
+        * it in smaller steps. This is particularly useful for systems with large
+        * mount tables, where we may only need to access one specific node (usually the
+        * last one).
+        *
+        * By default, libmount reads 512 nodes in one call. To test this sample
+        * on normal systems, we will reduce this number to 5 nodes. The listmount()
+        * function is used as a backend for regular mnt_table_next_fs().
+        * There is no need to make any changes to the application, just enable
+        * on-demand listmount() by using mnt_table_enable_listmount().
+        */
+       if (mnt_table_listmount_set_stepsiz(tb, 5) != 0)
+               warn("failed to initialize listmount()");
+       mnt_table_enable_listmount(tb, 1);
+
+       /* enable also statmount() */
+       mnt_statmnt_disable_fetching(sm, 0);
+
+       fprintf(stdout, "\nlistmount() - small steps (reverse):\n");
+       print_table_reverse(tb, itr);
+
+
+       mnt_unref_table(tb);
+       mnt_unref_statmnt(sm);
+       mnt_free_iter(itr);
+
+       return EXIT_SUCCESS;
+}