-
Notifications
You must be signed in to change notification settings - Fork 0
/
swap_usage.c
240 lines (196 loc) · 5.38 KB
/
swap_usage.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/* swap-usage.c - Check actual swap consumption for each process
*
* Aaron Tomlin <atomlin@redhat.com>
*
* Copyright (C) 2013 Red Hat, Inc. All rights reserved.
*
* 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 DISPLAY_KB (0x2)
#ifdef ARM
#define _PAGE_FILE (1 << 2)
#endif /* ARM */
#ifdef X86
#define _PAGE_FILE (1 << 6) /* _PAGE_BIT_DIRTY */
#endif /* X86 */
#ifdef X86_64
/* set in defs.h already */
#define _PAGE_FILE 0x040
#endif /* X86_64 */
#ifdef ALPHA
#define _PAGE_FILE 0x80000 /* set:pagecache, unset:swap */
#endif /* ALPHA */
#ifdef IA64
#define _PAGE_FILE (1 << 1) /* see swap & file pte remarks below */
#endif /* IA64 */
#ifdef S390
#define _PAGE_FILE 0x601
#endif /* S390 */
#define pte_file_present(pte) (pte & _PAGE_FILE)
#define MEMBER_FOUND 1
#define MEMBER_NOT_FOUND 0
#define PRINT_HEADER() \
fprintf(fp, \
"PID SWAP COMM\n");
int _init(void);
int _fini(void);
void cmd_pswap(void);
char *help_pswap[];
static unsigned int swap_usage_offset;
static struct command_table_entry command_table[] = {
{ "pswap", cmd_pswap, help_pswap, 0 },
{ NULL }
};
int
_init(void)
{
register_extension(command_table);
return 1;
}
int
_fini(void)
{
return 1;
}
void
show_swap_usage(struct task_context *tc, ulong exists, ulong flag)
{
struct task_mem_usage task_mem_usage, *tm;
tm = &task_mem_usage;
get_task_mem_usage(tc->task, tm);
physaddr_t paddr;
ulong mm;
ulong vma;
ulong vm_start;
ulong vm_end;
ulong vm_next;
ulong swap_usage = 0;
readmem(tc->task + OFFSET(task_struct_mm), KVADDR, &mm,
sizeof(void *), "mm_struct mm", FAULT_ON_ERROR);
if (!mm)
return;
switch (exists) {
case MEMBER_FOUND:
readmem((mm + swap_usage_offset), KVADDR, &swap_usage,
sizeof(void *), "mm_counter_t", FAULT_ON_ERROR);
break;
case MEMBER_NOT_FOUND:
default:
readmem(mm + OFFSET(mm_struct_mmap), KVADDR, &vma,
sizeof(void *), "mm_struct mmap", FAULT_ON_ERROR);
for (; vma; vma = vm_next) {
readmem(vma + OFFSET(vm_area_struct_vm_start), KVADDR, &vm_start,
sizeof(void *), "vm_area_struct vm_start", FAULT_ON_ERROR);
readmem(vma + OFFSET(vm_area_struct_vm_end), KVADDR, &vm_end,
sizeof(void *), "vm_area_struct vm_end", FAULT_ON_ERROR);
readmem(vma + OFFSET(vm_area_struct_vm_next), KVADDR, &vm_next,
sizeof(void *), "vm_area_struct vm_next", FAULT_ON_ERROR);
while (vm_start < vm_end) {
if (!uvtop(tc, vm_start, &paddr, 0)) {
if (paddr && !(pte_file_present(paddr))) {
swap_usage++;
}
}
vm_start += PAGESIZE();
}
}
}
if (flag & DISPLAY_KB)
swap_usage <<= (PAGESHIFT()-10);
fprintf(fp, "%5ld %5ld%s%5s\n",
tc->pid, swap_usage, (flag & DISPLAY_KB) ? "k\t" : "\t", tc->comm);
}
void
cmd_pswap(void)
{
struct task_context *tc;
int i;
int c;
ulong value;
ulong flag = 0;
int subsequent = 0;
ulong exists = MEMBER_NOT_FOUND;
if (MEMBER_EXISTS("mm_struct", "_swap_usage")) {
swap_usage_offset = MEMBER_OFFSET("mm_struct", "_swap_usage");
exists = MEMBER_FOUND;
}
while ((c = getopt(argcnt, args, "k")) != EOF) {
switch (c) {
case 'k':
flag |= DISPLAY_KB;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
if (!args[optind]) {
PRINT_HEADER();
tc = FIRST_CONTEXT();
for (i = 0; i < RUNNING_TASKS(); i++, tc++) {
if (!is_kernel_thread(tc->task))
show_swap_usage(tc, exists, flag);
}
return;
}
PRINT_HEADER();
while (args[optind]) {
switch (str_to_context(args[optind], &value, &tc)) {
case STR_PID:
for (tc = pid_to_context(value); tc; tc = tc->tc_next) {
if (!is_kernel_thread(tc->task)) {
show_swap_usage(tc, exists, flag);
} else {
error(INFO, "only specify a user task or pid: %s\n",
args[optind]);
}
}
break;
case STR_TASK:
for (; tc; tc = tc->tc_next) {
if (!is_kernel_thread(tc->task)) {
show_swap_usage(tc, exists, flag);
} else {
error(INFO, "only specify a user task or pid: %s\n",
args[optind]);
}
}
break;
case STR_INVALID:
error(INFO, "invalid task or pid value: %s\n",
args[optind]);
break;
}
subsequent++;
optind++;
}
}
char *help_pswap[] = {
"pswap",
"Returns the actual swap consumption of a user process",
"[-k] [pid | taskp]",
" This command obtains the swap consumption (in pages) of a user process.",
" The -k option can be used to print in kilobytes.\n"
" If no arguments are specified, every user process will be checked.",
" Supported on ARM, X86, X86_64, ALPHA, IA64 and S390 only.",
"\nEXAMPLE",
" Show the swap consumption for pid 1232, 1353 and 2275:\n",
" crash> pswap 1232 1353 2275",
" PID SWAP COMM",
" 1232 34 auditd",
" 1353 526 vi",
" 2275 30237 gnome-shell",
" crash>",
NULL
};