aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2013-05-03 21:11:57 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2013-05-03 21:11:57 +0000
commit958aa57537952c7e7018518bb9d643b81e85e827 (patch)
tree4b4ec8c6d14c8986e2139b96edf75a870d996980
parent14303aa88998c64be2962e89ea48306fb44b4037 (diff)
downloadsrc-958aa57537952c7e7018518bb9d643b81e85e827.tar.gz
src-958aa57537952c7e7018518bb9d643b81e85e827.zip
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
Notes
Notes: svn path=/head/; revision=250223
-rw-r--r--lib/libprocstat/Symbol.map1
-rw-r--r--lib/libprocstat/libprocstat.314
-rw-r--r--lib/libprocstat/libprocstat.c90
-rw-r--r--lib/libprocstat/libprocstat.h6
-rw-r--r--sys/kern/kern_descrip.c31
-rw-r--r--sys/kern/uipc_sem.c19
-rw-r--r--sys/sys/ksem.h8
-rw-r--r--sys/sys/user.h4
-rw-r--r--usr.bin/fstat/fstat.12
-rw-r--r--usr.bin/fstat/fstat.c29
10 files changed, 201 insertions, 3 deletions
diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map
index 085720cf4590..1495bfc28c66 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 3312427a0ed2..e82c30a21612 100644
--- a/lib/libprocstat/libprocstat.3
+++ b/lib/libprocstat/libprocstat.3
@@ -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 dd16c80d1c79..78eae9f7e4ed 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -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;
@@ -1003,6 +1012,87 @@ procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
}
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 2c2662d5dbeb..65a5eb955324 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -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,
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index a9795ca74448..c0ecf1514cb6 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -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:
@@ -3621,6 +3633,25 @@ fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif)
}
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)
{
struct thread *td;
diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c
index 509f32e909b7..a9f60f1e538d 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 da868fad1016..c11c8656b64d 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 2f6514bb25e6..aa81dc9c60ba 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -365,6 +365,10 @@ struct kinfo_file {
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;
uint32_t kf_pipe_buffer_cnt;
diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1
index 7403a8e725ee..268b70f4526f 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 265791d1daac..1aeee67511dd 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,
@@ -424,6 +429,30 @@ print_pts_info(struct procstat *procstat, struct filestat *fst)
}
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)
{
struct shmstat shm;