From 5763e58d9a27565c87a1ccd647854ad022f46ce4 Mon Sep 17 00:00:00 2001 From: jhb Date: Mon, 24 Jun 2013 16:04:59 +0000 Subject: [PATCH] MFC 250223,250233: Similar to 233760 and 236717, export some more useful info about the kernel-based POSIX semaphore descriptors to userland via procstat(1) and fstat(1): - Change sem file descriptors to track the pathname they are associated with and add a ksem_info() method to copy the path out to a caller-supplied buffer. - Use the fo_stat() method of shared memory objects and ksem_info() to export the path, mode, and value of a semaphore via struct kinfo_file. - Add a struct semstat to the libprocstat(3) interface along with a procstat_get_sem_info() to export the mode and value of a semaphore. - Teach fstat about semaphores and to display their path, mode, and value. git-svn-id: svn://svn.freebsd.org/base/stable/9@252163 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/libprocstat.3 | 16 ++++++- lib/libprocstat/libprocstat.c | 90 +++++++++++++++++++++++++++++++++++ lib/libprocstat/libprocstat.h | 6 +++ sys/kern/kern_descrip.c | 31 ++++++++++++ sys/kern/uipc_sem.c | 19 +++++++- sys/sys/ksem.h | 8 +++- sys/sys/user.h | 4 ++ usr.bin/fstat/fstat.1 | 2 + usr.bin/fstat/fstat.c | 29 +++++++++++ 10 files changed, 202 insertions(+), 4 deletions(-) diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 085720cf4..1495bfc28 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -22,6 +22,7 @@ FBSD_1.3 { procstat_freegroups; procstat_freekstack; procstat_freevmmap; + procstat_get_sem_info; procstat_get_shm_info; procstat_getargv; procstat_getauxv; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 3312427a0..b472900dd 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 20, 2013 +.Dd May 3, 2013 .Dt LIBPROCSTAT 3 .Os .Sh NAME @@ -53,6 +53,7 @@ .Nm procstat_freevmmap , .Nm procstat_get_pipe_info , .Nm procstat_get_pts_info , +.Nm procstat_get_sem_info , .Nm procstat_get_shm_info , .Nm procstat_get_socket_info , .Nm procstat_get_vnode_info @@ -115,6 +116,13 @@ .Fa "char *errbuf" .Fc .Ft int +.Fo procstat_get_sem_info +.Fa "struct procstat *procstat" +.Fa "struct filestat *fst" +.Fa "struct semstat *sem" +.Fa "char *errbuf" +.Fc +.Ft int .Fo procstat_get_shm_info .Fa "struct procstat *procstat" .Fa "struct filestat *fst" @@ -463,12 +471,13 @@ function call. The .Fn procstat_get_pipe_info , .Fn procstat_get_pts_info , +.Fn procstat_get_sem_info , .Fn procstat_get_shm_info , .Fn procstat_get_socket_info and .Fn procstat_get_vnode_info functions are used to retrieve information about pipes, pseudo-terminals, -shared memory objects, +semaphores, shared memory objects, sockets, and vnodes, respectively. Each of them have a similar interface API. The @@ -505,6 +514,8 @@ argument indicates an actual error message in case of failure. .Nm procstat_get_pipe_info .It Li PS_FST_TYPE_PTS .Nm procstat_get_pts_info +.It Li PS_FST_TYPE_SEM +.Nm procstat_get_sem_info .It Li PS_FST_TYPE_SHM .Nm procstat_get_shm_info .El @@ -517,6 +528,7 @@ argument indicates an actual error message in case of failure. .Xr elf 3 , .Xr kvm 3 , .Xr queue 3 , +.Xr sem_open 3 , .Xr sysctl 3 , .Xr pts 4 , .Xr core 5 , diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index d4bb12e23..8c91f33a4 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #define _WANT_FILE #include #include +#include #include #define _KERNEL #include @@ -129,6 +130,10 @@ static int procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, char *errbuf); static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, struct ptsstat *pts, char *errbuf); +static int procstat_get_sem_info_sysctl(struct filestat *fst, + struct semstat *sem, char *errbuf); +static int procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, + struct semstat *sem, char *errbuf); static int procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, char *errbuf); static int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, @@ -560,6 +565,10 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap data = file.f_data; break; #endif + case DTYPE_SEM: + type = PS_FST_TYPE_SEM; + data = file.f_data; + break; case DTYPE_SHM: type = PS_FST_TYPE_SHM; data = file.f_data; @@ -1007,6 +1016,87 @@ procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, return (0); } +int +procstat_get_sem_info(struct procstat *procstat, struct filestat *fst, + struct semstat *sem, char *errbuf) +{ + + assert(sem); + if (procstat->type == PROCSTAT_KVM) { + return (procstat_get_sem_info_kvm(procstat->kd, fst, sem, + errbuf)); + } else if (procstat->type == PROCSTAT_SYSCTL || + procstat->type == PROCSTAT_CORE) { + return (procstat_get_sem_info_sysctl(fst, sem, errbuf)); + } else { + warnx("unknown access method: %d", procstat->type); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (1); + } +} + +static int +procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, + struct semstat *sem, char *errbuf) +{ + struct ksem ksem; + void *ksemp; + char *path; + int i; + + assert(kd); + assert(sem); + assert(fst); + bzero(sem, sizeof(*sem)); + ksemp = fst->fs_typedep; + if (ksemp == NULL) + goto fail; + if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem, + sizeof(struct ksem))) { + warnx("can't read ksem at %p", (void *)ksemp); + goto fail; + } + sem->mode = S_IFREG | ksem.ks_mode; + sem->value = ksem.ks_value; + if (fst->fs_path == NULL && ksem.ks_path != NULL) { + path = malloc(MAXPATHLEN); + for (i = 0; i < MAXPATHLEN - 1; i++) { + if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i, + path + i, 1)) + break; + if (path[i] == '\0') + break; + } + path[i] = '\0'; + if (i == 0) + free(path); + else + fst->fs_path = path; + } + return (0); + +fail: + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (1); +} + +static int +procstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem, + char *errbuf __unused) +{ + struct kinfo_file *kif; + + assert(sem); + assert(fst); + bzero(sem, sizeof(*sem)); + kif = fst->fs_typedep; + if (kif == NULL) + return (0); + sem->value = kif->kf_un.kf_sem.kf_sem_value; + sem->mode = kif->kf_un.kf_sem.kf_sem_mode; + return (0); +} + int procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, struct shmstat *shm, char *errbuf) diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 6688cea77..028846c79 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -134,6 +134,10 @@ struct pipestat { uint64_t addr; uint64_t peer; }; +struct semstat { + uint32_t value; + uint16_t mode; +}; struct shmstat { uint64_t size; uint16_t mode; @@ -178,6 +182,8 @@ int procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, struct pipestat *pipe, char *errbuf); int procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, struct ptsstat *pts, char *errbuf); +int procstat_get_sem_info(struct procstat *procstat, struct filestat *fst, + struct semstat *sem, char *errbuf); int procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, struct shmstat *shm, char *errbuf); int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 6a8c88711..bb4cab6c8 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ MALLOC_DECLARE(M_FADVISE); static uma_zone_t file_zone; +void (*ksem_info)(struct ksem *ks, char *path, size_t size, uint32_t *value); /* Flags for do_dup() */ #define DUP_FIXED 0x1 /* Force fixed allocation */ @@ -129,6 +131,7 @@ static int fill_pts_info(struct tty *tp, struct kinfo_file *kif); static int fill_pipe_info(struct pipe *pi, struct kinfo_file *kif); static int fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif); +static int fill_sem_info(struct file *fp, struct kinfo_file *kif); static int fill_shm_info(struct file *fp, struct kinfo_file *kif); /* @@ -3008,6 +3011,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct shmfd *shmfd; struct socket *so; struct vnode *vp; + struct ksem *ks; struct file *fp; struct proc *p; struct tty *tp; @@ -3037,6 +3041,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) continue; bzero(kif, sizeof(*kif)); kif->kf_structsize = sizeof(*kif); + ks = NULL; vp = NULL; so = NULL; tp = NULL; @@ -3097,6 +3102,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) case DTYPE_SEM: kif->kf_type = KF_TYPE_SEM; + ks = fp->f_data; break; case DTYPE_PTS: @@ -3208,6 +3214,8 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) } if (shmfd != NULL) shm_path(shmfd, kif->kf_path, sizeof(kif->kf_path)); + if (ks != NULL && ksem_info != NULL) + ksem_info(ks, kif->kf_path, sizeof(kif->kf_path), NULL); error = SYSCTL_OUT(req, kif, sizeof(*kif)); if (error) break; @@ -3280,6 +3288,9 @@ export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt, case KF_TYPE_PROCDESC: error = fill_procdesc_info((struct procdesc *)data, kif); break; + case KF_TYPE_SEM: + error = fill_sem_info((struct file *)data, kif); + break; case KF_TYPE_SHM: error = fill_shm_info((struct file *)data, kif); break; @@ -3463,6 +3474,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) case DTYPE_SEM: type = KF_TYPE_SEM; + data = fp; break; case DTYPE_PTS: @@ -3698,6 +3710,25 @@ fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif) return (0); } +static int +fill_sem_info(struct file *fp, struct kinfo_file *kif) +{ + struct thread *td; + struct stat sb; + + td = curthread; + if (fp->f_data == NULL) + return (1); + if (fo_stat(fp, &sb, td->td_ucred, td) != 0) + return (1); + if (ksem_info == NULL) + return (1); + ksem_info(fp->f_data, kif->kf_path, sizeof(kif->kf_path), + &kif->kf_un.kf_sem.kf_sem_value); + kif->kf_un.kf_sem.kf_sem_mode = sb.st_mode; + return (0); +} + static int fill_shm_info(struct file *fp, struct kinfo_file *kif) { diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 509f32e90..a9f60f1e5 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -71,7 +71,6 @@ FEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support"); * TODO * * - Resource limits? - * - Update fstat(1) * - Replace global sem_lock with mtx_pool locks? * - Add a MAC check_create() hook for creating new named semaphores. */ @@ -407,6 +406,7 @@ ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks) map->km_path = path; map->km_fnv = fnv; map->km_ksem = ksem_hold(ks); + ks->ks_path = path; LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link); } @@ -428,6 +428,7 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred) error = ksem_access(map->km_ksem, ucred); if (error) return (error); + map->km_ksem->ks_path = NULL; LIST_REMOVE(map, km_link); ksem_drop(map->km_ksem); free(map->km_path, M_KSEM); @@ -439,6 +440,20 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred) return (ENOENT); } +static void +ksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value) +{ + + if (ks->ks_path == NULL) + return; + sx_slock(&ksem_dict_lock); + if (ks->ks_path != NULL) + strlcpy(path, ks->ks_path, size); + if (value != NULL) + *value = ks->ks_value; + sx_sunlock(&ksem_dict_lock); +} + static int ksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd, int compat32) @@ -1014,6 +1029,7 @@ ksem_module_init(void) p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L); p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX); p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX); + ksem_info = ksem_info_impl; error = syscall_helper_register(ksem_syscalls); if (error) @@ -1035,6 +1051,7 @@ ksem_module_destroy(void) #endif syscall_helper_unregister(ksem_syscalls); + ksem_info = NULL; p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0); hashdestroy(ksem_dictionary, M_KSEM, ksem_hash); sx_destroy(&ksem_dict_lock); diff --git a/sys/sys/ksem.h b/sys/sys/ksem.h index da868fad1..c11c8656b 100644 --- a/sys/sys/ksem.h +++ b/sys/sys/ksem.h @@ -29,7 +29,7 @@ #ifndef _POSIX4_KSEM_H_ #define _POSIX4_KSEM_H_ -#ifndef _KERNEL +#if !defined(_KERNEL) && !defined(_WANT_FILE) #error "no user-servicable parts inside" #endif @@ -57,9 +57,15 @@ struct ksem { struct timespec ks_birthtime; struct label *ks_label; /* MAC label */ + const char *ks_path; }; #define KS_ANONYMOUS 0x0001 /* Anonymous (unnamed) semaphore. */ #define KS_DEAD 0x0002 /* No new waiters allowed. */ +#ifdef _KERNEL +extern void (*ksem_info)(struct ksem *ks, char *path, size_t size, + uint32_t *value); +#endif + #endif /* !_POSIX4_KSEM_H_ */ diff --git a/sys/sys/user.h b/sys/sys/user.h index d5a8ec445..ef046b4e3 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -366,6 +366,10 @@ struct kinfo_file { uint16_t kf_file_pad0; uint32_t kf_file_pad1; } kf_file; + struct { + uint32_t kf_sem_value; + uint16_t kf_sem_mode; + } kf_sem; struct { uint64_t kf_pipe_addr; uint64_t kf_pipe_peer; diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1 index e1f1c1bed..1301ed85a 100644 --- a/usr.bin/fstat/fstat.1 +++ b/usr.bin/fstat/fstat.1 @@ -155,6 +155,8 @@ using a symbolic format (see otherwise, the mode is printed as an octal number. .It Li SZ\&|DV +If the file is a semaphore, +prints the current value of the semaphore. If the file is not a character or block special, prints the size of the file in bytes. Otherwise, if the diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c index 8c2faf1ad..27bea37c3 100644 --- a/usr.bin/fstat/fstat.c +++ b/usr.bin/fstat/fstat.c @@ -84,6 +84,8 @@ static void print_pipe_info(struct procstat *procstat, struct filestat *fst); static void print_pts_info(struct procstat *procstat, struct filestat *fst); +static void print_sem_info(struct procstat *procstat, + struct filestat *fst); static void print_shm_info(struct procstat *procstat, struct filestat *fst); static void print_socket_info(struct procstat *procstat, @@ -294,6 +296,9 @@ print_file_info(struct procstat *procstat, struct filestat *fst, case PS_FST_TYPE_SHM: print_shm_info(procstat, fst); break; + case PS_FST_TYPE_SEM: + print_sem_info(procstat, fst); + break; default: if (vflg) fprintf(stderr, @@ -423,6 +428,30 @@ print_pts_info(struct procstat *procstat, struct filestat *fst) print_access_flags(fst->fs_fflags); } +static void +print_sem_info(struct procstat *procstat, struct filestat *fst) +{ + struct semstat sem; + char errbuf[_POSIX2_LINE_MAX]; + char mode[15]; + int error; + + error = procstat_get_sem_info(procstat, fst, &sem, errbuf); + if (error != 0) { + printf("* error"); + return; + } + if (nflg) { + printf(" "); + (void)snprintf(mode, sizeof(mode), "%o", sem.mode); + } else { + printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-"); + strmode(sem.mode, mode); + } + printf(" %10s %6u", mode, sem.value); + print_access_flags(fst->fs_fflags); +} + static void print_shm_info(struct procstat *procstat, struct filestat *fst) { -- 2.45.0