]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: fill NAME column of inotify files with the information about their monitoring...
authorMasatake YAMATO <yamato@redhat.com>
Fri, 9 Jun 2023 05:55:05 +0000 (14:55 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Tue, 13 Jun 2023 10:18:35 +0000 (19:18 +0900)
    # ./lsfd  -p 1  -Q '(TYPE == "inotify") and (FD > 7)'
    COMMAND PID USER ASSOC MODE    TYPE       SOURCE MNTID INODE NAME
    systemd   1 root    11  r-- inotify anon_inodefs    15  1060 inodes=116@dm-0
    systemd   1 root    13  r-- inotify anon_inodefs    15  1060 inodes=299@tmpfs
    systemd   1 root    19  r-- inotify anon_inodefs    15  1060 inodes=41@tmpfs,2@tmpfs,1@tmpfs,96@dm-0
    systemd   1 root    21  r-- inotify anon_inodefs    15  1060 inodes=41@tmpfs,2@tmpfs,1@tmpfs,96@dm-0

In addition, INOTIFY.INODES and INOTIFY.INODES.RAW column are added.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
misc-utils/lsfd-unkn.c
misc-utils/lsfd.1.adoc
misc-utils/lsfd.c
misc-utils/lsfd.h

index 8b8320bb185d6f103d38dfc38b36ea7952715ca6..0045a6a47209e2aa4f1bc71eecfa38bf6f2a8c8c 100644 (file)
@@ -809,6 +809,148 @@ static const struct anon_ops anon_signalfd_ops = {
        .handle_fdinfo = anon_signalfd_handle_fdinfo,
 };
 
+/*
+ * inotify
+ */
+struct anon_inotify_data {
+       struct list_head inodes;
+};
+
+struct anon_inotify_inode {
+       ino_t ino;
+       dev_t sdev;
+       struct list_head inodes;
+};
+
+static bool anon_inotify_probe(const char *str)
+{
+       return strncmp(str, "inotify", 7) == 0;
+}
+
+/* A device number appeared in fdinfo of an inotify file uses the kernel
+ * internal representation. It is different from what we are familiar with;
+ * major(3) and minor(3) don't work with the representation.
+ * See linux/include/linux/kdev_t.h. */
+#define ANON_INOTIFY_MINORBITS 20
+#define ANON_INOTIFY_MINORMASK ((1U << ANON_INOTIFY_MINORBITS) - 1)
+
+#define ANON_INOTIFY_MAJOR(dev)        ((unsigned int) ((dev) >> ANON_INOTIFY_MINORBITS))
+#define ANON_INOTIFY_MINOR(dev)        ((unsigned int) ((dev) &  ANON_INOTIFY_MINORMASK))
+
+static char *anon_inotify_make_inodes_string(const char *prefix,
+                                            enum decode_source_level decode_level,
+                                            struct anon_inotify_data *data)
+{
+       char *str = NULL;
+       char buf[BUFSIZ] = {'\0'};
+       bool first_element = true;
+
+       struct list_head *i;
+       list_for_each(i, &data->inodes) {
+               char source[BUFSIZ/2] = {'\0'};
+               struct anon_inotify_inode *inode = list_entry(i,
+                                                             struct anon_inotify_inode,
+                                                             inodes);
+
+               decode_source(source, sizeof(source),
+                             ANON_INOTIFY_MAJOR(inode->sdev), ANON_INOTIFY_MINOR(inode->sdev),
+                             decode_level);
+               snprintf(buf, sizeof(buf), "%s%llu@%s", first_element? prefix: ",",
+                        (unsigned long long)inode->ino, source);
+               first_element = false;
+
+               xstrappend(&str, buf);
+       }
+
+       return str;
+}
+
+static char *anon_inotify_get_name(struct unkn *unkn)
+{
+       return anon_inotify_make_inodes_string("inodes=", DECODE_SOURCE_FULL,
+                                              (struct anon_inotify_data *)unkn->anon_data);
+}
+
+static void anon_inotify_init(struct unkn *unkn)
+{
+       struct anon_inotify_data *data = xcalloc(1, sizeof(struct anon_inotify_data));
+       INIT_LIST_HEAD (&data->inodes);
+       unkn->anon_data = data;
+}
+
+static void anon_inotify_free(struct unkn *unkn)
+{
+       struct anon_inotify_data *data = unkn->anon_data;
+
+       list_free(&data->inodes, struct anon_inotify_inode, inodes,
+                 free);
+       free(data);
+}
+
+static void add_inode(struct anon_inotify_data *data, ino_t ino, dev_t sdev)
+{
+       struct anon_inotify_inode *inode = xmalloc(sizeof(*inode));
+
+       INIT_LIST_HEAD (&inode->inodes);
+       inode->ino = ino;
+       inode->sdev = sdev;
+
+       list_add_tail(&inode->inodes, &data->inodes);
+}
+
+static int anon_inotify_handle_fdinfo(struct unkn *unkn, const char *key, const char *value)
+{
+       struct anon_inotify_data *data = (struct anon_inotify_data *)unkn->anon_data;
+
+       if (strcmp(key, "inotify wd") == 0) {
+               unsigned long long ino;
+               unsigned long long sdev;
+
+               if (sscanf(value, "%*d ino:%llx sdev:%llx %*s", &ino, &sdev) == 2) {
+                       add_inode(data, (ino_t)ino, (dev_t)sdev);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static bool anon_inotify_fill_column(struct proc *proc  __attribute__((__unused__)),
+                                    struct unkn *unkn,
+                                    struct libscols_line *ln __attribute__((__unused__)),
+                                    int column_id,
+                                    size_t column_index __attribute__((__unused__)),
+                                    char **str)
+{
+       struct anon_inotify_data *data = (struct anon_inotify_data *)unkn->anon_data;
+
+       switch(column_id) {
+       case COL_INOTIFY_INODES:
+               *str = anon_inotify_make_inodes_string("", DECODE_SOURCE_FULL,
+                                                      data);
+               if (*str)
+                       return true;
+               break;
+       case COL_INOTIFY_INODES_RAW:
+               *str = anon_inotify_make_inodes_string("", DECODE_SOURCE_MAJMIN,
+                                                      data);
+               if (*str)
+                       return true;
+               break;
+       }
+
+       return false;
+}
+
+static const struct anon_ops anon_inotify_ops = {
+       .class = "inotify",
+       .probe = anon_inotify_probe,
+       .get_name = anon_inotify_get_name,
+       .fill_column = anon_inotify_fill_column,
+       .init = anon_inotify_init,
+       .free = anon_inotify_free,
+       .handle_fdinfo = anon_inotify_handle_fdinfo,
+};
+
 /*
  * generic (fallback implementation)
  */
@@ -827,6 +969,7 @@ static const struct anon_ops *anon_ops[] = {
        &anon_eventpoll_ops,
        &anon_timerfd_ops,
        &anon_signalfd_ops,
+       &anon_inotify_ops,
 };
 
 static const struct anon_ops *anon_probe(const char *str)
index 1317741925fc4df215d9f81eecbdc1d713e4f18a..c26d2a7da71b1056cec2a25bd8134a31da876585 100644 (file)
@@ -194,6 +194,15 @@ Remote IP6 address.
 INODE <``number``>::
 Inode number.
 
+INOTIFY.INODES <``string``>::
+Cooked version of INOTIFY.INODES.RAW.
+The format of the element is
+_inode-number_,_source-of-inode_.
+
+INOTIFY.INODES.RAW <``string``>::
+List of monitoring inodes. The format of the element
+is _inode-number_,_device-major_:_device-minor_.
+
 KNAME <``string``>::
 //
 // It seems that the manpage backend of asciidoctor has limitations
@@ -235,6 +244,9 @@ tfds=_EVENTPOLL.TFDS_
 eventfd:::
 id=_EVENTFD.ID_
 +
+inotify:::
+iodes=_INOTIFY.INODES_
++
 NETLINK:::
 protocol=_NETLINK.PROTOCOL_[ lport=_NETLINK.LPORT_[ group=_NETLINK.GROUPS_]]
 +
index 590787bf43f06ce0d764d98f187077cb04e32db1..15280407c5661ffaf169411763301214b5773225 100644 (file)
@@ -177,6 +177,12 @@ static const struct colinfo infos[] = {
        [COL_INODE]            = { "INODE",
                                   0,   SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER,
                                   N_("inode number") },
+       [COL_INOTIFY_INODES]   = { "INOTIFY.INODES",
+                                  0,   SCOLS_FL_WRAP,  SCOLS_JSON_STRING,
+                                  N_("list of monitoring inodes (cooked)") },
+       [COL_INOTIFY_INODES_RAW]={ "INOTIFY.INODES.RAW",
+                                  0,   SCOLS_FL_WRAP,  SCOLS_JSON_STRING,
+                                  N_("list of monitoring inodes (raw, don't decode devices)") },
        [COL_KNAME]            = { "KNAME",
                                   0.4, SCOLS_FL_TRUNC, SCOLS_JSON_STRING,
                                   N_("name of the file (raw)") },
index f300c0cc223b9d32d2d2b3c3d281dd2dd4a98182..1b86b625b3c3b48a25d84d47eca7cdb9e3d2d30a 100644 (file)
@@ -56,6 +56,8 @@ enum {
        COL_INET6_LADDR,
        COL_INET6_RADDR,
        COL_INODE,
+       COL_INOTIFY_INODES,
+       COL_INOTIFY_INODES_RAW,
        COL_KNAME,
        COL_KTHREAD,
        COL_MAJMIN,