diff options
Diffstat (limited to 'tools')
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 | |||
40 | cpupower: FORCE | 41 | cpupower: FORCE |
41 | $(call descend,power/$@) | 42 | $(call descend,power/$@) |
42 | 43 | ||
43 | cgroup firewire guest usb virtio vm net: FORCE | 44 | cgroup firewire hv guest usb virtio vm net: FORCE |
44 | $(call descend,$@) | 45 | $(call descend,$@) |
45 | 46 | ||
46 | libapikfs: FORCE | 47 | libapikfs: FORCE |
@@ -64,7 +65,7 @@ acpi_install: | |||
64 | cpupower_install: | 65 | cpupower_install: |
65 | $(call descend,power/$(@:_install=),install) | 66 | $(call descend,power/$(@:_install=),install) |
66 | 67 | ||
67 | cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install: | 68 | cgroup_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 | ||
70 | selftests_install: | 71 | selftests_install: |
@@ -76,7 +77,7 @@ turbostat_install x86_energy_perf_policy_install: | |||
76 | tmon_install: | 77 | tmon_install: |
77 | $(call descend,thermal/$(@:_install=),install) | 78 | $(call descend,thermal/$(@:_install=),install) |
78 | 79 | ||
79 | install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \ | 80 | install: 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: | |||
87 | cpupower_clean: | 88 | cpupower_clean: |
88 | $(call descend,power/cpupower,clean) | 89 | $(call descend,power/cpupower,clean) |
89 | 90 | ||
90 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: | 91 | cgroup_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 | ||
93 | libapikfs_clean: | 94 | libapikfs_clean: |
@@ -105,7 +106,7 @@ turbostat_clean x86_energy_perf_policy_clean: | |||
105 | tmon_clean: | 106 | tmon_clean: |
106 | $(call descend,thermal/tmon,clean) | 107 | $(call descend,thermal/tmon,clean) |
107 | 108 | ||
108 | clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \ | 109 | clean: 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 | |||
3 | CC = $(CROSS_COMPILE)gcc | ||
4 | PTHREAD_LIBS = -lpthread | ||
5 | WARNINGS = -Wall -Wextra | ||
6 | CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) | ||
7 | |||
8 | all: hv_kvp_daemon hv_vss_daemon | ||
9 | %: %.c | ||
10 | $(CC) $(CFLAGS) -o $@ $^ | ||
11 | |||
12 | clean: | ||
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 | |||
37 | static int target_fd; | ||
38 | static char target_fname[W_MAX_PATH]; | ||
39 | |||
40 | static 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; | ||
96 | done: | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | static 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 | |||
113 | static int hv_copy_finished(void) | ||
114 | { | ||
115 | close(target_fd); | ||
116 | return 0; | ||
117 | } | ||
118 | static int hv_copy_cancel(void) | ||
119 | { | ||
120 | close(target_fd); | ||
121 | unlink(target_fname); | ||
122 | return 0; | ||
123 | |||
124 | } | ||
125 | |||
126 | int 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 | |||
93 | enum { | 90 | enum { |
94 | CMD_OK, | 91 | CMD_OK, |
95 | CMD_ERR, | 92 | CMD_ERR, |
@@ -145,32 +142,32 @@ static size_t pcap_map_size = 0; | |||
145 | static char *pcap_ptr_va_start, *pcap_ptr_va_curr; | 142 | static char *pcap_ptr_va_start, *pcap_ptr_va_curr; |
146 | 143 | ||
147 | static const char * const op_table[] = { | 144 | static 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 | ||
176 | static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) | 173 | static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) |
@@ -1127,7 +1124,6 @@ static int cmd_step(char *num) | |||
1127 | static int cmd_select(char *num) | 1124 | static 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) | |||
1177 | static int cmd_run(char *num) | 1173 | static 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 | ||
1247 | static const struct shell_cmd cmds[] = { | 1242 | static 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 | ||
1258 | static int execf(char *arg) | 1253 | static int execf(char *arg) |
@@ -1280,7 +1275,6 @@ out: | |||
1280 | static char *shell_comp_gen(const char *buf, int state) | 1275 | static 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 | ||
1358 | static void exit_shell(void) | 1347 | static 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 | ||
1373 | static int run_shell_loop(FILE *fin, FILE *fout) | 1365 | static 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 |
11 | ifeq ($(ARCH),i386) | 12 | ifeq ($(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 |
11 | CONSOLE = virsh console ${MACHINE} | 11 | CONSOLE = virsh console ${MACHINE} |
12 | 12 | ||
13 | # Use SIGKILL to terminate virsh console. We can't kill virsh console | ||
14 | # by the default signal, SIGINT. | ||
15 | CLOSE_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 | ||
14 | export CC CFLAGS | 14 | export CC CFLAGS |
15 | 15 | ||
16 | TARGETS = pmu | 16 | TARGETS = pmu copyloops |
17 | 17 | ||
18 | endif | 18 | endif |
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 | ||
2 | CFLAGS += -m64 | ||
3 | CFLAGS += -I$(CURDIR) | ||
4 | CFLAGS += -D SELFTEST | ||
5 | |||
6 | # Use our CFLAGS for the implicit .S rule | ||
7 | ASFLAGS = $(CFLAGS) | ||
8 | |||
9 | PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 | ||
10 | EXTRA_SOURCES := validate.c ../harness.c | ||
11 | |||
12 | all: $(PROGS) | ||
13 | |||
14 | copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base | ||
15 | copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7 | ||
16 | memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy | ||
17 | memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7 | ||
18 | |||
19 | $(PROGS): $(EXTRA_SOURCES) | ||
20 | |||
21 | run_tests: all | ||
22 | @-for PROG in $(PROGS); do \ | ||
23 | ./$$PROG; \ | ||
24 | done; | ||
25 | |||
26 | clean: | ||
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 | |||
58 | FUNC_START(enter_vmx_usercopy) | ||
59 | li r3,1 | ||
60 | blr | ||
61 | |||
62 | FUNC_START(exit_vmx_usercopy) | ||
63 | li r3,0 | ||
64 | blr | ||
65 | |||
66 | FUNC_START(enter_vmx_copy) | ||
67 | li r3,1 | ||
68 | blr | ||
69 | |||
70 | FUNC_START(exit_vmx_copy) | ||
71 | blr | ||
72 | |||
73 | FUNC_START(memcpy_power7) | ||
74 | blr | ||
75 | |||
76 | FUNC_START(__copy_tofrom_user_power7) | ||
77 | blr | ||
78 | |||
79 | FUNC_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 | |||
14 | unsigned long COPY_LOOP(void *to, const void *from, unsigned long size); | ||
15 | |||
16 | static 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 | |||
62 | int 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 | |||
96 | int 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 @@ | |||
1 | static 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 | ||
66 | void virtqueue_kick(struct virtqueue *vq); | 66 | bool virtqueue_kick(struct virtqueue *vq); |
67 | 67 | ||
68 | void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); | 68 | void *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); |
85 | void vring_del_virtqueue(struct virtqueue *vq); | 85 | void 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 */ | |||
158 | static int opt_list; /* list pages (in ranges) */ | 162 | static int opt_list; /* list pages (in ranges) */ |
159 | static int opt_no_summary; /* don't show summary */ | 163 | static int opt_no_summary; /* don't show summary */ |
160 | static pid_t opt_pid; /* process to walk */ | 164 | static pid_t opt_pid; /* process to walk */ |
165 | const char * opt_file; | ||
161 | 166 | ||
162 | #define MAX_ADDR_RANGES 1024 | 167 | #define MAX_ADDR_RANGES 1024 |
163 | static int nr_addr_ranges; | 168 | static 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 | ||
346 | static void show_page_range(unsigned long voffset, | 346 | static 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 | |||
375 | static void flush_page_range(void) | ||
376 | { | ||
377 | show_page_range(0, 0, 0, 0); | ||
371 | } | 378 | } |
372 | 379 | ||
373 | static void show_page(unsigned long voffset, | 380 | static 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 | ||
809 | static 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 | |||
827 | static 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 | |||
892 | int 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 | |||
907 | static 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 | |||
802 | static void parse_file(const char *name) | 930 | static void parse_file(const char *name) |
803 | { | 931 | { |
932 | opt_file = name; | ||
804 | } | 933 | } |
805 | 934 | ||
806 | static void parse_addr_range(const char *optarg) | 935 | static 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; |