Hello Dave,
I have changed the command according to your suggestion. But I haven't
got any SUSE at hand, so the problems with SLES9 may need a bit of time
to get fixed.
I send the mail together with "ipcs.c" file which hasn't fix the
problems of SLES9. Later, I will focus on it. Once the problems are
fixed, I will resend the code again.
--
--
Regards
Qiao Nuohan
/* ipcs.c - provide information on ipc facilities
*
* Copyright (C) 2012 FUJITSU LIMITED
* Auther: Qiao Nuohan <qiaonuohan@xxxxxxxxxxxxxx>
*
* 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" /* From the crash source top-level directory */
#define SPECIFIED_NOTHING 0x0
#define SPECIFIED_ID 0x1
#define SPECIFIED_ADDR 0x2
#define IPCS_INIT 0x1
#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
#define MAX_ID_MASK (MAX_ID_BIT - 1)
#define SHM_DEST 01000
#define SHM_LOCKED 02000
#define IPCS_MEMBER_OFFSET_INIT(X, Y, Z) (ipcs_offset_table.X = MEMBER_OFFSET(Y, Z))
#define IPCS_ANON_MEMBER_OFFSET_INIT(X, Y, Z) (ipcs_offset_table.X = ANON_MEMBER_OFFSET(Y, Z))
#define IPCS_STRUCT_SIZE_INIT(X, Y) (ipcs_size_table.X = STRUCT_SIZE(Y))
#define IPCS_OFFSET(X) (OFFSET_verify(ipcs_offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define IPCS_SIZE(X) (SIZE_verify(ipcs_size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define IPCS_INVALID_MEMBER(X) (ipcs_offset_table.X == INVALID_OFFSET)
#define IPCS_INVALID_SIZE(X) (ipcs_size_table.X == -1)
#define IPCS_VALID_SIZE(X) (ipcs_size_table.X >= 0)
#define IPCS_VALID_STRUCT(X) (ipcs_size_table.X >= 0)
#define IPCS_VALID_MEMBER(X) (ipcs_offset_table.X >= 0)
/*
* struct declaration
*/
struct ipcs_offset_table {
long file_f_op;
long file_private_data;
long hstate_order;
long hugetlbfs_sb_info_hstate;
long idr_layer_ary;
long idr_layer_layer;
long idr_layers;
long idr_top;
long ipc_id_ary_p;
long ipc_ids_entries;
long ipc_ids_max_id;
long ipc_ids_ipcs_idr;
long ipc_ids_in_use;
long ipc_namespace_ids;
long kern_ipc_perm_deleted;
long kern_ipc_perm_key;
long kern_ipc_perm_mode;
long kern_ipc_perm_uid;
long kern_ipc_perm_id;
long kern_ipc_perm_seq;
long nsproxy_ipc_ns;
long shmem_inode_info_swapped;
long shmem_inode_info_vfs_inode;
long shm_file_data_file;
long shmid_kernel_shm_file;
long shmid_kernel_shm_nattch;
long shmid_kernel_shm_perm;
long shmid_kernel_shm_segsz;
long shmid_kernel_id;
long sem_array_sem_perm;
long sem_array_sem_id;
long sem_array_sem_nsems;
long msg_queue_q_perm;
long msg_queue_q_id;
long msg_queue_q_cbytes;
long msg_queue_q_qnum;
long super_block_s_fs_info;
};
struct ipcs_size_table {
long hstate;
long ipc_ids;
long shmid_kernel;
long sem_array;
long msg_queue;
};
struct shm_info {
ulong shmid_kernel;
int key;
int shmid;
ulong rss;
ulong swap;
unsigned int uid;
unsigned int perms;
ulong bytes;
ulong nattch;
ulong shm_inode;
int deleted;
};
struct sem_info {
ulong sem_array;
int key;
int semid;
unsigned int uid;
unsigned int perms;
ulong nsems;
int deleted;
};
struct msg_info {
ulong msg_queue;
int key;
int msgid;
unsigned int uid;
unsigned int perms;
ulong bytes;
ulong messages;
int deleted;
};
struct ipcs_table {
int idr_bits;
ulong init_flags;
ulong hugetlbfs_f_op_addr;
ulong shm_f_op_addr;
ulong shm_f_op_huge_addr;
int use_shm_f_op;
int seq_multiplier;
};
/*
* function declaration
*/
int _init(void);
int _fini(void);
void cmd_ipcs(void); /* Declare the commands and their help data. */
char *help_ipcs[];
static void ipcs_init(void);
static void dump_shared_memory(int, ulong, int);
static void dump_semaphore_arrays(int, ulong, int);
static void dump_message_queues(int, ulong, int);
static void ipc_search_idr(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
static void ipc_search_array(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
static ulong idr_find(ulong, int);
static int dump_shm_info(ulong, int, ulong, int, int);
static int dump_sem_info(ulong, int, ulong, int, int);
static int dump_msg_info(ulong, int, ulong, int, int);
static void get_shm_info(struct shm_info *, ulong, int);
static void get_sem_info(struct sem_info *, ulong, int);
static void get_msg_info(struct msg_info *, ulong, int);
static void add_rss_swap(ulong, int, ulong *, ulong *);
static int is_file_hugepages(ulong);
static struct command_table_entry command_table[] = {
{ "ipcs", cmd_ipcs, help_ipcs, 0 }, /* One or more commands, */
{ NULL } /* terminated by NULL, */
};
/*
* global data
*/
static struct ipcs_offset_table ipcs_offset_table = { 0 };
static struct ipcs_size_table ipcs_size_table = { 0 };
static struct ipcs_table ipcs_table = { 0 };
int
_init(void) /* Register the command set. */
{
register_extension(command_table);
return 1;
}
/*
* The _fini() function is called if the shared object is unloaded.
* If desired, perform any cleanups here.
*/
int
_fini(void)
{
return 1;
}
static void
ipcs_init(void)
{
if (ipcs_table.init_flags & IPCS_INIT) {
return;
}
ipcs_table.init_flags |= IPCS_INIT;
IPCS_MEMBER_OFFSET_INIT(file_f_op, "file", "f_op");
IPCS_MEMBER_OFFSET_INIT(file_private_data, "file", "private_data");
IPCS_MEMBER_OFFSET_INIT(hstate_order, "hstate", "order");
IPCS_MEMBER_OFFSET_INIT(hugetlbfs_sb_info_hstate, "hugetlbfs_sb_info",
"hstate");
IPCS_MEMBER_OFFSET_INIT(idr_layers, "idr", "layers");
IPCS_MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer");
IPCS_MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary");
IPCS_MEMBER_OFFSET_INIT(idr_top, "idr", "top");
IPCS_MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_in_use, "ipc_ids", "in_use");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_ipcs_idr, "ipc_ids", "ipcs_idr");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_ids, "ipc_namespace", "ids");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_key, "kern_ipc_perm", "key");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_id, "kern_ipc_perm", "id");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_uid, "kern_ipc_perm", "uid");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_mode, "kern_ipc_perm", "mode");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_deleted, "kern_ipc_perm",
"deleted");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_seq, "kern_ipc_perm", "seq");
IPCS_MEMBER_OFFSET_INIT(nsproxy_ipc_ns, "nsproxy", "ipc_ns");
IPCS_MEMBER_OFFSET_INIT(shmem_inode_info_vfs_inode, "shmem_inode_info",
"vfs_inode");
IPCS_MEMBER_OFFSET_INIT(shmem_inode_info_swapped, "shmem_inode_info",
"swapped");
if (IPCS_INVALID_MEMBER(shmem_inode_info_swapped))
IPCS_ANON_MEMBER_OFFSET_INIT(shmem_inode_info_swapped,
"shmem_inode_info", "swapped");
IPCS_MEMBER_OFFSET_INIT(shm_file_data_file, "shm_file_data", "file");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_perm, "shmid_kernel",
"shm_perm");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_segsz, "shmid_kernel",
"shm_segsz");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_nattch, "shmid_kernel",
"shm_nattch");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_file, "shmid_kernel",
"shm_file");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_id, "shmid_kernel", "id");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_perm, "sem_array", "sem_perm");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_id, "sem_array", "sem_id");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_nsems, "sem_array", "sem_nsems");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_perm, "msg_queue", "q_perm");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_id, "msg_queue", "q_id");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_cbytes, "msg_queue", "q_cbytes");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_qnum, "msg_queue", "q_qnum");
IPCS_MEMBER_OFFSET_INIT(super_block_s_fs_info, "super_block",
"s_fs_info");
/*
* struct size
*/
IPCS_STRUCT_SIZE_INIT(ipc_ids, "ipc_ids");
IPCS_STRUCT_SIZE_INIT(shmid_kernel, "shmid_kernel");
IPCS_STRUCT_SIZE_INIT(sem_array, "sem_array");
IPCS_STRUCT_SIZE_INIT(msg_queue, "msg_queue");
IPCS_STRUCT_SIZE_INIT(hstate, "hstate");
if (symbol_exists("hugetlbfs_file_operations"))
ipcs_table.hugetlbfs_f_op_addr =
symbol_value("hugetlbfs_file_operations");
if (symbol_exists("is_file_shm_hugepages")) {
ipcs_table.use_shm_f_op = TRUE;
ipcs_table.shm_f_op_addr =
symbol_value("shm_file_operations");
if (symbol_exists("shm_file_operations_huge")) {
ipcs_table.shm_f_op_huge_addr =
symbol_value("shm_file_operations_huge");
} else {
ipcs_table.shm_f_op_huge_addr = -1;
}
} else {
ipcs_table.use_shm_f_op = FALSE;
ipcs_table.shm_f_op_addr = -1;
ipcs_table.shm_f_op_huge_addr = -1;
}
if (BITS32())
ipcs_table.idr_bits = 5;
else if (BITS64())
ipcs_table.idr_bits = 6;
else
error(FATAL, "machdep->bits is not 32 or 64");
ipcs_table.seq_multiplier = 32768;
}
/*
* Arguments are passed to the command functions in the global args[argcnt]
* array. See getopt(3) for info on dash arguments. Check out defs.h and
* other crash commands for usage of the myriad of utility routines available
* to accomplish what your task.
*/
void
cmd_ipcs(void)
{
int show_summary, specified;
ulong specified_value;
int c;
int shm, sem, msg, verbose;
specified_value = SPECIFIED_NOTHING;
show_summary = 0;
specified = 0;
shm = 0;
sem = 0;
msg = 0;
verbose = 0;
while ((c = getopt(argcnt, args, "smMqi:")) != EOF) {
switch(c) {
case 'i':
specified = SPECIFIED_ID;
specified_value =
dtol(optarg, FAULT_ON_ERROR, NULL);
break;
case 's':
sem = 1;
break;
case 'm':
shm = 1;
break;
case 'M':
shm = 1;
verbose = 1;
break;
case 'q':
msg = 1;
break;
default:
cmd_usage(pc->curcmd, SYNOPSIS);;
return;
}
}
if (args[optind]) {
if (specified != SPECIFIED_NOTHING)
error(FATAL, "addr is invalid with -i option\n");
specified = SPECIFIED_ADDR;
specified_value = htol(args[optind], FAULT_ON_ERROR, NULL);
if (args[++optind])
error(FATAL, "multiple addr is not supported\n");
}
if (specified != SPECIFIED_NOTHING && (shm + sem + msg) != 1) {
error(INFO,
"specified one of -s -m -M -q together with -i option/addr\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
if (THIS_KERNEL_VERSION < LINUX(2,6,0))
command_not_supported();
ipcs_init();
if (!shm && !sem && !msg)
shm = sem = msg = 1;
if (shm)
dump_shared_memory(specified, specified_value, verbose);
if (sem)
dump_semaphore_arrays(specified, specified_value, 0);
if (msg)
dump_message_queues(specified, specified_value, 0);
}
char *help_ipcs[] = {
"ipcs", /* command name */
"provide information on ipc facilities", /* short description */
"[-smMq] [-i id | addr]", /* argument synopsis, or " " if none */
" This command provides information on the ipc facilities. Without",
" specified one of -s -m -q -M, the command will show all of three",
" facilities.",
" ",
" -s shows semaphore arrays",
" -m shows shared memory segments",
" -M shows shared memory segments with some detailed",
" information",
" -q shows message queue",
" -i id it allows a specific resource id to be specified, and the",
" information on this id will be printed",
" addr it allows a specific resource's address to be specified,",
" the address is listed by ipcs command in the first column",
"\nEXAMPLE",
" display all ipc facilities:\n",
" %s> ipcs",
" ------ Shared Memory Segments ------",
" SHMID_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff880473a28310 00000000 0 0 666 90000 1 ",
" ffff880473a28490 00000001 32769 0 666 90000 1 ",
" ffff880473a28250 00000002 65538 0 666 90000 1 ",
" ",
" ------ Semaphore Arrays --------",
" SEM_ARRAY KEY SEMID UID PERMS NSEMS ",
" ffff88047200f9d0 0x00000000 0 0 600 1 ",
" ffff88046f826910 0x00000000 32769 0 600 1 ",
" ",
" ------ Message Queues --------",
" MSG_QUEUE KEY MSQID UID PERMS USED-BYTES MESSAGES ",
" (none allocated)",
" ",
" display shared memory with detailed information:\n",
" %s> ipcs -M",
" ------ Shared Memory Segments ------",
" SHMID_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff880473a28310 00000000 0 0 666 90000 1 ",
" PAGES ALLOCATED 22",
" PAGES RESIDENT 1",
" PAGES SWAPPED 0",
" SWAP PERFORMANCE ATTEMPTS 0",
" SWAP PERFORMANCE SUCCESSES 0",
" vfs_inode 0xffff88047239cd98",
" ",
" SHMID_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff880473a28490 00000001 32769 0 666 90000 1 ",
" PAGES ALLOCATED 22",
" PAGES RESIDENT 0",
" PAGES SWAPPED 0",
" SWAP PERFORMANCE ATTEMPTS 0",
" SWAP PERFORMANCE SUCCESSES 0",
" vfs_inode 0xffff88047239c118",
" ",
" SHMID_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff880473a28250 00000002 65538 0 666 90000 1 ",
" PAGES ALLOCATED 22",
" PAGES RESIDENT 1",
" PAGES SWAPPED 0",
" SWAP PERFORMANCE ATTEMPTS 0",
" SWAP PERFORMANCE SUCCESSES 0",
" vfs_inode 0xffff880470503758",
" ",
" display a specified resource in detail with an address\n",
" %s> ipcs -M ffff880473a28250",
" SHMID_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff880473a28250 00000002 65538 0 666 90000 1 ",
" PAGES ALLOCATED 22",
" PAGES RESIDENT 1",
" PAGES SWAPPED 0",
" SWAP PERFORMANCE ATTEMPTS 0",
" SWAP PERFORMANCE SUCCESSES 0",
" vfs_inode 0xffff880470503758",
NULL
};
static void
dump_shared_memory(int specified, ulong specified_value, int verbose)
{
ulong cur_task = CURRENT_TASK();
ulong nsproxy_p, ipc_ns_p;
ulong ipc_ids_p;
void (*ipc_search)(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
int (*dump_shm)(ulong, int, ulong, int, int);
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
char buf6[BUFSIZE];
char buf7[BUFSIZE];
if (specified == SPECIFIED_NOTHING)
fprintf(fp, "------ Shared Memory Segments ------\n");
if (!verbose) {
fprintf(fp, "%s %s %s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=12?12:VADDR_PRLEN,
LJUST, "SHMID_KERNEL"),
mkstring(buf1, 8, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "SHMID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 10, LJUST, "BYTES"),
mkstring(buf6, 6, LJUST, "NATTCH"),
mkstring(buf7, 6, LJUST, "STATUS"));
}
dump_shm = dump_shm_info;
if (IPCS_VALID_MEMBER(kern_ipc_perm_id)) {
ipc_search = ipc_search_idr;
} else {
ipc_search = ipc_search_array;
}
if (symbol_exists("shm_ids")) {
ipc_ids_p = symbol_value("shm_ids");
} else {
readmem(cur_task + OFFSET(task_struct_nsproxy), KVADDR,
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
FAULT_ON_ERROR);
if (!readmem(nsproxy_p + IPCS_OFFSET(nsproxy_ipc_ns), KVADDR,
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
RETURN_ON_ERROR|QUIET))
error(FATAL,
"cannot determine ipc_namespace location!\n");
if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
readmem(ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids) +
sizeof(ulong) * 2, KVADDR, &ipc_ids_p,
sizeof(ulong), "ipc_namespace.ids[2]",
FAULT_ON_ERROR);
else
ipc_ids_p = ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids) +
2 * IPCS_SIZE(ipc_ids);
}
ipc_search(ipc_ids_p, specified, specified_value, dump_shm, verbose);
}
static void
dump_semaphore_arrays(int specified, ulong specified_value, int verbose)
{
ulong cur_task = CURRENT_TASK();
ulong nsproxy_p, ipc_ns_p;
ulong ipc_ids_p;
void (*ipc_search)(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
int (*dump_sem)(ulong, int, ulong, int, int);
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
if(specified == SPECIFIED_NOTHING)
fprintf(fp, "------ Semaphore Arrays --------\n");
fprintf(fp, "%s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
LJUST, "SEM_ARRAY"),
mkstring(buf1, 10, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "SEMID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 10, LJUST, "NSEMS"));
dump_sem = dump_sem_info;
if (IPCS_VALID_MEMBER(kern_ipc_perm_id)) {
ipc_search = ipc_search_idr;
} else {
ipc_search = ipc_search_array;
}
if (symbol_exists("sem_ids")) {
ipc_ids_p = symbol_value("sem_ids");
} else {
readmem(cur_task + OFFSET(task_struct_nsproxy), KVADDR,
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
FAULT_ON_ERROR);
readmem(nsproxy_p + IPCS_OFFSET(nsproxy_ipc_ns), KVADDR,
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
FAULT_ON_ERROR);
if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
readmem(ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids),
KVADDR, &ipc_ids_p, sizeof(ulong),
"ipc_namespace.ids[2]", FAULT_ON_ERROR);
else
ipc_ids_p = ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids);
}
ipc_search(ipc_ids_p, specified, specified_value, dump_sem, verbose);
}
static void
dump_message_queues(int specified, ulong specified_value, int verbose)
{
ulong cur_task = CURRENT_TASK();
ulong nsproxy_p, ipc_ns_p;
ulong ipc_ids_p;
void (*ipc_search)(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
int (*dump_msg)(ulong, int, ulong, int, int);
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
char buf6[BUFSIZE];
if(specified == SPECIFIED_NOTHING)
fprintf(fp, "------ Message Queues --------\n");
fprintf(fp, "%s %s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
LJUST, "MSG_QUEUE"),
mkstring(buf1, 10, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "MSQID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 12, LJUST, "USED-BYTES"),
mkstring(buf6, 12, LJUST, "MESSAGES"));
dump_msg = dump_msg_info;
if (IPCS_VALID_MEMBER(kern_ipc_perm_id)) {
ipc_search = ipc_search_idr;
} else {
ipc_search = ipc_search_array;
}
if (symbol_exists("msg_ids")) {
ipc_ids_p = symbol_value("msg_ids");
} else {
readmem(cur_task + OFFSET(task_struct_nsproxy), KVADDR,
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
FAULT_ON_ERROR);
readmem(nsproxy_p + IPCS_OFFSET(nsproxy_ipc_ns), KVADDR,
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
FAULT_ON_ERROR);
if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
readmem(ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids) +
sizeof(ulong), KVADDR, &ipc_ids_p,
sizeof(ulong), "ipc_namespace.ids[2]",
FAULT_ON_ERROR);
else
ipc_ids_p = ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids) +
IPCS_SIZE(ipc_ids);
}
ipc_search(ipc_ids_p, specified, specified_value, dump_msg, verbose);
}
/*
* if shared memory information is stored in an array, use this function.
*/
static void
ipc_search_array(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)(ulong, int, ulong, int, int), int verbose)
{
ulong entries_p;
int max_id, i;
ulong *array;
int found = 0;
int allocated = 0;
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_entries), KVADDR, &entries_p,
sizeof(ulong), "ipc_ids.entries", FAULT_ON_ERROR);
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_max_id), KVADDR, &max_id,
sizeof(int), "ipc_ids.max_id", FAULT_ON_ERROR);
if (specified ==SPECIFIED_NOTHING && max_id < 0) {
fprintf(fp, "(none allocated)");
return;
}
array = (ulong *)GETBUF(sizeof(ulong *) * (max_id + 1));
if (IPCS_VALID_MEMBER(ipc_id_ary_p))
readmem(entries_p + IPCS_OFFSET(ipc_id_ary_p), KVADDR, array,
sizeof(ulong *) * (max_id + 1), "ipc_id_ary.p",
FAULT_ON_ERROR);
else
readmem(entries_p, KVADDR, array, sizeof(ulong *)*(max_id+1),
"ipc_id array", FAULT_ON_ERROR);
for (i=0; i<=max_id; i++) {
if (array[i] == 0)
continue;
allocated++;
if (fn(array[i], specified, specified_value, i, verbose)) {
found = 1;
break;
}
}
if (specified == SPECIFIED_NOTHING && !allocated)
fprintf(fp, "(none allocated)\n");
if (specified != SPECIFIED_NOTHING && !found)
fprintf(fp, "(none found)\n");
if (!verbose)
fprintf(fp, "\n");
FREEBUF(array);
}
/*
* if shared memory information is stored by using idr, use this function to
* get data.
*/
static void
ipc_search_idr(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)(ulong, int, ulong, int, int), int verbose)
{
int in_use;
ulong ipcs_idr_p;
ulong ipc;
int next_id, total;
int found = 0;
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_in_use), KVADDR, &in_use,
sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
ipcs_idr_p = ipc_ids_p + IPCS_OFFSET(ipc_ids_ipcs_idr);
if (specified == SPECIFIED_NOTHING && !in_use)
fprintf(fp, "(none allocated)\n");
for (total = 0, next_id = 0; total < in_use; next_id++) {
ipc = idr_find(ipcs_idr_p, next_id);
if (ipc == 0)
continue;
total++;
if (fn(ipc, specified, specified_value, next_id, verbose)) {
found = 1;
break;
}
}
if (specified != SPECIFIED_NOTHING && !found)
fprintf(fp, "(none found)\n");
if (!verbose)
fprintf(fp, "\n");
}
/*
* search every idr_layer
*/
static ulong
idr_find(ulong idp, int id)
{
ulong idr_layer_p;
int layer;
int idr_layers;
int n;
int index;
readmem(idp + IPCS_OFFSET(idr_top), KVADDR, &idr_layer_p,
sizeof(ulong), "idr.top", FAULT_ON_ERROR);
if (!idr_layer_p)
return 0;
if (IPCS_VALID_MEMBER(idr_layer_layer)) {
readmem(idr_layer_p + IPCS_OFFSET(idr_layer_layer), KVADDR,
&layer, sizeof(int), "idr_layer.layer",
FAULT_ON_ERROR);
n = (layer + 1) * ipcs_table.idr_bits;
} else {
readmem(idp + IPCS_OFFSET(idr_layers), KVADDR, &idr_layers,
sizeof(int), "idr.layers", FAULT_ON_ERROR);
n = idr_layers * ipcs_table.idr_bits;
}
id &= MAX_ID_MASK;
if (id >= (1 << n))
return 0;
while (n > 0 && idr_layer_p) {
n -= ipcs_table.idr_bits;
index = (id >> n) & ((1 << ipcs_table.idr_bits) - 1);
readmem(idr_layer_p + IPCS_OFFSET(idr_layer_ary) +
sizeof(ulong) * index, KVADDR, &idr_layer_p,
sizeof(ulong), "idr_layer.ary", FAULT_ON_ERROR);
}
return idr_layer_p;
}
static int
dump_shm_info(ulong shp, int specified, ulong specified_value, int id, int verbose)
{
struct shm_info shm_info;
char buf[BUFSIZE];
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
char buf6[BUFSIZE];
char buf7[BUFSIZE];
get_shm_info(&shm_info, shp, id);
if (shm_info.deleted)
return 0;
if ((specified == SPECIFIED_ID && shm_info.shmid == specified_value) ||
(specified == SPECIFIED_ADDR && shm_info.shmid_kernel ==
specified_value) || !specified) {
if (verbose) {
fprintf(fp, "%s %s %s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=12?12:VADDR_PRLEN,
LJUST, "SHMID_KERNEL"),
mkstring(buf1, 8, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "SHMID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 10, LJUST, "BYTES"),
mkstring(buf6, 6, LJUST, "NATTCH"),
mkstring(buf7, 6, LJUST, "STATUS"));
}
fprintf(fp, "%s %08x %-10d %-5d %-5o %-10ld %-6ld %-s %-s\n",
mkstring(buf, VADDR_PRLEN <= 12 ? 12 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)shm_info.shmid_kernel),
shm_info.key,
shm_info.shmid,
shm_info.uid,
shm_info.perms & 0777,
shm_info.bytes,
shm_info.nattch,
shm_info.perms & SHM_DEST ? "dest" : "",
shm_info.perms & SHM_LOCKED ? "locked" : "");
if (verbose) {
fprintf(fp, "PAGES ALLOCATED %ld\n",
(shm_info.bytes+PAGESIZE()-1) >> PAGESHIFT());
fprintf(fp, "PAGES RESIDENT %ld\n",
shm_info.rss);
fprintf(fp, "PAGES SWAPPED %ld\n",
shm_info.swap);
fprintf(fp, "SWAP PERFORMANCE ATTEMPTS %ld\n", 0L);
fprintf(fp, "SWAP PERFORMANCE SUCCESSES %ld\n", 0L);
fprintf(fp, "vfs_inode 0x%lx\n\n",
shm_info.shm_inode);
}
}
if ((specified == SPECIFIED_ID && shm_info.shmid == specified_value) ||
(specified == SPECIFIED_ADDR && shm_info.shmid_kernel ==
specified_value))
return 1;
else
return 0;
}
static int
dump_sem_info(ulong shp, int specified, ulong specified_value, int id, int verbose)
{
struct sem_info sem_info;
char buf[BUFSIZE];
get_sem_info(&sem_info, shp, id);
if (sem_info.deleted)
return 0;
if ((specified == SPECIFIED_ID && sem_info.semid == specified_value) ||
(specified == SPECIFIED_ADDR && sem_info.sem_array ==
specified_value) || !specified) {
fprintf(fp, "%s 0x%08x %-10d %-5d %-5o %-10ld\n",
mkstring(buf, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)sem_info.sem_array),
sem_info.key,
sem_info.semid,
sem_info.uid,
sem_info.perms & 0777,
sem_info.nsems);
}
if ((specified == SPECIFIED_ID && sem_info.semid == specified_value) ||
(specified == SPECIFIED_ADDR && sem_info.sem_array ==
specified_value))
return 1;
else
return 0;
}
static int
dump_msg_info(ulong shp, int specified, ulong specified_value, int id, int verbose)
{
struct msg_info msg_info;
char buf[BUFSIZE];
get_msg_info(&msg_info, shp, id);
if (msg_info.deleted)
return 0;
if ((specified == SPECIFIED_ID && msg_info.msgid == specified_value) ||
(specified == SPECIFIED_ADDR && msg_info.msg_queue ==
specified_value) || !specified) {
fprintf(fp, "%s 0x%08x %-10d %-5d %-5o %-12ld %-12ld\n",
mkstring(buf, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)msg_info.msg_queue),
msg_info.key,
msg_info.msgid,
msg_info.uid,
msg_info.perms & 0777,
msg_info.bytes,
msg_info.messages);
}
if ((specified == SPECIFIED_ID && msg_info.msgid == specified_value) ||
(specified == SPECIFIED_ADDR && msg_info.msg_queue ==
specified_value))
return 1;
else
return 0;
}
static void
get_shm_info(struct shm_info *shm_info, ulong shp, int id)
{
char buf[BUFSIZE];
ulong filep, dentryp, inodep;
shm_info->shmid_kernel = shp - IPCS_OFFSET(shmid_kernel_shm_perm);
//cache shmid_kernel
readmem(shm_info->shmid_kernel, KVADDR, buf, IPCS_SIZE(shmid_kernel),
"shmid_kernel", FAULT_ON_ERROR);
shm_info->key = INT(buf + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(shmid_kernel_id))
shm_info->shmid = INT(buf + IPCS_OFFSET(shmid_kernel_id));
else
shm_info->shmid = INT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
shm_info->uid = UINT(buf + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
shm_info->perms = USHORT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
shm_info->perms = UINT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
shm_info->bytes = ULONG(buf + IPCS_OFFSET(shmid_kernel_shm_segsz));
shm_info->nattch = ULONG(buf + IPCS_OFFSET(shmid_kernel_shm_nattch));
filep = ULONG(buf + IPCS_OFFSET(shmid_kernel_shm_file));
readmem(filep + OFFSET(file_f_dentry), KVADDR, &dentryp, sizeof(ulong),
"file.f_dentry", FAULT_ON_ERROR);
readmem(dentryp + OFFSET(dentry_d_inode), KVADDR, &inodep,
sizeof(ulong), "dentry.d_inode", FAULT_ON_ERROR);
// shm_inode here is the vfs_inode of struct shmem_inode_info
shm_info->shm_inode = inodep;
shm_info->rss = 0;
shm_info->swap = 0;
add_rss_swap(inodep, is_file_hugepages(filep), &shm_info->rss,
&shm_info->swap);
shm_info->deleted = UINT(buf + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_deleted));
}
static void
get_sem_info(struct sem_info *sem_info, ulong shp, int id)
{
char buf[BUFSIZE];
sem_info->sem_array = shp - IPCS_OFFSET(sem_array_sem_perm);
//cache sem_array
readmem(sem_info->sem_array, KVADDR, buf, IPCS_SIZE(sem_array),
"sem_array", FAULT_ON_ERROR);
sem_info->key = INT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(sem_array_sem_id))
sem_info->semid = INT(buf + IPCS_OFFSET(sem_array_sem_id));
else if (IPCS_VALID_MEMBER(kern_ipc_perm_id))
sem_info->semid = INT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
else {
ulong seq;
seq = ULONG(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_seq));
sem_info->semid = ipcs_table.seq_multiplier * seq + id;
}
sem_info->uid = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
sem_info->perms = USHORT(buf +
IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
sem_info->perms = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
sem_info->nsems = ULONG(buf + IPCS_OFFSET(sem_array_sem_nsems));
sem_info->deleted = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_deleted));
}
static void
get_msg_info(struct msg_info *msg_info, ulong shp, int id)
{
char buf[BUFSIZE];
msg_info->msg_queue = shp - IPCS_OFFSET(msg_queue_q_perm);
//cache msg_queue;
readmem(msg_info->msg_queue, KVADDR, buf, IPCS_SIZE(msg_queue),
"msg_queue", FAULT_ON_ERROR);
msg_info->key = INT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(msg_queue_q_id))
msg_info->msgid = INT(buf + IPCS_OFFSET(msg_queue_q_id));
else if (IPCS_VALID_MEMBER(kern_ipc_perm_id))
msg_info->msgid = INT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
else {
ulong seq;
seq = ULONG(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_seq));
msg_info->msgid = ipcs_table.seq_multiplier * seq + id;
}
msg_info->uid = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
msg_info->perms = USHORT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
msg_info->perms = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
msg_info->bytes = ULONG(buf + IPCS_OFFSET(msg_queue_q_cbytes));
msg_info->messages = ULONG(buf + IPCS_OFFSET(msg_queue_q_qnum));
msg_info->deleted = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_deleted));
}
/*
* get rss & swap related to every shared memory, and get the total number of rss
* & swap
*/
static void
add_rss_swap(ulong inode_p, int hugepage, ulong *rss, ulong *swap)
{
unsigned long mapping_p, nr_pages;
readmem(inode_p + OFFSET(inode_i_mapping), KVADDR, &mapping_p,
sizeof(ulong), "inode.i_mapping", FAULT_ON_ERROR);
readmem(mapping_p + OFFSET(address_space_nrpages), KVADDR, &nr_pages,
sizeof(ulong), "address_space.nrpages",
FAULT_ON_ERROR);
if (hugepage) {
unsigned long pages_per_hugepage;
if (IPCS_VALID_SIZE(hstate)) {
unsigned long i_sb_p, hsb_p, hstate_p;
unsigned int order;
readmem(inode_p + OFFSET(inode_i_sb), KVADDR, &i_sb_p,
sizeof(ulong), "inode.i_sb",
FAULT_ON_ERROR);
readmem(i_sb_p + IPCS_OFFSET(super_block_s_fs_info),
KVADDR, &hsb_p, sizeof(ulong),
"super_block.s_fs_info", FAULT_ON_ERROR);
readmem(hsb_p + IPCS_OFFSET(hugetlbfs_sb_info_hstate),
KVADDR, &hstate_p, sizeof(ulong),
"hugetlbfs_sb_info.hstate", FAULT_ON_ERROR);
readmem(hstate_p + IPCS_OFFSET(hstate_order), KVADDR,
&order, sizeof(uint), "hstate.order",
FAULT_ON_ERROR);
pages_per_hugepage = 1 << order;
} else {
unsigned long hpage_shift;
/*
* HPAGE_SHIFT is 21 after commit 83a5101b
* (kernel > 2.6.24)
*/
if (THIS_KERNEL_VERSION > LINUX(2, 6, 24)) {
hpage_shift = 21;
} else {
/*
* HPAGE_SHIFT:
* x86(PAE): 21
* x86(no PAE): 22
* x86_64: 21
*/
if ((machine_type("X86") &&
!(machdep->flags & PAE)))
hpage_shift = 22;
else
hpage_shift = 21;
}
pages_per_hugepage = (1 << hpage_shift) / PAGESIZE();
}
*rss += pages_per_hugepage * nr_pages;
} else {
unsigned long swapped;
*rss += nr_pages;
readmem(inode_p - IPCS_OFFSET(shmem_inode_info_vfs_inode) +
IPCS_OFFSET(shmem_inode_info_swapped), KVADDR,
&swapped, sizeof(ulong), "shmem_inode_info.swapped",
FAULT_ON_ERROR);
*swap += swapped;
}
}
static int
is_file_hugepages(ulong file_p)
{
unsigned long f_op, sfd_p;
again:
readmem(file_p + IPCS_OFFSET(file_f_op), KVADDR, &f_op, sizeof(ulong),
"file.f_op", FAULT_ON_ERROR);
if (f_op == ipcs_table.hugetlbfs_f_op_addr)
return 1;
if (ipcs_table.use_shm_f_op) {
if (ipcs_table.shm_f_op_huge_addr != -1) {
if (f_op == ipcs_table.shm_f_op_huge_addr)
return 1;
} else {
if (f_op == ipcs_table.shm_f_op_addr) {
readmem(file_p +
IPCS_OFFSET(file_private_data),
KVADDR, &sfd_p, sizeof(ulong),
"file.private_data", FAULT_ON_ERROR);
readmem(sfd_p +
IPCS_OFFSET(shm_file_data_file),
KVADDR, &file_p, sizeof(ulong),
"shm_file_data.file", FAULT_ON_ERROR);
goto again;
}
}
}
return 0;
}
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility