On Sat, Sep 24, 2016 at 04:35:39PM -0700, Philip Guenther wrote: > On Sat, 24 Sep 2016, Sebastien Marie wrote: > ... > > 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'. > > The idea seems sound, but the placement of the member in the structure is > a problem: > > > --- 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]; > > That changes the layout of the structure, changing the ABI. If instead > the new member is placed at the end of structure then there's no ABI > break, as the API permits additions to the end of structure. > > Also, libkvm/kvm_file2.c should be updated to match the change to > kern_sysctl.c, so that the information is returned when debugging kernel > crash dumps.
I updated my diff: - adding the new member at end of kinfo_file : no more ABI change. - updating libkvm to match the change One remark about libkvm changes: msdos and ntfs doesn't track va_nlink in kernel (always set it to 1). So I keep the same behaviour in libkvm. Maybe it could be revised later (and update kernel and libkvm to track at least unlinking). For the other part (adding mmap references to files to KERN_FILE API), I need more time to understand the internals and make a diff. > > 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. > > Yeah, mmap's hold references to files, but the KERN_FILE API doesn't see > them. To get that you would need to walk the maps in the uvmspace and > pick out the non-anonymous mappings, skipping the base executable (which > _is_ already returned by KERN_FILE). Doing that without races in the > kernel would be tricky, as copyout() can sleep if there's a page fault. > Could you deadlock the kernel by asking for information about your own > mappings, with sysctl() writing to a mapping which would need to be > faulted in? > > Perhaps better to not hold a lock over copyout() but instead just track > the vaddr range that was being reported, and then restart the tree walk > from there. That guarantees progress with no locks held. > -- Sebastien Marie Index: lib/libkvm/kvm_cd9660.c =================================================================== RCS file: /cvs/src/lib/libkvm/kvm_cd9660.c,v retrieving revision 1.6 diff -u -p -r1.6 kvm_cd9660.c --- lib/libkvm/kvm_cd9660.c 16 Dec 2014 03:21:10 -0000 1.6 +++ lib/libkvm/kvm_cd9660.c 25 Sep 2016 15:50:08 -0000 @@ -50,6 +50,7 @@ _kvm_stat_cd9660(kvm_t *kd, struct kinfo kf->va_mode = inode.inode.iso_mode; kf->va_size = inode.i_size; kf->va_rdev = inode.i_dev; + kf->va_nlink = inode.inode.iso_links; return (0); } Index: lib/libkvm/kvm_file2.c =================================================================== RCS file: /cvs/src/lib/libkvm/kvm_file2.c,v retrieving revision 1.49 diff -u -p -r1.49 kvm_file2.c --- lib/libkvm/kvm_file2.c 4 May 2016 01:28:42 -0000 1.49 +++ lib/libkvm/kvm_file2.c 25 Sep 2016 15:50:08 -0000 @@ -798,6 +798,7 @@ ufs_filestat(kvm_t *kd, struct kinfo_fil kf->va_mode = inode.i_ffs1_mode; kf->va_size = inode.i_ffs1_size; kf->va_rdev = inode.i_ffs1_rdev; + kf->va_nlink = inode.i_ffs1_nlink; return (0); } @@ -826,6 +827,7 @@ ext2fs_filestat(kvm_t *kd, struct kinfo_ kf->va_mode = inode.i_e2fs_mode; kf->va_size = inode.i_e2fs_size; kf->va_rdev = 0; /* XXX */ + kf->va_nlink = inode.i_e2fs_nlink; return (0); } @@ -851,6 +853,7 @@ msdos_filestat(kvm_t *kd, struct kinfo_f kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type); kf->va_size = de.de_FileSize; kf->va_rdev = 0; /* msdosfs doesn't support device files */ + kf->va_nlink = 1; return (0); } @@ -870,6 +873,7 @@ nfs_filestat(kvm_t *kd, struct kinfo_fil kf->va_size = nfsnode.n_size; kf->va_rdev = nfsnode.n_vattr.va_rdev; kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type); + kf->va_nlink = nfsnode.n_vattr.va_nlink; return (0); } Index: lib/libkvm/kvm_ntfs.c =================================================================== RCS file: /cvs/src/lib/libkvm/kvm_ntfs.c,v retrieving revision 1.4 diff -u -p -r1.4 kvm_ntfs.c --- lib/libkvm/kvm_ntfs.c 16 Nov 2013 00:37:11 -0000 1.4 +++ lib/libkvm/kvm_ntfs.c 25 Sep 2016 15:50:08 -0000 @@ -78,6 +78,7 @@ _kvm_stat_ntfs(kvm_t *kd, struct kinfo_f kf->va_mode = (mode_t)ntm.ntm_mode | _kvm_getftype(vp->v_type); kf->va_size = fn.f_size; kf->va_rdev = 0; /* XXX */ + kf->va_nlink = 1; return (0); } Index: lib/libkvm/kvm_udf.c =================================================================== RCS file: /cvs/src/lib/libkvm/kvm_udf.c,v retrieving revision 1.9 diff -u -p -r1.9 kvm_udf.c --- lib/libkvm/kvm_udf.c 16 Dec 2014 03:21:10 -0000 1.9 +++ lib/libkvm/kvm_udf.c 25 Sep 2016 15:50:08 -0000 @@ -95,6 +95,7 @@ _kvm_stat_udf(kvm_t *kd, struct kinfo_fi kf->va_fileid = (long)up.u_ino; kf->va_mode = udf_permtomode(&up); /* XXX */ kf->va_rdev = 0; + kf->va_nlink = letoh16(fentry.link_cnt); if (vp->v_type & VDIR) { /* * Directories that are recorded within their ICB will show 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 25 Sep 2016 15:50:09 -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 25 Sep 2016 15:50:09 -0000 @@ -748,6 +748,8 @@ struct kinfo_file { uint64_t t_rcv_wnd; /* ULONG: tcp receive window */ uint64_t t_snd_wnd; /* ULONG: tcp send window */ uint64_t t_snd_cwnd; /* ULONG: congestion-controlled win */ + + uint32_t va_nlink; /* NLINK_T: number of references to file */ }; /* 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 25 Sep 2016 15:50:10 -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 25 Sep 2016 15:50:10 -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);