Hi,

I would like access to `va_nlink' information in struct vattr. The
purpose is to know when VTEXT node of a running process is "detached"
from filesystem (read: the running process isn't the same anymore than
the file on disk, maybe due to upgrade).

`va_nlink' is the number of references of the vnode. When it is zero, it
means, if I correctly understood, that underling file is dangle. The
file has been unlinked.

Currently, in order to access to this information from userland, I need
to copte with kvm, which is bad (from my perspective). I implemented it
for my personal use (https://github.com/semarie/checkrestart), but I
would prefer a better approch, and if it is available from base, it
would be wonderful.

The following diff adds a `va_nlink' member in `struct kinfo_file'. The
information become available though sysctl(3) via KERN_FILE interface,
as some others members of `struct vattr'.

In order to illustrate the use of the va_nlink information, I also makes
a diff for fstat(1): the inode number will be followed by `*' when it
is unlinked from disk.

For me, this information is highlty desirable as it could permit to
easily found processes that would need restart after packages upgrades
(rcctl restart ...).

Formally, for the final purpose, the information could be only partial:
a library dynamically linked isn't referenced via KERN_FILE interface (I
am unsure about the availability of the information). But as proper
packages will have their signature changed by any library crank, a
package update will make old program to be remplaced by a new one.


Here a concret example with fstat(1):

# get the inode of the file sndiod

$ ls -i /usr/bin/sndiod
2754462 /usr/bin/sndiod

# check the inode of the running sndiod process

$ fstat | grep 'sndio.*text'
_sndio   sndiod     56390 text /usr      2754462  -r-xr-xr-x   r    80160
_sndiop  sndiod     27240 text /usr      2754462  -r-xr-xr-x   r    80160

# recompile sndiod program, and install it: inode 2754462 will be
# removed, and a new file installed.

$ cd /usr/src/usr.bin/sndiod && make clean && make && doas make install
...

# get the new inode

$ ls -i /usr/bin/sndiod
2754467 /usr/bin/sndiod

# check that the running sndiod process is still the "old" one:
# the inode 2754462 is suffixed with `*'

$ fstat | grep 'sndio.*text'
_sndio   sndiod     56390 text /usr      2754462* -r-xr-xr-x   r    80160
_sndiop  sndiod     27240 text /usr      2754462* -r-xr-xr-x   r    80160

# restart sndiod, as the running copy isn't in sync with filesystem

$ doas rcctl restart sndiod
sndiod(ok)
sndiod(ok)

# check that now, the running process use the new inode.

$ fstat | grep 'sndio.*text'
_sndio   sndiod     79950 text /usr      2754467  -r-xr-xr-x   r    80160
_sndiop  sndiod      1725 text /usr      2754467  -r-xr-xr-x   r    80160


Does it make any interest ?

Thanks.
-- 
Sebastien Marie


Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.311
diff -u -p -r1.311 kern_sysctl.c
--- sys/kern/kern_sysctl.c      21 Sep 2016 14:06:50 -0000      1.311
+++ sys/kern/kern_sysctl.c      24 Sep 2016 11:26:24 -0000
@@ -1057,6 +1057,7 @@ fill_file(struct kinfo_file *kf, struct 
                        kf->va_size = va.va_size;
                        kf->va_rdev = va.va_rdev;
                        kf->va_fsid = va.va_fsid & 0xffffffff;
+                       kf->va_nlink = va.va_nlink;
                }
                break;
 
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvs/src/sys/sys/sysctl.h,v
retrieving revision 1.166
diff -u -p -r1.166 sysctl.h
--- sys/sys/sysctl.h    21 Sep 2016 14:06:50 -0000      1.166
+++ sys/sys/sysctl.h    24 Sep 2016 11:26:25 -0000
@@ -697,6 +697,7 @@ struct kinfo_file {
        uint64_t        va_size;        /* UINT64_T: file size in bytes */
        uint32_t        va_mode;        /* MODE_T: file access mode and type */
        uint32_t        va_fsid;        /* DEV_T: filesystem device */
+       uint32_t        va_nlink;       /* NLINK_T: number of references to 
file */
        char            f_mntonname[KI_MNAMELEN];
 
        /* socket information */
Index: usr.bin/fstat/fstat.1
===================================================================
RCS file: /cvs/src/usr.bin/fstat/fstat.1,v
retrieving revision 1.52
diff -u -p -r1.52 fstat.1
--- usr.bin/fstat/fstat.1       25 Apr 2016 19:18:41 -0000      1.52
+++ usr.bin/fstat/fstat.1       24 Sep 2016 11:26:25 -0000
@@ -146,6 +146,9 @@ flag is specified, this header is presen
 major/minor number of the device that this file resides in.
 .It Li INUM
 The inode number of the file.
+It will be followed by an asterisk
+.Pq Ql *
+if the inode is unlinked from disk.
 .It Li MODE
 The mode of the file.
 If the
Index: usr.bin/fstat/fstat.c
===================================================================
RCS file: /cvs/src/usr.bin/fstat/fstat.c,v
retrieving revision 1.88
diff -u -p -r1.88 fstat.c
--- usr.bin/fstat/fstat.c       4 May 2016 19:48:08 -0000       1.88
+++ usr.bin/fstat/fstat.c       24 Sep 2016 11:26:27 -0000
@@ -441,7 +441,9 @@ vtrans(struct kinfo_file *kf)
                (void)snprintf(mode, sizeof(mode), "%o", kf->va_mode);
        else
                strmode(kf->va_mode, mode);
-       printf(" %8llu %11s", kf->va_fileid, mode);
+       printf(" %8llu%s %11s", kf->va_fileid,
+           kf->va_nlink == 0 ? "*" : " ",
+           mode);
        rw[0] = '\0';
        if (kf->f_flag & FREAD)
                strlcat(rw, "r", sizeof rw);

Reply via email to