svn commit: r250223 - in head: lib/libprocstat sys/kern sys/sys usr.bin/fstat

John Baldwin jhb at FreeBSD.org
Fri May 3 21:11:59 UTC 2013


Author: jhb
Date: Fri May  3 21:11:57 2013
New Revision: 250223
URL: http://svnweb.freebsd.org/changeset/base/250223

Log:
  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

Modified:
  head/lib/libprocstat/Symbol.map
  head/lib/libprocstat/libprocstat.3
  head/lib/libprocstat/libprocstat.c
  head/lib/libprocstat/libprocstat.h
  head/sys/kern/kern_descrip.c
  head/sys/kern/uipc_sem.c
  head/sys/sys/ksem.h
  head/sys/sys/user.h
  head/usr.bin/fstat/fstat.1
  head/usr.bin/fstat/fstat.c

Modified: head/lib/libprocstat/Symbol.map
==============================================================================
--- head/lib/libprocstat/Symbol.map	Fri May  3 20:39:53 2013	(r250222)
+++ head/lib/libprocstat/Symbol.map	Fri May  3 21:11:57 2013	(r250223)
@@ -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;

Modified: head/lib/libprocstat/libprocstat.3
==============================================================================
--- head/lib/libprocstat/libprocstat.3	Fri May  3 20:39:53 2013	(r250222)
+++ head/lib/libprocstat/libprocstat.3	Fri May  3 21:11:57 2013	(r250223)
@@ -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 messa
 .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 messa
 .Xr elf 3 ,
 .Xr kvm 3 ,
 .Xr queue 3 ,
+.Xr sem_open 3 ,
 .Xr sysctl 3 ,
 .Xr pts 4 ,
 .Xr core 5 ,

Modified: head/lib/libprocstat/libprocstat.c
==============================================================================
--- head/lib/libprocstat/libprocstat.c	Fri May  3 20:39:53 2013	(r250222)
+++ head/lib/libprocstat/libprocstat.c	Fri May  3 21:11:57 2013	(r250223)
@@ -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 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 *p
 			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 file
 }
 
 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)
 {

Modified: head/lib/libprocstat/libprocstat.h
==============================================================================
--- head/lib/libprocstat/libprocstat.h	Fri May  3 20:39:53 2013	(r250222)
+++ head/lib/libprocstat/libprocstat.h	Fri May  3 21:11:57 2013	(r250223)
@@ -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 procst
     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,

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c	Fri May  3 20:39:53 2013	(r250222)
+++ head/sys/kern/kern_descrip.c	Fri May  3 21:11:57 2013	(r250223)
@@ -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 *p
 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_HANDLE
 	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_HANDLE
 			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_HANDLE
 
 		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_HANDLE
 		}
 		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, in
 	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,  
 
 		case DTYPE_SEM:
 			type = KF_TYPE_SEM;
+			data = fp;
 			break;
 
 		case DTYPE_PTS:
@@ -3621,6 +3633,25 @@ fill_procdesc_info(struct procdesc *pdp,
 }
 
 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;

Modified: head/sys/kern/uipc_sem.c
==============================================================================
--- head/sys/kern/uipc_sem.c	Fri May  3 20:39:53 2013	(r250222)
+++ head/sys/kern/uipc_sem.c	Fri May  3 21:11:57 2013	(r250223)
@@ -71,7 +71,6 @@ FEATURE(p1003_1b_semaphores, "POSIX P100
  * 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, str
 	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, str
 			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, str
 	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);

Modified: head/sys/sys/ksem.h
==============================================================================
--- head/sys/sys/ksem.h	Fri May  3 20:39:53 2013	(r250222)
+++ head/sys/sys/ksem.h	Fri May  3 21:11:57 2013	(r250223)
@@ -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_ */

Modified: head/sys/sys/user.h
==============================================================================
--- head/sys/sys/user.h	Fri May  3 20:39:53 2013	(r250222)
+++ head/sys/sys/user.h	Fri May  3 21:11:57 2013	(r250223)
@@ -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;

Modified: head/usr.bin/fstat/fstat.1
==============================================================================
--- head/usr.bin/fstat/fstat.1	Fri May  3 20:39:53 2013	(r250222)
+++ head/usr.bin/fstat/fstat.1	Fri May  3 21:11:57 2013	(r250223)
@@ -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

Modified: head/usr.bin/fstat/fstat.c
==============================================================================
--- head/usr.bin/fstat/fstat.c	Fri May  3 20:39:53 2013	(r250222)
+++ head/usr.bin/fstat/fstat.c	Fri May  3 21:11:57 2013	(r250223)
@@ -84,6 +84,8 @@ static void	print_pipe_info(struct procs
     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 *procsta
 	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
 }
 
 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;


More information about the svn-src-head mailing list