mirror of
https://github.com/crash-utility/crash
synced 2025-02-24 01:16:49 +00:00
error where IPCS entries are not displayed because of a faulty read of the "deleted" member of the embedded "kern_ipc_perm" data structure. The "deleted" member was being read as a 4-byte integer, but since it is declared as a "bool" type, only the lowest byte gets set to 1 or 0. Since the structure is not zeroed-out when allocated, stale data may be left in the upper 3 bytes, and the IPCS entry gets rejected. The update is required for Linux 4.11 and greater kernels, which reimplemented the IDR facility to use radix trees in kernel commit 0a835c4f090af2c76fc2932c539c3b32fd21fbbb, titled "Reimplement IDR and IDA using the radix tree". Without the patch, if any IPCS entry exists, the command would fail with the message "ipcs: invalid structure member offset: idr_top" (anderson@redhat.com)
1121 lines
31 KiB
C
1121 lines
31 KiB
C
/* ipcs.c - provide information on ipc facilities
|
|
*
|
|
* Copyright (C) 2012 FUJITSU LIMITED
|
|
* Auther: Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
|
|
*
|
|
* 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
|
|
|
|
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;
|
|
int rt_cnt;
|
|
struct radix_tree_pair *rtp;
|
|
};
|
|
|
|
/*
|
|
* function declaration
|
|
*/
|
|
|
|
static void ipcs_init(void);
|
|
static int dump_shared_memory(int, ulong, int, ulong);
|
|
static int dump_semaphore_arrays(int, ulong, int, ulong);
|
|
static int dump_message_queues(int, ulong, int, ulong);
|
|
static int ipc_search_idr(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
|
|
static int 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 void gather_radix_tree_entries(ulong);
|
|
|
|
/*
|
|
* global data
|
|
*/
|
|
static struct ipcs_table ipcs_table = { 0 };
|
|
|
|
static void
|
|
ipcs_init(void)
|
|
{
|
|
if (ipcs_table.init_flags & IPCS_INIT) {
|
|
return;
|
|
}
|
|
|
|
ipcs_table.init_flags |= IPCS_INIT;
|
|
|
|
MEMBER_OFFSET_INIT(file_f_op, "file", "f_op");
|
|
MEMBER_OFFSET_INIT(file_private_data, "file", "private_data");
|
|
MEMBER_OFFSET_INIT(hstate_order, "hstate", "order");
|
|
MEMBER_OFFSET_INIT(hugetlbfs_sb_info_hstate, "hugetlbfs_sb_info",
|
|
"hstate");
|
|
MEMBER_OFFSET_INIT(idr_layers, "idr", "layers");
|
|
MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer");
|
|
MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary");
|
|
MEMBER_OFFSET_INIT(idr_top, "idr", "top");
|
|
MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p");
|
|
MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries");
|
|
MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id");
|
|
MEMBER_OFFSET_INIT(ipc_ids_in_use, "ipc_ids", "in_use");
|
|
MEMBER_OFFSET_INIT(ipc_ids_ipcs_idr, "ipc_ids", "ipcs_idr");
|
|
MEMBER_OFFSET_INIT(ipc_namespace_ids, "ipc_namespace", "ids");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_key, "kern_ipc_perm", "key");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_id, "kern_ipc_perm", "id");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_uid, "kern_ipc_perm", "uid");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_mode, "kern_ipc_perm", "mode");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_deleted, "kern_ipc_perm",
|
|
"deleted");
|
|
MEMBER_OFFSET_INIT(kern_ipc_perm_seq, "kern_ipc_perm", "seq");
|
|
MEMBER_OFFSET_INIT(nsproxy_ipc_ns, "nsproxy", "ipc_ns");
|
|
MEMBER_OFFSET_INIT(shmem_inode_info_vfs_inode, "shmem_inode_info",
|
|
"vfs_inode");
|
|
MEMBER_OFFSET_INIT(shmem_inode_info_swapped, "shmem_inode_info",
|
|
"swapped");
|
|
if (INVALID_MEMBER(shmem_inode_info_swapped))
|
|
ANON_MEMBER_OFFSET_INIT(shmem_inode_info_swapped,
|
|
"shmem_inode_info", "swapped");
|
|
MEMBER_OFFSET_INIT(shm_file_data_file, "shm_file_data", "file");
|
|
MEMBER_OFFSET_INIT(shmid_kernel_shm_perm, "shmid_kernel",
|
|
"shm_perm");
|
|
MEMBER_OFFSET_INIT(shmid_kernel_shm_segsz, "shmid_kernel",
|
|
"shm_segsz");
|
|
MEMBER_OFFSET_INIT(shmid_kernel_shm_nattch, "shmid_kernel",
|
|
"shm_nattch");
|
|
MEMBER_OFFSET_INIT(shmid_kernel_shm_file, "shmid_kernel",
|
|
"shm_file");
|
|
MEMBER_OFFSET_INIT(shmid_kernel_id, "shmid_kernel", "id");
|
|
MEMBER_OFFSET_INIT(sem_array_sem_perm, "sem_array", "sem_perm");
|
|
MEMBER_OFFSET_INIT(sem_array_sem_id, "sem_array", "sem_id");
|
|
MEMBER_OFFSET_INIT(sem_array_sem_nsems, "sem_array", "sem_nsems");
|
|
MEMBER_OFFSET_INIT(msg_queue_q_perm, "msg_queue", "q_perm");
|
|
MEMBER_OFFSET_INIT(msg_queue_q_id, "msg_queue", "q_id");
|
|
MEMBER_OFFSET_INIT(msg_queue_q_cbytes, "msg_queue", "q_cbytes");
|
|
MEMBER_OFFSET_INIT(msg_queue_q_qnum, "msg_queue", "q_qnum");
|
|
MEMBER_OFFSET_INIT(super_block_s_fs_info, "super_block",
|
|
"s_fs_info");
|
|
|
|
/*
|
|
* struct size
|
|
*/
|
|
STRUCT_SIZE_INIT(ipc_ids, "ipc_ids");
|
|
STRUCT_SIZE_INIT(shmid_kernel, "shmid_kernel");
|
|
STRUCT_SIZE_INIT(sem_array, "sem_array");
|
|
STRUCT_SIZE_INIT(msg_queue, "msg_queue");
|
|
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 specified;
|
|
char *specified_value[MAXARGS];
|
|
int value_index;
|
|
int c;
|
|
int shm, sem, msg, verbose;
|
|
int i;
|
|
ulong value, task;
|
|
int found;
|
|
struct task_context *tc;
|
|
char buf[BUFSIZE];
|
|
|
|
value_index = 0;
|
|
specified = SPECIFIED_NOTHING;
|
|
shm = 0;
|
|
sem = 0;
|
|
msg = 0;
|
|
verbose = 0;
|
|
tc = NULL;
|
|
|
|
while ((c = getopt(argcnt, args, "smMqn:")) != EOF) {
|
|
switch(c) {
|
|
case 's':
|
|
sem = 1;
|
|
break;
|
|
case 'm':
|
|
shm = 1;
|
|
break;
|
|
case 'M':
|
|
shm = 1;
|
|
verbose = 1;
|
|
break;
|
|
case 'q':
|
|
msg = 1;
|
|
break;
|
|
case 'n':
|
|
switch (str_to_context(optarg, &value, &tc)) {
|
|
case STR_PID:
|
|
case STR_TASK:
|
|
break;
|
|
case STR_INVALID:
|
|
error(FATAL, "invalid task or pid value: %s\n",
|
|
optarg);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
cmd_usage(pc->curcmd, SYNOPSIS);;
|
|
return;
|
|
}
|
|
}
|
|
|
|
while (args[optind]) {
|
|
if (value_index >= MAXARGS)
|
|
error(FATAL, "too many id/member specified\n");
|
|
specified |= SPECIFIED_ID | SPECIFIED_ADDR;
|
|
specified_value[value_index] = args[optind];
|
|
stol(args[optind], FAULT_ON_ERROR, NULL);
|
|
optind++;
|
|
value_index++;
|
|
}
|
|
|
|
if (THIS_KERNEL_VERSION < LINUX(2,6,0))
|
|
command_not_supported();
|
|
|
|
ipcs_init();
|
|
|
|
if (!shm && !sem && !msg)
|
|
shm = sem = msg = 1;
|
|
|
|
task = tc ? tc->task : pid_to_task(0);
|
|
|
|
if (!value_index) {
|
|
if (shm)
|
|
dump_shared_memory(specified, 0, verbose, task);
|
|
if (sem)
|
|
dump_semaphore_arrays(specified, 0, 0, task);
|
|
if (msg)
|
|
dump_message_queues(specified, 0, 0, task);
|
|
} else {
|
|
open_tmpfile();
|
|
i = 0;
|
|
while (i < value_index) {
|
|
found = 0;
|
|
value = stol(specified_value[i], FAULT_ON_ERROR, NULL);
|
|
if (shm)
|
|
found += dump_shared_memory(specified,
|
|
value, verbose, task);
|
|
if (sem)
|
|
found += dump_semaphore_arrays(specified,
|
|
value, 0, task);
|
|
if (msg)
|
|
found += dump_message_queues(specified,
|
|
value, 0, task);
|
|
|
|
if (!found)
|
|
fprintf(pc->saved_fp, "invalid id or address: %s\n\n",
|
|
specified_value[i]);
|
|
|
|
i++;
|
|
}
|
|
fflush(fp);
|
|
rewind(fp);
|
|
|
|
while (fgets(buf, BUFSIZE, fp))
|
|
fprintf(pc->saved_fp, "%s", buf);
|
|
|
|
close_tmpfile();
|
|
}
|
|
}
|
|
|
|
static int
|
|
dump_shared_memory(int specified, ulong specified_value, int verbose, ulong task)
|
|
{
|
|
ulong nsproxy_p, ipc_ns_p;
|
|
ulong ipc_ids_p;
|
|
int (*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 (!verbose && specified == SPECIFIED_NOTHING) {
|
|
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 (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(task + OFFSET(task_struct_nsproxy), KVADDR,
|
|
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
|
|
FAULT_ON_ERROR);
|
|
if (!readmem(nsproxy_p + 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 + 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 + OFFSET(ipc_namespace_ids) +
|
|
2 * SIZE(ipc_ids);
|
|
}
|
|
|
|
if (ipc_search(ipc_ids_p, specified, specified_value, dump_shm, verbose)) {
|
|
return 1;
|
|
} else {
|
|
if (verbose && specified == SPECIFIED_NOTHING) {
|
|
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, "(none allocated)\n\n");
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
dump_semaphore_arrays(int specified, ulong specified_value, int verbose, ulong task)
|
|
{
|
|
ulong nsproxy_p, ipc_ns_p;
|
|
ulong ipc_ids_p;
|
|
int (*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, "%s %s %s %s %s %s\n",
|
|
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
|
|
LJUST, "SEM_ARRAY"),
|
|
mkstring(buf1, 8, 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 (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(task + OFFSET(task_struct_nsproxy), KVADDR,
|
|
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
|
|
FAULT_ON_ERROR);
|
|
|
|
if (!readmem(nsproxy_p + OFFSET(nsproxy_ipc_ns), KVADDR,
|
|
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
|
|
FAULT_ON_ERROR|QUIET))
|
|
error(FATAL,
|
|
"cannot determine ipc_namespace location!\n");
|
|
|
|
if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
|
|
readmem(ipc_ns_p + OFFSET(ipc_namespace_ids),
|
|
KVADDR, &ipc_ids_p, sizeof(ulong),
|
|
"ipc_namespace.ids[2]", FAULT_ON_ERROR);
|
|
else
|
|
ipc_ids_p = ipc_ns_p + OFFSET(ipc_namespace_ids);
|
|
}
|
|
|
|
return ipc_search(ipc_ids_p, specified, specified_value, dump_sem, verbose);
|
|
}
|
|
|
|
static int
|
|
dump_message_queues(int specified, ulong specified_value, int verbose, ulong task)
|
|
{
|
|
ulong nsproxy_p, ipc_ns_p;
|
|
ulong ipc_ids_p;
|
|
int (*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, "%s %s %s %s %s %s %s\n",
|
|
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
|
|
LJUST, "MSG_QUEUE"),
|
|
mkstring(buf1, 8, 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 (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(task + OFFSET(task_struct_nsproxy), KVADDR,
|
|
&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
|
|
FAULT_ON_ERROR);
|
|
if (!readmem(nsproxy_p + OFFSET(nsproxy_ipc_ns), KVADDR,
|
|
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
|
|
FAULT_ON_ERROR|QUIET))
|
|
error(FATAL,
|
|
"cannot determine ipc_namespace location!\n");
|
|
|
|
if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
|
|
readmem(ipc_ns_p + 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 + OFFSET(ipc_namespace_ids) +
|
|
SIZE(ipc_ids);
|
|
}
|
|
|
|
return ipc_search(ipc_ids_p, specified, specified_value, dump_msg, verbose);
|
|
}
|
|
|
|
/*
|
|
* if shared memory information is stored in an array, use this function.
|
|
*/
|
|
static int
|
|
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 + OFFSET(ipc_ids_entries), KVADDR, &entries_p,
|
|
sizeof(ulong), "ipc_ids.entries", FAULT_ON_ERROR);
|
|
readmem(ipc_ids_p + OFFSET(ipc_ids_max_id), KVADDR, &max_id,
|
|
sizeof(int), "ipc_ids.max_id", FAULT_ON_ERROR);
|
|
|
|
if (max_id < 0) {
|
|
if (specified == SPECIFIED_NOTHING && !verbose)
|
|
fprintf(fp, "(none allocated)\n\n");
|
|
return 0;
|
|
}
|
|
|
|
array = (ulong *)GETBUF(sizeof(ulong *) * (max_id + 1));
|
|
if (VALID_MEMBER(ipc_id_ary_p))
|
|
readmem(entries_p + 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;
|
|
if (fn(array[i], specified, specified_value, i, verbose)) {
|
|
allocated++;
|
|
found = 1;
|
|
if (specified != SPECIFIED_NOTHING)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (specified == SPECIFIED_NOTHING && !verbose) {
|
|
if (!allocated)
|
|
fprintf(fp, "(none allocated)\n");
|
|
fprintf(fp, "\n");
|
|
}
|
|
|
|
FREEBUF(array);
|
|
|
|
if (found)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* if shared memory information is stored by using idr, use this function to
|
|
* get data.
|
|
*/
|
|
static int
|
|
ipc_search_idr(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)(ulong, int, ulong, int, int), int verbose)
|
|
{
|
|
int i, in_use;
|
|
ulong ipcs_idr_p;
|
|
ulong ipc;
|
|
int next_id, total;
|
|
int found = 0;
|
|
|
|
readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &in_use,
|
|
sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
|
|
|
|
ipcs_idr_p = ipc_ids_p + OFFSET(ipc_ids_ipcs_idr);
|
|
|
|
if (!in_use) {
|
|
if (specified == SPECIFIED_NOTHING && !verbose)
|
|
fprintf(fp, "(none allocated)\n\n");
|
|
return 0;
|
|
}
|
|
|
|
if (VALID_MEMBER(idr_idr_rt)) {
|
|
gather_radix_tree_entries(ipcs_idr_p);
|
|
|
|
for (i = 0; i < ipcs_table.rt_cnt; i++) {
|
|
ipc = (ulong)ipcs_table.rtp[i].value;
|
|
if (fn(ipc, specified, specified_value, UNUSED, verbose)) {
|
|
found = 1;
|
|
if (specified != SPECIFIED_NOTHING)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ipcs_table.rtp)
|
|
FREEBUF(ipcs_table.rtp);
|
|
} else {
|
|
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;
|
|
if (specified != SPECIFIED_NOTHING)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!verbose && specified == SPECIFIED_NOTHING)
|
|
fprintf(fp, "\n");
|
|
|
|
if (found || specified == SPECIFIED_NOTHING)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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 + OFFSET(idr_top), KVADDR, &idr_layer_p,
|
|
sizeof(ulong), "idr.top", FAULT_ON_ERROR);
|
|
|
|
if (!idr_layer_p)
|
|
return 0;
|
|
|
|
if (VALID_MEMBER(idr_layer_layer)) {
|
|
readmem(idr_layer_p + OFFSET(idr_layer_layer), KVADDR,
|
|
&layer, sizeof(int), "idr_layer.layer",
|
|
FAULT_ON_ERROR);
|
|
n = (layer + 1) * ipcs_table.idr_bits;
|
|
} else {
|
|
readmem(idp + 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 + OFFSET(idr_layer_ary) +
|
|
sizeof(ulong) * index, KVADDR, &idr_layer_p,
|
|
sizeof(ulong), "idr_layer.ary", FAULT_ON_ERROR);
|
|
}
|
|
|
|
return idr_layer_p;
|
|
}
|
|
|
|
/*
|
|
* only specified is not SPECIFIED_NOTHIND, and the specified_value is found,
|
|
* then return 1
|
|
*/
|
|
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 == SPECIFIED_NOTHING) {
|
|
if (verbose || specified != SPECIFIED_NOTHING) {
|
|
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/RESIDENT/SWAPPED: %ld/%ld/%ld\n",
|
|
(shm_info.bytes+PAGESIZE()-1) >> PAGESHIFT(),
|
|
shm_info.rss, shm_info.swap);
|
|
fprintf(fp, "INODE: %lx\n", shm_info.shm_inode);
|
|
}
|
|
|
|
if (verbose || specified != SPECIFIED_NOTHING)
|
|
fprintf(fp, "\n");
|
|
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* only specified is not SPECIFIED_NOTHIND, and the specified_value is found,
|
|
* then return 1
|
|
*/
|
|
static int
|
|
dump_sem_info(ulong shp, int specified, ulong specified_value, int id, int verbose)
|
|
{
|
|
struct sem_info sem_info;
|
|
char buf[BUFSIZE];
|
|
char buf0[BUFSIZE];
|
|
char buf1[BUFSIZE];
|
|
char buf2[BUFSIZE];
|
|
char buf3[BUFSIZE];
|
|
char buf4[BUFSIZE];
|
|
char buf5[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 == SPECIFIED_NOTHING) {
|
|
if (specified != SPECIFIED_NOTHING) {
|
|
fprintf(fp, "%s %s %s %s %s %s\n",
|
|
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
|
|
LJUST, "SEM_ARRAY"),
|
|
mkstring(buf1, 8, LJUST, "KEY"),
|
|
mkstring(buf2, 10, LJUST, "SEMID"),
|
|
mkstring(buf3, 5, LJUST, "UID"),
|
|
mkstring(buf4, 5, LJUST, "PERMS"),
|
|
mkstring(buf5, 10, LJUST, "NSEMS"));
|
|
}
|
|
|
|
fprintf(fp, "%s %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_NOTHING)
|
|
fprintf(fp, "\n");
|
|
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* only specified is not SPECIFIED_NOTHIND, and the specified_value is found,
|
|
* then return 1
|
|
*/
|
|
static int
|
|
dump_msg_info(ulong shp, int specified, ulong specified_value, int id, int verbose)
|
|
{
|
|
struct msg_info msg_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];
|
|
|
|
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 == SPECIFIED_NOTHING) {
|
|
if (specified != SPECIFIED_NOTHING) {
|
|
fprintf(fp, "%s %s %s %s %s %s %s\n",
|
|
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
|
|
LJUST, "MSG_QUEUE"),
|
|
mkstring(buf1, 8, 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"));
|
|
}
|
|
|
|
fprintf(fp, "%s %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_NOTHING)
|
|
fprintf(fp, "\n");
|
|
|
|
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 - OFFSET(shmid_kernel_shm_perm);
|
|
|
|
/*
|
|
* cache shmid_kernel
|
|
*/
|
|
readmem(shm_info->shmid_kernel, KVADDR, buf, SIZE(shmid_kernel),
|
|
"shmid_kernel", FAULT_ON_ERROR);
|
|
|
|
shm_info->key = INT(buf + OFFSET(shmid_kernel_shm_perm) +
|
|
OFFSET(kern_ipc_perm_key));
|
|
if (VALID_MEMBER(shmid_kernel_id))
|
|
shm_info->shmid = INT(buf + OFFSET(shmid_kernel_id));
|
|
else
|
|
shm_info->shmid = INT(buf +
|
|
OFFSET(shmid_kernel_shm_perm) +
|
|
OFFSET(kern_ipc_perm_id));
|
|
|
|
shm_info->uid = UINT(buf + OFFSET(shmid_kernel_shm_perm) +
|
|
OFFSET(kern_ipc_perm_uid));
|
|
|
|
if (BITS32())
|
|
shm_info->perms = USHORT(buf +
|
|
OFFSET(shmid_kernel_shm_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
else
|
|
shm_info->perms = UINT(buf +
|
|
OFFSET(shmid_kernel_shm_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
|
|
shm_info->bytes = ULONG(buf + OFFSET(shmid_kernel_shm_segsz));
|
|
|
|
shm_info->nattch = ULONG(buf + OFFSET(shmid_kernel_shm_nattch));
|
|
|
|
filep = ULONG(buf + 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 = UCHAR(buf + OFFSET(shmid_kernel_shm_perm) +
|
|
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 - OFFSET(sem_array_sem_perm);
|
|
|
|
/*
|
|
* cache sem_array
|
|
*/
|
|
readmem(sem_info->sem_array, KVADDR, buf, SIZE(sem_array),
|
|
"sem_array", FAULT_ON_ERROR);
|
|
|
|
sem_info->key = INT(buf + OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_key));
|
|
|
|
if (VALID_MEMBER(sem_array_sem_id))
|
|
sem_info->semid = INT(buf + OFFSET(sem_array_sem_id));
|
|
else if (VALID_MEMBER(kern_ipc_perm_id))
|
|
sem_info->semid = INT(buf + OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_id));
|
|
else {
|
|
ulong seq;
|
|
seq = ULONG(buf + OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_seq));
|
|
sem_info->semid = ipcs_table.seq_multiplier * seq + id;
|
|
}
|
|
|
|
sem_info->uid = UINT(buf + OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_uid));
|
|
|
|
if (BITS32())
|
|
sem_info->perms = USHORT(buf +
|
|
OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
else
|
|
sem_info->perms = UINT(buf + OFFSET(sem_array_sem_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
|
|
sem_info->nsems = ULONG(buf + OFFSET(sem_array_sem_nsems));
|
|
|
|
sem_info->deleted = UCHAR(buf + OFFSET(sem_array_sem_perm) +
|
|
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 - OFFSET(msg_queue_q_perm);
|
|
|
|
/*
|
|
* cache msg_queue
|
|
*/
|
|
readmem(msg_info->msg_queue, KVADDR, buf, SIZE(msg_queue),
|
|
"msg_queue", FAULT_ON_ERROR);
|
|
|
|
msg_info->key = INT(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_key));
|
|
|
|
if (VALID_MEMBER(msg_queue_q_id))
|
|
msg_info->msgid = INT(buf + OFFSET(msg_queue_q_id));
|
|
else if (VALID_MEMBER(kern_ipc_perm_id))
|
|
msg_info->msgid = INT(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_id));
|
|
else {
|
|
ulong seq;
|
|
seq = ULONG(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_seq));
|
|
msg_info->msgid = ipcs_table.seq_multiplier * seq + id;
|
|
}
|
|
|
|
msg_info->uid = UINT(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_uid));
|
|
|
|
if (BITS32())
|
|
msg_info->perms = USHORT(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
else
|
|
msg_info->perms = UINT(buf + OFFSET(msg_queue_q_perm) +
|
|
OFFSET(kern_ipc_perm_mode));
|
|
|
|
msg_info->bytes = ULONG(buf + OFFSET(msg_queue_q_cbytes));
|
|
|
|
msg_info->messages = ULONG(buf + OFFSET(msg_queue_q_qnum));
|
|
|
|
msg_info->deleted = UCHAR(buf + OFFSET(msg_queue_q_perm) +
|
|
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 (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 + OFFSET(super_block_s_fs_info),
|
|
KVADDR, &hsb_p, sizeof(ulong),
|
|
"super_block.s_fs_info", FAULT_ON_ERROR);
|
|
readmem(hsb_p + OFFSET(hugetlbfs_sb_info_hstate),
|
|
KVADDR, &hstate_p, sizeof(ulong),
|
|
"hugetlbfs_sb_info.hstate", FAULT_ON_ERROR);
|
|
readmem(hstate_p + 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 - OFFSET(shmem_inode_info_vfs_inode) +
|
|
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 + 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 +
|
|
OFFSET(file_private_data),
|
|
KVADDR, &sfd_p, sizeof(ulong),
|
|
"file.private_data", FAULT_ON_ERROR);
|
|
readmem(sfd_p +
|
|
OFFSET(shm_file_data_file),
|
|
KVADDR, &file_p, sizeof(ulong),
|
|
"shm_file_data.file", FAULT_ON_ERROR);
|
|
goto again;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
gather_radix_tree_entries(ulong ipcs_idr_p)
|
|
{
|
|
long len;
|
|
|
|
ipcs_table.rt_cnt = do_radix_tree(ipcs_idr_p, RADIX_TREE_COUNT, NULL);
|
|
|
|
if (ipcs_table.rt_cnt) {
|
|
len = sizeof(struct radix_tree_pair) * (ipcs_table.rt_cnt+1);
|
|
ipcs_table.rtp = (struct radix_tree_pair *)GETBUF(len);
|
|
ipcs_table.rtp[0].index = ipcs_table.rt_cnt;
|
|
ipcs_table.rt_cnt = do_radix_tree(ipcs_idr_p, RADIX_TREE_GATHER, ipcs_table.rtp);
|
|
} else
|
|
ipcs_table.rtp = NULL;
|
|
}
|
|
|