Add a kern.ipc.posix_shm_list sysctl.

The sysctl provides the listing on named linked posix shared memory
segments existing in the system.

Reuse shm_fill_kinfo() for filling individual struct kinfo_file.
Remove unneeded lock around reading of shmfd->shm_mode.

Reviewed by:	jilles, tmunro
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D20258
This commit is contained in:
kib 2019-05-23 12:35:40 +00:00
parent b45119a2cb
commit 83a359ea2a

View File

@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
#include <sys/refcount.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
#include <sys/sbuf.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
@ -1101,34 +1102,89 @@ shm_unmap(struct file *fp, void *mem, size_t size)
}
static int
shm_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
shm_fill_kinfo_locked(struct shmfd *shmfd, struct kinfo_file *kif, bool list)
{
const char *path, *pr_path;
struct shmfd *shmfd;
size_t pr_pathlen;
bool visible;
sx_assert(&shm_dict_lock, SA_LOCKED);
kif->kf_type = KF_TYPE_SHM;
shmfd = fp->f_data;
mtx_lock(&shm_timestamp_lock);
kif->kf_un.kf_file.kf_file_mode = S_IFREG | shmfd->shm_mode; /* XXX */
mtx_unlock(&shm_timestamp_lock);
kif->kf_un.kf_file.kf_file_mode = S_IFREG | shmfd->shm_mode;
kif->kf_un.kf_file.kf_file_size = shmfd->shm_size;
if (shmfd->shm_path != NULL) {
sx_slock(&shm_dict_lock);
if (shmfd->shm_path != NULL) {
path = shmfd->shm_path;
pr_path = curthread->td_ucred->cr_prison->pr_path;
if (strcmp(pr_path, "/") != 0) {
/* Return the jail-rooted pathname. */
pr_pathlen = strlen(pr_path);
if (strncmp(path, pr_path, pr_pathlen) == 0 &&
path[pr_pathlen] == '/')
visible = strncmp(path, pr_path, pr_pathlen)
== 0 && path[pr_pathlen] == '/';
if (list && !visible)
return (EPERM);
if (visible)
path += pr_pathlen;
}
strlcpy(kif->kf_path, path, sizeof(kif->kf_path));
}
sx_sunlock(&shm_dict_lock);
}
return (0);
}
static int
shm_fill_kinfo(struct file *fp, struct kinfo_file *kif,
struct filedesc *fdp __unused)
{
int res;
sx_slock(&shm_dict_lock);
res = shm_fill_kinfo_locked(fp->f_data, kif, false);
sx_sunlock(&shm_dict_lock);
return (res);
}
static int
sysctl_posix_shm_list(SYSCTL_HANDLER_ARGS)
{
struct shm_mapping *shmm;
struct sbuf sb;
struct kinfo_file kif;
u_long i;
ssize_t curlen;
int error, error2;
sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_file) * 5, req);
sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
curlen = 0;
error = 0;
sx_slock(&shm_dict_lock);
for (i = 0; i < shm_hash + 1; i++) {
LIST_FOREACH(shmm, &shm_dictionary[i], sm_link) {
error = shm_fill_kinfo_locked(shmm->sm_shmfd,
&kif, true);
if (error == EPERM)
continue;
if (error != 0)
break;
pack_kinfo(&kif);
if (req->oldptr != NULL &&
kif.kf_structsize + curlen > req->oldlen)
break;
error = sbuf_bcat(&sb, &kif, kif.kf_structsize) == 0 ?
0 : ENOMEM;
if (error != 0)
break;
curlen += kif.kf_structsize;
}
}
sx_sunlock(&shm_dict_lock);
error2 = sbuf_finish(&sb);
sbuf_delete(&sb);
return (error != 0 ? error : error2);
}
SYSCTL_PROC(_kern_ipc, OID_AUTO, posix_shm_list,
CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_OPAQUE,
NULL, 0, sysctl_posix_shm_list, "",
"POSIX SHM list");