vz extension contains OpenVZ specific commands:
vzlist shows list of OpenVZ containers,
vzps shows all tasks executed inside of specified container,
ctid shows ContainerID of given task.
Signed-off-by: Vasily Averin <vvs(a)parallels.com>
---
extensions/vz.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 345 insertions(+)
create mode 100644 extensions/vz.c
diff --git a/extensions/vz.c b/extensions/vz.c
new file mode 100644
index 0000000..f48d428
--- /dev/null
+++ b/extensions/vz.c
@@ -0,0 +1,345 @@
+/* vz.c - crash extension for OpenVZ containers
+ *
+ * Copyright (C) 2015 Vasily Averin
+ * Copyright (C) 2015 Parallels IP Holdings GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "defs.h"
+
+#define VZ_MEMBER_OFFSET_INIT(X,Y,Z) (vz_offset_table.X=MEMBER_OFFSET(Y,Z))
+#define VZ_OFFSET(X) (OFFSET_verify(vz_offset_table.X, (char *)__FUNCTION__, __FILE__,
__LINE__, #X))
+#define VZ_INIT 0x1
+
+struct vz_offset_table {
+ long task_veinfo;
+ long veinfo_ve;
+ long ve_veid;
+ long ve_nsproxy;
+ long nsproxy_pidns;
+ long pidns_init;
+};
+
+static struct vz_offset_table vz_offset_table = { 0 };
+static int init_flags = 0;
+static int id_size;
+
+void vz_init(void);
+void vz_fini(void);
+
+static ulong
+ve_to_task(ulong ve)
+{
+ ulong ns, pidns, task;
+
+ readmem(ve + VZ_OFFSET(ve_nsproxy), KVADDR, &ns,
+ sizeof(ulong), "ve_struct.ve_ns", FAULT_ON_ERROR);
+ readmem(ns + VZ_OFFSET(nsproxy_pidns), KVADDR, &pidns,
+ sizeof(ulong), "nsproxy.ve_pidns", FAULT_ON_ERROR);
+ readmem(pidns + VZ_OFFSET(pidns_init), KVADDR, &task,
+ sizeof(ulong), "pid_namespace.child_reaper", FAULT_ON_ERROR);
+
+ return task;
+}
+
+#define VZLIST_HEADER \
+" CTID VE_STRUCT TASK PID COMM\n"
+
+static void
+show_container(ulong ve, ulong ctid, ulong flag)
+{
+ ulong task;
+ struct task_context *tc;
+
+ task = ve_to_task(ve);
+ tc = task_to_context(task);
+
+ if (!(flag & PS_NO_HEADER))
+ fprintf(fp, VZLIST_HEADER);
+
+ fprintf(fp, "%9ld %16lx %16lx %6ld %s\n",
+ ctid, ve, tc->task, tc->pid, tc->comm);
+ return;
+}
+
+static void
+show_containers(ulong ctid)
+{
+ struct list_data list_data, *ld;
+ ulong ve, id, flag = 0;
+ int i, cnt;
+
+ ld = &list_data;
+ BZERO(ld, sizeof(struct list_data));
+ ld->flags |= LIST_ALLOCATE;
+
+ ld->start = ld->end = symbol_value("ve_list_head");
+ ld->list_head_offset = 0;
+
+ cnt = do_list(ld);
+
+ for (i = 1; i < cnt; i++) {
+ id = 0;
+ ve = ld->list_ptr[i];
+ readmem(ve + VZ_OFFSET(ve_veid), KVADDR, &id,
+ id_size, "ve_struct.veid", FAULT_ON_ERROR);
+ if ((ctid == -1) || ctid == id) {
+ show_container(ve, id, flag);
+ flag = PS_NO_HEADER;
+ }
+ }
+ return;
+}
+
+void
+cmd_vzlist(void)
+{
+ int c;
+ ulong ctid = -1;
+
+ while ((c = getopt(argcnt, args, "E:")) != EOF) {
+ switch(c)
+ {
+ case 'E':
+ ctid = stol(optarg, FAULT_ON_ERROR, NULL);
+ break;
+ default:
+ argerrs++;
+ break;
+ }
+ }
+ if (argerrs) {
+ cmd_usage(pc->curcmd, SYNOPSIS);
+ return;
+ }
+
+ show_containers(ctid);
+ return;
+}
+
+char *help_vzlist[] = {
+"vzlist",
+"shows list of runnig OpenVZ containers",
+"[-E CTID]",
+"If no argument is entered, command shows IDs of all running containers\n",
+" -E Container ID",
+"\nEXAMPLES",
+"%s> vzlist",
+" CTID VE_STRUCT TASK PID COMM",
+" 121 ffff8801491e7000 ffff8801493d0ff0 95990 init",
+" 123 ffff880135a37000 ffff8803fb0a3470 95924 init",
+" 321 ffff88045a778000 ffff880400616300 95923 init",
+" 700 ffff88019ddae000 ffff88019ddd4fb0 95882 init",
+" 503 ffff88045a84e800 ffff8803c3c782c0 95902 init",
+" 122 ffff8804004ea000 ffff88045612afb0 95886 init",
+" 600 ffff88016e467000 ffff880459d653f0 95885 init",
+" 0 ffffffff81aaa220 ffff88045e530b30 1 init",
+NULL
+};
+
+static ulong
+task_to_ctid(ulong task)
+{
+ ulong veinfo, ve, ctid = 0;
+
+ veinfo = task + VZ_OFFSET(task_veinfo);
+ readmem(veinfo + VZ_OFFSET(veinfo_ve), KVADDR, &ve,
+ sizeof(ulong), "ve_task_info.exec_env", FAULT_ON_ERROR);
+ readmem(ve + VZ_OFFSET(ve_veid), KVADDR, &ctid,
+ id_size, "ve_struct.veid", FAULT_ON_ERROR);
+
+ return ctid;
+}
+
+static void
+show_ctid(struct task_context *tc, ulong flag)
+{
+ ulong ctid;
+
+ ctid = task_to_ctid(tc->task);
+ if (!(flag & PS_NO_HEADER))
+ fprintf(fp, " CTID PID TASK COMM\n");
+
+ fprintf(fp, "%9ld %6ld %16lx %s\n",
+ ctid, tc->pid, tc->task, tc->comm);
+ return;
+}
+
+void
+cmd_ctid(void)
+{
+ ulong value, flag = 0;
+ struct task_context *tc;
+ int c;
+
+ while ((c = getopt(argcnt, args, "")) != EOF) {
+ switch(c)
+ {
+ default:
+ cmd_usage(pc->curcmd, SYNOPSIS);
+ return;
+ }
+ }
+
+ if (!args[optind]) {
+ tc = task_to_context(CURRENT_TASK());
+ show_ctid(tc, flag);
+ }
+ while (args[optind]) {
+ switch (str_to_context(args[optind], &value, &tc))
+ {
+ case STR_PID:
+ case STR_TASK:
+ break;
+ case STR_INVALID:
+ error(INFO, "invalid task or pid value: %s\n",
+ args[optind]);
+ default:
+ argerrs++;
+ break;
+ }
+ if (argerrs)
+ break;
+ show_ctid(tc, flag);
+ flag = PS_NO_HEADER;
+ optind++;
+ }
+ if (argerrs)
+ cmd_usage(pc->curcmd, SYNOPSIS);
+
+ return;
+}
+
+char *help_ctid[] = {
+"ctid",
+"shows Container ID of given tasks",
+"[task|pid]",
+" If no argument is entered, command shows CTID of current task",
+"\nEXAMPLES",
+"%s> ctid 99583",
+" CTID PID TASK COMM",
+" 121 99583 ffff880203e56f30 httpd",
+NULL
+};
+
+static void
+show_vzps(ulong ctid)
+{
+ struct task_context *tc;
+ ulong flag;
+ int i;
+
+ tc = FIRST_CONTEXT();
+ for (i = 0; i < RUNNING_TASKS(); i++, tc++) {
+ ulong id = task_to_ctid(tc->task);
+ if ((ctid == -1) || (ctid == id)) {
+ show_ctid(tc, flag);
+ flag = PS_NO_HEADER;
+ }
+ }
+ return;
+}
+
+void
+cmd_vzps(void)
+{
+ ulong ctid = -1;
+ int c;
+
+ while ((c = getopt(argcnt, args, "E:")) != EOF) {
+ switch(c)
+ {
+ case 'E':
+ ctid = stol(optarg, FAULT_ON_ERROR, NULL);
+ break;
+ default:
+ argerrs++;
+ break;
+ }
+ }
+ if (argerrs)
+ cmd_usage(pc->curcmd, SYNOPSIS);
+
+ show_vzps(ctid);
+ return;
+}
+
+char *help_vzps[] = {
+"vzps",
+"shows list of tasks related to specified CTID",
+" [ -E CTID]",
+" If no argument is entered, command shows CTID for all processes\n",
+"\nEXAMPLES",
+"%s> vzps -E 121",
+" CTID PID TASK COMM",
+" 121 95990 ffff8801493d0ff0 init",
+" 121 95996 ffff8803c3e3b0f0 kthreadd/121",
+" 121 95997 ffff8803cd3aacb0 khelper/121",
+" 121 97267 ffff880405e4b2f0 udevd",
+" 121 99341 ffff8803c3fd2440 syslogd",
+" 121 99404 ffff880405e0c2c0 klogd",
+" 121 99424 ffff8803fb0f68c0 sshd",
+" 121 99445 ffff8801493d0500 xinetd",
+" 121 99557 ffff8804599f9230 sendmail",
+" 121 99568 ffff8804591b00c0 sendmail",
+" 121 99583 ffff880203e56f30 httpd",
+" 121 99594 ffff88016e4e01c0 crond",
+" 121 99614 ffff8803fb26cf70 xfs",
+" 121 99624 ffff88045a6ce2c0 saslauthd",
+" 121 99625 ffff8801ce134ff0 saslauthd",
+" 121 248691 ffff88040e2ee9c0 httpd",
+NULL
+};
+
+static struct command_table_entry command_table[] = {
+ { "vzlist", cmd_vzlist, help_vzlist, 0},
+ { "ctid", cmd_ctid, help_ctid, 0},
+ { "vzps", cmd_vzps, help_vzps, 0},
+ { NULL },
+};
+
+void __attribute__((constructor))
+vz_init(void)
+{
+ if (init_flags & VZ_INIT)
+ return;
+
+ if (!symbol_exists("ve_list_head")) {
+ fprintf(fp, "vz commands only work on OpenVZ kernels\n");
+ return;
+ }
+ init_flags |= VZ_INIT;
+
+ BNEG(&vz_offset_table, sizeof(vz_offset_table));
+
+ if (STRUCT_EXISTS("ve_task_info")) {
+ VZ_MEMBER_OFFSET_INIT(task_veinfo,
+ "task_struct", "ve_task_info");
+ VZ_MEMBER_OFFSET_INIT(veinfo_ve, "ve_task_info", "exec_env");
+ }
+ if (STRUCT_EXISTS("ve_struct")) {
+ VZ_MEMBER_OFFSET_INIT(ve_veid, "ve_struct", "veid");
+ VZ_MEMBER_OFFSET_INIT(ve_nsproxy, "ve_struct", "ve_ns");
+ id_size = MEMBER_SIZE("ve_struct", "veid");
+ }
+ if (STRUCT_EXISTS("nsproxy")) {
+ VZ_MEMBER_OFFSET_INIT(nsproxy_pidns, "nsproxy", "pid_ns");
+ }
+ if (STRUCT_EXISTS("pid_namespace"))
+ VZ_MEMBER_OFFSET_INIT(pidns_init,
+ "pid_namespace", "child_reaper");
+
+ register_extension(command_table);
+}
+
+void __attribute__((destructor))
+vz_fini(void) { }
--
1.7.12.4