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. MFC after: 2 weeks
This commit is contained in:
parent
14303aa889
commit
958aa57537
@ -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;
|
||||
|
@ -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 ,
|
||||
|
@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define _WANT_FILE
|
||||
#include <sys/file.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/ksem.h>
|
||||
#include <sys/mman.h>
|
||||
#define _KERNEL
|
||||
#include <sys/mount.h>
|
||||
@ -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,
|
||||
@ -556,6 +561,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;
|
||||
@ -1002,6 +1011,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)
|
||||
|
@ -133,6 +133,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;
|
||||
@ -177,6 +181,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,
|
||||
|
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/filio.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ksem.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
@ -111,6 +112,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);
|
||||
|
||||
static int closefp(struct filedesc *fdp, int fd, struct file *fp,
|
||||
struct thread *td, int holdleaders);
|
||||
@ -123,6 +125,7 @@ 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_pts_info(struct tty *tp, 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);
|
||||
static int fill_socket_info(struct socket *so, struct kinfo_file *kif);
|
||||
static int fill_vnode_info(struct vnode *vp, struct kinfo_file *kif);
|
||||
@ -2968,6 +2971,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;
|
||||
@ -2996,6 +3000,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;
|
||||
@ -3041,6 +3046,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:
|
||||
@ -3150,6 +3156,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;
|
||||
@ -3220,6 +3228,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;
|
||||
@ -3387,6 +3398,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:
|
||||
@ -3620,6 +3632,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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -364,6 +364,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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user