summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2015-02-27 17:47:32 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2015-02-27 17:47:32 +0000
commitfbc60aab728012fb47e62bf8834c38b73936cb60 (patch)
treea6cfbae3fe5e1502c55a244cca74affa6bc51851 /usr/src
parent51106d5c3986510206c5fa818eb5ebc090a7b475 (diff)
downloadillumos-joyent-fbc60aab728012fb47e62bf8834c38b73936cb60.tar.gz
OS-3314 want /proc/<pid>/task/<tid>/stat
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_proc.h18
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prsubr.c26
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c588
3 files changed, 588 insertions, 44 deletions
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_proc.h b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
index a5c2391c95..b57de11525 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_proc.h
+++ b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
@@ -115,8 +115,25 @@ typedef enum lxpr_nodetype {
LXPR_PID_STAT, /* /proc/<pid>/stat */
LXPR_PID_STATM, /* /proc/<pid>/statm */
LXPR_PID_STATUS, /* /proc/<pid>/status */
+ LXPR_PID_TASKDIR, /* /proc/<pid>/task */
+ LXPR_PID_TASK_IDDIR, /* /proc/<pid>/task/<tid> */
LXPR_PID_FDDIR, /* /proc/<pid>/fd */
LXPR_PID_FD_FD, /* /proc/<pid>/fd/nn */
+ LXPR_PID_TID_CMDLINE, /* /proc/<pid>/task/<tid>/cmdline */
+ LXPR_PID_TID_CPU, /* /proc/<pid>/task/<tid>/cpu */
+ LXPR_PID_TID_CURDIR, /* /proc/<pid>/task/<tid>/cwd */
+ LXPR_PID_TID_ENV, /* /proc/<pid>/task/<tid>/environ */
+ LXPR_PID_TID_EXE, /* /proc/<pid>/task/<tid>/exe */
+ LXPR_PID_TID_LIMITS, /* /proc/<pid>/task/<tid>/limits */
+ LXPR_PID_TID_MAPS, /* /proc/<pid>/task/<tid>/maps */
+ LXPR_PID_TID_MEM, /* /proc/<pid>/task/<tid>/mem */
+ LXPR_PID_TID_MOUNTINFO, /* /proc/<pid>/task/<tid>/mountinfo */
+ LXPR_PID_TID_ROOTDIR, /* /proc/<pid>/task/<tid>/root */
+ LXPR_PID_TID_STAT, /* /proc/<pid>/task/<tid>/stat */
+ LXPR_PID_TID_STATM, /* /proc/<pid>/task/<tid>/statm */
+ LXPR_PID_TID_STATUS, /* /proc/<pid>/task/<tid>/status */
+ LXPR_PID_TID_FDDIR, /* /proc/<pid>/task/<tid>/fd */
+ LXPR_PID_TID_FD_FD, /* /proc/<pid>/task/<tid>/fd/nn */
LXPR_CMDLINE, /* /proc/cmdline */
LXPR_CPUINFO, /* /proc/cpuinfo */
LXPR_DEVICES, /* /proc/devices */
@@ -205,6 +222,7 @@ typedef struct lxpr_node {
uid_t lxpr_uid; /* file owner */
gid_t lxpr_gid; /* file group owner */
pid_t lxpr_pid; /* pid of proc referred to */
+ uint_t lxpr_desc; /* addl. descriptor (fd or tid) */
ino_t lxpr_ino; /* node id */
ldi_handle_t lxpr_cons_ldih; /* ldi handle for console device */
} lxpr_node_t;
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c b/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
index 3d96a1ceb2..6dad5ce7d2 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
@@ -319,7 +319,7 @@ lxpr_node_destructor(void *buf, void *un)
* to give the inode number for an lxproc node
*/
ino_t
-lxpr_inode(lxpr_nodetype_t type, pid_t pid, int fd)
+lxpr_inode(lxpr_nodetype_t type, pid_t pid, int desc)
{
if (pid == 1) {
pid = curproc->p_zone->zone_proc_initpid;
@@ -329,13 +329,15 @@ lxpr_inode(lxpr_nodetype_t type, pid_t pid, int fd)
switch (type) {
case LXPR_PIDDIR:
- return (pid + 1);
+ return (maxpid + pid + 1);
+ case LXPR_PID_TASK_IDDIR:
+ return (maxpid + (desc * 10));
case LXPR_PROCDIR:
return (maxpid + 2);
case LXPR_PID_FD_FD:
return (maxpid + 2 +
(pid * (LXPR_FD_PERPROC + LXPR_NFILES)) +
- LXPR_NFILES + fd);
+ LXPR_NFILES + desc);
default:
return (maxpid + 2 +
(pid * (LXPR_FD_PERPROC + LXPR_NFILES)) +
@@ -365,7 +367,7 @@ lxpr_parentinode(lxpr_node_t *lxpnp)
* This also allocates the vnode associated with it
*/
lxpr_node_t *
-lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int fd)
+lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int desc)
{
lxpr_node_t *lxpnp;
vnode_t *vp;
@@ -384,6 +386,7 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int fd)
lxpnp->lxpr_type = type;
lxpnp->lxpr_realvp = NULL;
lxpnp->lxpr_parent = dp;
+ lxpnp->lxpr_desc = desc;
VN_HOLD(dp);
if (p != NULL) {
if (p->p_pid == curproc->p_zone->zone_proc_initpid) {
@@ -397,7 +400,7 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int fd)
lxpnp->lxpr_time = PTOU(p)->u_start;
lxpnp->lxpr_uid = crgetruid(p->p_cred);
lxpnp->lxpr_gid = crgetrgid(p->p_cred);
- lxpnp->lxpr_ino = lxpr_inode(type, p->p_pid, fd);
+ lxpnp->lxpr_ino = lxpr_inode(type, p->p_pid, desc);
} else {
/* Pretend files without a proc belong to sched */
lxpnp->lxpr_pid = 0;
@@ -479,6 +482,18 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int fd)
lxpnp->lxpr_mode = 0777; /* anyone does anything ! */
break;
+ case LXPR_PID_TASKDIR:
+ ASSERT(p != NULL);
+ vp->v_type = VDIR;
+ lxpnp->lxpr_mode = 0555; /* read-search by everyone */
+ break;
+
+ case LXPR_PID_TASK_IDDIR:
+ ASSERT(p != NULL);
+ vp->v_type = VDIR;
+ lxpnp->lxpr_mode = 0555; /* read-search by everyone */
+ break;
+
case LXPR_PID_FD_FD:
ASSERT(p != NULL);
/* lxpr_realvp is set after we return */
@@ -487,6 +502,7 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int fd)
break;
case LXPR_PID_FDDIR:
+ case LXPR_PID_TID_FDDIR:
ASSERT(p != NULL);
vp->v_type = VDIR;
lxpnp->lxpr_mode = 0500; /* read-search by owner only */
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index b810818ef6..5cf9e753bb 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -31,17 +31,19 @@
* the Linux /proc implementation for purposes of offering some compatibility
* for simple Linux /proc readers (e.g., ps/top/htop). However, it is not
* intended to exactly mimic Linux semantics; when choosing between offering
- * compatibility and telling the truth, we emphatically pick the truth. A
- * particular glaring example of this is the Linux notion of "tasks" (that is,
- * threads), which -- due to historical misadventures on Linux -- allocate their
- * identifiers from the process identifier space. (That is, each thread has in
- * effect a pid.) Some Linux /proc readers have come to depend on this
- * attribute, and become confused when threads appear with proper identifiers,
- * so we simply opt for the pre-2.6 behavior, and do not present the tasks
- * directory at all. Similarly, when choosing between offering compatibility
- * and remaining consistent with our broader security model, we (obviously)
- * choose security over compatibility. In short, this is meant to be a best
- * effort -- no more.
+ * compatibility and telling the truth, we emphatically pick the truth (in most
+ * cases ;-) ). A particular glaring example of this is the Linux notion of
+ * "tasks" (that is, threads), which -- due to historical misadventures on
+ * Linux -- allocate their identifiers from the process identifier space (that
+ * is, each thread has in effect a pid). Some Linux /proc readers have come to
+ * depend on this attribute, and become confused when threads appear with
+ * proper identifiers. To deal with this the lx brand emulates per-thread pids
+ * in the per-lwp brand data (see lx_pid_assign in the lx brand module). Under
+ * the tasks directory we use this lx-assigned pid instead of the real tid.
+ *
+ * Similarly, when choosing between offering compatibility and remaining
+ * consistent with our broader security model, we (obviously) choose security
+ * over compatibility. In short, this is meant to be a best effort -- no more.
*/
#include <sys/cpupart.h>
@@ -70,6 +72,7 @@
#include <sys/rctl.h>
#include <sys/kstat.h>
#include <sys/lx_misc.h>
+#include <sys/brand.h>
#include <sys/cred_impl.h>
#include <sys/tihdr.h>
#include <inet/ip.h>
@@ -125,6 +128,8 @@ static vnode_t *lxpr_lookup_sysdir(vnode_t *, char *);
static vnode_t *lxpr_lookup_sys_fsdir(vnode_t *, char *);
static vnode_t *lxpr_lookup_sys_fs_inotifydir(vnode_t *, char *);
static vnode_t *lxpr_lookup_sys_kerneldir(vnode_t *, char *);
+static vnode_t *lxpr_lookup_taskdir(vnode_t *, char *);
+static vnode_t *lxpr_lookup_task_tid_dir(vnode_t *, char *);
static int lxpr_readdir_procdir(lxpr_node_t *, uio_t *, int *);
static int lxpr_readdir_piddir(lxpr_node_t *, uio_t *, int *);
@@ -135,6 +140,8 @@ static int lxpr_readdir_sysdir(lxpr_node_t *, uio_t *, int *);
static int lxpr_readdir_sys_fsdir(lxpr_node_t *, uio_t *, int *);
static int lxpr_readdir_sys_fs_inotifydir(lxpr_node_t *, uio_t *, int *);
static int lxpr_readdir_sys_kerneldir(lxpr_node_t *, uio_t *, int *);
+static int lxpr_readdir_taskdir(lxpr_node_t *, uio_t *, int *);
+static int lxpr_readdir_task_tid_dir(lxpr_node_t *, uio_t *, int *);
static void lxpr_read_invalid(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_empty(lxpr_node_t *, lxpr_uiobuf_t *);
@@ -159,6 +166,9 @@ static void lxpr_read_pid_stat(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_pid_statm(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_pid_status(lxpr_node_t *, lxpr_uiobuf_t *);
+static void lxpr_read_pid_tid_stat(lxpr_node_t *, lxpr_uiobuf_t *);
+static void lxpr_read_pid_tid_status(lxpr_node_t *, lxpr_uiobuf_t *);
+
static void lxpr_read_net_arp(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_dev(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_dev_mcast(lxpr_node_t *, lxpr_uiobuf_t *);
@@ -200,6 +210,8 @@ static void lxpr_read_sys_kernel_threads_max(lxpr_node_t *, lxpr_uiobuf_t *);
#define btok(x) ((x) >> 10) /* bytes to kbytes */
#define ptok(x) ((x) << (PAGESHIFT - 10)) /* pages to kbytes */
+#define ttolxlwp(t) ((struct lx_lwp_data *)ttolwpbrand(t))
+
extern rctl_hndl_t rc_zone_msgmni;
extern rctl_hndl_t rc_zone_shmmax;
#define FOURGB 4294967295
@@ -277,11 +289,34 @@ static lxpr_dirent_t piddir[] = {
{ LXPR_PID_STAT, "stat" },
{ LXPR_PID_STATM, "statm" },
{ LXPR_PID_STATUS, "status" },
+ { LXPR_PID_TASKDIR, "task" },
{ LXPR_PID_FDDIR, "fd" }
};
#define PIDDIRFILES (sizeof (piddir) / sizeof (piddir[0]))
+/*
+ * Contents of an lx /proc/<pid>/task/<tid> directory.
+ */
+static lxpr_dirent_t tiddir[] = {
+ { LXPR_PID_CMDLINE, "cmdline" },
+ { LXPR_PID_CPU, "cpu" },
+ { LXPR_PID_CURDIR, "cwd" },
+ { LXPR_PID_ENV, "environ" },
+ { LXPR_PID_EXE, "exe" },
+ { LXPR_PID_LIMITS, "limits" },
+ { LXPR_PID_MAPS, "maps" },
+ { LXPR_PID_MEM, "mem" },
+ { LXPR_PID_MOUNTINFO, "mountinfo" },
+ { LXPR_PID_ROOTDIR, "root" },
+ { LXPR_PID_TID_STAT, "stat" },
+ { LXPR_PID_STATM, "statm" },
+ { LXPR_PID_TID_STATUS, "status" },
+ { LXPR_PID_FDDIR, "fd" }
+};
+
+#define TIDDIRFILES (sizeof (tiddir) / sizeof (tiddir[0]))
+
#define LX_RLIM_INFINITY 0xFFFFFFFFFFFFFFFF
#define RCTL_INFINITE(x) \
@@ -484,8 +519,25 @@ static void (*lxpr_read_function[LXPR_NFILES])() = {
lxpr_read_pid_stat, /* /proc/<pid>/stat */
lxpr_read_pid_statm, /* /proc/<pid>/statm */
lxpr_read_pid_status, /* /proc/<pid>/status */
+ lxpr_read_isdir, /* /proc/<pid>/task */
+ lxpr_read_isdir, /* /proc/<pid>/task/nn */
lxpr_read_isdir, /* /proc/<pid>/fd */
lxpr_read_fd, /* /proc/<pid>/fd/nn */
+ lxpr_read_pid_cmdline, /* /proc/<pid>/task/<tid>/cmdline */
+ lxpr_read_empty, /* /proc/<pid>/task/<tid>/cpu */
+ lxpr_read_invalid, /* /proc/<pid>/task/<tid>/cwd */
+ lxpr_read_empty, /* /proc/<pid>/task/<tid>/environ */
+ lxpr_read_invalid, /* /proc/<pid>/task/<tid>/exe */
+ lxpr_read_pid_limits, /* /proc/<pid>/task/<tid>/limits */
+ lxpr_read_pid_maps, /* /proc/<pid>/task/<tid>/maps */
+ lxpr_read_empty, /* /proc/<pid>/task/<tid>/mem */
+ lxpr_read_pid_mountinfo, /* /proc/<pid>/task/<tid>/mountinfo */
+ lxpr_read_invalid, /* /proc/<pid>/task/<tid>/root */
+ lxpr_read_pid_tid_stat, /* /proc/<pid>/task/<tid>/stat */
+ lxpr_read_pid_statm, /* /proc/<pid>/task/<tid>/statm */
+ lxpr_read_pid_tid_status, /* /proc/<pid>/task/<tid>/status */
+ lxpr_read_isdir, /* /proc/<pid>/task/<tid>/fd */
+ lxpr_read_fd, /* /proc/<pid>/task/<tid>/fd/nn */
lxpr_read_empty, /* /proc/cmdline */
lxpr_read_cpuinfo, /* /proc/cpuinfo */
lxpr_read_empty, /* /proc/devices */
@@ -562,8 +614,25 @@ static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
lxpr_lookup_not_a_dir, /* /proc/<pid>/stat */
lxpr_lookup_not_a_dir, /* /proc/<pid>/statm */
lxpr_lookup_not_a_dir, /* /proc/<pid>/status */
+ lxpr_lookup_taskdir, /* /proc/<pid>/task */
+ lxpr_lookup_task_tid_dir, /* /proc/<pid>/task/nn */
lxpr_lookup_fddir, /* /proc/<pid>/fd */
lxpr_lookup_not_a_dir, /* /proc/<pid>/fd/nn */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/cmdline */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/cpu */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/cwd */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/environ */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/exe */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/limits */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/maps */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/mem */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/mountinfo */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/root */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/stat */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/statm */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/status */
+ lxpr_lookup_fddir, /* /proc/<pid>/task/<tid>/fd */
+ lxpr_lookup_not_a_dir, /* /proc/<pid>/task/<tid>/fd/nn */
lxpr_lookup_not_a_dir, /* /proc/cmdline */
lxpr_lookup_not_a_dir, /* /proc/cpuinfo */
lxpr_lookup_not_a_dir, /* /proc/devices */
@@ -640,8 +709,25 @@ static int (*lxpr_readdir_function[LXPR_NFILES])() = {
lxpr_readdir_not_a_dir, /* /proc/<pid>/stat */
lxpr_readdir_not_a_dir, /* /proc/<pid>/statm */
lxpr_readdir_not_a_dir, /* /proc/<pid>/status */
+ lxpr_readdir_taskdir, /* /proc/<pid>/task */
+ lxpr_readdir_task_tid_dir, /* /proc/<pid>/task/nn */
lxpr_readdir_fddir, /* /proc/<pid>/fd */
lxpr_readdir_not_a_dir, /* /proc/<pid>/fd/nn */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/cmdline */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/cpu */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/cwd */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/environ */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/exe */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/limits */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/maps */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/mem */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/mountinfo */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/root */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/stat */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/statm */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/status */
+ lxpr_readdir_fddir, /* /proc/<pid>/task/<tid>/fd */
+ lxpr_readdir_not_a_dir, /* /proc/<pid>/task/<tid>/fd/nn */
lxpr_readdir_not_a_dir, /* /proc/cmdline */
lxpr_readdir_not_a_dir, /* /proc/cpuinfo */
lxpr_readdir_not_a_dir, /* /proc/devices */
@@ -800,7 +886,8 @@ lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
char *buf;
size_t asz = lxpr_maxargvlen, sz;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE ||
+ lxpnp->lxpr_type == LXPR_PID_TID_CMDLINE);
buf = kmem_alloc(asz, KM_SLEEP);
@@ -834,7 +921,8 @@ lxpr_read_pid_limits(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
char *kname;
int i;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_LIMITS);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_LIMITS ||
+ lxpnp->lxpr_type == LXPR_PID_TID_LIMITS);
nval = kmem_alloc(sizeof (rctl_val_t), KM_SLEEP);
@@ -913,7 +1001,8 @@ lxpr_read_pid_maps(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
struct print_data **print_tail = &print_head;
struct print_data *pbuf;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_MAPS);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_MAPS ||
+ lxpnp->lxpr_type == LXPR_PID_TID_MAPS);
p = lxpr_lock(lxpnp->lxpr_pid);
if (p == NULL) {
@@ -1046,7 +1135,8 @@ lxpr_read_pid_mountinfo(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
int root_id = 15; /* use a made-up value */
int mnt_id;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_MOUNTINFO);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_MOUNTINFO ||
+ lxpnp->lxpr_type == LXPR_PID_TID_MOUNTINFO);
vfs_list_read_lock();
@@ -1195,7 +1285,8 @@ lxpr_read_pid_statm(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
size_t vsize;
size_t rss;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_STATM);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_STATM ||
+ lxpnp->lxpr_type == LXPR_PID_TID_STATM);
p = lxpr_lock(lxpnp->lxpr_pid);
if (p == NULL) {
@@ -1256,33 +1347,75 @@ get_locked(proc_t *p)
}
/*
- * Linux wants to prefer the main thread for the pid status info so we
- * only use prchoose if we can't find the main thread.
+ * Look for either the main thread (lookup_id is 0) or the specified thread.
+ * If we're looking for the main thread but the proc does not have one, we
+ * fallback to using prchoose to get any thread available.
*/
static kthread_t *
-get_main_thread(proc_t *p)
+lxpr_get_thread(proc_t *p, uint_t lookup_id)
{
kthread_t *t;
+ uint_t emul_tid;
+ lx_lwp_data_t *lwpd;
+ pid_t pid = p->p_pid;
+ pid_t init_pid = curproc->p_zone->zone_proc_initpid;
+ /* get specified thread */
if ((t = p->p_tlist) == NULL)
- return (t);
+ return (NULL);
do {
- /* we know the main thread is always tid 1 */
- if (t->t_tid == 1) {
+ if (lookup_id == 0 && t->t_tid == 1) {
+ thread_lock(t);
+ return (t);
+ }
+
+ lwpd = ttolxlwp(t);
+ if (lwpd == NULL) {
+ emul_tid = t->t_tid;
+ } else {
+ if (pid == init_pid && lookup_id == 1) {
+ emul_tid = t->t_tid;
+ } else {
+ emul_tid = lwpd->br_pid;
+ }
+ }
+ if (emul_tid == lookup_id) {
thread_lock(t);
return (t);
}
} while ((t = t->t_forw) != p->p_tlist);
- return (prchoose(p));
+ if (lookup_id == 0)
+ return (prchoose(p));
+ return (NULL);
}
/*
- * lxpr_read_pid_status(): status file
+ * Lookup the real pid for procs 0 or 1.
+ */
+static pid_t
+get_real_pid(pid_t p)
+{
+ pid_t find_pid;
+
+ if (p == 1) {
+ find_pid = curproc->p_zone->zone_proc_initpid;
+ } else if (p == 0) {
+ find_pid = curproc->p_zone->zone_zsched->p_pid;
+ } else {
+ find_pid = p;
+ }
+
+ return (find_pid);
+}
+
+/*
+ * pid/tid common code to read status file
*/
static void
-lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+lxpr_read_status_common(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf,
+ uint_t lookup_id)
{
proc_t *p;
kthread_t *t;
@@ -1298,10 +1431,10 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
size_t rss;
k_sigset_t current, ignore, handle;
int i, lx_sig;
+ pid_t real_pid;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_STATUS);
-
- p = lxpr_lock(lxpnp->lxpr_pid);
+ real_pid = get_real_pid(lxpnp->lxpr_pid);
+ p = lxpr_lock(real_pid);
if (p == NULL) {
lxpr_uiobuf_seterr(uiobuf, EINVAL);
return;
@@ -1335,7 +1468,7 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
ppid = 1;
}
- t = get_main_thread(p);
+ t = lxpr_get_thread(p, lookup_id);
if (t != NULL) {
switch (t->t_state) {
case TS_SLEEP:
@@ -1357,6 +1490,13 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
}
thread_unlock(t);
} else {
+ if (lookup_id != 0) {
+ /* we can't find this specific thread */
+ lxpr_uiobuf_seterr(uiobuf, EINVAL);
+ lxpr_unlock(p);
+ return;
+ }
+
/*
* there is a hole in the exit code, where a proc can have
* no threads but it is yet to be flagged SZOMB. We will
@@ -1384,13 +1524,14 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
up->u_comm,
status,
pid, /* thread group id - same as pid */
- pid,
+ (lookup_id == 0) ? pid : lxpnp->lxpr_desc,
ppid,
0,
crgetruid(cr), crgetuid(cr), crgetsuid(cr), crgetuid(cr),
crgetrgid(cr), crgetgid(cr), crgetsgid(cr), crgetgid(cr),
p->p_fno_ctl);
+
ngroups = crgetngroups(cr);
groups = crgetgroups(cr);
for (i = 0; i < ngroups; i++) {
@@ -1428,6 +1569,8 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
0l);
}
+ lxpr_uiobuf_printf(uiobuf, "\nThreads:\t%u", p->p_lwpcnt);
+
sigemptyset(&current);
sigemptyset(&ignore);
sigemptyset(&handle);
@@ -1467,12 +1610,33 @@ lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
lxpr_unlock(p);
}
+/*
+ * lxpr_read_pid_status(): status file
+ */
+static void
+lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_STATUS);
+
+ lxpr_read_status_common(lxpnp, uiobuf, 0);
+}
/*
- * lxpr_read_pid_stat(): pid stat file
+ * lxpr_read_pid_tid_status(): status file
*/
static void
-lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+lxpr_read_pid_tid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_TID_STATUS);
+ lxpr_read_status_common(lxpnp, uiobuf, lxpnp->lxpr_desc);
+}
+
+/*
+ * pid/tid common code to read stat file
+ */
+static void
+lxpr_read_stat_common(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf,
+ uint_t lookup_id)
{
proc_t *p;
kthread_t *t;
@@ -1485,10 +1649,10 @@ lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
int nice, pri;
caddr_t wchan;
processorid_t cpu;
+ pid_t real_pid;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_STAT);
-
- p = lxpr_lock(lxpnp->lxpr_pid);
+ real_pid = get_real_pid(lxpnp->lxpr_pid);
+ p = lxpr_lock(real_pid);
if (p == NULL) {
lxpr_uiobuf_seterr(uiobuf, EINVAL);
return;
@@ -1543,7 +1707,7 @@ lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
mutex_exit(&p->p_splock);
}
- t = get_main_thread(p);
+ t = lxpr_get_thread(p, lookup_id);
if (t != NULL) {
switch (t->t_state) {
case TS_SLEEP:
@@ -1567,6 +1731,13 @@ lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
cpu = t->t_cpu->cpu_id;
thread_unlock(t);
} else {
+ if (lookup_id != 0) {
+ /* we can't find this specific thread */
+ lxpr_uiobuf_seterr(uiobuf, EINVAL);
+ lxpr_unlock(p);
+ return;
+ }
+
/* Only zombies have no threads */
stat = 'Z';
nice = 0;
@@ -1598,7 +1769,8 @@ lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
"%d "
"%d"
"\n",
- pid, PTOU(p)->u_comm, stat, ppid, pgpid, spid, psdev, psgid,
+ (lookup_id == 0) ? pid : lxpnp->lxpr_desc,
+ PTOU(p)->u_comm, stat, ppid, pgpid, spid, psdev, psgid,
0l, 0l, 0l, 0l, 0l, /* flags, minflt, cminflt, majflt, cmajflt */
p->p_utime, p->p_stime, p->p_cutime, p->p_cstime,
pri, nice, p->p_lwpcnt,
@@ -1616,6 +1788,27 @@ lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
lxpr_unlock(p);
}
+/*
+ * lxpr_read_pid_stat(): pid stat file
+ */
+static void
+lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_STAT);
+
+ lxpr_read_stat_common(lxpnp, uiobuf, 0);
+}
+
+/*
+ * lxpr_read_pid_tid_stat(): pid stat file
+ */
+static void
+lxpr_read_pid_tid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_TID_STAT);
+ lxpr_read_stat_common(lxpnp, uiobuf, lxpnp->lxpr_desc);
+}
+
/* ARGSUSED */
static void
lxpr_read_net_arp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
@@ -3588,11 +3781,16 @@ lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
vap->va_nlink = PIDDIRFILES;
vap->va_size = PIDDIRFILES * LXPR_SDSIZE;
break;
+ case LXPR_PID_TASK_IDDIR:
+ vap->va_nlink = TIDDIRFILES;
+ vap->va_size = TIDDIRFILES * LXPR_SDSIZE;
+ break;
case LXPR_SELF:
vap->va_uid = crgetruid(curproc->p_cred);
vap->va_gid = crgetrgid(curproc->p_cred);
break;
case LXPR_PID_FD_FD:
+ case LXPR_PID_TID_FD_FD:
/*
* Restore VLNK type for lstat-type activity.
* See lxpr_readlink for more details.
@@ -3636,6 +3834,8 @@ lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
case LXPR_PID_ROOTDIR:
case LXPR_PID_FDDIR:
case LXPR_PID_FD_FD:
+ case LXPR_PID_TID_FDDIR:
+ case LXPR_PID_TID_FD_FD:
if ((tp = lxpr_lock(lxpnp->lxpr_pid)) == NULL)
return (ENOENT);
if (tp != curproc && secpolicy_proc_access(cr) != 0 &&
@@ -3779,6 +3979,131 @@ lxpr_lookup_piddir(vnode_t *dp, char *comp)
}
/*
+ * Lookup one of the process's task ID's.
+ */
+static vnode_t *
+lxpr_lookup_taskdir(vnode_t *dp, char *comp)
+{
+ lxpr_node_t *dlxpnp = VTOLXP(dp);
+ lxpr_node_t *lxpnp;
+ proc_t *p;
+ pid_t real_pid;
+ uint_t tid;
+ int c;
+ kthread_t *t;
+
+ ASSERT(dlxpnp->lxpr_type == LXPR_PID_TASKDIR);
+
+ /*
+ * convert the string rendition of the filename to a thread ID
+ */
+ tid = 0;
+ while ((c = *comp++) != '\0') {
+ int otid;
+ if (c < '0' || c > '9')
+ return (NULL);
+
+ otid = tid;
+ tid = 10 * tid + c - '0';
+ /* integer overflow */
+ if (tid / 10 != otid)
+ return (NULL);
+ }
+
+ /*
+ * get the proc to work with and lock it
+ */
+ real_pid = get_real_pid(dlxpnp->lxpr_pid);
+ p = lxpr_lock(real_pid);
+ if ((p == NULL))
+ return (NULL);
+
+ /*
+ * If the process is a zombie or system process
+ * it can't have any threads.
+ */
+ if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas)) {
+ lxpr_unlock(p);
+ return (NULL);
+ }
+
+ t = lxpr_get_thread(p, tid);
+ if (t == NULL) {
+ lxpr_unlock(p);
+ return (NULL);
+ }
+ thread_unlock(t);
+
+ /*
+ * Allocate and fill in a new lx /proc taskid node.
+ * Instead of the last arg being a fd, it is a tid.
+ */
+ lxpnp = lxpr_getnode(dp, LXPR_PID_TASK_IDDIR, p, tid);
+ dp = LXPTOV(lxpnp);
+ ASSERT(dp != NULL);
+ lxpr_unlock(p);
+ return (dp);
+}
+
+/*
+ * Lookup one of the process's task ID's.
+ */
+static vnode_t *
+lxpr_lookup_task_tid_dir(vnode_t *dp, char *comp)
+{
+ lxpr_node_t *dlxpnp = VTOLXP(dp);
+ lxpr_node_t *lxpnp;
+ proc_t *p;
+ pid_t real_pid;
+ kthread_t *t;
+ int i;
+
+ ASSERT(dlxpnp->lxpr_type == LXPR_PID_TASK_IDDIR);
+
+ /*
+ * get the proc to work with and lock it
+ */
+ real_pid = get_real_pid(dlxpnp->lxpr_pid);
+ p = lxpr_lock(real_pid);
+ if ((p == NULL))
+ return (NULL);
+
+ /*
+ * If the process is a zombie or system process
+ * it can't have any threads.
+ */
+ if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas)) {
+ lxpr_unlock(p);
+ return (NULL);
+ }
+
+ /* need to confirm tid is still there */
+ t = lxpr_get_thread(p, dlxpnp->lxpr_desc);
+ if (t == NULL) {
+ lxpr_unlock(p);
+ return (NULL);
+ }
+ thread_unlock(t);
+
+ /*
+ * allocate and fill in the new lx /proc taskid dir node
+ */
+ for (i = 0; i < TIDDIRFILES; i++) {
+ if (strcmp(tiddir[i].d_name, comp) == 0) {
+ lxpnp = lxpr_getnode(dp, tiddir[i].d_type, p,
+ dlxpnp->lxpr_desc);
+ dp = LXPTOV(lxpnp);
+ ASSERT(dp != NULL);
+ lxpr_unlock(p);
+ return (dp);
+ }
+ }
+
+ lxpr_unlock(p);
+ return (NULL);
+}
+
+/*
* Lookup one of the process's open files.
*/
static vnode_t *
@@ -3794,7 +4119,8 @@ lxpr_lookup_fddir(vnode_t *dp, char *comp)
uf_entry_t *ufp;
uf_info_t *fip;
- ASSERT(dlxpnp->lxpr_type == LXPR_PID_FDDIR);
+ ASSERT(dlxpnp->lxpr_type == LXPR_PID_FDDIR ||
+ dlxpnp->lxpr_type == LXPR_PID_TID_FDDIR);
/*
* convert the string rendition of the filename
@@ -4326,6 +4652,189 @@ lxpr_readdir_netdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
}
static int
+lxpr_readdir_taskdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
+{
+ /* bp holds one dirent64 structure */
+ longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
+ dirent64_t *dirent = (dirent64_t *)bp;
+ ssize_t oresid; /* save a copy for testing later */
+ ssize_t uresid;
+ off_t uoffset;
+ int error;
+ int ceof;
+ proc_t *p;
+ int tiddirsize = -1;
+ int tasknum;
+ pid_t real_pid;
+ kthread_t *t;
+
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_TASKDIR);
+
+ oresid = uiop->uio_resid;
+
+ real_pid = get_real_pid(lxpnp->lxpr_pid);
+ p = lxpr_lock(real_pid);
+
+ /* can't read its contents if it died */
+ if (p == NULL) {
+ return (ENOENT);
+ }
+ if (p->p_stat == SIDL) {
+ lxpr_unlock(p);
+ return (ENOENT);
+ }
+
+ if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas))
+ tiddirsize = 0;
+
+ /*
+ * Drop p_lock, but keep the process P_PR_LOCK'd to prevent it from
+ * going away while we iterate over its threads.
+ */
+ mutex_exit(&p->p_lock);
+
+ if (tiddirsize == -1)
+ tiddirsize = p->p_lwpcnt;
+
+ /* Do the fixed entries (in this case just "." & "..") */
+ error = lxpr_readdir_common(lxpnp, uiop, &ceof, 0, 0);
+
+ /* Finished if we got an error or if we couldn't do all the table */
+ if (error != 0 || ceof == 0)
+ goto out;
+
+ if ((t = p->p_tlist) == NULL) {
+ if (eofp != NULL)
+ *eofp = 1;
+ goto out;
+ }
+
+ /* clear out the dirent buffer */
+ bzero(bp, sizeof (bp));
+
+ /*
+ * Loop until user's request is satisfied or until all thread's have
+ * been returned.
+ */
+ for (tasknum = 0; (uresid = uiop->uio_resid) > 0; tasknum++) {
+ int i;
+ int reclen;
+ int len;
+ uint_t emul_tid;
+ lx_lwp_data_t *lwpd;
+
+ uoffset = uiop->uio_offset;
+
+ /*
+ * Stop at the end of the thread list
+ */
+ i = (uoffset / LXPR_SDSIZE) - 2;
+ if (i >= tiddirsize) {
+ if (eofp) {
+ *eofp = 1;
+ }
+ goto out;
+ }
+
+ if (i != tasknum)
+ goto next;
+
+ lwpd = ttolxlwp(t);
+ if (lwpd == NULL) {
+ emul_tid = t->t_tid;
+ } else {
+ emul_tid = lwpd->br_pid;
+ /*
+ * Convert pid to Linux default of 1 if we're the
+ * zone's init.
+ */
+ if (emul_tid == curproc->p_zone->zone_proc_initpid)
+ emul_tid = 1;
+ }
+
+ dirent->d_ino = lxpr_inode(LXPR_PID_TASK_IDDIR, lxpnp->lxpr_pid,
+ emul_tid);
+ len = snprintf(dirent->d_name, LXPNSIZ, "%d", emul_tid);
+ ASSERT(len < LXPNSIZ);
+ reclen = DIRENT64_RECLEN(len);
+
+ dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
+ dirent->d_reclen = (ushort_t)reclen;
+
+ if (reclen > uresid) {
+ /*
+ * Error if no entries have been returned yet.
+ */
+ if (uresid == oresid)
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * uiomove() updates both uiop->uio_resid and uiop->uio_offset
+ * by the same amount. But we want uiop->uio_offset to change
+ * in increments of LXPR_SDSIZE, which is different from the
+ * number of bytes being returned to the user. So we set
+ * uiop->uio_offset separately, in the increment of this for
+ * the loop, ignoring what uiomove() does.
+ */
+ if ((error = uiomove((caddr_t)dirent, reclen, UIO_READ,
+ uiop)) != 0)
+ goto out;
+
+next:
+ uiop->uio_offset = uoffset + LXPR_SDSIZE;
+
+ if ((t = t->t_forw) == p->p_tlist) {
+ if (eofp != NULL)
+ *eofp = 1;
+ goto out;
+ }
+ }
+
+ if (eofp != NULL)
+ *eofp = 0;
+
+out:
+ mutex_enter(&p->p_lock);
+ lxpr_unlock(p);
+ return (error);
+}
+
+static int
+lxpr_readdir_task_tid_dir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
+{
+ proc_t *p;
+ pid_t real_pid;
+ kthread_t *t;
+
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_TASK_IDDIR);
+
+ mutex_enter(&pidlock);
+
+ real_pid = get_real_pid(lxpnp->lxpr_pid);
+ p = prfind(real_pid);
+
+ /* can't read its contents if it died */
+ if (p == NULL || p->p_stat == SIDL) {
+ mutex_exit(&pidlock);
+ return (ENOENT);
+ }
+
+ mutex_exit(&pidlock);
+
+ /* need to confirm tid is still there */
+ t = lxpr_get_thread(p, lxpnp->lxpr_desc);
+ if (t == NULL) {
+ /* we can't find this specific thread */
+ return (NULL);
+ }
+ thread_unlock(t);
+
+ return (lxpr_readdir_common(lxpnp, uiop, eofp, tiddir, TIDDIRFILES));
+}
+
+static int
lxpr_readdir_fddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
{
/* bp holds one dirent64 structure */
@@ -4340,7 +4849,8 @@ lxpr_readdir_fddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
int fddirsize = -1;
uf_info_t *fip;
- ASSERT(lxpnp->lxpr_type == LXPR_PID_FDDIR);
+ ASSERT(lxpnp->lxpr_type == LXPR_PID_FDDIR ||
+ lxpnp->lxpr_type == LXPR_PID_TID_FDDIR);
oresid = uiop->uio_resid;