lkml.org 
[lkml]   [2020]   [Aug]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 11/18] fsinfo: sample: Mount listing program [ver #21]
    From
    Date
    Implement a program to demonstrate mount listing using the new fsinfo()
    syscall. For example, to dump the tree from mount 21:

    # ./test-mntinfo -m 21
    MOUNT MOUNT ID CHANGE# AT P DEV TYPE
    -------------------------------- ---------- -------- -- - ----- --------
    21 21 0 e 4 0:14 sysfs
    \_ kernel/security 24 0 e 4 0:8 securityfs
    \_ fs/cgroup 28 4 2f 4 0:18 tmpfs
    | \_ unified 29 0 e 4 0:19 cgroup2
    | \_ systemd 30 0 e 4 0:1a cgroup
    | \_ blkio 34 0 e 4 0:1e cgroup
    | \_ net_cls,net_prio 35 0 e 4 0:1f cgroup
    | \_ perf_event 36 0 e 4 0:20 cgroup
    | \_ freezer 37 0 e 4 0:21 cgroup
    | \_ devices 38 0 e 4 0:22 cgroup
    | \_ cpu,cpuacct 39 0 e 4 0:23 cgroup
    | \_ rdma 40 0 e 4 0:24 cgroup
    | \_ memory 41 0 e 4 0:25 cgroup
    | \_ cpuset 42 0 e 4 0:26 cgroup
    | \_ hugetlb 43 0 e 4 0:27 cgroup
    \_ fs/pstore 31 0 e 4 0:1b pstore
    \_ firmware/efi/efivars 32 0 e 4 0:1c efivarfs
    \_ fs/bpf 33 0 e 4 0:1d bpf
    \_ kernel/config 92 0 0 4 0:28 configfs
    \_ fs/selinux 44 0 0 4 0:11 selinuxfs
    \_ kernel/debug 45 1 0 4 0:7 debugfs

    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    samples/vfs/Makefile | 6 +
    samples/vfs/test-mntinfo.c | 277 ++++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 282 insertions(+), 1 deletion(-)
    create mode 100644 samples/vfs/test-mntinfo.c

    diff --git a/samples/vfs/Makefile b/samples/vfs/Makefile
    index d63af5106fc2..7bcdd7a2829e 100644
    --- a/samples/vfs/Makefile
    +++ b/samples/vfs/Makefile
    @@ -1,5 +1,9 @@
    # SPDX-License-Identifier: GPL-2.0-only
    -userprogs := test-fsinfo test-fsmount test-statx
    +userprogs := \
    + test-fsinfo \
    + test-fsmount \
    + test-mntinfo \
    + test-statx
    always-y := $(userprogs)

    userccflags += -I usr/include
    diff --git a/samples/vfs/test-mntinfo.c b/samples/vfs/test-mntinfo.c
    new file mode 100644
    index 000000000000..a706b5e85997
    --- /dev/null
    +++ b/samples/vfs/test-mntinfo.c
    @@ -0,0 +1,277 @@
    +// SPDX-License-Identifier: GPL-2.0-or-later
    +/* Test the fsinfo() system call
    + *
    + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
    + * Written by David Howells (dhowells@redhat.com)
    + */
    +
    +#define _GNU_SOURCE
    +#define _ATFILE_SOURCE
    +#include <stdbool.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <stdint.h>
    +#include <string.h>
    +#include <unistd.h>
    +#include <ctype.h>
    +#include <errno.h>
    +#include <time.h>
    +#include <math.h>
    +#include <sys/syscall.h>
    +#include <linux/fsinfo.h>
    +#include <linux/socket.h>
    +#include <linux/fcntl.h>
    +#include <sys/stat.h>
    +#include <arpa/inet.h>
    +
    +#ifndef __NR_fsinfo
    +#define __NR_fsinfo -1
    +#endif
    +
    +static __attribute__((unused))
    +ssize_t fsinfo(int dfd, const char *filename,
    + struct fsinfo_params *params, size_t params_size,
    + void *result_buffer, size_t result_buf_size)
    +{
    + return syscall(__NR_fsinfo, dfd, filename,
    + params, params_size,
    + result_buffer, result_buf_size);
    +}
    +
    +static char tree_buf[4096];
    +static char bar_buf[4096];
    +static unsigned int children_list_interval;
    +
    +/*
    + * Get an fsinfo attribute in a statically allocated buffer.
    + */
    +static void get_attr(unsigned int mnt_id, unsigned int attr, unsigned int Nth,
    + void *buf, size_t buf_size)
    +{
    + struct fsinfo_params params = {
    + .flags = FSINFO_FLAGS_QUERY_MOUNT,
    + .request = attr,
    + .Nth = Nth,
    + };
    + char file[32];
    + long ret;
    +
    + sprintf(file, "%u", mnt_id);
    +
    + memset(buf, 0xbd, buf_size);
    +
    + ret = fsinfo(AT_FDCWD, file, &params, sizeof(params), buf, buf_size);
    + if (ret == -1) {
    + fprintf(stderr, "mount-%s: %m\n", file);
    + exit(1);
    + }
    +}
    +
    +/*
    + * Get an fsinfo attribute in a dynamically allocated buffer.
    + */
    +static void *get_attr_alloc(unsigned int mnt_id, unsigned int attr,
    + unsigned int Nth, size_t *_size)
    +{
    + struct fsinfo_params params = {
    + .flags = FSINFO_FLAGS_QUERY_MOUNT,
    + .request = attr,
    + .Nth = Nth,
    + };
    + size_t buf_size = 4096;
    + char file[32];
    + void *r;
    + long ret;
    +
    + sprintf(file, "%u", mnt_id);
    +
    + for (;;) {
    + r = malloc(buf_size);
    + if (!r) {
    + perror("malloc");
    + exit(1);
    + }
    + memset(r, 0xbd, buf_size);
    +
    + ret = fsinfo(AT_FDCWD, file, &params, sizeof(params), r, buf_size);
    + if (ret == -1) {
    + fprintf(stderr, "mount-%s: %x,%x,%x %m\n",
    + file, params.request, params.Nth, params.Mth);
    + exit(1);
    + }
    +
    + if (ret <= buf_size) {
    + *_size = ret;
    + break;
    + }
    + buf_size = (ret + 4096 - 1) & ~(4096 - 1);
    + }
    +
    + return r;
    +}
    +
    +/*
    + * Display a mount and then recurse through its children.
    + */
    +static void display_mount(unsigned int mnt_id, unsigned int depth, char *path)
    +{
    + struct fsinfo_mount_topology top;
    + struct fsinfo_mount_child child;
    + struct fsinfo_mount_info info;
    + struct fsinfo_ids ids;
    + void *children;
    + unsigned int d;
    + size_t ch_size, p_size;
    + char dev[64];
    + int i, n, s;
    +
    + get_attr(mnt_id, FSINFO_ATTR_MOUNT_TOPOLOGY, 0, &top, sizeof(top));
    + get_attr(mnt_id, FSINFO_ATTR_MOUNT_INFO, 0, &info, sizeof(info));
    + get_attr(mnt_id, FSINFO_ATTR_IDS, 0, &ids, sizeof(ids));
    + if (depth > 0)
    + printf("%s", tree_buf);
    +
    + s = strlen(path);
    + printf("%s", !s ? "\"\"" : path);
    + if (!s)
    + s += 2;
    + s += depth;
    + if (s < 38)
    + s = 38 - s;
    + else
    + s = 1;
    + printf("%*.*s", s, s, "");
    +
    + sprintf(dev, "%x:%x", ids.f_dev_major, ids.f_dev_minor);
    + printf("%10u %8llx %2x %x %5s %s",
    + info.mnt_id,
    + (info.mnt_attr_changes +
    + info.mnt_topology_changes +
    + info.mnt_subtree_notifications),
    + info.attr, top.propagation_type,
    + dev, ids.f_fs_name);
    + putchar('\n');
    +
    + children = get_attr_alloc(mnt_id, FSINFO_ATTR_MOUNT_CHILDREN, 0, &ch_size);
    + n = ch_size / children_list_interval - 1;
    +
    + bar_buf[depth + 1] = '|';
    + if (depth > 0) {
    + tree_buf[depth - 4 + 1] = bar_buf[depth - 4 + 1];
    + tree_buf[depth - 4 + 2] = ' ';
    + }
    +
    + tree_buf[depth + 0] = ' ';
    + tree_buf[depth + 1] = '\\';
    + tree_buf[depth + 2] = '_';
    + tree_buf[depth + 3] = ' ';
    + tree_buf[depth + 4] = 0;
    + d = depth + 4;
    +
    + memset(&child, 0, sizeof(child));
    + for (i = 0; i < n; i++) {
    + void *p = children + i * children_list_interval;
    +
    + if (sizeof(child) >= children_list_interval)
    + memcpy(&child, p, children_list_interval);
    + else
    + memcpy(&child, p, sizeof(child));
    +
    + if (i == n - 1)
    + bar_buf[depth + 1] = ' ';
    + path = get_attr_alloc(child.mnt_id, FSINFO_ATTR_MOUNT_POINT,
    + 0, &p_size);
    + display_mount(child.mnt_id, d, path + 1);
    + free(path);
    + }
    +
    + free(children);
    + if (depth > 0) {
    + tree_buf[depth - 4 + 1] = '\\';
    + tree_buf[depth - 4 + 2] = '_';
    + }
    + tree_buf[depth] = 0;
    +}
    +
    +/*
    + * Find the ID of whatever is at the nominated path.
    + */
    +static unsigned int lookup_mnt_by_path(const char *path)
    +{
    + struct fsinfo_mount_info mnt;
    + struct fsinfo_params params = {
    + .flags = FSINFO_FLAGS_QUERY_PATH,
    + .request = FSINFO_ATTR_MOUNT_INFO,
    + };
    +
    + if (fsinfo(AT_FDCWD, path, &params, sizeof(params), &mnt, sizeof(mnt)) == -1) {
    + perror(path);
    + exit(1);
    + }
    +
    + return mnt.mnt_id;
    +}
    +
    +/*
    + * Determine the element size for the mount child list.
    + */
    +static unsigned int query_list_element_size(int mnt_id, unsigned int attr)
    +{
    + struct fsinfo_attribute_info attr_info;
    +
    + get_attr(mnt_id, FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, attr,
    + &attr_info, sizeof(attr_info));
    + return attr_info.size;
    +}
    +
    +/*
    + *
    + */
    +int main(int argc, char **argv)
    +{
    + unsigned int mnt_id;
    + char *path;
    + bool use_mnt_id = false;
    + int opt;
    +
    + while ((opt = getopt(argc, argv, "m"))) {
    + switch (opt) {
    + case 'm':
    + use_mnt_id = true;
    + continue;
    + }
    + break;
    + }
    +
    + argc -= optind;
    + argv += optind;
    +
    + switch (argc) {
    + case 0:
    + mnt_id = lookup_mnt_by_path("/");
    + path = "ROOT";
    + break;
    + case 1:
    + path = argv[0];
    + if (use_mnt_id) {
    + mnt_id = strtoul(argv[0], NULL, 0);
    + break;
    + }
    +
    + mnt_id = lookup_mnt_by_path(argv[0]);
    + break;
    + default:
    + printf("Format: test-mntinfo\n");
    + printf("Format: test-mntinfo <path>\n");
    + printf("Format: test-mntinfo -m <mnt_id>\n");
    + exit(2);
    + }
    +
    + children_list_interval =
    + query_list_element_size(mnt_id, FSINFO_ATTR_MOUNT_CHILDREN);
    +
    + printf("MOUNT MOUNT ID CHANGE# AT P DEV TYPE\n");
    + printf("------------------------------------- ---------- -------- -- - ----- --------\n");
    + display_mount(mnt_id, 0, path);
    + return 0;
    +}

    \
     
     \ /
      Last update: 2020-08-03 15:38    [W:4.146 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site