aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile11
-rw-r--r--tools/hv/Makefile13
-rw-r--r--tools/hv/hv_fcopy_daemon.c195
-rw-r--r--tools/hv/hv_vss_daemon.c2
-rw-r--r--tools/net/bpf_dbg.c119
-rw-r--r--tools/perf/config/Makefile.arch3
-rw-r--r--tools/perf/perf.h8
-rw-r--r--tools/testing/ktest/examples/kvm.conf4
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/copyloops/Makefile29
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h86
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/processor.h0
l---------tools/testing/selftests/powerpc/copyloops/copyuser_64.S1
l---------tools/testing/selftests/powerpc/copyloops/copyuser_power7.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_64.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_power7.S1
-rw-r--r--tools/testing/selftests/powerpc/copyloops/validate.c99
-rw-r--r--tools/testing/selftests/powerpc/utils.h3
-rw-r--r--tools/virtio/linux/kmemleak.h3
-rw-r--r--tools/virtio/linux/virtio.h4
-rw-r--r--tools/virtio/virtio_test.c2
-rw-r--r--tools/vm/page-types.c170
22 files changed, 665 insertions, 92 deletions
diff --git a/tools/Makefile b/tools/Makefile
index feec3ad5fd09..bcae806b0c39 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -7,6 +7,7 @@ help:
7 @echo ' cgroup - cgroup tools' 7 @echo ' cgroup - cgroup tools'
8 @echo ' cpupower - a tool for all things x86 CPU power' 8 @echo ' cpupower - a tool for all things x86 CPU power'
9 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' 9 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
10 @echo ' hv - tools used when in Hyper-V clients'
10 @echo ' lguest - a minimal 32-bit x86 hypervisor' 11 @echo ' lguest - a minimal 32-bit x86 hypervisor'
11 @echo ' perf - Linux performance measurement and analysis tool' 12 @echo ' perf - Linux performance measurement and analysis tool'
12 @echo ' selftests - various kernel selftests' 13 @echo ' selftests - various kernel selftests'
@@ -40,7 +41,7 @@ acpi: FORCE
40cpupower: FORCE 41cpupower: FORCE
41 $(call descend,power/$@) 42 $(call descend,power/$@)
42 43
43cgroup firewire guest usb virtio vm net: FORCE 44cgroup firewire hv guest usb virtio vm net: FORCE
44 $(call descend,$@) 45 $(call descend,$@)
45 46
46libapikfs: FORCE 47libapikfs: FORCE
@@ -64,7 +65,7 @@ acpi_install:
64cpupower_install: 65cpupower_install:
65 $(call descend,power/$(@:_install=),install) 66 $(call descend,power/$(@:_install=),install)
66 67
67cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install: 68cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install:
68 $(call descend,$(@:_install=),install) 69 $(call descend,$(@:_install=),install)
69 70
70selftests_install: 71selftests_install:
@@ -76,7 +77,7 @@ turbostat_install x86_energy_perf_policy_install:
76tmon_install: 77tmon_install:
77 $(call descend,thermal/$(@:_install=),install) 78 $(call descend,thermal/$(@:_install=),install)
78 79
79install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \ 80install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
80 perf_install selftests_install turbostat_install usb_install \ 81 perf_install selftests_install turbostat_install usb_install \
81 virtio_install vm_install net_install x86_energy_perf_policy_install \ 82 virtio_install vm_install net_install x86_energy_perf_policy_install \
82 tmon 83 tmon
@@ -87,7 +88,7 @@ acpi_clean:
87cpupower_clean: 88cpupower_clean:
88 $(call descend,power/cpupower,clean) 89 $(call descend,power/cpupower,clean)
89 90
90cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: 91cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
91 $(call descend,$(@:_clean=),clean) 92 $(call descend,$(@:_clean=),clean)
92 93
93libapikfs_clean: 94libapikfs_clean:
@@ -105,7 +106,7 @@ turbostat_clean x86_energy_perf_policy_clean:
105tmon_clean: 106tmon_clean:
106 $(call descend,thermal/tmon,clean) 107 $(call descend,thermal/tmon,clean)
107 108
108clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \ 109clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
109 perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ 110 perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \
110 vm_clean net_clean x86_energy_perf_policy_clean tmon_clean 111 vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
111 112
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
new file mode 100644
index 000000000000..bd22f786a60c
--- /dev/null
+++ b/tools/hv/Makefile
@@ -0,0 +1,13 @@
1# Makefile for Hyper-V tools
2
3CC = $(CROSS_COMPILE)gcc
4PTHREAD_LIBS = -lpthread
5WARNINGS = -Wall -Wextra
6CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
7
8all: hv_kvp_daemon hv_vss_daemon
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^
11
12clean:
13 $(RM) hv_kvp_daemon hv_vss_daemon
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
new file mode 100644
index 000000000000..4ecc4fd0bc1b
--- /dev/null
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -0,0 +1,195 @@
1/*
2 * An implementation of host to guest copy functionality for Linux.
3 *
4 * Copyright (C) 2014, Microsoft, Inc.
5 *
6 * Author : K. Y. Srinivasan <kys@microsoft.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 */
18
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <sys/poll.h>
23#include <linux/types.h>
24#include <linux/kdev_t.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <string.h>
29#include <ctype.h>
30#include <errno.h>
31#include <linux/hyperv.h>
32#include <syslog.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <dirent.h>
36
37static int target_fd;
38static char target_fname[W_MAX_PATH];
39
40static int hv_start_fcopy(struct hv_start_fcopy *smsg)
41{
42 int error = HV_E_FAIL;
43 char *q, *p;
44
45 /*
46 * If possile append a path seperator to the path.
47 */
48 if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
49 strcat((char *)smsg->path_name, "/");
50
51 p = (char *)smsg->path_name;
52 snprintf(target_fname, sizeof(target_fname), "%s/%s",
53 (char *)smsg->path_name, smsg->file_name);
54
55 syslog(LOG_INFO, "Target file name: %s", target_fname);
56 /*
57 * Check to see if the path is already in place; if not,
58 * create if required.
59 */
60 while ((q = strchr(p, '/')) != NULL) {
61 if (q == p) {
62 p++;
63 continue;
64 }
65 *q = '\0';
66 if (access((char *)smsg->path_name, F_OK)) {
67 if (smsg->copy_flags & CREATE_PATH) {
68 if (mkdir((char *)smsg->path_name, 0755)) {
69 syslog(LOG_ERR, "Failed to create %s",
70 (char *)smsg->path_name);
71 goto done;
72 }
73 } else {
74 syslog(LOG_ERR, "Invalid path: %s",
75 (char *)smsg->path_name);
76 goto done;
77 }
78 }
79 p = q + 1;
80 *q = '/';
81 }
82
83 if (!access(target_fname, F_OK)) {
84 syslog(LOG_INFO, "File: %s exists", target_fname);
85 if (!smsg->copy_flags & OVER_WRITE)
86 goto done;
87 }
88
89 target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
90 if (target_fd == -1) {
91 syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
92 goto done;
93 }
94
95 error = 0;
96done:
97 return error;
98}
99
100static int hv_copy_data(struct hv_do_fcopy *cpmsg)
101{
102 ssize_t bytes_written;
103
104 bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
105 cpmsg->offset);
106
107 if (bytes_written != cpmsg->size)
108 return HV_E_FAIL;
109
110 return 0;
111}
112
113static int hv_copy_finished(void)
114{
115 close(target_fd);
116 return 0;
117}
118static int hv_copy_cancel(void)
119{
120 close(target_fd);
121 unlink(target_fname);
122 return 0;
123
124}
125
126int main(void)
127{
128 int fd, fcopy_fd, len;
129 int error;
130 int version = FCOPY_CURRENT_VERSION;
131 char *buffer[4096 * 2];
132 struct hv_fcopy_hdr *in_msg;
133
134 if (daemon(1, 0)) {
135 syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
136 exit(EXIT_FAILURE);
137 }
138
139 openlog("HV_FCOPY", 0, LOG_USER);
140 syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
141
142 fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
143
144 if (fcopy_fd < 0) {
145 syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
146 errno, strerror(errno));
147 exit(EXIT_FAILURE);
148 }
149
150 /*
151 * Register with the kernel.
152 */
153 if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
154 syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
155 exit(EXIT_FAILURE);
156 }
157
158 while (1) {
159 /*
160 * In this loop we process fcopy messages after the
161 * handshake is complete.
162 */
163 len = pread(fcopy_fd, buffer, (4096 * 2), 0);
164 if (len < 0) {
165 syslog(LOG_ERR, "pread failed: %s", strerror(errno));
166 exit(EXIT_FAILURE);
167 }
168 in_msg = (struct hv_fcopy_hdr *)buffer;
169
170 switch (in_msg->operation) {
171 case START_FILE_COPY:
172 error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
173 break;
174 case WRITE_TO_FILE:
175 error = hv_copy_data((struct hv_do_fcopy *)in_msg);
176 break;
177 case COMPLETE_FCOPY:
178 error = hv_copy_finished();
179 break;
180 case CANCEL_FCOPY:
181 error = hv_copy_cancel();
182 break;
183
184 default:
185 syslog(LOG_ERR, "Unknown operation: %d",
186 in_msg->operation);
187
188 }
189
190 if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
191 syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
192 exit(EXIT_FAILURE);
193 }
194 }
195}
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 520de3304571..6a213b8cd7b9 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -87,6 +87,8 @@ static int vss_operate(int operation)
87 continue; 87 continue;
88 if (strcmp(ent->mnt_type, "iso9660") == 0) 88 if (strcmp(ent->mnt_type, "iso9660") == 0)
89 continue; 89 continue;
90 if (strcmp(ent->mnt_type, "vfat") == 0)
91 continue;
90 if (strcmp(ent->mnt_dir, "/") == 0) { 92 if (strcmp(ent->mnt_dir, "/") == 0) {
91 root_seen = 1; 93 root_seen = 1;
92 continue; 94 continue;
diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c
index 65dc757f7f7b..bb31813e43dd 100644
--- a/tools/net/bpf_dbg.c
+++ b/tools/net/bpf_dbg.c
@@ -87,9 +87,6 @@
87 __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs)))) 87 __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs))))
88#endif 88#endif
89 89
90#define CMD(_name, _func) { .name = _name, .func = _func, }
91#define OP(_op, _name) [_op] = _name
92
93enum { 90enum {
94 CMD_OK, 91 CMD_OK,
95 CMD_ERR, 92 CMD_ERR,
@@ -145,32 +142,32 @@ static size_t pcap_map_size = 0;
145static char *pcap_ptr_va_start, *pcap_ptr_va_curr; 142static char *pcap_ptr_va_start, *pcap_ptr_va_curr;
146 143
147static const char * const op_table[] = { 144static const char * const op_table[] = {
148 OP(BPF_ST, "st"), 145 [BPF_ST] = "st",
149 OP(BPF_STX, "stx"), 146 [BPF_STX] = "stx",
150 OP(BPF_LD_B, "ldb"), 147 [BPF_LD_B] = "ldb",
151 OP(BPF_LD_H, "ldh"), 148 [BPF_LD_H] = "ldh",
152 OP(BPF_LD_W, "ld"), 149 [BPF_LD_W] = "ld",
153 OP(BPF_LDX, "ldx"), 150 [BPF_LDX] = "ldx",
154 OP(BPF_LDX_B, "ldxb"), 151 [BPF_LDX_B] = "ldxb",
155 OP(BPF_JMP_JA, "ja"), 152 [BPF_JMP_JA] = "ja",
156 OP(BPF_JMP_JEQ, "jeq"), 153 [BPF_JMP_JEQ] = "jeq",
157 OP(BPF_JMP_JGT, "jgt"), 154 [BPF_JMP_JGT] = "jgt",
158 OP(BPF_JMP_JGE, "jge"), 155 [BPF_JMP_JGE] = "jge",
159 OP(BPF_JMP_JSET, "jset"), 156 [BPF_JMP_JSET] = "jset",
160 OP(BPF_ALU_ADD, "add"), 157 [BPF_ALU_ADD] = "add",
161 OP(BPF_ALU_SUB, "sub"), 158 [BPF_ALU_SUB] = "sub",
162 OP(BPF_ALU_MUL, "mul"), 159 [BPF_ALU_MUL] = "mul",
163 OP(BPF_ALU_DIV, "div"), 160 [BPF_ALU_DIV] = "div",
164 OP(BPF_ALU_MOD, "mod"), 161 [BPF_ALU_MOD] = "mod",
165 OP(BPF_ALU_NEG, "neg"), 162 [BPF_ALU_NEG] = "neg",
166 OP(BPF_ALU_AND, "and"), 163 [BPF_ALU_AND] = "and",
167 OP(BPF_ALU_OR, "or"), 164 [BPF_ALU_OR] = "or",
168 OP(BPF_ALU_XOR, "xor"), 165 [BPF_ALU_XOR] = "xor",
169 OP(BPF_ALU_LSH, "lsh"), 166 [BPF_ALU_LSH] = "lsh",
170 OP(BPF_ALU_RSH, "rsh"), 167 [BPF_ALU_RSH] = "rsh",
171 OP(BPF_MISC_TAX, "tax"), 168 [BPF_MISC_TAX] = "tax",
172 OP(BPF_MISC_TXA, "txa"), 169 [BPF_MISC_TXA] = "txa",
173 OP(BPF_RET, "ret"), 170 [BPF_RET] = "ret",
174}; 171};
175 172
176static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) 173static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...)
@@ -1127,7 +1124,6 @@ static int cmd_step(char *num)
1127static int cmd_select(char *num) 1124static int cmd_select(char *num)
1128{ 1125{
1129 unsigned int which, i; 1126 unsigned int which, i;
1130 struct pcap_pkthdr *hdr;
1131 bool have_next = true; 1127 bool have_next = true;
1132 1128
1133 if (!pcap_loaded() || strlen(num) == 0) 1129 if (!pcap_loaded() || strlen(num) == 0)
@@ -1144,7 +1140,7 @@ static int cmd_select(char *num)
1144 1140
1145 for (i = 0; i < which && (have_next = pcap_next_pkt()); i++) 1141 for (i = 0; i < which && (have_next = pcap_next_pkt()); i++)
1146 /* noop */; 1142 /* noop */;
1147 if (!have_next || (hdr = pcap_curr_pkt()) == NULL) { 1143 if (!have_next || pcap_curr_pkt() == NULL) {
1148 rl_printf("no packet #%u available!\n", which); 1144 rl_printf("no packet #%u available!\n", which);
1149 pcap_reset_pkt(); 1145 pcap_reset_pkt();
1150 return CMD_ERR; 1146 return CMD_ERR;
@@ -1177,9 +1173,8 @@ static int cmd_breakpoint(char *subcmd)
1177static int cmd_run(char *num) 1173static int cmd_run(char *num)
1178{ 1174{
1179 static uint32_t pass = 0, fail = 0; 1175 static uint32_t pass = 0, fail = 0;
1180 struct pcap_pkthdr *hdr;
1181 bool has_limit = true; 1176 bool has_limit = true;
1182 int ret, pkts = 0, i = 0; 1177 int pkts = 0, i = 0;
1183 1178
1184 if (!bpf_prog_loaded() || !pcap_loaded()) 1179 if (!bpf_prog_loaded() || !pcap_loaded())
1185 return CMD_ERR; 1180 return CMD_ERR;
@@ -1189,10 +1184,10 @@ static int cmd_run(char *num)
1189 has_limit = false; 1184 has_limit = false;
1190 1185
1191 do { 1186 do {
1192 hdr = pcap_curr_pkt(); 1187 struct pcap_pkthdr *hdr = pcap_curr_pkt();
1193 ret = bpf_run_all(bpf_image, bpf_prog_len, 1188 int ret = bpf_run_all(bpf_image, bpf_prog_len,
1194 (uint8_t *) hdr + sizeof(*hdr), 1189 (uint8_t *) hdr + sizeof(*hdr),
1195 hdr->caplen, hdr->len); 1190 hdr->caplen, hdr->len);
1196 if (ret > 0) 1191 if (ret > 0)
1197 pass++; 1192 pass++;
1198 else if (ret == 0) 1193 else if (ret == 0)
@@ -1245,14 +1240,14 @@ static int cmd_quit(char *dontcare)
1245} 1240}
1246 1241
1247static const struct shell_cmd cmds[] = { 1242static const struct shell_cmd cmds[] = {
1248 CMD("load", cmd_load), 1243 { .name = "load", .func = cmd_load },
1249 CMD("select", cmd_select), 1244 { .name = "select", .func = cmd_select },
1250 CMD("step", cmd_step), 1245 { .name = "step", .func = cmd_step },
1251 CMD("run", cmd_run), 1246 { .name = "run", .func = cmd_run },
1252 CMD("breakpoint", cmd_breakpoint), 1247 { .name = "breakpoint", .func = cmd_breakpoint },
1253 CMD("disassemble", cmd_disassemble), 1248 { .name = "disassemble", .func = cmd_disassemble },
1254 CMD("dump", cmd_dump), 1249 { .name = "dump", .func = cmd_dump },
1255 CMD("quit", cmd_quit), 1250 { .name = "quit", .func = cmd_quit },
1256}; 1251};
1257 1252
1258static int execf(char *arg) 1253static int execf(char *arg)
@@ -1280,7 +1275,6 @@ out:
1280static char *shell_comp_gen(const char *buf, int state) 1275static char *shell_comp_gen(const char *buf, int state)
1281{ 1276{
1282 static int list_index, len; 1277 static int list_index, len;
1283 const char *name;
1284 1278
1285 if (!state) { 1279 if (!state) {
1286 list_index = 0; 1280 list_index = 0;
@@ -1288,9 +1282,9 @@ static char *shell_comp_gen(const char *buf, int state)
1288 } 1282 }
1289 1283
1290 for (; list_index < array_size(cmds); ) { 1284 for (; list_index < array_size(cmds); ) {
1291 name = cmds[list_index].name; 1285 const char *name = cmds[list_index].name;
1292 list_index++;
1293 1286
1287 list_index++;
1294 if (strncmp(name, buf, len) == 0) 1288 if (strncmp(name, buf, len) == 0)
1295 return strdup(name); 1289 return strdup(name);
1296 } 1290 }
@@ -1322,16 +1316,9 @@ static void init_shell(FILE *fin, FILE *fout)
1322{ 1316{
1323 char file[128]; 1317 char file[128];
1324 1318
1325 memset(file, 0, sizeof(file)); 1319 snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
1326 snprintf(file, sizeof(file) - 1,
1327 "%s/.bpf_dbg_history", getenv("HOME"));
1328
1329 read_history(file); 1320 read_history(file);
1330 1321
1331 memset(file, 0, sizeof(file));
1332 snprintf(file, sizeof(file) - 1,
1333 "%s/.bpf_dbg_init", getenv("HOME"));
1334
1335 rl_instream = fin; 1322 rl_instream = fin;
1336 rl_outstream = fout; 1323 rl_outstream = fout;
1337 1324
@@ -1348,37 +1335,41 @@ static void init_shell(FILE *fin, FILE *fout)
1348 rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap); 1335 rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap);
1349 rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap); 1336 rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap);
1350 1337
1338 snprintf(file, sizeof(file), "%s/.bpf_dbg_init", getenv("HOME"));
1351 rl_read_init_file(file); 1339 rl_read_init_file(file);
1340
1352 rl_prep_terminal(0); 1341 rl_prep_terminal(0);
1353 rl_set_signals(); 1342 rl_set_signals();
1354 1343
1355 signal(SIGINT, intr_shell); 1344 signal(SIGINT, intr_shell);
1356} 1345}
1357 1346
1358static void exit_shell(void) 1347static void exit_shell(FILE *fin, FILE *fout)
1359{ 1348{
1360 char file[128]; 1349 char file[128];
1361 1350
1362 memset(file, 0, sizeof(file)); 1351 snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
1363 snprintf(file, sizeof(file) - 1,
1364 "%s/.bpf_dbg_history", getenv("HOME"));
1365
1366 write_history(file); 1352 write_history(file);
1353
1367 clear_history(); 1354 clear_history();
1368 rl_deprep_terminal(); 1355 rl_deprep_terminal();
1369 1356
1370 try_close_pcap(); 1357 try_close_pcap();
1358
1359 if (fin != stdin)
1360 fclose(fin);
1361 if (fout != stdout)
1362 fclose(fout);
1371} 1363}
1372 1364
1373static int run_shell_loop(FILE *fin, FILE *fout) 1365static int run_shell_loop(FILE *fin, FILE *fout)
1374{ 1366{
1375 char *buf; 1367 char *buf;
1376 int ret;
1377 1368
1378 init_shell(fin, fout); 1369 init_shell(fin, fout);
1379 1370
1380 while ((buf = readline("> ")) != NULL) { 1371 while ((buf = readline("> ")) != NULL) {
1381 ret = execf(buf); 1372 int ret = execf(buf);
1382 if (ret == CMD_EX) 1373 if (ret == CMD_EX)
1383 break; 1374 break;
1384 if (ret == CMD_OK && strlen(buf) > 0) 1375 if (ret == CMD_OK && strlen(buf) > 0)
@@ -1387,7 +1378,7 @@ static int run_shell_loop(FILE *fin, FILE *fout)
1387 free(buf); 1378 free(buf);
1388 } 1379 }
1389 1380
1390 exit_shell(); 1381 exit_shell(fin, fout);
1391 return 0; 1382 return 0;
1392} 1383}
1393 1384
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
index fef8ae922800..4b06719ee984 100644
--- a/tools/perf/config/Makefile.arch
+++ b/tools/perf/config/Makefile.arch
@@ -5,7 +5,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
5 -e s/arm.*/arm/ -e s/sa110/arm/ \ 5 -e s/arm.*/arm/ -e s/sa110/arm/ \
6 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 6 -e s/s390x/s390/ -e s/parisc64/parisc/ \
7 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 7 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
8 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) 8 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
9 -e s/tile.*/tile/ )
9 10
10# Additional ARCH settings for x86 11# Additional ARCH settings for x86
11ifeq ($(ARCH),i386) 12ifeq ($(ARCH),i386)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e18a8b5e6953..5c11ecad02a9 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -145,6 +145,14 @@
145#define CPUINFO_PROC "core ID" 145#define CPUINFO_PROC "core ID"
146#endif 146#endif
147 147
148#ifdef __tile__
149#define mb() asm volatile ("mf" ::: "memory")
150#define wmb() asm volatile ("mf" ::: "memory")
151#define rmb() asm volatile ("mf" ::: "memory")
152#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
153#define CPUINFO_PROC "model name"
154#endif
155
148#define barrier() asm volatile ("" ::: "memory") 156#define barrier() asm volatile ("" ::: "memory")
149 157
150#ifndef cpu_relax 158#ifndef cpu_relax
diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf
index 831c7c5395f1..fbc134f9ac6e 100644
--- a/tools/testing/ktest/examples/kvm.conf
+++ b/tools/testing/ktest/examples/kvm.conf
@@ -10,6 +10,10 @@ MACHINE = Guest
10# Use virsh to read the serial console of the guest 10# Use virsh to read the serial console of the guest
11CONSOLE = virsh console ${MACHINE} 11CONSOLE = virsh console ${MACHINE}
12 12
13# Use SIGKILL to terminate virsh console. We can't kill virsh console
14# by the default signal, SIGINT.
15CLOSE_CONSOLE_SIGNAL = KILL
16
13#*************************************# 17#*************************************#
14# This part is the same as test.conf # 18# This part is the same as test.conf #
15#*************************************# 19#*************************************#
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index bd24ae5aaeab..316194f26ff4 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
13 13
14export CC CFLAGS 14export CC CFLAGS
15 15
16TARGETS = pmu 16TARGETS = pmu copyloops
17 17
18endif 18endif
19 19
diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile
new file mode 100644
index 000000000000..6f2d3be227f9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/Makefile
@@ -0,0 +1,29 @@
1# The loops are all 64-bit code
2CFLAGS += -m64
3CFLAGS += -I$(CURDIR)
4CFLAGS += -D SELFTEST
5
6# Use our CFLAGS for the implicit .S rule
7ASFLAGS = $(CFLAGS)
8
9PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7
10EXTRA_SOURCES := validate.c ../harness.c
11
12all: $(PROGS)
13
14copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base
15copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7
16memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy
17memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7
18
19$(PROGS): $(EXTRA_SOURCES)
20
21run_tests: all
22 @-for PROG in $(PROGS); do \
23 ./$$PROG; \
24 done;
25
26clean:
27 rm -f $(PROGS) *.o
28
29.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
new file mode 100644
index 000000000000..ccd9c84c4e3f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
@@ -0,0 +1,86 @@
1#include <ppc-asm.h>
2
3#define CONFIG_ALTIVEC
4
5#define r1 1
6
7#define vr0 0
8#define vr1 1
9#define vr2 2
10#define vr3 3
11#define vr4 4
12#define vr5 5
13#define vr6 6
14#define vr7 7
15#define vr8 8
16#define vr9 9
17#define vr10 10
18#define vr11 11
19#define vr12 12
20#define vr13 13
21#define vr14 14
22#define vr15 15
23#define vr16 16
24#define vr17 17
25#define vr18 18
26#define vr19 19
27#define vr20 20
28#define vr21 21
29#define vr22 22
30#define vr23 23
31#define vr24 24
32#define vr25 25
33#define vr26 26
34#define vr27 27
35#define vr28 28
36#define vr29 29
37#define vr30 30
38#define vr31 31
39
40#define R14 r14
41#define R15 r15
42#define R16 r16
43#define R17 r17
44#define R18 r18
45#define R19 r19
46#define R20 r20
47#define R21 r21
48#define R22 r22
49
50#define STACKFRAMESIZE 256
51#define STK_PARAM(i) (48 + ((i)-3)*8)
52#define STK_REG(i) (112 + ((i)-14)*8)
53
54#define _GLOBAL(A) FUNC_START(test_ ## A)
55
56#define PPC_MTOCRF(A, B) mtocrf A, B
57
58FUNC_START(enter_vmx_usercopy)
59 li r3,1
60 blr
61
62FUNC_START(exit_vmx_usercopy)
63 li r3,0
64 blr
65
66FUNC_START(enter_vmx_copy)
67 li r3,1
68 blr
69
70FUNC_START(exit_vmx_copy)
71 blr
72
73FUNC_START(memcpy_power7)
74 blr
75
76FUNC_START(__copy_tofrom_user_power7)
77 blr
78
79FUNC_START(__copy_tofrom_user_base)
80 blr
81
82#define BEGIN_FTR_SECTION
83#define FTR_SECTION_ELSE
84#define ALT_FTR_SECTION_END_IFCLR(x)
85#define ALT_FTR_SECTION_END(x, y)
86#define END_FTR_SECTION_IFCLR(x)
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/processor.h b/tools/testing/selftests/powerpc/copyloops/asm/processor.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/processor.h
diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_64.S b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S
new file mode 120000
index 000000000000..f1c418a2521a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S
@@ -0,0 +1 @@
../../../../../arch/powerpc/lib/copyuser_64.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S
new file mode 120000
index 000000000000..478689598298
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S
@@ -0,0 +1 @@
../../../../../arch/powerpc/lib/copyuser_power7.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_64.S b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S
new file mode 120000
index 000000000000..cce33fb6f9d8
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S
@@ -0,0 +1 @@
../../../../../arch/powerpc/lib/memcpy_64.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S
new file mode 120000
index 000000000000..0d6fbfaf3d59
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S
@@ -0,0 +1 @@
../../../../../arch/powerpc/lib/memcpy_power7.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/validate.c b/tools/testing/selftests/powerpc/copyloops/validate.c
new file mode 100644
index 000000000000..1750ff57ee58
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/validate.c
@@ -0,0 +1,99 @@
1#include <malloc.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdbool.h>
5
6#include "../utils.h"
7
8#define MAX_LEN 8192
9#define MAX_OFFSET 16
10#define MIN_REDZONE 128
11#define BUFLEN (MAX_LEN+MAX_OFFSET+2*MIN_REDZONE)
12#define POISON 0xa5
13
14unsigned long COPY_LOOP(void *to, const void *from, unsigned long size);
15
16static void do_one(char *src, char *dst, unsigned long src_off,
17 unsigned long dst_off, unsigned long len, void *redzone,
18 void *fill)
19{
20 char *srcp, *dstp;
21 unsigned long ret;
22 unsigned long i;
23
24 srcp = src + MIN_REDZONE + src_off;
25 dstp = dst + MIN_REDZONE + dst_off;
26
27 memset(src, POISON, BUFLEN);
28 memset(dst, POISON, BUFLEN);
29 memcpy(srcp, fill, len);
30
31 ret = COPY_LOOP(dstp, srcp, len);
32 if (ret && ret != (unsigned long)dstp) {
33 printf("(%p,%p,%ld) returned %ld\n", dstp, srcp, len, ret);
34 abort();
35 }
36
37 if (memcmp(dstp, srcp, len)) {
38 printf("(%p,%p,%ld) miscompare\n", dstp, srcp, len);
39 printf("src: ");
40 for (i = 0; i < len; i++)
41 printf("%02x ", srcp[i]);
42 printf("\ndst: ");
43 for (i = 0; i < len; i++)
44 printf("%02x ", dstp[i]);
45 printf("\n");
46 abort();
47 }
48
49 if (memcmp(dst, redzone, dstp - dst)) {
50 printf("(%p,%p,%ld) redzone before corrupted\n",
51 dstp, srcp, len);
52 abort();
53 }
54
55 if (memcmp(dstp+len, redzone, dst+BUFLEN-(dstp+len))) {
56 printf("(%p,%p,%ld) redzone after corrupted\n",
57 dstp, srcp, len);
58 abort();
59 }
60}
61
62int test_copy_loop(void)
63{
64 char *src, *dst, *redzone, *fill;
65 unsigned long len, src_off, dst_off;
66 unsigned long i;
67
68 src = memalign(BUFLEN, BUFLEN);
69 dst = memalign(BUFLEN, BUFLEN);
70 redzone = malloc(BUFLEN);
71 fill = malloc(BUFLEN);
72
73 if (!src || !dst || !redzone || !fill) {
74 fprintf(stderr, "malloc failed\n");
75 exit(1);
76 }
77
78 memset(redzone, POISON, BUFLEN);
79
80 /* Fill with sequential bytes */
81 for (i = 0; i < BUFLEN; i++)
82 fill[i] = i & 0xff;
83
84 for (len = 1; len < MAX_LEN; len++) {
85 for (src_off = 0; src_off < MAX_OFFSET; src_off++) {
86 for (dst_off = 0; dst_off < MAX_OFFSET; dst_off++) {
87 do_one(src, dst, src_off, dst_off, len,
88 redzone, fill);
89 }
90 }
91 }
92
93 return 0;
94}
95
96int main(void)
97{
98 return test_harness(test_copy_loop, str(COPY_LOOP));
99}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index 5851c4b0f553..0de064406dab 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -31,4 +31,7 @@ do { \
31 } \ 31 } \
32} while (0) 32} while (0)
33 33
34#define _str(s) #s
35#define str(s) _str(s)
36
34#endif /* _SELFTESTS_POWERPC_UTILS_H */ 37#endif /* _SELFTESTS_POWERPC_UTILS_H */
diff --git a/tools/virtio/linux/kmemleak.h b/tools/virtio/linux/kmemleak.h
new file mode 100644
index 000000000000..c07072270e2f
--- /dev/null
+++ b/tools/virtio/linux/kmemleak.h
@@ -0,0 +1,3 @@
1static inline void kmemleak_ignore(const void *ptr)
2{
3}
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 844783040703..5a2d1f0f6bc7 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -63,7 +63,7 @@ int virtqueue_add_inbuf(struct virtqueue *vq,
63 void *data, 63 void *data,
64 gfp_t gfp); 64 gfp_t gfp);
65 65
66void virtqueue_kick(struct virtqueue *vq); 66bool virtqueue_kick(struct virtqueue *vq);
67 67
68void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); 68void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
69 69
@@ -79,7 +79,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
79 struct virtio_device *vdev, 79 struct virtio_device *vdev,
80 bool weak_barriers, 80 bool weak_barriers,
81 void *pages, 81 void *pages,
82 void (*notify)(struct virtqueue *vq), 82 bool (*notify)(struct virtqueue *vq),
83 void (*callback)(struct virtqueue *vq), 83 void (*callback)(struct virtqueue *vq),
84 const char *name); 84 const char *name);
85void vring_del_virtqueue(struct virtqueue *vq); 85void vring_del_virtqueue(struct virtqueue *vq);
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index bdb71a26ae35..00ea679b3826 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -172,7 +172,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
172 GFP_ATOMIC); 172 GFP_ATOMIC);
173 if (likely(r == 0)) { 173 if (likely(r == 0)) {
174 ++started; 174 ++started;
175 if (unlikely(!virtqueue_kick(vq->vq)) 175 if (unlikely(!virtqueue_kick(vq->vq)))
176 r = -1; 176 r = -1;
177 } 177 }
178 } else 178 } else
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index f9be24d9efac..05654f5e48d5 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -19,7 +19,8 @@
19 * Authors: Wu Fengguang <fengguang.wu@intel.com> 19 * Authors: Wu Fengguang <fengguang.wu@intel.com>
20 */ 20 */
21 21
22#define _LARGEFILE64_SOURCE 22#define _FILE_OFFSET_BITS 64
23#define _GNU_SOURCE
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <unistd.h> 26#include <unistd.h>
@@ -29,11 +30,14 @@
29#include <getopt.h> 30#include <getopt.h>
30#include <limits.h> 31#include <limits.h>
31#include <assert.h> 32#include <assert.h>
33#include <ftw.h>
34#include <time.h>
32#include <sys/types.h> 35#include <sys/types.h>
33#include <sys/errno.h> 36#include <sys/errno.h>
34#include <sys/fcntl.h> 37#include <sys/fcntl.h>
35#include <sys/mount.h> 38#include <sys/mount.h>
36#include <sys/statfs.h> 39#include <sys/statfs.h>
40#include <sys/mman.h>
37#include "../../include/uapi/linux/magic.h" 41#include "../../include/uapi/linux/magic.h"
38#include "../../include/uapi/linux/kernel-page-flags.h" 42#include "../../include/uapi/linux/kernel-page-flags.h"
39#include <api/fs/debugfs.h> 43#include <api/fs/debugfs.h>
@@ -158,6 +162,7 @@ static int opt_raw; /* for kernel developers */
158static int opt_list; /* list pages (in ranges) */ 162static int opt_list; /* list pages (in ranges) */
159static int opt_no_summary; /* don't show summary */ 163static int opt_no_summary; /* don't show summary */
160static pid_t opt_pid; /* process to walk */ 164static pid_t opt_pid; /* process to walk */
165const char * opt_file;
161 166
162#define MAX_ADDR_RANGES 1024 167#define MAX_ADDR_RANGES 1024
163static int nr_addr_ranges; 168static int nr_addr_ranges;
@@ -253,12 +258,7 @@ static unsigned long do_u64_read(int fd, char *name,
253 if (index > ULONG_MAX / 8) 258 if (index > ULONG_MAX / 8)
254 fatal("index overflow: %lu\n", index); 259 fatal("index overflow: %lu\n", index);
255 260
256 if (lseek(fd, index * 8, SEEK_SET) < 0) { 261 bytes = pread(fd, buf, count * 8, (off_t)index * 8);
257 perror(name);
258 exit(EXIT_FAILURE);
259 }
260
261 bytes = read(fd, buf, count * 8);
262 if (bytes < 0) { 262 if (bytes < 0) {
263 perror(name); 263 perror(name);
264 exit(EXIT_FAILURE); 264 exit(EXIT_FAILURE);
@@ -343,8 +343,8 @@ static char *page_flag_longname(uint64_t flags)
343 * page list and summary 343 * page list and summary
344 */ 344 */
345 345
346static void show_page_range(unsigned long voffset, 346static void show_page_range(unsigned long voffset, unsigned long offset,
347 unsigned long offset, uint64_t flags) 347 unsigned long size, uint64_t flags)
348{ 348{
349 static uint64_t flags0; 349 static uint64_t flags0;
350 static unsigned long voff; 350 static unsigned long voff;
@@ -352,14 +352,16 @@ static void show_page_range(unsigned long voffset,
352 static unsigned long count; 352 static unsigned long count;
353 353
354 if (flags == flags0 && offset == index + count && 354 if (flags == flags0 && offset == index + count &&
355 (!opt_pid || voffset == voff + count)) { 355 size && voffset == voff + count) {
356 count++; 356 count += size;
357 return; 357 return;
358 } 358 }
359 359
360 if (count) { 360 if (count) {
361 if (opt_pid) 361 if (opt_pid)
362 printf("%lx\t", voff); 362 printf("%lx\t", voff);
363 if (opt_file)
364 printf("%lu\t", voff);
363 printf("%lx\t%lx\t%s\n", 365 printf("%lx\t%lx\t%s\n",
364 index, count, page_flag_name(flags0)); 366 index, count, page_flag_name(flags0));
365 } 367 }
@@ -367,7 +369,12 @@ static void show_page_range(unsigned long voffset,
367 flags0 = flags; 369 flags0 = flags;
368 index = offset; 370 index = offset;
369 voff = voffset; 371 voff = voffset;
370 count = 1; 372 count = size;
373}
374
375static void flush_page_range(void)
376{
377 show_page_range(0, 0, 0, 0);
371} 378}
372 379
373static void show_page(unsigned long voffset, 380static void show_page(unsigned long voffset,
@@ -375,6 +382,8 @@ static void show_page(unsigned long voffset,
375{ 382{
376 if (opt_pid) 383 if (opt_pid)
377 printf("%lx\t", voffset); 384 printf("%lx\t", voffset);
385 if (opt_file)
386 printf("%lu\t", voffset);
378 printf("%lx\t%s\n", offset, page_flag_name(flags)); 387 printf("%lx\t%s\n", offset, page_flag_name(flags));
379} 388}
380 389
@@ -565,7 +574,7 @@ static void add_page(unsigned long voffset,
565 unpoison_page(offset); 574 unpoison_page(offset);
566 575
567 if (opt_list == 1) 576 if (opt_list == 1)
568 show_page_range(voffset, offset, flags); 577 show_page_range(voffset, offset, 1, flags);
569 else if (opt_list == 2) 578 else if (opt_list == 2)
570 show_page(voffset, offset, flags); 579 show_page(voffset, offset, flags);
571 580
@@ -667,7 +676,7 @@ static void walk_addr_ranges(void)
667 676
668 for (i = 0; i < nr_addr_ranges; i++) 677 for (i = 0; i < nr_addr_ranges; i++)
669 if (!opt_pid) 678 if (!opt_pid)
670 walk_pfn(0, opt_offset[i], opt_size[i], 0); 679 walk_pfn(opt_offset[i], opt_offset[i], opt_size[i], 0);
671 else 680 else
672 walk_task(opt_offset[i], opt_size[i]); 681 walk_task(opt_offset[i], opt_size[i]);
673 682
@@ -699,9 +708,7 @@ static void usage(void)
699" -a|--addr addr-spec Walk a range of pages\n" 708" -a|--addr addr-spec Walk a range of pages\n"
700" -b|--bits bits-spec Walk pages with specified bits\n" 709" -b|--bits bits-spec Walk pages with specified bits\n"
701" -p|--pid pid Walk process address space\n" 710" -p|--pid pid Walk process address space\n"
702#if 0 /* planned features */
703" -f|--file filename Walk file address space\n" 711" -f|--file filename Walk file address space\n"
704#endif
705" -l|--list Show page details in ranges\n" 712" -l|--list Show page details in ranges\n"
706" -L|--list-each Show page details one by one\n" 713" -L|--list-each Show page details one by one\n"
707" -N|--no-summary Don't show summary info\n" 714" -N|--no-summary Don't show summary info\n"
@@ -799,8 +806,130 @@ static void parse_pid(const char *str)
799 fclose(file); 806 fclose(file);
800} 807}
801 808
809static void show_file(const char *name, const struct stat *st)
810{
811 unsigned long long size = st->st_size;
812 char atime[64], mtime[64];
813 long now = time(NULL);
814
815 printf("%s\tInode: %u\tSize: %llu (%llu pages)\n",
816 name, (unsigned)st->st_ino,
817 size, (size + page_size - 1) / page_size);
818
819 strftime(atime, sizeof(atime), "%c", localtime(&st->st_atime));
820 strftime(mtime, sizeof(mtime), "%c", localtime(&st->st_mtime));
821
822 printf("Modify: %s (%ld seconds ago)\nAccess: %s (%ld seconds ago)\n",
823 mtime, now - st->st_mtime,
824 atime, now - st->st_atime);
825}
826
827static void walk_file(const char *name, const struct stat *st)
828{
829 uint8_t vec[PAGEMAP_BATCH];
830 uint64_t buf[PAGEMAP_BATCH], flags;
831 unsigned long nr_pages, pfn, i;
832 int fd;
833 off_t off;
834 ssize_t len;
835 void *ptr;
836 int first = 1;
837
838 fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW);
839
840 for (off = 0; off < st->st_size; off += len) {
841 nr_pages = (st->st_size - off + page_size - 1) / page_size;
842 if (nr_pages > PAGEMAP_BATCH)
843 nr_pages = PAGEMAP_BATCH;
844 len = nr_pages * page_size;
845
846 ptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off);
847 if (ptr == MAP_FAILED)
848 fatal("mmap failed: %s", name);
849
850 /* determine cached pages */
851 if (mincore(ptr, len, vec))
852 fatal("mincore failed: %s", name);
853
854 /* turn off readahead */
855 if (madvise(ptr, len, MADV_RANDOM))
856 fatal("madvice failed: %s", name);
857
858 /* populate ptes */
859 for (i = 0; i < nr_pages ; i++) {
860 if (vec[i] & 1)
861 (void)*(volatile int *)(ptr + i * page_size);
862 }
863
864 /* turn off harvesting reference bits */
865 if (madvise(ptr, len, MADV_SEQUENTIAL))
866 fatal("madvice failed: %s", name);
867
868 if (pagemap_read(buf, (unsigned long)ptr / page_size,
869 nr_pages) != nr_pages)
870 fatal("cannot read pagemap");
871
872 munmap(ptr, len);
873
874 for (i = 0; i < nr_pages; i++) {
875 pfn = pagemap_pfn(buf[i]);
876 if (!pfn)
877 continue;
878 if (!kpageflags_read(&flags, pfn, 1))
879 continue;
880 if (first && opt_list) {
881 first = 0;
882 flush_page_range();
883 show_file(name, st);
884 }
885 add_page(off / page_size + i, pfn, flags, buf[i]);
886 }
887 }
888
889 close(fd);
890}
891
892int walk_tree(const char *name, const struct stat *st, int type, struct FTW *f)
893{
894 (void)f;
895 switch (type) {
896 case FTW_F:
897 if (S_ISREG(st->st_mode))
898 walk_file(name, st);
899 break;
900 case FTW_DNR:
901 fprintf(stderr, "cannot read dir: %s\n", name);
902 break;
903 }
904 return 0;
905}
906
907static void walk_page_cache(void)
908{
909 struct stat st;
910
911 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
912 pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
913
914 if (stat(opt_file, &st))
915 fatal("stat failed: %s\n", opt_file);
916
917 if (S_ISREG(st.st_mode)) {
918 walk_file(opt_file, &st);
919 } else if (S_ISDIR(st.st_mode)) {
920 /* do not follow symlinks and mountpoints */
921 if (nftw(opt_file, walk_tree, 64, FTW_MOUNT | FTW_PHYS) < 0)
922 fatal("nftw failed: %s\n", opt_file);
923 } else
924 fatal("unhandled file type: %s\n", opt_file);
925
926 close(kpageflags_fd);
927 close(pagemap_fd);
928}
929
802static void parse_file(const char *name) 930static void parse_file(const char *name)
803{ 931{
932 opt_file = name;
804} 933}
805 934
806static void parse_addr_range(const char *optarg) 935static void parse_addr_range(const char *optarg)
@@ -991,15 +1120,20 @@ int main(int argc, char *argv[])
991 1120
992 if (opt_list && opt_pid) 1121 if (opt_list && opt_pid)
993 printf("voffset\t"); 1122 printf("voffset\t");
1123 if (opt_list && opt_file)
1124 printf("foffset\t");
994 if (opt_list == 1) 1125 if (opt_list == 1)
995 printf("offset\tlen\tflags\n"); 1126 printf("offset\tlen\tflags\n");
996 if (opt_list == 2) 1127 if (opt_list == 2)
997 printf("offset\tflags\n"); 1128 printf("offset\tflags\n");
998 1129
999 walk_addr_ranges(); 1130 if (opt_file)
1131 walk_page_cache();
1132 else
1133 walk_addr_ranges();
1000 1134
1001 if (opt_list == 1) 1135 if (opt_list == 1)
1002 show_page_range(0, 0, 0); /* drain the buffer */ 1136 flush_page_range();
1003 1137
1004 if (opt_no_summary) 1138 if (opt_no_summary)
1005 return 0; 1139 return 0;