From 93169df13964f6579e26140e4dbd4d7bb642acfb Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 15 Aug 2024 11:08:52 +0200 Subject: [PATCH] libmount: add listmount() sample Signed-off-by: Karel Zak --- libmount/samples/Makemodule.am | 7 +- libmount/samples/listmount.c | 166 +++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 libmount/samples/listmount.c diff --git a/libmount/samples/Makemodule.am b/libmount/samples/Makemodule.am index dc9f641f4..39c3e8166 100644 --- a/libmount/samples/Makemodule.am +++ b/libmount/samples/Makemodule.am @@ -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 index 000000000..aeca96d58 --- /dev/null +++ b/libmount/samples/listmount.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2024 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include + +#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; +} -- 2.47.3