diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-10-24 04:20:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-10-24 04:20:57 -0400 |
commit | ef8c029fa793423439e67ef0416b220d3fa3321a (patch) | |
tree | 4199cefa6e1dcad1783040755246a14371f029af /tools | |
parent | 6fcdb1ed2ef3548d5a9428d6ae60158ddd46a608 (diff) | |
parent | c13d38e4a1fd5dd07135403c613c8091af444169 (diff) |
Merge branch 'perf/urgent' into perf/core
Pick up v3.7-rc2 and fixes before applying more patches.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
49 files changed, 3179 insertions, 233 deletions
diff --git a/tools/hv/hv_get_dhcp_info.sh b/tools/hv/hv_get_dhcp_info.sh new file mode 100755 index 00000000000..ccd3e953276 --- /dev/null +++ b/tools/hv/hv_get_dhcp_info.sh | |||
@@ -0,0 +1,28 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This example script retrieves the DHCP state of a given interface. | ||
4 | # In the interest of keeping the KVP daemon code free of distro specific | ||
5 | # information; the kvp daemon code invokes this external script to gather | ||
6 | # DHCP setting for the specific interface. | ||
7 | # | ||
8 | # Input: Name of the interface | ||
9 | # | ||
10 | # Output: The script prints the string "Enabled" to stdout to indicate | ||
11 | # that DHCP is enabled on the interface. If DHCP is not enabled, | ||
12 | # the script prints the string "Disabled" to stdout. | ||
13 | # | ||
14 | # Each Distro is expected to implement this script in a distro specific | ||
15 | # fashion. For instance on Distros that ship with Network Manager enabled, | ||
16 | # this script can be based on the Network Manager APIs for retrieving DHCP | ||
17 | # information. | ||
18 | |||
19 | if_file="/etc/sysconfig/network-scripts/ifcfg-"$1 | ||
20 | |||
21 | dhcp=$(grep "dhcp" $if_file 2>/dev/null) | ||
22 | |||
23 | if [ "$dhcp" != "" ]; | ||
24 | then | ||
25 | echo "Enabled" | ||
26 | else | ||
27 | echo "Disabled" | ||
28 | fi | ||
diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh new file mode 100755 index 00000000000..058c17b46ff --- /dev/null +++ b/tools/hv/hv_get_dns_info.sh | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This example script parses /etc/resolv.conf to retrive DNS information. | ||
4 | # In the interest of keeping the KVP daemon code free of distro specific | ||
5 | # information; the kvp daemon code invokes this external script to gather | ||
6 | # DNS information. | ||
7 | # This script is expected to print the nameserver values to stdout. | ||
8 | # Each Distro is expected to implement this script in a distro specific | ||
9 | # fashion. For instance on Distros that ship with Network Manager enabled, | ||
10 | # this script can be based on the Network Manager APIs for retrieving DNS | ||
11 | # entries. | ||
12 | |||
13 | cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' | ||
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index d9834b36294..5959affd882 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | #include <unistd.h> | 32 | #include <unistd.h> |
33 | #include <string.h> | 33 | #include <string.h> |
34 | #include <ctype.h> | ||
34 | #include <errno.h> | 35 | #include <errno.h> |
35 | #include <arpa/inet.h> | 36 | #include <arpa/inet.h> |
36 | #include <linux/connector.h> | 37 | #include <linux/connector.h> |
@@ -41,6 +42,7 @@ | |||
41 | #include <syslog.h> | 42 | #include <syslog.h> |
42 | #include <sys/stat.h> | 43 | #include <sys/stat.h> |
43 | #include <fcntl.h> | 44 | #include <fcntl.h> |
45 | #include <dirent.h> | ||
44 | 46 | ||
45 | /* | 47 | /* |
46 | * KVP protocol: The user mode component first registers with the | 48 | * KVP protocol: The user mode component first registers with the |
@@ -68,25 +70,39 @@ enum key_index { | |||
68 | ProcessorArchitecture | 70 | ProcessorArchitecture |
69 | }; | 71 | }; |
70 | 72 | ||
73 | |||
74 | enum { | ||
75 | IPADDR = 0, | ||
76 | NETMASK, | ||
77 | GATEWAY, | ||
78 | DNS | ||
79 | }; | ||
80 | |||
71 | static char kvp_send_buffer[4096]; | 81 | static char kvp_send_buffer[4096]; |
72 | static char kvp_recv_buffer[4096]; | 82 | static char kvp_recv_buffer[4096 * 2]; |
73 | static struct sockaddr_nl addr; | 83 | static struct sockaddr_nl addr; |
84 | static int in_hand_shake = 1; | ||
74 | 85 | ||
75 | static char *os_name = ""; | 86 | static char *os_name = ""; |
76 | static char *os_major = ""; | 87 | static char *os_major = ""; |
77 | static char *os_minor = ""; | 88 | static char *os_minor = ""; |
78 | static char *processor_arch; | 89 | static char *processor_arch; |
79 | static char *os_build; | 90 | static char *os_build; |
80 | static char *lic_version; | 91 | static char *lic_version = "Unknown version"; |
81 | static struct utsname uts_buf; | 92 | static struct utsname uts_buf; |
82 | 93 | ||
94 | /* | ||
95 | * The location of the interface configuration file. | ||
96 | */ | ||
97 | |||
98 | #define KVP_CONFIG_LOC "/var/opt/" | ||
83 | 99 | ||
84 | #define MAX_FILE_NAME 100 | 100 | #define MAX_FILE_NAME 100 |
85 | #define ENTRIES_PER_BLOCK 50 | 101 | #define ENTRIES_PER_BLOCK 50 |
86 | 102 | ||
87 | struct kvp_record { | 103 | struct kvp_record { |
88 | __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; | 104 | char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; |
89 | __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; | 105 | char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; |
90 | }; | 106 | }; |
91 | 107 | ||
92 | struct kvp_file_state { | 108 | struct kvp_file_state { |
@@ -94,7 +110,7 @@ struct kvp_file_state { | |||
94 | int num_blocks; | 110 | int num_blocks; |
95 | struct kvp_record *records; | 111 | struct kvp_record *records; |
96 | int num_records; | 112 | int num_records; |
97 | __u8 fname[MAX_FILE_NAME]; | 113 | char fname[MAX_FILE_NAME]; |
98 | }; | 114 | }; |
99 | 115 | ||
100 | static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; | 116 | static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; |
@@ -106,7 +122,7 @@ static void kvp_acquire_lock(int pool) | |||
106 | 122 | ||
107 | if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { | 123 | if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { |
108 | syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); | 124 | syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); |
109 | exit(-1); | 125 | exit(EXIT_FAILURE); |
110 | } | 126 | } |
111 | } | 127 | } |
112 | 128 | ||
@@ -118,7 +134,7 @@ static void kvp_release_lock(int pool) | |||
118 | if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { | 134 | if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { |
119 | perror("fcntl"); | 135 | perror("fcntl"); |
120 | syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); | 136 | syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); |
121 | exit(-1); | 137 | exit(EXIT_FAILURE); |
122 | } | 138 | } |
123 | } | 139 | } |
124 | 140 | ||
@@ -137,14 +153,19 @@ static void kvp_update_file(int pool) | |||
137 | if (!filep) { | 153 | if (!filep) { |
138 | kvp_release_lock(pool); | 154 | kvp_release_lock(pool); |
139 | syslog(LOG_ERR, "Failed to open file, pool: %d", pool); | 155 | syslog(LOG_ERR, "Failed to open file, pool: %d", pool); |
140 | exit(-1); | 156 | exit(EXIT_FAILURE); |
141 | } | 157 | } |
142 | 158 | ||
143 | bytes_written = fwrite(kvp_file_info[pool].records, | 159 | bytes_written = fwrite(kvp_file_info[pool].records, |
144 | sizeof(struct kvp_record), | 160 | sizeof(struct kvp_record), |
145 | kvp_file_info[pool].num_records, filep); | 161 | kvp_file_info[pool].num_records, filep); |
146 | 162 | ||
147 | fflush(filep); | 163 | if (ferror(filep) || fclose(filep)) { |
164 | kvp_release_lock(pool); | ||
165 | syslog(LOG_ERR, "Failed to write file, pool: %d", pool); | ||
166 | exit(EXIT_FAILURE); | ||
167 | } | ||
168 | |||
148 | kvp_release_lock(pool); | 169 | kvp_release_lock(pool); |
149 | } | 170 | } |
150 | 171 | ||
@@ -163,14 +184,19 @@ static void kvp_update_mem_state(int pool) | |||
163 | if (!filep) { | 184 | if (!filep) { |
164 | kvp_release_lock(pool); | 185 | kvp_release_lock(pool); |
165 | syslog(LOG_ERR, "Failed to open file, pool: %d", pool); | 186 | syslog(LOG_ERR, "Failed to open file, pool: %d", pool); |
166 | exit(-1); | 187 | exit(EXIT_FAILURE); |
167 | } | 188 | } |
168 | while (!feof(filep)) { | 189 | for (;;) { |
169 | readp = &record[records_read]; | 190 | readp = &record[records_read]; |
170 | records_read += fread(readp, sizeof(struct kvp_record), | 191 | records_read += fread(readp, sizeof(struct kvp_record), |
171 | ENTRIES_PER_BLOCK * num_blocks, | 192 | ENTRIES_PER_BLOCK * num_blocks, |
172 | filep); | 193 | filep); |
173 | 194 | ||
195 | if (ferror(filep)) { | ||
196 | syslog(LOG_ERR, "Failed to read file, pool: %d", pool); | ||
197 | exit(EXIT_FAILURE); | ||
198 | } | ||
199 | |||
174 | if (!feof(filep)) { | 200 | if (!feof(filep)) { |
175 | /* | 201 | /* |
176 | * We have more data to read. | 202 | * We have more data to read. |
@@ -180,7 +206,7 @@ static void kvp_update_mem_state(int pool) | |||
180 | 206 | ||
181 | if (record == NULL) { | 207 | if (record == NULL) { |
182 | syslog(LOG_ERR, "malloc failed"); | 208 | syslog(LOG_ERR, "malloc failed"); |
183 | exit(-1); | 209 | exit(EXIT_FAILURE); |
184 | } | 210 | } |
185 | continue; | 211 | continue; |
186 | } | 212 | } |
@@ -191,14 +217,15 @@ static void kvp_update_mem_state(int pool) | |||
191 | kvp_file_info[pool].records = record; | 217 | kvp_file_info[pool].records = record; |
192 | kvp_file_info[pool].num_records = records_read; | 218 | kvp_file_info[pool].num_records = records_read; |
193 | 219 | ||
220 | fclose(filep); | ||
194 | kvp_release_lock(pool); | 221 | kvp_release_lock(pool); |
195 | } | 222 | } |
196 | static int kvp_file_init(void) | 223 | static int kvp_file_init(void) |
197 | { | 224 | { |
198 | int ret, fd; | 225 | int fd; |
199 | FILE *filep; | 226 | FILE *filep; |
200 | size_t records_read; | 227 | size_t records_read; |
201 | __u8 *fname; | 228 | char *fname; |
202 | struct kvp_record *record; | 229 | struct kvp_record *record; |
203 | struct kvp_record *readp; | 230 | struct kvp_record *readp; |
204 | int num_blocks; | 231 | int num_blocks; |
@@ -208,7 +235,7 @@ static int kvp_file_init(void) | |||
208 | if (access("/var/opt/hyperv", F_OK)) { | 235 | if (access("/var/opt/hyperv", F_OK)) { |
209 | if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { | 236 | if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { |
210 | syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); | 237 | syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); |
211 | exit(-1); | 238 | exit(EXIT_FAILURE); |
212 | } | 239 | } |
213 | } | 240 | } |
214 | 241 | ||
@@ -232,12 +259,18 @@ static int kvp_file_init(void) | |||
232 | fclose(filep); | 259 | fclose(filep); |
233 | return 1; | 260 | return 1; |
234 | } | 261 | } |
235 | while (!feof(filep)) { | 262 | for (;;) { |
236 | readp = &record[records_read]; | 263 | readp = &record[records_read]; |
237 | records_read += fread(readp, sizeof(struct kvp_record), | 264 | records_read += fread(readp, sizeof(struct kvp_record), |
238 | ENTRIES_PER_BLOCK, | 265 | ENTRIES_PER_BLOCK, |
239 | filep); | 266 | filep); |
240 | 267 | ||
268 | if (ferror(filep)) { | ||
269 | syslog(LOG_ERR, "Failed to read file, pool: %d", | ||
270 | i); | ||
271 | exit(EXIT_FAILURE); | ||
272 | } | ||
273 | |||
241 | if (!feof(filep)) { | 274 | if (!feof(filep)) { |
242 | /* | 275 | /* |
243 | * We have more data to read. | 276 | * We have more data to read. |
@@ -311,7 +344,6 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, | |||
311 | int value_size) | 344 | int value_size) |
312 | { | 345 | { |
313 | int i; | 346 | int i; |
314 | int j, k; | ||
315 | int num_records; | 347 | int num_records; |
316 | struct kvp_record *record; | 348 | struct kvp_record *record; |
317 | int num_blocks; | 349 | int num_blocks; |
@@ -394,7 +426,7 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, | |||
394 | return 1; | 426 | return 1; |
395 | } | 427 | } |
396 | 428 | ||
397 | static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | 429 | static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, |
398 | __u8 *value, int value_size) | 430 | __u8 *value, int value_size) |
399 | { | 431 | { |
400 | struct kvp_record *record; | 432 | struct kvp_record *record; |
@@ -406,16 +438,12 @@ static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | |||
406 | record = kvp_file_info[pool].records; | 438 | record = kvp_file_info[pool].records; |
407 | 439 | ||
408 | if (index >= kvp_file_info[pool].num_records) { | 440 | if (index >= kvp_file_info[pool].num_records) { |
409 | /* | 441 | return 1; |
410 | * This is an invalid index; terminate enumeration; | ||
411 | * - a NULL value will do the trick. | ||
412 | */ | ||
413 | strcpy(value, ""); | ||
414 | return; | ||
415 | } | 442 | } |
416 | 443 | ||
417 | memcpy(key, record[index].key, key_size); | 444 | memcpy(key, record[index].key, key_size); |
418 | memcpy(value, record[index].value, value_size); | 445 | memcpy(value, record[index].value, value_size); |
446 | return 0; | ||
419 | } | 447 | } |
420 | 448 | ||
421 | 449 | ||
@@ -426,6 +454,7 @@ void kvp_get_os_info(void) | |||
426 | 454 | ||
427 | uname(&uts_buf); | 455 | uname(&uts_buf); |
428 | os_build = uts_buf.release; | 456 | os_build = uts_buf.release; |
457 | os_name = uts_buf.sysname; | ||
429 | processor_arch = uts_buf.machine; | 458 | processor_arch = uts_buf.machine; |
430 | 459 | ||
431 | /* | 460 | /* |
@@ -437,20 +466,70 @@ void kvp_get_os_info(void) | |||
437 | if (p) | 466 | if (p) |
438 | *p = '\0'; | 467 | *p = '\0'; |
439 | 468 | ||
469 | /* | ||
470 | * Parse the /etc/os-release file if present: | ||
471 | * http://www.freedesktop.org/software/systemd/man/os-release.html | ||
472 | */ | ||
473 | file = fopen("/etc/os-release", "r"); | ||
474 | if (file != NULL) { | ||
475 | while (fgets(buf, sizeof(buf), file)) { | ||
476 | char *value, *q; | ||
477 | |||
478 | /* Ignore comments */ | ||
479 | if (buf[0] == '#') | ||
480 | continue; | ||
481 | |||
482 | /* Split into name=value */ | ||
483 | p = strchr(buf, '='); | ||
484 | if (!p) | ||
485 | continue; | ||
486 | *p++ = 0; | ||
487 | |||
488 | /* Remove quotes and newline; un-escape */ | ||
489 | value = p; | ||
490 | q = p; | ||
491 | while (*p) { | ||
492 | if (*p == '\\') { | ||
493 | ++p; | ||
494 | if (!*p) | ||
495 | break; | ||
496 | *q++ = *p++; | ||
497 | } else if (*p == '\'' || *p == '"' || | ||
498 | *p == '\n') { | ||
499 | ++p; | ||
500 | } else { | ||
501 | *q++ = *p++; | ||
502 | } | ||
503 | } | ||
504 | *q = 0; | ||
505 | |||
506 | if (!strcmp(buf, "NAME")) { | ||
507 | p = strdup(value); | ||
508 | if (!p) | ||
509 | break; | ||
510 | os_name = p; | ||
511 | } else if (!strcmp(buf, "VERSION_ID")) { | ||
512 | p = strdup(value); | ||
513 | if (!p) | ||
514 | break; | ||
515 | os_major = p; | ||
516 | } | ||
517 | } | ||
518 | fclose(file); | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | /* Fallback for older RH/SUSE releases */ | ||
440 | file = fopen("/etc/SuSE-release", "r"); | 523 | file = fopen("/etc/SuSE-release", "r"); |
441 | if (file != NULL) | 524 | if (file != NULL) |
442 | goto kvp_osinfo_found; | 525 | goto kvp_osinfo_found; |
443 | file = fopen("/etc/redhat-release", "r"); | 526 | file = fopen("/etc/redhat-release", "r"); |
444 | if (file != NULL) | 527 | if (file != NULL) |
445 | goto kvp_osinfo_found; | 528 | goto kvp_osinfo_found; |
446 | /* | ||
447 | * Add code for other supported platforms. | ||
448 | */ | ||
449 | 529 | ||
450 | /* | 530 | /* |
451 | * We don't have information about the os. | 531 | * We don't have information about the os. |
452 | */ | 532 | */ |
453 | os_name = uts_buf.sysname; | ||
454 | return; | 533 | return; |
455 | 534 | ||
456 | kvp_osinfo_found: | 535 | kvp_osinfo_found: |
@@ -494,82 +573,458 @@ done: | |||
494 | return; | 573 | return; |
495 | } | 574 | } |
496 | 575 | ||
576 | |||
577 | |||
578 | /* | ||
579 | * Retrieve an interface name corresponding to the specified guid. | ||
580 | * If there is a match, the function returns a pointer | ||
581 | * to the interface name and if not, a NULL is returned. | ||
582 | * If a match is found, the caller is responsible for | ||
583 | * freeing the memory. | ||
584 | */ | ||
585 | |||
586 | static char *kvp_get_if_name(char *guid) | ||
587 | { | ||
588 | DIR *dir; | ||
589 | struct dirent *entry; | ||
590 | FILE *file; | ||
591 | char *p, *q, *x; | ||
592 | char *if_name = NULL; | ||
593 | char buf[256]; | ||
594 | char *kvp_net_dir = "/sys/class/net/"; | ||
595 | char dev_id[256]; | ||
596 | |||
597 | dir = opendir(kvp_net_dir); | ||
598 | if (dir == NULL) | ||
599 | return NULL; | ||
600 | |||
601 | snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); | ||
602 | q = dev_id + strlen(kvp_net_dir); | ||
603 | |||
604 | while ((entry = readdir(dir)) != NULL) { | ||
605 | /* | ||
606 | * Set the state for the next pass. | ||
607 | */ | ||
608 | *q = '\0'; | ||
609 | strcat(dev_id, entry->d_name); | ||
610 | strcat(dev_id, "/device/device_id"); | ||
611 | |||
612 | file = fopen(dev_id, "r"); | ||
613 | if (file == NULL) | ||
614 | continue; | ||
615 | |||
616 | p = fgets(buf, sizeof(buf), file); | ||
617 | if (p) { | ||
618 | x = strchr(p, '\n'); | ||
619 | if (x) | ||
620 | *x = '\0'; | ||
621 | |||
622 | if (!strcmp(p, guid)) { | ||
623 | /* | ||
624 | * Found the guid match; return the interface | ||
625 | * name. The caller will free the memory. | ||
626 | */ | ||
627 | if_name = strdup(entry->d_name); | ||
628 | fclose(file); | ||
629 | break; | ||
630 | } | ||
631 | } | ||
632 | fclose(file); | ||
633 | } | ||
634 | |||
635 | closedir(dir); | ||
636 | return if_name; | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * Retrieve the MAC address given the interface name. | ||
641 | */ | ||
642 | |||
643 | static char *kvp_if_name_to_mac(char *if_name) | ||
644 | { | ||
645 | FILE *file; | ||
646 | char *p, *x; | ||
647 | char buf[256]; | ||
648 | char addr_file[256]; | ||
649 | int i; | ||
650 | char *mac_addr = NULL; | ||
651 | |||
652 | snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/", | ||
653 | if_name, "/address"); | ||
654 | |||
655 | file = fopen(addr_file, "r"); | ||
656 | if (file == NULL) | ||
657 | return NULL; | ||
658 | |||
659 | p = fgets(buf, sizeof(buf), file); | ||
660 | if (p) { | ||
661 | x = strchr(p, '\n'); | ||
662 | if (x) | ||
663 | *x = '\0'; | ||
664 | for (i = 0; i < strlen(p); i++) | ||
665 | p[i] = toupper(p[i]); | ||
666 | mac_addr = strdup(p); | ||
667 | } | ||
668 | |||
669 | fclose(file); | ||
670 | return mac_addr; | ||
671 | } | ||
672 | |||
673 | |||
674 | /* | ||
675 | * Retrieve the interface name given tha MAC address. | ||
676 | */ | ||
677 | |||
678 | static char *kvp_mac_to_if_name(char *mac) | ||
679 | { | ||
680 | DIR *dir; | ||
681 | struct dirent *entry; | ||
682 | FILE *file; | ||
683 | char *p, *q, *x; | ||
684 | char *if_name = NULL; | ||
685 | char buf[256]; | ||
686 | char *kvp_net_dir = "/sys/class/net/"; | ||
687 | char dev_id[256]; | ||
688 | int i; | ||
689 | |||
690 | dir = opendir(kvp_net_dir); | ||
691 | if (dir == NULL) | ||
692 | return NULL; | ||
693 | |||
694 | snprintf(dev_id, sizeof(dev_id), kvp_net_dir); | ||
695 | q = dev_id + strlen(kvp_net_dir); | ||
696 | |||
697 | while ((entry = readdir(dir)) != NULL) { | ||
698 | /* | ||
699 | * Set the state for the next pass. | ||
700 | */ | ||
701 | *q = '\0'; | ||
702 | |||
703 | strcat(dev_id, entry->d_name); | ||
704 | strcat(dev_id, "/address"); | ||
705 | |||
706 | file = fopen(dev_id, "r"); | ||
707 | if (file == NULL) | ||
708 | continue; | ||
709 | |||
710 | p = fgets(buf, sizeof(buf), file); | ||
711 | if (p) { | ||
712 | x = strchr(p, '\n'); | ||
713 | if (x) | ||
714 | *x = '\0'; | ||
715 | |||
716 | for (i = 0; i < strlen(p); i++) | ||
717 | p[i] = toupper(p[i]); | ||
718 | |||
719 | if (!strcmp(p, mac)) { | ||
720 | /* | ||
721 | * Found the MAC match; return the interface | ||
722 | * name. The caller will free the memory. | ||
723 | */ | ||
724 | if_name = strdup(entry->d_name); | ||
725 | fclose(file); | ||
726 | break; | ||
727 | } | ||
728 | } | ||
729 | fclose(file); | ||
730 | } | ||
731 | |||
732 | closedir(dir); | ||
733 | return if_name; | ||
734 | } | ||
735 | |||
736 | |||
737 | static void kvp_process_ipconfig_file(char *cmd, | ||
738 | char *config_buf, int len, | ||
739 | int element_size, int offset) | ||
740 | { | ||
741 | char buf[256]; | ||
742 | char *p; | ||
743 | char *x; | ||
744 | FILE *file; | ||
745 | |||
746 | /* | ||
747 | * First execute the command. | ||
748 | */ | ||
749 | file = popen(cmd, "r"); | ||
750 | if (file == NULL) | ||
751 | return; | ||
752 | |||
753 | if (offset == 0) | ||
754 | memset(config_buf, 0, len); | ||
755 | while ((p = fgets(buf, sizeof(buf), file)) != NULL) { | ||
756 | if ((len - strlen(config_buf)) < (element_size + 1)) | ||
757 | break; | ||
758 | |||
759 | x = strchr(p, '\n'); | ||
760 | *x = '\0'; | ||
761 | strcat(config_buf, p); | ||
762 | strcat(config_buf, ";"); | ||
763 | } | ||
764 | pclose(file); | ||
765 | } | ||
766 | |||
767 | static void kvp_get_ipconfig_info(char *if_name, | ||
768 | struct hv_kvp_ipaddr_value *buffer) | ||
769 | { | ||
770 | char cmd[512]; | ||
771 | char dhcp_info[128]; | ||
772 | char *p; | ||
773 | FILE *file; | ||
774 | |||
775 | /* | ||
776 | * Get the address of default gateway (ipv4). | ||
777 | */ | ||
778 | sprintf(cmd, "%s %s", "ip route show dev", if_name); | ||
779 | strcat(cmd, " | awk '/default/ {print $3 }'"); | ||
780 | |||
781 | /* | ||
782 | * Execute the command to gather gateway info. | ||
783 | */ | ||
784 | kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, | ||
785 | (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); | ||
786 | |||
787 | /* | ||
788 | * Get the address of default gateway (ipv6). | ||
789 | */ | ||
790 | sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name); | ||
791 | strcat(cmd, " | awk '/default/ {print $3 }'"); | ||
792 | |||
793 | /* | ||
794 | * Execute the command to gather gateway info (ipv6). | ||
795 | */ | ||
796 | kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, | ||
797 | (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); | ||
798 | |||
799 | |||
800 | /* | ||
801 | * Gather the DNS state. | ||
802 | * Since there is no standard way to get this information | ||
803 | * across various distributions of interest; we just invoke | ||
804 | * an external script that needs to be ported across distros | ||
805 | * of interest. | ||
806 | * | ||
807 | * Following is the expected format of the information from the script: | ||
808 | * | ||
809 | * ipaddr1 (nameserver1) | ||
810 | * ipaddr2 (nameserver2) | ||
811 | * . | ||
812 | * . | ||
813 | */ | ||
814 | |||
815 | sprintf(cmd, "%s", "hv_get_dns_info"); | ||
816 | |||
817 | /* | ||
818 | * Execute the command to gather DNS info. | ||
819 | */ | ||
820 | kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, | ||
821 | (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); | ||
822 | |||
823 | /* | ||
824 | * Gather the DHCP state. | ||
825 | * We will gather this state by invoking an external script. | ||
826 | * The parameter to the script is the interface name. | ||
827 | * Here is the expected output: | ||
828 | * | ||
829 | * Enabled: DHCP enabled. | ||
830 | */ | ||
831 | |||
832 | sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name); | ||
833 | |||
834 | file = popen(cmd, "r"); | ||
835 | if (file == NULL) | ||
836 | return; | ||
837 | |||
838 | p = fgets(dhcp_info, sizeof(dhcp_info), file); | ||
839 | if (p == NULL) { | ||
840 | pclose(file); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | if (!strncmp(p, "Enabled", 7)) | ||
845 | buffer->dhcp_enabled = 1; | ||
846 | else | ||
847 | buffer->dhcp_enabled = 0; | ||
848 | |||
849 | pclose(file); | ||
850 | } | ||
851 | |||
852 | |||
853 | static unsigned int hweight32(unsigned int *w) | ||
854 | { | ||
855 | unsigned int res = *w - ((*w >> 1) & 0x55555555); | ||
856 | res = (res & 0x33333333) + ((res >> 2) & 0x33333333); | ||
857 | res = (res + (res >> 4)) & 0x0F0F0F0F; | ||
858 | res = res + (res >> 8); | ||
859 | return (res + (res >> 16)) & 0x000000FF; | ||
860 | } | ||
861 | |||
862 | static int kvp_process_ip_address(void *addrp, | ||
863 | int family, char *buffer, | ||
864 | int length, int *offset) | ||
865 | { | ||
866 | struct sockaddr_in *addr; | ||
867 | struct sockaddr_in6 *addr6; | ||
868 | int addr_length; | ||
869 | char tmp[50]; | ||
870 | const char *str; | ||
871 | |||
872 | if (family == AF_INET) { | ||
873 | addr = (struct sockaddr_in *)addrp; | ||
874 | str = inet_ntop(family, &addr->sin_addr, tmp, 50); | ||
875 | addr_length = INET_ADDRSTRLEN; | ||
876 | } else { | ||
877 | addr6 = (struct sockaddr_in6 *)addrp; | ||
878 | str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); | ||
879 | addr_length = INET6_ADDRSTRLEN; | ||
880 | } | ||
881 | |||
882 | if ((length - *offset) < addr_length + 1) | ||
883 | return HV_E_FAIL; | ||
884 | if (str == NULL) { | ||
885 | strcpy(buffer, "inet_ntop failed\n"); | ||
886 | return HV_E_FAIL; | ||
887 | } | ||
888 | if (*offset == 0) | ||
889 | strcpy(buffer, tmp); | ||
890 | else | ||
891 | strcat(buffer, tmp); | ||
892 | strcat(buffer, ";"); | ||
893 | |||
894 | *offset += strlen(str) + 1; | ||
895 | return 0; | ||
896 | } | ||
897 | |||
497 | static int | 898 | static int |
498 | kvp_get_ip_address(int family, char *buffer, int length) | 899 | kvp_get_ip_info(int family, char *if_name, int op, |
900 | void *out_buffer, int length) | ||
499 | { | 901 | { |
500 | struct ifaddrs *ifap; | 902 | struct ifaddrs *ifap; |
501 | struct ifaddrs *curp; | 903 | struct ifaddrs *curp; |
502 | int ipv4_len = strlen("255.255.255.255") + 1; | ||
503 | int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1; | ||
504 | int offset = 0; | 904 | int offset = 0; |
505 | const char *str; | 905 | int sn_offset = 0; |
506 | char tmp[50]; | ||
507 | int error = 0; | 906 | int error = 0; |
508 | 907 | char *buffer; | |
908 | struct hv_kvp_ipaddr_value *ip_buffer; | ||
909 | char cidr_mask[5]; /* /xyz */ | ||
910 | int weight; | ||
911 | int i; | ||
912 | unsigned int *w; | ||
913 | char *sn_str; | ||
914 | struct sockaddr_in6 *addr6; | ||
915 | |||
916 | if (op == KVP_OP_ENUMERATE) { | ||
917 | buffer = out_buffer; | ||
918 | } else { | ||
919 | ip_buffer = out_buffer; | ||
920 | buffer = (char *)ip_buffer->ip_addr; | ||
921 | ip_buffer->addr_family = 0; | ||
922 | } | ||
509 | /* | 923 | /* |
510 | * On entry into this function, the buffer is capable of holding the | 924 | * On entry into this function, the buffer is capable of holding the |
511 | * maximum key value (2048 bytes). | 925 | * maximum key value. |
512 | */ | 926 | */ |
513 | 927 | ||
514 | if (getifaddrs(&ifap)) { | 928 | if (getifaddrs(&ifap)) { |
515 | strcpy(buffer, "getifaddrs failed\n"); | 929 | strcpy(buffer, "getifaddrs failed\n"); |
516 | return 1; | 930 | return HV_E_FAIL; |
517 | } | 931 | } |
518 | 932 | ||
519 | curp = ifap; | 933 | curp = ifap; |
520 | while (curp != NULL) { | 934 | while (curp != NULL) { |
521 | if ((curp->ifa_addr != NULL) && | 935 | if (curp->ifa_addr == NULL) { |
522 | (curp->ifa_addr->sa_family == family)) { | 936 | curp = curp->ifa_next; |
523 | if (family == AF_INET) { | 937 | continue; |
524 | struct sockaddr_in *addr = | 938 | } |
525 | (struct sockaddr_in *) curp->ifa_addr; | ||
526 | |||
527 | str = inet_ntop(family, &addr->sin_addr, | ||
528 | tmp, 50); | ||
529 | if (str == NULL) { | ||
530 | strcpy(buffer, "inet_ntop failed\n"); | ||
531 | error = 1; | ||
532 | goto getaddr_done; | ||
533 | } | ||
534 | if (offset == 0) | ||
535 | strcpy(buffer, tmp); | ||
536 | else | ||
537 | strcat(buffer, tmp); | ||
538 | strcat(buffer, ";"); | ||
539 | 939 | ||
540 | offset += strlen(str) + 1; | 940 | if ((if_name != NULL) && |
541 | if ((length - offset) < (ipv4_len + 1)) | 941 | (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { |
542 | goto getaddr_done; | 942 | /* |
943 | * We want info about a specific interface; | ||
944 | * just continue. | ||
945 | */ | ||
946 | curp = curp->ifa_next; | ||
947 | continue; | ||
948 | } | ||
543 | 949 | ||
544 | } else { | 950 | /* |
951 | * We only support two address families: AF_INET and AF_INET6. | ||
952 | * If a family value of 0 is specified, we collect both | ||
953 | * supported address families; if not we gather info on | ||
954 | * the specified address family. | ||
955 | */ | ||
956 | if ((family != 0) && (curp->ifa_addr->sa_family != family)) { | ||
957 | curp = curp->ifa_next; | ||
958 | continue; | ||
959 | } | ||
960 | if ((curp->ifa_addr->sa_family != AF_INET) && | ||
961 | (curp->ifa_addr->sa_family != AF_INET6)) { | ||
962 | curp = curp->ifa_next; | ||
963 | continue; | ||
964 | } | ||
545 | 965 | ||
966 | if (op == KVP_OP_GET_IP_INFO) { | ||
546 | /* | 967 | /* |
547 | * We only support AF_INET and AF_INET6 | 968 | * Gather info other than the IP address. |
548 | * and the list of addresses is separated by a ";". | 969 | * IP address info will be gathered later. |
549 | */ | 970 | */ |
550 | struct sockaddr_in6 *addr = | 971 | if (curp->ifa_addr->sa_family == AF_INET) { |
551 | (struct sockaddr_in6 *) curp->ifa_addr; | 972 | ip_buffer->addr_family |= ADDR_FAMILY_IPV4; |
552 | 973 | /* | |
553 | str = inet_ntop(family, | 974 | * Get subnet info. |
554 | &addr->sin6_addr.s6_addr, | 975 | */ |
555 | tmp, 50); | 976 | error = kvp_process_ip_address( |
556 | if (str == NULL) { | 977 | curp->ifa_netmask, |
557 | strcpy(buffer, "inet_ntop failed\n"); | 978 | AF_INET, |
558 | error = 1; | 979 | (char *) |
559 | goto getaddr_done; | 980 | ip_buffer->sub_net, |
560 | } | 981 | length, |
561 | if (offset == 0) | 982 | &sn_offset); |
562 | strcpy(buffer, tmp); | 983 | if (error) |
563 | else | 984 | goto gather_ipaddr; |
564 | strcat(buffer, tmp); | 985 | } else { |
565 | strcat(buffer, ";"); | 986 | ip_buffer->addr_family |= ADDR_FAMILY_IPV6; |
566 | offset += strlen(str) + 1; | ||
567 | if ((length - offset) < (ipv6_len + 1)) | ||
568 | goto getaddr_done; | ||
569 | 987 | ||
988 | /* | ||
989 | * Get subnet info in CIDR format. | ||
990 | */ | ||
991 | weight = 0; | ||
992 | sn_str = (char *)ip_buffer->sub_net; | ||
993 | addr6 = (struct sockaddr_in6 *) | ||
994 | curp->ifa_netmask; | ||
995 | w = addr6->sin6_addr.s6_addr32; | ||
996 | |||
997 | for (i = 0; i < 4; i++) | ||
998 | weight += hweight32(&w[i]); | ||
999 | |||
1000 | sprintf(cidr_mask, "/%d", weight); | ||
1001 | if ((length - sn_offset) < | ||
1002 | (strlen(cidr_mask) + 1)) | ||
1003 | goto gather_ipaddr; | ||
1004 | |||
1005 | if (sn_offset == 0) | ||
1006 | strcpy(sn_str, cidr_mask); | ||
1007 | else | ||
1008 | strcat(sn_str, cidr_mask); | ||
1009 | strcat((char *)ip_buffer->sub_net, ";"); | ||
1010 | sn_offset += strlen(sn_str) + 1; | ||
570 | } | 1011 | } |
571 | 1012 | ||
1013 | /* | ||
1014 | * Collect other ip related configuration info. | ||
1015 | */ | ||
1016 | |||
1017 | kvp_get_ipconfig_info(if_name, ip_buffer); | ||
572 | } | 1018 | } |
1019 | |||
1020 | gather_ipaddr: | ||
1021 | error = kvp_process_ip_address(curp->ifa_addr, | ||
1022 | curp->ifa_addr->sa_family, | ||
1023 | buffer, | ||
1024 | length, &offset); | ||
1025 | if (error) | ||
1026 | goto getaddr_done; | ||
1027 | |||
573 | curp = curp->ifa_next; | 1028 | curp = curp->ifa_next; |
574 | } | 1029 | } |
575 | 1030 | ||
@@ -579,6 +1034,315 @@ getaddr_done: | |||
579 | } | 1034 | } |
580 | 1035 | ||
581 | 1036 | ||
1037 | static int expand_ipv6(char *addr, int type) | ||
1038 | { | ||
1039 | int ret; | ||
1040 | struct in6_addr v6_addr; | ||
1041 | |||
1042 | ret = inet_pton(AF_INET6, addr, &v6_addr); | ||
1043 | |||
1044 | if (ret != 1) { | ||
1045 | if (type == NETMASK) | ||
1046 | return 1; | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" | ||
1051 | "%02x%02x:%02x%02x:%02x%02x", | ||
1052 | (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], | ||
1053 | (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], | ||
1054 | (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], | ||
1055 | (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], | ||
1056 | (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], | ||
1057 | (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], | ||
1058 | (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], | ||
1059 | (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); | ||
1060 | |||
1061 | return 1; | ||
1062 | |||
1063 | } | ||
1064 | |||
1065 | static int is_ipv4(char *addr) | ||
1066 | { | ||
1067 | int ret; | ||
1068 | struct in_addr ipv4_addr; | ||
1069 | |||
1070 | ret = inet_pton(AF_INET, addr, &ipv4_addr); | ||
1071 | |||
1072 | if (ret == 1) | ||
1073 | return 1; | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static int parse_ip_val_buffer(char *in_buf, int *offset, | ||
1078 | char *out_buf, int out_len) | ||
1079 | { | ||
1080 | char *x; | ||
1081 | char *start; | ||
1082 | |||
1083 | /* | ||
1084 | * in_buf has sequence of characters that are seperated by | ||
1085 | * the character ';'. The last sequence does not have the | ||
1086 | * terminating ";" character. | ||
1087 | */ | ||
1088 | start = in_buf + *offset; | ||
1089 | |||
1090 | x = strchr(start, ';'); | ||
1091 | if (x) | ||
1092 | *x = 0; | ||
1093 | else | ||
1094 | x = start + strlen(start); | ||
1095 | |||
1096 | if (strlen(start) != 0) { | ||
1097 | int i = 0; | ||
1098 | /* | ||
1099 | * Get rid of leading spaces. | ||
1100 | */ | ||
1101 | while (start[i] == ' ') | ||
1102 | i++; | ||
1103 | |||
1104 | if ((x - start) <= out_len) { | ||
1105 | strcpy(out_buf, (start + i)); | ||
1106 | *offset += (x - start) + 1; | ||
1107 | return 1; | ||
1108 | } | ||
1109 | } | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3) | ||
1114 | { | ||
1115 | int ret; | ||
1116 | |||
1117 | ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); | ||
1118 | |||
1119 | if (ret < 0) | ||
1120 | return HV_E_FAIL; | ||
1121 | |||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | |||
1126 | static int process_ip_string(FILE *f, char *ip_string, int type) | ||
1127 | { | ||
1128 | int error = 0; | ||
1129 | char addr[INET6_ADDRSTRLEN]; | ||
1130 | int i = 0; | ||
1131 | int j = 0; | ||
1132 | char str[256]; | ||
1133 | char sub_str[10]; | ||
1134 | int offset = 0; | ||
1135 | |||
1136 | memset(addr, 0, sizeof(addr)); | ||
1137 | |||
1138 | while (parse_ip_val_buffer(ip_string, &offset, addr, | ||
1139 | (MAX_IP_ADDR_SIZE * 2))) { | ||
1140 | |||
1141 | sub_str[0] = 0; | ||
1142 | if (is_ipv4(addr)) { | ||
1143 | switch (type) { | ||
1144 | case IPADDR: | ||
1145 | snprintf(str, sizeof(str), "%s", "IPADDR"); | ||
1146 | break; | ||
1147 | case NETMASK: | ||
1148 | snprintf(str, sizeof(str), "%s", "NETMASK"); | ||
1149 | break; | ||
1150 | case GATEWAY: | ||
1151 | snprintf(str, sizeof(str), "%s", "GATEWAY"); | ||
1152 | break; | ||
1153 | case DNS: | ||
1154 | snprintf(str, sizeof(str), "%s", "DNS"); | ||
1155 | break; | ||
1156 | } | ||
1157 | if (i != 0) { | ||
1158 | if (type != DNS) { | ||
1159 | snprintf(sub_str, sizeof(sub_str), | ||
1160 | "_%d", i++); | ||
1161 | } else { | ||
1162 | snprintf(sub_str, sizeof(sub_str), | ||
1163 | "%d", ++i); | ||
1164 | } | ||
1165 | } else if (type == DNS) { | ||
1166 | snprintf(sub_str, sizeof(sub_str), "%d", ++i); | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | } else if (expand_ipv6(addr, type)) { | ||
1171 | switch (type) { | ||
1172 | case IPADDR: | ||
1173 | snprintf(str, sizeof(str), "%s", "IPV6ADDR"); | ||
1174 | break; | ||
1175 | case NETMASK: | ||
1176 | snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); | ||
1177 | break; | ||
1178 | case GATEWAY: | ||
1179 | snprintf(str, sizeof(str), "%s", | ||
1180 | "IPV6_DEFAULTGW"); | ||
1181 | break; | ||
1182 | case DNS: | ||
1183 | snprintf(str, sizeof(str), "%s", "DNS"); | ||
1184 | break; | ||
1185 | } | ||
1186 | if ((j != 0) || (type == DNS)) { | ||
1187 | if (type != DNS) { | ||
1188 | snprintf(sub_str, sizeof(sub_str), | ||
1189 | "_%d", j++); | ||
1190 | } else { | ||
1191 | snprintf(sub_str, sizeof(sub_str), | ||
1192 | "%d", ++i); | ||
1193 | } | ||
1194 | } else if (type == DNS) { | ||
1195 | snprintf(sub_str, sizeof(sub_str), | ||
1196 | "%d", ++i); | ||
1197 | } | ||
1198 | } else { | ||
1199 | return HV_INVALIDARG; | ||
1200 | } | ||
1201 | |||
1202 | error = kvp_write_file(f, str, sub_str, addr); | ||
1203 | if (error) | ||
1204 | return error; | ||
1205 | memset(addr, 0, sizeof(addr)); | ||
1206 | } | ||
1207 | |||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) | ||
1212 | { | ||
1213 | int error = 0; | ||
1214 | char if_file[128]; | ||
1215 | FILE *file; | ||
1216 | char cmd[512]; | ||
1217 | char *mac_addr; | ||
1218 | |||
1219 | /* | ||
1220 | * Set the configuration for the specified interface with | ||
1221 | * the information provided. Since there is no standard | ||
1222 | * way to configure an interface, we will have an external | ||
1223 | * script that does the job of configuring the interface and | ||
1224 | * flushing the configuration. | ||
1225 | * | ||
1226 | * The parameters passed to this external script are: | ||
1227 | * 1. A configuration file that has the specified configuration. | ||
1228 | * | ||
1229 | * We will embed the name of the interface in the configuration | ||
1230 | * file: ifcfg-ethx (where ethx is the interface name). | ||
1231 | * | ||
1232 | * The information provided here may be more than what is needed | ||
1233 | * in a given distro to configure the interface and so are free | ||
1234 | * ignore information that may not be relevant. | ||
1235 | * | ||
1236 | * Here is the format of the ip configuration file: | ||
1237 | * | ||
1238 | * HWADDR=macaddr | ||
1239 | * IF_NAME=interface name | ||
1240 | * DHCP=yes (This is optional; if yes, DHCP is configured) | ||
1241 | * | ||
1242 | * IPADDR=ipaddr1 | ||
1243 | * IPADDR_1=ipaddr2 | ||
1244 | * IPADDR_x=ipaddry (where y = x + 1) | ||
1245 | * | ||
1246 | * NETMASK=netmask1 | ||
1247 | * NETMASK_x=netmasky (where y = x + 1) | ||
1248 | * | ||
1249 | * GATEWAY=ipaddr1 | ||
1250 | * GATEWAY_x=ipaddry (where y = x + 1) | ||
1251 | * | ||
1252 | * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) | ||
1253 | * | ||
1254 | * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be | ||
1255 | * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as | ||
1256 | * IPV6NETMASK. | ||
1257 | * | ||
1258 | * The host can specify multiple ipv4 and ipv6 addresses to be | ||
1259 | * configured for the interface. Furthermore, the configuration | ||
1260 | * needs to be persistent. A subsequent GET call on the interface | ||
1261 | * is expected to return the configuration that is set via the SET | ||
1262 | * call. | ||
1263 | */ | ||
1264 | |||
1265 | snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, | ||
1266 | "hyperv/ifcfg-", if_name); | ||
1267 | |||
1268 | file = fopen(if_file, "w"); | ||
1269 | |||
1270 | if (file == NULL) { | ||
1271 | syslog(LOG_ERR, "Failed to open config file"); | ||
1272 | return HV_E_FAIL; | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1276 | * First write out the MAC address. | ||
1277 | */ | ||
1278 | |||
1279 | mac_addr = kvp_if_name_to_mac(if_name); | ||
1280 | if (mac_addr == NULL) { | ||
1281 | error = HV_E_FAIL; | ||
1282 | goto setval_error; | ||
1283 | } | ||
1284 | |||
1285 | error = kvp_write_file(file, "HWADDR", "", mac_addr); | ||
1286 | if (error) | ||
1287 | goto setval_error; | ||
1288 | |||
1289 | error = kvp_write_file(file, "IF_NAME", "", if_name); | ||
1290 | if (error) | ||
1291 | goto setval_error; | ||
1292 | |||
1293 | if (new_val->dhcp_enabled) { | ||
1294 | error = kvp_write_file(file, "DHCP", "", "yes"); | ||
1295 | if (error) | ||
1296 | goto setval_error; | ||
1297 | |||
1298 | /* | ||
1299 | * We are done!. | ||
1300 | */ | ||
1301 | goto setval_done; | ||
1302 | } | ||
1303 | |||
1304 | /* | ||
1305 | * Write the configuration for ipaddress, netmask, gateway and | ||
1306 | * name servers. | ||
1307 | */ | ||
1308 | |||
1309 | error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); | ||
1310 | if (error) | ||
1311 | goto setval_error; | ||
1312 | |||
1313 | error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); | ||
1314 | if (error) | ||
1315 | goto setval_error; | ||
1316 | |||
1317 | error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); | ||
1318 | if (error) | ||
1319 | goto setval_error; | ||
1320 | |||
1321 | error = process_ip_string(file, (char *)new_val->dns_addr, DNS); | ||
1322 | if (error) | ||
1323 | goto setval_error; | ||
1324 | |||
1325 | setval_done: | ||
1326 | free(mac_addr); | ||
1327 | fclose(file); | ||
1328 | |||
1329 | /* | ||
1330 | * Now that we have populated the configuration file, | ||
1331 | * invoke the external script to do its magic. | ||
1332 | */ | ||
1333 | |||
1334 | snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file); | ||
1335 | system(cmd); | ||
1336 | return 0; | ||
1337 | |||
1338 | setval_error: | ||
1339 | syslog(LOG_ERR, "Failed to write config file"); | ||
1340 | free(mac_addr); | ||
1341 | fclose(file); | ||
1342 | return error; | ||
1343 | } | ||
1344 | |||
1345 | |||
582 | static int | 1346 | static int |
583 | kvp_get_domain_name(char *buffer, int length) | 1347 | kvp_get_domain_name(char *buffer, int length) |
584 | { | 1348 | { |
@@ -646,6 +1410,10 @@ int main(void) | |||
646 | char *p; | 1410 | char *p; |
647 | char *key_value; | 1411 | char *key_value; |
648 | char *key_name; | 1412 | char *key_name; |
1413 | int op; | ||
1414 | int pool; | ||
1415 | char *if_name; | ||
1416 | struct hv_kvp_ipaddr_value *kvp_ip_val; | ||
649 | 1417 | ||
650 | daemon(1, 0); | 1418 | daemon(1, 0); |
651 | openlog("KVP", 0, LOG_USER); | 1419 | openlog("KVP", 0, LOG_USER); |
@@ -657,13 +1425,13 @@ int main(void) | |||
657 | 1425 | ||
658 | if (kvp_file_init()) { | 1426 | if (kvp_file_init()) { |
659 | syslog(LOG_ERR, "Failed to initialize the pools"); | 1427 | syslog(LOG_ERR, "Failed to initialize the pools"); |
660 | exit(-1); | 1428 | exit(EXIT_FAILURE); |
661 | } | 1429 | } |
662 | 1430 | ||
663 | fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | 1431 | fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); |
664 | if (fd < 0) { | 1432 | if (fd < 0) { |
665 | syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); | 1433 | syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); |
666 | exit(-1); | 1434 | exit(EXIT_FAILURE); |
667 | } | 1435 | } |
668 | addr.nl_family = AF_NETLINK; | 1436 | addr.nl_family = AF_NETLINK; |
669 | addr.nl_pad = 0; | 1437 | addr.nl_pad = 0; |
@@ -675,7 +1443,7 @@ int main(void) | |||
675 | if (error < 0) { | 1443 | if (error < 0) { |
676 | syslog(LOG_ERR, "bind failed; error:%d", error); | 1444 | syslog(LOG_ERR, "bind failed; error:%d", error); |
677 | close(fd); | 1445 | close(fd); |
678 | exit(-1); | 1446 | exit(EXIT_FAILURE); |
679 | } | 1447 | } |
680 | sock_opt = addr.nl_groups; | 1448 | sock_opt = addr.nl_groups; |
681 | setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); | 1449 | setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); |
@@ -687,7 +1455,7 @@ int main(void) | |||
687 | message->id.val = CN_KVP_VAL; | 1455 | message->id.val = CN_KVP_VAL; |
688 | 1456 | ||
689 | hv_msg = (struct hv_kvp_msg *)message->data; | 1457 | hv_msg = (struct hv_kvp_msg *)message->data; |
690 | hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; | 1458 | hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; |
691 | message->ack = 0; | 1459 | message->ack = 0; |
692 | message->len = sizeof(struct hv_kvp_msg); | 1460 | message->len = sizeof(struct hv_kvp_msg); |
693 | 1461 | ||
@@ -695,7 +1463,7 @@ int main(void) | |||
695 | if (len < 0) { | 1463 | if (len < 0) { |
696 | syslog(LOG_ERR, "netlink_send failed; error:%d", len); | 1464 | syslog(LOG_ERR, "netlink_send failed; error:%d", len); |
697 | close(fd); | 1465 | close(fd); |
698 | exit(-1); | 1466 | exit(EXIT_FAILURE); |
699 | } | 1467 | } |
700 | 1468 | ||
701 | pfd.fd = fd; | 1469 | pfd.fd = fd; |
@@ -721,12 +1489,21 @@ int main(void) | |||
721 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); | 1489 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); |
722 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; | 1490 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; |
723 | 1491 | ||
724 | switch (hv_msg->kvp_hdr.operation) { | 1492 | /* |
725 | case KVP_OP_REGISTER: | 1493 | * We will use the KVP header information to pass back |
1494 | * the error from this daemon. So, first copy the state | ||
1495 | * and set the error code to success. | ||
1496 | */ | ||
1497 | op = hv_msg->kvp_hdr.operation; | ||
1498 | pool = hv_msg->kvp_hdr.pool; | ||
1499 | hv_msg->error = HV_S_OK; | ||
1500 | |||
1501 | if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { | ||
726 | /* | 1502 | /* |
727 | * Driver is registering with us; stash away the version | 1503 | * Driver is registering with us; stash away the version |
728 | * information. | 1504 | * information. |
729 | */ | 1505 | */ |
1506 | in_hand_shake = 0; | ||
730 | p = (char *)hv_msg->body.kvp_register.version; | 1507 | p = (char *)hv_msg->body.kvp_register.version; |
731 | lic_version = malloc(strlen(p) + 1); | 1508 | lic_version = malloc(strlen(p) + 1); |
732 | if (lic_version) { | 1509 | if (lic_version) { |
@@ -737,44 +1514,82 @@ int main(void) | |||
737 | syslog(LOG_ERR, "malloc failed"); | 1514 | syslog(LOG_ERR, "malloc failed"); |
738 | } | 1515 | } |
739 | continue; | 1516 | continue; |
1517 | } | ||
740 | 1518 | ||
741 | /* | 1519 | switch (op) { |
742 | * The current protocol with the kernel component uses a | 1520 | case KVP_OP_GET_IP_INFO: |
743 | * NULL key name to pass an error condition. | 1521 | kvp_ip_val = &hv_msg->body.kvp_ip_val; |
744 | * For the SET, GET and DELETE operations, | 1522 | if_name = |
745 | * use the existing protocol to pass back error. | 1523 | kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id); |
746 | */ | 1524 | |
1525 | if (if_name == NULL) { | ||
1526 | /* | ||
1527 | * We could not map the mac address to an | ||
1528 | * interface name; return error. | ||
1529 | */ | ||
1530 | hv_msg->error = HV_E_FAIL; | ||
1531 | break; | ||
1532 | } | ||
1533 | error = kvp_get_ip_info( | ||
1534 | 0, if_name, KVP_OP_GET_IP_INFO, | ||
1535 | kvp_ip_val, | ||
1536 | (MAX_IP_ADDR_SIZE * 2)); | ||
1537 | |||
1538 | if (error) | ||
1539 | hv_msg->error = error; | ||
1540 | |||
1541 | free(if_name); | ||
1542 | break; | ||
1543 | |||
1544 | case KVP_OP_SET_IP_INFO: | ||
1545 | kvp_ip_val = &hv_msg->body.kvp_ip_val; | ||
1546 | if_name = kvp_get_if_name( | ||
1547 | (char *)kvp_ip_val->adapter_id); | ||
1548 | if (if_name == NULL) { | ||
1549 | /* | ||
1550 | * We could not map the guid to an | ||
1551 | * interface name; return error. | ||
1552 | */ | ||
1553 | hv_msg->error = HV_GUID_NOTFOUND; | ||
1554 | break; | ||
1555 | } | ||
1556 | error = kvp_set_ip_info(if_name, kvp_ip_val); | ||
1557 | if (error) | ||
1558 | hv_msg->error = error; | ||
1559 | |||
1560 | free(if_name); | ||
1561 | break; | ||
747 | 1562 | ||
748 | case KVP_OP_SET: | 1563 | case KVP_OP_SET: |
749 | if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, | 1564 | if (kvp_key_add_or_modify(pool, |
750 | hv_msg->body.kvp_set.data.key, | 1565 | hv_msg->body.kvp_set.data.key, |
751 | hv_msg->body.kvp_set.data.key_size, | 1566 | hv_msg->body.kvp_set.data.key_size, |
752 | hv_msg->body.kvp_set.data.value, | 1567 | hv_msg->body.kvp_set.data.value, |
753 | hv_msg->body.kvp_set.data.value_size)) | 1568 | hv_msg->body.kvp_set.data.value_size)) |
754 | strcpy(hv_msg->body.kvp_set.data.key, ""); | 1569 | hv_msg->error = HV_S_CONT; |
755 | break; | 1570 | break; |
756 | 1571 | ||
757 | case KVP_OP_GET: | 1572 | case KVP_OP_GET: |
758 | if (kvp_get_value(hv_msg->kvp_hdr.pool, | 1573 | if (kvp_get_value(pool, |
759 | hv_msg->body.kvp_set.data.key, | 1574 | hv_msg->body.kvp_set.data.key, |
760 | hv_msg->body.kvp_set.data.key_size, | 1575 | hv_msg->body.kvp_set.data.key_size, |
761 | hv_msg->body.kvp_set.data.value, | 1576 | hv_msg->body.kvp_set.data.value, |
762 | hv_msg->body.kvp_set.data.value_size)) | 1577 | hv_msg->body.kvp_set.data.value_size)) |
763 | strcpy(hv_msg->body.kvp_set.data.key, ""); | 1578 | hv_msg->error = HV_S_CONT; |
764 | break; | 1579 | break; |
765 | 1580 | ||
766 | case KVP_OP_DELETE: | 1581 | case KVP_OP_DELETE: |
767 | if (kvp_key_delete(hv_msg->kvp_hdr.pool, | 1582 | if (kvp_key_delete(pool, |
768 | hv_msg->body.kvp_delete.key, | 1583 | hv_msg->body.kvp_delete.key, |
769 | hv_msg->body.kvp_delete.key_size)) | 1584 | hv_msg->body.kvp_delete.key_size)) |
770 | strcpy(hv_msg->body.kvp_delete.key, ""); | 1585 | hv_msg->error = HV_S_CONT; |
771 | break; | 1586 | break; |
772 | 1587 | ||
773 | default: | 1588 | default: |
774 | break; | 1589 | break; |
775 | } | 1590 | } |
776 | 1591 | ||
777 | if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) | 1592 | if (op != KVP_OP_ENUMERATE) |
778 | goto kvp_done; | 1593 | goto kvp_done; |
779 | 1594 | ||
780 | /* | 1595 | /* |
@@ -782,13 +1597,14 @@ int main(void) | |||
782 | * both the key and the value; if not read from the | 1597 | * both the key and the value; if not read from the |
783 | * appropriate pool. | 1598 | * appropriate pool. |
784 | */ | 1599 | */ |
785 | if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { | 1600 | if (pool != KVP_POOL_AUTO) { |
786 | kvp_pool_enumerate(hv_msg->kvp_hdr.pool, | 1601 | if (kvp_pool_enumerate(pool, |
787 | hv_msg->body.kvp_enum_data.index, | 1602 | hv_msg->body.kvp_enum_data.index, |
788 | hv_msg->body.kvp_enum_data.data.key, | 1603 | hv_msg->body.kvp_enum_data.data.key, |
789 | HV_KVP_EXCHANGE_MAX_KEY_SIZE, | 1604 | HV_KVP_EXCHANGE_MAX_KEY_SIZE, |
790 | hv_msg->body.kvp_enum_data.data.value, | 1605 | hv_msg->body.kvp_enum_data.data.value, |
791 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | 1606 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) |
1607 | hv_msg->error = HV_S_CONT; | ||
792 | goto kvp_done; | 1608 | goto kvp_done; |
793 | } | 1609 | } |
794 | 1610 | ||
@@ -807,13 +1623,13 @@ int main(void) | |||
807 | strcpy(key_value, lic_version); | 1623 | strcpy(key_value, lic_version); |
808 | break; | 1624 | break; |
809 | case NetworkAddressIPv4: | 1625 | case NetworkAddressIPv4: |
810 | kvp_get_ip_address(AF_INET, key_value, | 1626 | kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE, |
811 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | 1627 | key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); |
812 | strcpy(key_name, "NetworkAddressIPv4"); | 1628 | strcpy(key_name, "NetworkAddressIPv4"); |
813 | break; | 1629 | break; |
814 | case NetworkAddressIPv6: | 1630 | case NetworkAddressIPv6: |
815 | kvp_get_ip_address(AF_INET6, key_value, | 1631 | kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE, |
816 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | 1632 | key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); |
817 | strcpy(key_name, "NetworkAddressIPv6"); | 1633 | strcpy(key_name, "NetworkAddressIPv6"); |
818 | break; | 1634 | break; |
819 | case OSBuildNumber: | 1635 | case OSBuildNumber: |
@@ -841,11 +1657,7 @@ int main(void) | |||
841 | strcpy(key_name, "ProcessorArchitecture"); | 1657 | strcpy(key_name, "ProcessorArchitecture"); |
842 | break; | 1658 | break; |
843 | default: | 1659 | default: |
844 | strcpy(key_value, "Unknown Key"); | 1660 | hv_msg->error = HV_S_CONT; |
845 | /* | ||
846 | * We use a null key name to terminate enumeration. | ||
847 | */ | ||
848 | strcpy(key_name, ""); | ||
849 | break; | 1661 | break; |
850 | } | 1662 | } |
851 | /* | 1663 | /* |
@@ -863,7 +1675,7 @@ kvp_done: | |||
863 | len = netlink_send(fd, incoming_cn_msg); | 1675 | len = netlink_send(fd, incoming_cn_msg); |
864 | if (len < 0) { | 1676 | if (len < 0) { |
865 | syslog(LOG_ERR, "net_link send failed; error:%d", len); | 1677 | syslog(LOG_ERR, "net_link send failed; error:%d", len); |
866 | exit(-1); | 1678 | exit(EXIT_FAILURE); |
867 | } | 1679 | } |
868 | } | 1680 | } |
869 | 1681 | ||
diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh new file mode 100755 index 00000000000..3e9427e08d8 --- /dev/null +++ b/tools/hv/hv_set_ifconfig.sh | |||
@@ -0,0 +1,68 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This example script activates an interface based on the specified | ||
4 | # configuration. | ||
5 | # | ||
6 | # In the interest of keeping the KVP daemon code free of distro specific | ||
7 | # information; the kvp daemon code invokes this external script to configure | ||
8 | # the interface. | ||
9 | # | ||
10 | # The only argument to this script is the configuration file that is to | ||
11 | # be used to configure the interface. | ||
12 | # | ||
13 | # Each Distro is expected to implement this script in a distro specific | ||
14 | # fashion. For instance on Distros that ship with Network Manager enabled, | ||
15 | # this script can be based on the Network Manager APIs for configuring the | ||
16 | # interface. | ||
17 | # | ||
18 | # This example script is based on a RHEL environment. | ||
19 | # | ||
20 | # Here is the format of the ip configuration file: | ||
21 | # | ||
22 | # HWADDR=macaddr | ||
23 | # IF_NAME=interface name | ||
24 | # DHCP=yes (This is optional; if yes, DHCP is configured) | ||
25 | # | ||
26 | # IPADDR=ipaddr1 | ||
27 | # IPADDR_1=ipaddr2 | ||
28 | # IPADDR_x=ipaddry (where y = x + 1) | ||
29 | # | ||
30 | # NETMASK=netmask1 | ||
31 | # NETMASK_x=netmasky (where y = x + 1) | ||
32 | # | ||
33 | # GATEWAY=ipaddr1 | ||
34 | # GATEWAY_x=ipaddry (where y = x + 1) | ||
35 | # | ||
36 | # DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) | ||
37 | # | ||
38 | # IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be | ||
39 | # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as | ||
40 | # IPV6NETMASK. | ||
41 | # | ||
42 | # The host can specify multiple ipv4 and ipv6 addresses to be | ||
43 | # configured for the interface. Furthermore, the configuration | ||
44 | # needs to be persistent. A subsequent GET call on the interface | ||
45 | # is expected to return the configuration that is set via the SET | ||
46 | # call. | ||
47 | # | ||
48 | |||
49 | |||
50 | |||
51 | echo "IPV6INIT=yes" >> $1 | ||
52 | echo "NM_CONTROLLED=no" >> $1 | ||
53 | echo "PEERDNS=yes" >> $1 | ||
54 | echo "ONBOOT=yes" >> $1 | ||
55 | |||
56 | dhcp=$(grep "DHCP" $1 2>/dev/null) | ||
57 | if [ "$dhcp" != "" ]; | ||
58 | then | ||
59 | echo "BOOTPROTO=dhcp" >> $1; | ||
60 | fi | ||
61 | |||
62 | cp $1 /etc/sysconfig/network-scripts/ | ||
63 | |||
64 | |||
65 | interface=$(echo $1 | awk -F - '{ print $2 }') | ||
66 | |||
67 | /sbin/ifdown $interface 2>/dev/null | ||
68 | /sbin/ifup $interfac 2>/dev/null | ||
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index f759f4f097c..fd2f9221b24 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -1299,6 +1299,7 @@ static struct device *new_device(const char *name, u16 type) | |||
1299 | dev->feature_len = 0; | 1299 | dev->feature_len = 0; |
1300 | dev->num_vq = 0; | 1300 | dev->num_vq = 0; |
1301 | dev->running = false; | 1301 | dev->running = false; |
1302 | dev->next = NULL; | ||
1302 | 1303 | ||
1303 | /* | 1304 | /* |
1304 | * Append to device list. Prepending to a single-linked list is | 1305 | * Append to device list. Prepending to a single-linked list is |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 47264b4652b..f2989c525e4 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -2602,6 +2602,9 @@ find_func_handler(struct pevent *pevent, char *func_name) | |||
2602 | { | 2602 | { |
2603 | struct pevent_function_handler *func; | 2603 | struct pevent_function_handler *func; |
2604 | 2604 | ||
2605 | if (!pevent) | ||
2606 | return NULL; | ||
2607 | |||
2605 | for (func = pevent->func_handlers; func; func = func->next) { | 2608 | for (func = pevent->func_handlers; func; func = func->next) { |
2606 | if (strcmp(func->name, func_name) == 0) | 2609 | if (strcmp(func->name, func_name) == 0) |
2607 | break; | 2610 | break; |
@@ -4938,6 +4941,9 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
4938 | goto event_alloc_failed; | 4941 | goto event_alloc_failed; |
4939 | } | 4942 | } |
4940 | 4943 | ||
4944 | /* Add pevent to event so that it can be referenced */ | ||
4945 | event->pevent = pevent; | ||
4946 | |||
4941 | ret = event_read_format(event); | 4947 | ret = event_read_format(event); |
4942 | if (ret < 0) { | 4948 | if (ret < 0) { |
4943 | ret = PEVENT_ERRNO__READ_FORMAT_FAILED; | 4949 | ret = PEVENT_ERRNO__READ_FORMAT_FAILED; |
@@ -5041,9 +5047,6 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
5041 | if (event == NULL) | 5047 | if (event == NULL) |
5042 | return ret; | 5048 | return ret; |
5043 | 5049 | ||
5044 | /* Add pevent to event so that it can be referenced */ | ||
5045 | event->pevent = pevent; | ||
5046 | |||
5047 | if (add_event(pevent, event)) { | 5050 | if (add_event(pevent, event)) { |
5048 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | 5051 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; |
5049 | goto event_add_failed; | 5052 | goto event_add_failed; |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index ad17855528f..5ea4326ad11 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -209,7 +209,16 @@ static void free_arg(struct filter_arg *arg) | |||
209 | switch (arg->type) { | 209 | switch (arg->type) { |
210 | case FILTER_ARG_NONE: | 210 | case FILTER_ARG_NONE: |
211 | case FILTER_ARG_BOOLEAN: | 211 | case FILTER_ARG_BOOLEAN: |
212 | break; | ||
213 | |||
212 | case FILTER_ARG_NUM: | 214 | case FILTER_ARG_NUM: |
215 | free_arg(arg->num.left); | ||
216 | free_arg(arg->num.right); | ||
217 | break; | ||
218 | |||
219 | case FILTER_ARG_EXP: | ||
220 | free_arg(arg->exp.left); | ||
221 | free_arg(arg->exp.right); | ||
213 | break; | 222 | break; |
214 | 223 | ||
215 | case FILTER_ARG_STR: | 224 | case FILTER_ARG_STR: |
@@ -218,6 +227,12 @@ static void free_arg(struct filter_arg *arg) | |||
218 | free(arg->str.buffer); | 227 | free(arg->str.buffer); |
219 | break; | 228 | break; |
220 | 229 | ||
230 | case FILTER_ARG_VALUE: | ||
231 | if (arg->value.type == FILTER_STRING || | ||
232 | arg->value.type == FILTER_CHAR) | ||
233 | free(arg->value.str); | ||
234 | break; | ||
235 | |||
221 | case FILTER_ARG_OP: | 236 | case FILTER_ARG_OP: |
222 | free_arg(arg->op.left); | 237 | free_arg(arg->op.left); |
223 | free_arg(arg->op.right); | 238 | free_arg(arg->op.right); |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 318bec8e14e..f530502630a 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -74,7 +74,7 @@ ifeq ($(ARCH),x86_64) | |||
74 | override ARCH := x86 | 74 | override ARCH := x86 |
75 | IS_X86_64 := 0 | 75 | IS_X86_64 := 0 |
76 | ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) | 76 | ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) |
77 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) | 77 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) |
78 | endif | 78 | endif |
79 | ifeq (${IS_X86_64}, 1) | 79 | ifeq (${IS_X86_64}, 1) |
80 | RAW_ARCH := x86_64 | 80 | RAW_ARCH := x86_64 |
@@ -191,9 +191,22 @@ SCRIPT_SH += perf-archive.sh | |||
191 | grep-libs = $(filter -l%,$(1)) | 191 | grep-libs = $(filter -l%,$(1)) |
192 | strip-libs = $(filter-out -l%,$(1)) | 192 | strip-libs = $(filter-out -l%,$(1)) |
193 | 193 | ||
194 | TRACE_EVENT_DIR = ../lib/traceevent/ | ||
195 | |||
196 | ifneq ($(OUTPUT),) | ||
197 | TE_PATH=$(OUTPUT) | ||
198 | else | ||
199 | TE_PATH=$(TRACE_EVENT_DIR) | ||
200 | endif | ||
201 | |||
202 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | ||
203 | TE_LIB := -L$(TE_PATH) -ltraceevent | ||
204 | |||
194 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 205 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
195 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | 206 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py |
196 | 207 | ||
208 | export LIBTRACEEVENT | ||
209 | |||
197 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 210 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
198 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 211 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
199 | --quiet build_ext; \ | 212 | --quiet build_ext; \ |
@@ -205,17 +218,6 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | |||
205 | 218 | ||
206 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) | 219 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) |
207 | 220 | ||
208 | TRACE_EVENT_DIR = ../lib/traceevent/ | ||
209 | |||
210 | ifneq ($(OUTPUT),) | ||
211 | TE_PATH=$(OUTPUT) | ||
212 | else | ||
213 | TE_PATH=$(TRACE_EVENT_DIR) | ||
214 | endif | ||
215 | |||
216 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | ||
217 | TE_LIB := -L$(TE_PATH) -ltraceevent | ||
218 | |||
219 | # | 221 | # |
220 | # Single 'perf' binary right now: | 222 | # Single 'perf' binary right now: |
221 | # | 223 | # |
@@ -259,10 +261,10 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | |||
259 | 261 | ||
260 | LIB_FILE=$(OUTPUT)libperf.a | 262 | LIB_FILE=$(OUTPUT)libperf.a |
261 | 263 | ||
262 | LIB_H += ../../include/linux/perf_event.h | 264 | LIB_H += ../../include/uapi/linux/perf_event.h |
263 | LIB_H += ../../include/linux/rbtree.h | 265 | LIB_H += ../../include/linux/rbtree.h |
264 | LIB_H += ../../include/linux/list.h | 266 | LIB_H += ../../include/linux/list.h |
265 | LIB_H += ../../include/linux/const.h | 267 | LIB_H += ../../include/uapi/linux/const.h |
266 | LIB_H += ../../include/linux/hash.h | 268 | LIB_H += ../../include/linux/hash.h |
267 | LIB_H += ../../include/linux/stringify.h | 269 | LIB_H += ../../include/linux/stringify.h |
268 | LIB_H += util/include/linux/bitmap.h | 270 | LIB_H += util/include/linux/bitmap.h |
@@ -277,6 +279,7 @@ LIB_H += util/include/linux/magic.h | |||
277 | LIB_H += util/include/linux/poison.h | 279 | LIB_H += util/include/linux/poison.h |
278 | LIB_H += util/include/linux/prefetch.h | 280 | LIB_H += util/include/linux/prefetch.h |
279 | LIB_H += util/include/linux/rbtree.h | 281 | LIB_H += util/include/linux/rbtree.h |
282 | LIB_H += util/include/linux/rbtree_augmented.h | ||
280 | LIB_H += util/include/linux/string.h | 283 | LIB_H += util/include/linux/string.h |
281 | LIB_H += util/include/linux/types.h | 284 | LIB_H += util/include/linux/types.h |
282 | LIB_H += util/include/linux/linkage.h | 285 | LIB_H += util/include/linux/linkage.h |
@@ -902,7 +905,7 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | |||
902 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 905 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
903 | 906 | ||
904 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 907 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
905 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 908 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
906 | 909 | ||
907 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS | 910 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS |
908 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< | 911 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 411ee5664e9..178b88ae3d2 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -414,7 +414,7 @@ static int show_html_page(const char *perf_cmd) | |||
414 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) | 414 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) |
415 | { | 415 | { |
416 | bool show_all = false; | 416 | bool show_all = false; |
417 | enum help_format help_format = HELP_FORMAT_NONE; | 417 | enum help_format help_format = HELP_FORMAT_MAN; |
418 | struct option builtin_help_options[] = { | 418 | struct option builtin_help_options[] = { |
419 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), | 419 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), |
420 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), | 420 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4e9320bf11e..14b32296180 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -63,6 +63,10 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
63 | { | 63 | { |
64 | char tp_name[128]; | 64 | char tp_name[128]; |
65 | struct syscall *sc; | 65 | struct syscall *sc; |
66 | const char *name = audit_syscall_to_name(id, trace->audit_machine); | ||
67 | |||
68 | if (name == NULL) | ||
69 | return -1; | ||
66 | 70 | ||
67 | if (id > trace->syscalls.max) { | 71 | if (id > trace->syscalls.max) { |
68 | struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); | 72 | struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); |
@@ -82,11 +86,8 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
82 | } | 86 | } |
83 | 87 | ||
84 | sc = trace->syscalls.table + id; | 88 | sc = trace->syscalls.table + id; |
85 | sc->name = audit_syscall_to_name(id, trace->audit_machine); | 89 | sc->name = name; |
86 | if (sc->name == NULL) | 90 | sc->fmt = syscall_fmt__find(sc->name); |
87 | return -1; | ||
88 | |||
89 | sc->fmt = syscall_fmt__find(sc->name); | ||
90 | 91 | ||
91 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 92 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
92 | sc->tp_format = event_format__new("syscalls", tp_name); | 93 | sc->tp_format = event_format__new("syscalls", tp_name); |
@@ -290,6 +291,13 @@ again: | |||
290 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) | 291 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) |
291 | printf("%d ", sample.tid); | 292 | printf("%d ", sample.tid); |
292 | 293 | ||
294 | if (sample.raw_data == NULL) { | ||
295 | printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | ||
296 | perf_evsel__name(evsel), sample.tid, | ||
297 | sample.cpu, sample.raw_size); | ||
298 | continue; | ||
299 | } | ||
300 | |||
293 | handler = evsel->handler.func; | 301 | handler = evsel->handler.func; |
294 | handler(trace, evsel, &sample); | 302 | handler(trace, evsel, &sample); |
295 | } | 303 | } |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 87f4ec6d1f3..c50985eaec4 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -57,7 +57,7 @@ void get_term_dimensions(struct winsize *ws); | |||
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | #ifdef __sparc__ | 59 | #ifdef __sparc__ |
60 | #include "../../arch/sparc/include/asm/unistd.h" | 60 | #include "../../arch/sparc/include/uapi/asm/unistd.h" |
61 | #define rmb() asm volatile("":::"memory") | 61 | #define rmb() asm volatile("":::"memory") |
62 | #define cpu_relax() asm volatile("":::"memory") | 62 | #define cpu_relax() asm volatile("":::"memory") |
63 | #define CPUINFO_PROC "cpu" | 63 | #define CPUINFO_PROC "cpu" |
@@ -88,6 +88,12 @@ void get_term_dimensions(struct winsize *ws); | |||
88 | #define CPUINFO_PROC "Processor" | 88 | #define CPUINFO_PROC "Processor" |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | #ifdef __aarch64__ | ||
92 | #include "../../arch/arm64/include/asm/unistd.h" | ||
93 | #define rmb() asm volatile("dmb ld" ::: "memory") | ||
94 | #define cpu_relax() asm volatile("yield" ::: "memory") | ||
95 | #endif | ||
96 | |||
91 | #ifdef __mips__ | 97 | #ifdef __mips__ |
92 | #include "../../arch/mips/include/asm/unistd.h" | 98 | #include "../../arch/mips/include/asm/unistd.h" |
93 | #define rmb() asm volatile( \ | 99 | #define rmb() asm volatile( \ |
@@ -106,7 +112,7 @@ void get_term_dimensions(struct winsize *ws); | |||
106 | #include <sys/types.h> | 112 | #include <sys/types.h> |
107 | #include <sys/syscall.h> | 113 | #include <sys/syscall.h> |
108 | 114 | ||
109 | #include "../../include/linux/perf_event.h" | 115 | #include "../../include/uapi/linux/perf_event.h" |
110 | #include "util/types.h" | 116 | #include "util/types.h" |
111 | #include <stdbool.h> | 117 | #include <stdbool.h> |
112 | 118 | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 0568536ecf6..ef2f93ca749 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -610,6 +610,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
610 | char folded_sign = ' '; | 610 | char folded_sign = ' '; |
611 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 611 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
612 | off_t row_offset = entry->row_offset; | 612 | off_t row_offset = entry->row_offset; |
613 | bool first = true; | ||
613 | 614 | ||
614 | if (current_entry) { | 615 | if (current_entry) { |
615 | browser->he_selection = entry; | 616 | browser->he_selection = entry; |
@@ -633,10 +634,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
633 | if (!perf_hpp__format[i].cond) | 634 | if (!perf_hpp__format[i].cond) |
634 | continue; | 635 | continue; |
635 | 636 | ||
636 | if (i) { | 637 | if (!first) { |
637 | slsmg_printf(" "); | 638 | slsmg_printf(" "); |
638 | width -= 2; | 639 | width -= 2; |
639 | } | 640 | } |
641 | first = false; | ||
640 | 642 | ||
641 | if (perf_hpp__format[i].color) { | 643 | if (perf_hpp__format[i].color) { |
642 | hpp.ptr = &percent; | 644 | hpp.ptr = &percent; |
@@ -645,7 +647,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
645 | 647 | ||
646 | ui_browser__set_percent_color(&browser->b, percent, current_entry); | 648 | ui_browser__set_percent_color(&browser->b, percent, current_entry); |
647 | 649 | ||
648 | if (i == 0 && symbol_conf.use_callchain) { | 650 | if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { |
649 | slsmg_printf("%c ", folded_sign); | 651 | slsmg_printf("%c ", folded_sign); |
650 | width -= 2; | 652 | width -= 2; |
651 | } | 653 | } |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 3bdb407f9cd..eb340571e7d 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -58,7 +58,7 @@ struct callchain_list { | |||
58 | /* | 58 | /* |
59 | * A callchain cursor is a single linked list that | 59 | * A callchain cursor is a single linked list that |
60 | * let one feed a callchain progressively. | 60 | * let one feed a callchain progressively. |
61 | * It keeps persitent allocated entries to minimize | 61 | * It keeps persistent allocated entries to minimize |
62 | * allocations. | 62 | * allocations. |
63 | */ | 63 | */ |
64 | struct callchain_cursor_node { | 64 | struct callchain_cursor_node { |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ffdd94e9c9c..618d41140ab 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "thread_map.h" | 19 | #include "thread_map.h" |
20 | #include "target.h" | 20 | #include "target.h" |
21 | #include "../../../include/linux/hw_breakpoint.h" | 21 | #include "../../../include/linux/hw_breakpoint.h" |
22 | #include "../../include/linux/perf_event.h" | 22 | #include "../../../include/uapi/linux/perf_event.h" |
23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
24 | 24 | ||
25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3ead0d59c03..6f94d6dea00 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "../../../include/linux/perf_event.h" | 6 | #include "../../../include/uapi/linux/perf_event.h" |
7 | #include "types.h" | 7 | #include "types.h" |
8 | #include "xyarray.h" | 8 | #include "xyarray.h" |
9 | #include "cgroup.h" | 9 | #include "cgroup.h" |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 99bdd3abce5..879d215cdac 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_HEADER_H | 1 | #ifndef __PERF_HEADER_H |
2 | #define __PERF_HEADER_H | 2 | #define __PERF_HEADER_H |
3 | 3 | ||
4 | #include "../../../include/linux/perf_event.h" | 4 | #include "../../../include/uapi/linux/perf_event.h" |
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include "types.h" | 7 | #include "types.h" |
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h index b722abe3a62..2a9bdc06630 100644 --- a/tools/perf/util/include/asm/byteorder.h +++ b/tools/perf/util/include/asm/byteorder.h | |||
@@ -1,2 +1,2 @@ | |||
1 | #include <asm/types.h> | 1 | #include <asm/types.h> |
2 | #include "../../../../include/linux/swab.h" | 2 | #include "../../../../include/uapi/linux/swab.h" |
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h index 1b476c9ae64..c10a35e1afb 100644 --- a/tools/perf/util/include/linux/const.h +++ b/tools/perf/util/include/linux/const.h | |||
@@ -1 +1 @@ | |||
#include "../../../../include/linux/const.h" | #include "../../../../include/uapi/linux/const.h" | ||
diff --git a/tools/perf/util/include/linux/rbtree_augmented.h b/tools/perf/util/include/linux/rbtree_augmented.h new file mode 100644 index 00000000000..9d6fcdf1788 --- /dev/null +++ b/tools/perf/util/include/linux/rbtree_augmented.h | |||
@@ -0,0 +1,2 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include "../../../../include/linux/rbtree_augmented.h" | ||
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index d7244e55367..516ecd9ddd6 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -513,7 +513,8 @@ static int test__group1(struct perf_evlist *evlist) | |||
513 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 513 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
514 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 514 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
515 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 515 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
516 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 516 | /* use of precise requires exclude_guest */ |
517 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
517 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 518 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
518 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 519 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
519 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 520 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -599,7 +600,8 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
599 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | 600 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); |
600 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | 601 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); |
601 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 602 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
602 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 603 | /* use of precise requires exclude_guest */ |
604 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
603 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 605 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
604 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); | 606 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); |
605 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 607 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -662,7 +664,8 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
662 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 664 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
663 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 665 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
664 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 666 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
665 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 667 | /* use of precise requires exclude_guest */ |
668 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
666 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 669 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
667 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); | 670 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); |
668 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 671 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
@@ -676,7 +679,8 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
676 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | 679 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); |
677 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | 680 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); |
678 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 681 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
679 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 682 | /* use of precise requires exclude_guest */ |
683 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
680 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 684 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
681 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 685 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
682 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 686 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -1016,7 +1020,7 @@ static int test_pmu(void) | |||
1016 | 1020 | ||
1017 | ret = stat(path, &st); | 1021 | ret = stat(path, &st); |
1018 | if (ret) | 1022 | if (ret) |
1019 | pr_debug("ommiting PMU cpu tests\n"); | 1023 | pr_debug("omitting PMU cpu tests\n"); |
1020 | return !ret; | 1024 | return !ret; |
1021 | } | 1025 | } |
1022 | 1026 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index aed38e4b9df..75c7b0fca6d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -690,6 +690,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
690 | eH = 0; | 690 | eH = 0; |
691 | } else if (*str == 'p') { | 691 | } else if (*str == 'p') { |
692 | precise++; | 692 | precise++; |
693 | /* use of precise requires exclude_guest */ | ||
694 | if (!exclude_GH) | ||
695 | eG = 1; | ||
693 | } else | 696 | } else |
694 | break; | 697 | break; |
695 | 698 | ||
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index c356e443448..839230ceb18 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include <linux/list.h> | 7 | #include <linux/list.h> |
8 | #include <stdbool.h> | 8 | #include <stdbool.h> |
9 | #include "types.h" | 9 | #include "types.h" |
10 | #include "../../../include/linux/perf_event.h" | 10 | #include "../../../include/uapi/linux/perf_event.h" |
11 | #include "types.h" | 11 | #include "types.h" |
12 | 12 | ||
13 | struct list_head; | 13 | struct list_head; |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 53c7794fc4b..39f3abac774 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define __PMU_H | 2 | #define __PMU_H |
3 | 3 | ||
4 | #include <linux/bitops.h> | 4 | #include <linux/bitops.h> |
5 | #include "../../../include/linux/perf_event.h" | 5 | #include "../../../include/uapi/linux/perf_event.h" |
6 | 6 | ||
7 | enum { | 7 | enum { |
8 | PERF_PMU_FORMAT_VALUE_CONFIG, | 8 | PERF_PMU_FORMAT_VALUE_CONFIG, |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 213362850ab..c40c2d33199 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # List of files needed by perf python extention | 2 | # List of files needed by perf python extension |
3 | # | 3 | # |
4 | # Each source file must be placed on its own line so that it can be | 4 | # Each source file must be placed on its own line so that it can be |
5 | # processed by Makefile and util/setup.py accordingly. | 5 | # processed by Makefile and util/setup.py accordingly. |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index aab414fbb64..dd6426163ba 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include "symbol.h" | 7 | #include "symbol.h" |
8 | #include "thread.h" | 8 | #include "thread.h" |
9 | #include <linux/rbtree.h> | 9 | #include <linux/rbtree.h> |
10 | #include "../../../include/linux/perf_event.h" | 10 | #include "../../../include/uapi/linux/perf_event.h" |
11 | 11 | ||
12 | struct sample_queue; | 12 | struct sample_queue; |
13 | struct ip_callchain; | 13 | struct ip_callchain; |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index d0f9f29cf18..73d51026978 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -23,6 +23,7 @@ cflags += getenv('CFLAGS', '').split() | |||
23 | 23 | ||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | libtraceevent = getenv('LIBTRACEEVENT') | ||
26 | 27 | ||
27 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 28 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
28 | if len(f.strip()) > 0 and f[0] != '#'] | 29 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -31,6 +32,7 @@ perf = Extension('perf', | |||
31 | sources = ext_sources, | 32 | sources = ext_sources, |
32 | include_dirs = ['util/include'], | 33 | include_dirs = ['util/include'], |
33 | extra_compile_args = cflags, | 34 | extra_compile_args = cflags, |
35 | extra_objects = [libtraceevent], | ||
34 | ) | 36 | ) |
35 | 37 | ||
36 | setup(name='perf', | 38 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b5b1b921196..cfd1c0feb32 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -260,6 +260,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
260 | if (path != NULL) | 260 | if (path != NULL) |
261 | goto out_path; | 261 | goto out_path; |
262 | 262 | ||
263 | if (!self->ms.map) | ||
264 | goto out_ip; | ||
265 | |||
266 | if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10)) | ||
267 | goto out_ip; | ||
268 | |||
263 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, | 269 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, |
264 | self->ms.map->dso->long_name, self->ip); | 270 | self->ms.map->dso->long_name, self->ip); |
265 | fp = popen(cmd, "r"); | 271 | fp = popen(cmd, "r"); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index fe3bb1ec188..df59623ac76 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -39,7 +39,6 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
39 | err = self->comm == NULL ? -ENOMEM : 0; | 39 | err = self->comm == NULL ? -ENOMEM : 0; |
40 | if (!err) { | 40 | if (!err) { |
41 | self->comm_set = true; | 41 | self->comm_set = true; |
42 | map_groups__flush(&self->mg); | ||
43 | } | 42 | } |
44 | return err; | 43 | return err; |
45 | } | 44 | } |
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile new file mode 100644 index 00000000000..6b9cf7a987c --- /dev/null +++ b/tools/power/acpi/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | PROG= acpidump | ||
2 | SRCS= acpidump.c | ||
3 | KERNEL_INCLUDE := ../../../include | ||
4 | CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) | ||
5 | |||
6 | all: acpidump | ||
7 | $(PROG) : $(SRCS) | ||
8 | $(CC) $(CFLAGS) $(SRCS) -o $(PROG) | ||
9 | |||
10 | CLEANFILES= $(PROG) | ||
11 | |||
12 | clean : | ||
13 | rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ | ||
14 | |||
15 | install : | ||
16 | install acpidump /usr/bin/acpidump | ||
17 | install acpidump.8 /usr/share/man/man8 | ||
18 | |||
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/acpidump.8 new file mode 100644 index 00000000000..adfa99166e5 --- /dev/null +++ b/tools/power/acpi/acpidump.8 | |||
@@ -0,0 +1,59 @@ | |||
1 | .TH ACPIDUMP 8 | ||
2 | .SH NAME | ||
3 | acpidump \- Dump system's ACPI tables to an ASCII file. | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B acpidump > acpidump.out | ||
7 | .SH DESCRIPTION | ||
8 | \fBacpidump \fP dumps the systems ACPI tables to an ASCII file | ||
9 | appropriate for attaching to a bug report. | ||
10 | |||
11 | Subsequently, they can be processed by utilities in the ACPICA package. | ||
12 | .SS Options | ||
13 | no options worth worrying about. | ||
14 | .PP | ||
15 | .SH EXAMPLE | ||
16 | |||
17 | .nf | ||
18 | # acpidump > acpidump.out | ||
19 | |||
20 | $ acpixtract -a acpidump.out | ||
21 | Acpi table [DSDT] - 15974 bytes written to DSDT.dat | ||
22 | Acpi table [FACS] - 64 bytes written to FACS.dat | ||
23 | Acpi table [FACP] - 116 bytes written to FACP.dat | ||
24 | Acpi table [APIC] - 120 bytes written to APIC.dat | ||
25 | Acpi table [MCFG] - 60 bytes written to MCFG.dat | ||
26 | Acpi table [SSDT] - 444 bytes written to SSDT1.dat | ||
27 | Acpi table [SSDT] - 439 bytes written to SSDT2.dat | ||
28 | Acpi table [SSDT] - 439 bytes written to SSDT3.dat | ||
29 | Acpi table [SSDT] - 439 bytes written to SSDT4.dat | ||
30 | Acpi table [SSDT] - 439 bytes written to SSDT5.dat | ||
31 | Acpi table [RSDT] - 76 bytes written to RSDT.dat | ||
32 | Acpi table [RSDP] - 20 bytes written to RSDP.dat | ||
33 | |||
34 | $ iasl -d *.dat | ||
35 | ... | ||
36 | .fi | ||
37 | creates *.dsl, a human readable form which can be edited | ||
38 | and compiled using iasl. | ||
39 | |||
40 | |||
41 | .SH NOTES | ||
42 | |||
43 | .B "acpidump " | ||
44 | must be run as root. | ||
45 | |||
46 | .SH REFERENCES | ||
47 | ACPICA: https://acpica.org/ | ||
48 | |||
49 | .SH FILES | ||
50 | .ta | ||
51 | .nf | ||
52 | /dev/mem | ||
53 | /sys/firmware/acpi/tables/dynamic/* | ||
54 | .fi | ||
55 | |||
56 | .PP | ||
57 | .SH AUTHOR | ||
58 | .nf | ||
59 | Written by Len Brown <len.brown@intel.com> | ||
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c new file mode 100644 index 00000000000..a84553a0e0d --- /dev/null +++ b/tools/power/acpi/acpidump.c | |||
@@ -0,0 +1,559 @@ | |||
1 | /* | ||
2 | * (c) Alexey Starikovskiy, Intel, 2005-2006. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions, and the following disclaimer, | ||
10 | * without modification. | ||
11 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
12 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
13 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
14 | * including a substantially similar Disclaimer requirement for further | ||
15 | * binary redistribution. | ||
16 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
17 | * of any contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * NO WARRANTY | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
29 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
33 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
34 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
35 | * POSSIBILITY OF SUCH DAMAGES. | ||
36 | */ | ||
37 | |||
38 | #ifdef DEFINE_ALTERNATE_TYPES | ||
39 | /* hack to enable building old application with new headers -lenb */ | ||
40 | #define acpi_fadt_descriptor acpi_table_fadt | ||
41 | #define acpi_rsdp_descriptor acpi_table_rsdp | ||
42 | #define DSDT_SIG ACPI_SIG_DSDT | ||
43 | #define FACS_SIG ACPI_SIG_FACS | ||
44 | #define FADT_SIG ACPI_SIG_FADT | ||
45 | #define xfirmware_ctrl Xfacs | ||
46 | #define firmware_ctrl facs | ||
47 | |||
48 | typedef int s32; | ||
49 | typedef unsigned char u8; | ||
50 | typedef unsigned short u16; | ||
51 | typedef unsigned int u32; | ||
52 | typedef unsigned long long u64; | ||
53 | typedef long long s64; | ||
54 | #endif | ||
55 | |||
56 | #include <sys/mman.h> | ||
57 | #include <sys/types.h> | ||
58 | #include <sys/stat.h> | ||
59 | #include <fcntl.h> | ||
60 | #include <stdio.h> | ||
61 | #include <string.h> | ||
62 | #include <unistd.h> | ||
63 | #include <getopt.h> | ||
64 | |||
65 | #include <dirent.h> | ||
66 | |||
67 | #include <acpi/acconfig.h> | ||
68 | #include <acpi/platform/acenv.h> | ||
69 | #include <acpi/actypes.h> | ||
70 | #include <acpi/actbl.h> | ||
71 | |||
72 | static inline u8 checksum(u8 * buffer, u32 length) | ||
73 | { | ||
74 | u8 sum = 0, *i = buffer; | ||
75 | buffer += length; | ||
76 | for (; i < buffer; sum += *(i++)); | ||
77 | return sum; | ||
78 | } | ||
79 | |||
80 | static unsigned long psz, addr, length; | ||
81 | static int print, connect, skip; | ||
82 | static u8 select_sig[4]; | ||
83 | |||
84 | static unsigned long read_efi_systab( void ) | ||
85 | { | ||
86 | char buffer[80]; | ||
87 | unsigned long addr; | ||
88 | FILE *f = fopen("/sys/firmware/efi/systab", "r"); | ||
89 | if (f) { | ||
90 | while (fgets(buffer, 80, f)) { | ||
91 | if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1) | ||
92 | return addr; | ||
93 | } | ||
94 | fclose(f); | ||
95 | } | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static u8 *acpi_map_memory(unsigned long where, unsigned length) | ||
100 | { | ||
101 | unsigned long offset; | ||
102 | u8 *there; | ||
103 | int fd = open("/dev/mem", O_RDONLY); | ||
104 | if (fd < 0) { | ||
105 | fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n"); | ||
106 | exit(1); | ||
107 | } | ||
108 | offset = where % psz; | ||
109 | there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE, | ||
110 | fd, where - offset); | ||
111 | close(fd); | ||
112 | if (there == MAP_FAILED) return 0; | ||
113 | return (there + offset); | ||
114 | } | ||
115 | |||
116 | static void acpi_unmap_memory(u8 * there, unsigned length) | ||
117 | { | ||
118 | unsigned long offset = (unsigned long)there % psz; | ||
119 | munmap(there - offset, length + offset); | ||
120 | } | ||
121 | |||
122 | static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig) | ||
123 | { | ||
124 | unsigned size; | ||
125 | struct acpi_table_header *tbl = (struct acpi_table_header *) | ||
126 | acpi_map_memory(where, sizeof(struct acpi_table_header)); | ||
127 | if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0; | ||
128 | size = tbl->length; | ||
129 | acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header)); | ||
130 | return (struct acpi_table_header *)acpi_map_memory(where, size); | ||
131 | } | ||
132 | |||
133 | static void acpi_unmap_table(struct acpi_table_header *tbl) | ||
134 | { | ||
135 | acpi_unmap_memory((u8 *)tbl, tbl->length); | ||
136 | } | ||
137 | |||
138 | static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length) | ||
139 | { | ||
140 | struct acpi_rsdp_descriptor *rsdp; | ||
141 | u8 *i, *end = begin + length; | ||
142 | /* Search from given start address for the requested length */ | ||
143 | for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) { | ||
144 | /* The signature and checksum must both be correct */ | ||
145 | if (memcmp((char *)i, "RSD PTR ", 8)) continue; | ||
146 | rsdp = (struct acpi_rsdp_descriptor *)i; | ||
147 | /* Signature matches, check the appropriate checksum */ | ||
148 | if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ? | ||
149 | ACPI_RSDP_CHECKSUM_LENGTH : | ||
150 | ACPI_RSDP_XCHECKSUM_LENGTH)) | ||
151 | /* Checksum valid, we have found a valid RSDP */ | ||
152 | return rsdp; | ||
153 | } | ||
154 | /* Searched entire block, no RSDP was found */ | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Output data | ||
160 | */ | ||
161 | static void acpi_show_data(int fd, u8 * data, int size) | ||
162 | { | ||
163 | char buffer[256]; | ||
164 | int len; | ||
165 | int i, remain = size; | ||
166 | while (remain > 0) { | ||
167 | len = snprintf(buffer, 256, " %04x:", size - remain); | ||
168 | for (i = 0; i < 16 && i < remain; i++) { | ||
169 | len += | ||
170 | snprintf(&buffer[len], 256 - len, " %02x", data[i]); | ||
171 | } | ||
172 | for (; i < 16; i++) { | ||
173 | len += snprintf(&buffer[len], 256 - len, " "); | ||
174 | } | ||
175 | len += snprintf(&buffer[len], 256 - len, " "); | ||
176 | for (i = 0; i < 16 && i < remain; i++) { | ||
177 | buffer[len++] = (isprint(data[i])) ? data[i] : '.'; | ||
178 | } | ||
179 | buffer[len++] = '\n'; | ||
180 | write(fd, buffer, len); | ||
181 | data += 16; | ||
182 | remain -= 16; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Output ACPI table | ||
188 | */ | ||
189 | static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) | ||
190 | { | ||
191 | char buff[80]; | ||
192 | int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr); | ||
193 | write(fd, buff, len); | ||
194 | acpi_show_data(fd, (u8 *) table, table->length); | ||
195 | buff[0] = '\n'; | ||
196 | write(fd, buff, 1); | ||
197 | } | ||
198 | |||
199 | static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) | ||
200 | { | ||
201 | static int select_done = 0; | ||
202 | if (!select_sig[0]) { | ||
203 | if (print) { | ||
204 | acpi_show_table(fd, tbl, addr); | ||
205 | } else { | ||
206 | write(fd, tbl, tbl->length); | ||
207 | } | ||
208 | } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) { | ||
209 | if (skip > 0) { | ||
210 | --skip; | ||
211 | return; | ||
212 | } | ||
213 | if (print) { | ||
214 | acpi_show_table(fd, tbl, addr); | ||
215 | } else { | ||
216 | write(fd, tbl, tbl->length); | ||
217 | } | ||
218 | select_done = 1; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { | ||
223 | struct acpi_fadt_descriptor x; | ||
224 | unsigned long addr; | ||
225 | size_t len = sizeof(struct acpi_fadt_descriptor); | ||
226 | if (len > tbl->length) len = tbl->length; | ||
227 | memcpy(&x, tbl, len); | ||
228 | x.header.length = len; | ||
229 | if (checksum((u8 *)tbl, len)) { | ||
230 | fprintf(stderr, "Wrong checksum for FADT!\n"); | ||
231 | } | ||
232 | if (x.header.length >= 148 && x.Xdsdt) { | ||
233 | addr = (unsigned long)x.Xdsdt; | ||
234 | if (connect) { | ||
235 | x.Xdsdt = lseek(fd, 0, SEEK_CUR); | ||
236 | } | ||
237 | } else if (x.header.length >= 44 && x.dsdt) { | ||
238 | addr = (unsigned long)x.dsdt; | ||
239 | if (connect) { | ||
240 | x.dsdt = lseek(fd, 0, SEEK_CUR); | ||
241 | } | ||
242 | } else { | ||
243 | fprintf(stderr, "No DSDT in FADT!\n"); | ||
244 | goto no_dsdt; | ||
245 | } | ||
246 | tbl = acpi_map_table(addr, DSDT_SIG); | ||
247 | if (!tbl) goto no_dsdt; | ||
248 | if (checksum((u8 *)tbl, tbl->length)) | ||
249 | fprintf(stderr, "Wrong checksum for DSDT!\n"); | ||
250 | write_table(fd, tbl, addr); | ||
251 | acpi_unmap_table(tbl); | ||
252 | no_dsdt: | ||
253 | if (x.header.length >= 140 && x.xfirmware_ctrl) { | ||
254 | addr = (unsigned long)x.xfirmware_ctrl; | ||
255 | if (connect) { | ||
256 | x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR); | ||
257 | } | ||
258 | } else if (x.header.length >= 40 && x.firmware_ctrl) { | ||
259 | addr = (unsigned long)x.firmware_ctrl; | ||
260 | if (connect) { | ||
261 | x.firmware_ctrl = lseek(fd, 0, SEEK_CUR); | ||
262 | } | ||
263 | } else { | ||
264 | fprintf(stderr, "No FACS in FADT!\n"); | ||
265 | goto no_facs; | ||
266 | } | ||
267 | tbl = acpi_map_table(addr, FACS_SIG); | ||
268 | if (!tbl) goto no_facs; | ||
269 | /* do not checksum FACS */ | ||
270 | write_table(fd, tbl, addr); | ||
271 | acpi_unmap_table(tbl); | ||
272 | no_facs: | ||
273 | write_table(fd, (struct acpi_table_header *)&x, xaddr); | ||
274 | } | ||
275 | |||
276 | static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp) | ||
277 | { | ||
278 | struct acpi_table_header *sdt, *tbl = 0; | ||
279 | int xsdt = 1, i, num; | ||
280 | char *offset; | ||
281 | unsigned long addr; | ||
282 | if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { | ||
283 | tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); | ||
284 | } | ||
285 | if (!tbl && rsdp->rsdt_physical_address) { | ||
286 | xsdt = 0; | ||
287 | tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); | ||
288 | } | ||
289 | if (!tbl) return 0; | ||
290 | sdt = malloc(tbl->length); | ||
291 | memcpy(sdt, tbl, tbl->length); | ||
292 | acpi_unmap_table(tbl); | ||
293 | if (checksum((u8 *)sdt, sdt->length)) | ||
294 | fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT"); | ||
295 | num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32)); | ||
296 | offset = (char *)sdt + sizeof(struct acpi_table_header); | ||
297 | for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) { | ||
298 | addr = (xsdt) ? (unsigned long)(*(u64 *)offset): | ||
299 | (unsigned long)(*(u32 *)offset); | ||
300 | if (!addr) continue; | ||
301 | tbl = acpi_map_table(addr, 0); | ||
302 | if (!tbl) continue; | ||
303 | if (!memcmp(tbl->signature, FADT_SIG, 4)) { | ||
304 | acpi_dump_FADT(fd, tbl, addr); | ||
305 | } else { | ||
306 | if (checksum((u8 *)tbl, tbl->length)) | ||
307 | fprintf(stderr, "Wrong checksum for generic table!\n"); | ||
308 | write_table(fd, tbl, addr); | ||
309 | } | ||
310 | acpi_unmap_table(tbl); | ||
311 | if (connect) { | ||
312 | if (xsdt) | ||
313 | (*(u64*)offset) = lseek(fd, 0, SEEK_CUR); | ||
314 | else | ||
315 | (*(u32*)offset) = lseek(fd, 0, SEEK_CUR); | ||
316 | } | ||
317 | } | ||
318 | if (xsdt) { | ||
319 | addr = (unsigned long)rsdp->xsdt_physical_address; | ||
320 | if (connect) { | ||
321 | rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
322 | } | ||
323 | } else { | ||
324 | addr = (unsigned long)rsdp->rsdt_physical_address; | ||
325 | if (connect) { | ||
326 | rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
327 | } | ||
328 | } | ||
329 | write_table(fd, sdt, addr); | ||
330 | free (sdt); | ||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | #define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic" | ||
335 | |||
336 | static void acpi_dump_dynamic_SSDT(int fd) | ||
337 | { | ||
338 | struct stat file_stat; | ||
339 | char filename[256], *ptr; | ||
340 | DIR *tabledir; | ||
341 | struct dirent *entry; | ||
342 | FILE *fp; | ||
343 | int count, readcount, length; | ||
344 | struct acpi_table_header table_header, *ptable; | ||
345 | |||
346 | if (stat(DYNAMIC_SSDT, &file_stat) == -1) { | ||
347 | /* The directory doesn't exist */ | ||
348 | return; | ||
349 | } | ||
350 | tabledir = opendir(DYNAMIC_SSDT); | ||
351 | if(!tabledir){ | ||
352 | /*can't open the directory */ | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | while ((entry = readdir(tabledir)) != 0){ | ||
357 | /* skip the file of . /.. */ | ||
358 | if (entry->d_name[0] == '.') | ||
359 | continue; | ||
360 | |||
361 | sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name); | ||
362 | fp = fopen(filename, "r"); | ||
363 | if (fp == NULL) { | ||
364 | fprintf(stderr, "Can't open the file of %s\n", | ||
365 | filename); | ||
366 | continue; | ||
367 | } | ||
368 | /* Read the Table header to parse the table length */ | ||
369 | count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); | ||
370 | if (count < sizeof(table_header)) { | ||
371 | /* the length is lessn than ACPI table header. skip it */ | ||
372 | fclose(fp); | ||
373 | continue; | ||
374 | } | ||
375 | length = table_header.length; | ||
376 | ptr = malloc(table_header.length); | ||
377 | fseek(fp, 0, SEEK_SET); | ||
378 | readcount = 0; | ||
379 | while(!feof(fp) && readcount < length) { | ||
380 | count = fread(ptr + readcount, 1, 256, fp); | ||
381 | readcount += count; | ||
382 | } | ||
383 | fclose(fp); | ||
384 | ptable = (struct acpi_table_header *) ptr; | ||
385 | if (checksum((u8 *) ptable, ptable->length)) | ||
386 | fprintf(stderr, "Wrong checksum " | ||
387 | "for dynamic SSDT table!\n"); | ||
388 | write_table(fd, ptable, 0); | ||
389 | free(ptr); | ||
390 | } | ||
391 | closedir(tabledir); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | static void usage(const char *progname) | ||
396 | { | ||
397 | puts("Usage:"); | ||
398 | printf("%s [--addr 0x1234][--table DSDT][--output filename]" | ||
399 | "[--binary][--length 0x456][--help]\n", progname); | ||
400 | puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address"); | ||
401 | puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature"); | ||
402 | puts("\t--output filename or -o filename -- redirect output from stdin to filename"); | ||
403 | puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format"); | ||
404 | puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory" | ||
405 | "\n\t\tregion without trying to understand it's contents"); | ||
406 | puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one"); | ||
407 | puts("\t--help or -h -- this help message"); | ||
408 | exit(0); | ||
409 | } | ||
410 | |||
411 | static struct option long_options[] = { | ||
412 | {"addr", 1, 0, 0}, | ||
413 | {"table", 1, 0, 0}, | ||
414 | {"output", 1, 0, 0}, | ||
415 | {"binary", 0, 0, 0}, | ||
416 | {"length", 1, 0, 0}, | ||
417 | {"skip", 1, 0, 0}, | ||
418 | {"help", 0, 0, 0}, | ||
419 | {0, 0, 0, 0} | ||
420 | }; | ||
421 | int main(int argc, char **argv) | ||
422 | { | ||
423 | int option_index, c, fd; | ||
424 | u8 *raw; | ||
425 | struct acpi_rsdp_descriptor rsdpx, *x = 0; | ||
426 | char *filename = 0; | ||
427 | char buff[80]; | ||
428 | memset(select_sig, 0, 4); | ||
429 | print = 1; | ||
430 | connect = 0; | ||
431 | addr = length = 0; | ||
432 | skip = 0; | ||
433 | while (1) { | ||
434 | option_index = 0; | ||
435 | c = getopt_long(argc, argv, "a:t:o:bl:s:h", | ||
436 | long_options, &option_index); | ||
437 | if (c == -1) | ||
438 | break; | ||
439 | |||
440 | switch (c) { | ||
441 | case 0: | ||
442 | switch (option_index) { | ||
443 | case 0: | ||
444 | addr = strtoul(optarg, (char **)NULL, 16); | ||
445 | break; | ||
446 | case 1: | ||
447 | memcpy(select_sig, optarg, 4); | ||
448 | break; | ||
449 | case 2: | ||
450 | filename = optarg; | ||
451 | break; | ||
452 | case 3: | ||
453 | print = 0; | ||
454 | break; | ||
455 | case 4: | ||
456 | length = strtoul(optarg, (char **)NULL, 16); | ||
457 | break; | ||
458 | case 5: | ||
459 | skip = strtoul(optarg, (char **)NULL, 10); | ||
460 | break; | ||
461 | case 6: | ||
462 | usage(argv[0]); | ||
463 | exit(0); | ||
464 | } | ||
465 | break; | ||
466 | case 'a': | ||
467 | addr = strtoul(optarg, (char **)NULL, 16); | ||
468 | break; | ||
469 | case 't': | ||
470 | memcpy(select_sig, optarg, 4); | ||
471 | break; | ||
472 | case 'o': | ||
473 | filename = optarg; | ||
474 | break; | ||
475 | case 'b': | ||
476 | print = 0; | ||
477 | break; | ||
478 | case 'l': | ||
479 | length = strtoul(optarg, (char **)NULL, 16); | ||
480 | break; | ||
481 | case 's': | ||
482 | skip = strtoul(optarg, (char **)NULL, 10); | ||
483 | break; | ||
484 | case 'h': | ||
485 | usage(argv[0]); | ||
486 | exit(0); | ||
487 | default: | ||
488 | printf("Unknown option!\n"); | ||
489 | usage(argv[0]); | ||
490 | exit(0); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | fd = STDOUT_FILENO; | ||
495 | if (filename) { | ||
496 | fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); | ||
497 | if (fd < 0) | ||
498 | return fd; | ||
499 | } | ||
500 | |||
501 | if (!select_sig[0] && !print) { | ||
502 | connect = 1; | ||
503 | } | ||
504 | |||
505 | psz = sysconf(_SC_PAGESIZE); | ||
506 | if (length && addr) { | ||
507 | /* We know length and address, it means we just want a memory dump */ | ||
508 | if (!(raw = acpi_map_memory(addr, length))) | ||
509 | goto not_found; | ||
510 | write(fd, raw, length); | ||
511 | acpi_unmap_memory(raw, length); | ||
512 | close(fd); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | length = sizeof(struct acpi_rsdp_descriptor); | ||
517 | if (!addr) { | ||
518 | addr = read_efi_systab(); | ||
519 | if (!addr) { | ||
520 | addr = ACPI_HI_RSDP_WINDOW_BASE; | ||
521 | length = ACPI_HI_RSDP_WINDOW_SIZE; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | if (!(raw = acpi_map_memory(addr, length)) || | ||
526 | !(x = acpi_scan_for_rsdp(raw, length))) | ||
527 | goto not_found; | ||
528 | |||
529 | /* Find RSDP and print all found tables */ | ||
530 | memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor)); | ||
531 | acpi_unmap_memory(raw, length); | ||
532 | if (connect) { | ||
533 | lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); | ||
534 | } | ||
535 | if (!acpi_dump_SDT(fd, &rsdpx)) | ||
536 | goto not_found; | ||
537 | if (connect) { | ||
538 | lseek(fd, 0, SEEK_SET); | ||
539 | write(fd, x, (rsdpx.revision < 2) ? | ||
540 | ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); | ||
541 | } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) { | ||
542 | addr += (long)x - (long)raw; | ||
543 | length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr); | ||
544 | write(fd, buff, length); | ||
545 | acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ? | ||
546 | ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); | ||
547 | buff[0] = '\n'; | ||
548 | write(fd, buff, 1); | ||
549 | } | ||
550 | acpi_dump_dynamic_SSDT(fd); | ||
551 | close(fd); | ||
552 | return 0; | ||
553 | not_found: | ||
554 | close(fd); | ||
555 | fprintf(stderr, "ACPI tables were not found. If you know location " | ||
556 | "of RSD PTR table (from dmesg, etc), " | ||
557 | "supply it with either --addr or -a option\n"); | ||
558 | return 1; | ||
559 | } | ||
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index a93e06cfcc2..cf397bd26d0 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -111,7 +111,7 @@ GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; | |||
111 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | 111 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS |
112 | 112 | ||
113 | # check if compiler option is supported | 113 | # check if compiler option is supported |
114 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | 114 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} |
115 | 115 | ||
116 | # use '-Os' optimization if available, else use -O2 | 116 | # use '-Os' optimization if available, else use -O2 |
117 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | 117 | OPTIMIZATION := $(call cc-supports,-Os,-O2) |
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 74e44507dfe..e4d0690cccf 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 | |||
@@ -4,15 +4,11 @@ turbostat \- Report processor frequency and idle statistics | |||
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .ft B | 5 | .ft B |
6 | .B turbostat | 6 | .B turbostat |
7 | .RB [ "\-s" ] | 7 | .RB [ Options ] |
8 | .RB [ "\-v" ] | ||
9 | .RB [ "\-M MSR#" ] | ||
10 | .RB command | 8 | .RB command |
11 | .br | 9 | .br |
12 | .B turbostat | 10 | .B turbostat |
13 | .RB [ "\-s" ] | 11 | .RB [ Options ] |
14 | .RB [ "\-v" ] | ||
15 | .RB [ "\-M MSR#" ] | ||
16 | .RB [ "\-i interval_sec" ] | 12 | .RB [ "\-i interval_sec" ] |
17 | .SH DESCRIPTION | 13 | .SH DESCRIPTION |
18 | \fBturbostat \fP reports processor topology, frequency | 14 | \fBturbostat \fP reports processor topology, frequency |
@@ -27,16 +23,23 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs. | |||
27 | on processors that additionally support C-state residency counters. | 23 | on processors that additionally support C-state residency counters. |
28 | 24 | ||
29 | .SS Options | 25 | .SS Options |
30 | The \fB-s\fP option limits output to a 1-line system summary for each interval. | 26 | The \fB-p\fP option limits output to the 1st thread in 1st core of each package. |
31 | .PP | 27 | .PP |
32 | The \fB-c\fP option limits output to the 1st thread in each core. | 28 | The \fB-P\fP option limits output to the 1st thread in each Package. |
33 | .PP | 29 | .PP |
34 | The \fB-p\fP option limits output to the 1st thread in each package. | 30 | The \fB-S\fP option limits output to a 1-line System Summary for each interval. |
35 | .PP | 31 | .PP |
36 | The \fB-v\fP option increases verbosity. | 32 | The \fB-v\fP option increases verbosity. |
37 | .PP | 33 | .PP |
38 | The \fB-M MSR#\fP option dumps the specified MSR, | 34 | The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34" |
39 | in addition to the usual frequency and idle statistics. | 35 | .PP |
36 | The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter. | ||
37 | .PP | ||
38 | The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter. | ||
39 | .PP | ||
40 | The \fB-m MSR#\fP option includes the the specified 32-bit MSR value. | ||
41 | .PP | ||
42 | The \fB-M MSR#\fP option includes the the specified 64-bit MSR value. | ||
40 | .PP | 43 | .PP |
41 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. | 44 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. |
42 | The default is 5 seconds. | 45 | The default is 5 seconds. |
@@ -150,6 +153,29 @@ Note that turbostat reports average GHz of 3.63, while | |||
150 | the arithmetic average of the GHz column above is lower. | 153 | the arithmetic average of the GHz column above is lower. |
151 | This is a weighted average, where the weight is %c0. ie. it is the total number of | 154 | This is a weighted average, where the weight is %c0. ie. it is the total number of |
152 | un-halted cycles elapsed per time divided by the number of CPUs. | 155 | un-halted cycles elapsed per time divided by the number of CPUs. |
156 | .SH SMI COUNTING EXAMPLE | ||
157 | On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. | ||
158 | Using the -m option, you can display how many SMIs have fired since reset, or if there | ||
159 | are SMIs during the measurement interval, you can display the delta using the -d option. | ||
160 | .nf | ||
161 | [root@x980 ~]# turbostat -m 0x34 | ||
162 | cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6 | ||
163 | 1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55 | ||
164 | 0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55 | ||
165 | 0 6 0.14 1.63 3.38 0x00000056 5.30 | ||
166 | 1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52 | ||
167 | 1 8 0.10 1.65 3.38 0x00000056 18.05 | ||
168 | 2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50 | ||
169 | 2 10 0.10 1.63 3.38 0x00000056 6.93 | ||
170 | 8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16 | ||
171 | 8 7 0.08 1.64 3.38 0x00000056 5.12 | ||
172 | 9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38 | ||
173 | 9 9 0.09 1.68 3.38 0x00000056 9.32 | ||
174 | 10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23 | ||
175 | 10 11 1.72 1.65 3.38 0x00000056 15.05 | ||
176 | ^C | ||
177 | [root@x980 ~]# | ||
178 | .fi | ||
153 | .SH NOTES | 179 | .SH NOTES |
154 | 180 | ||
155 | .B "turbostat " | 181 | .B "turbostat " |
@@ -165,6 +191,13 @@ may work poorly on Linux-2.6.20 through 2.6.29, | |||
165 | as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF | 191 | as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF |
166 | in those kernels. | 192 | in those kernels. |
167 | 193 | ||
194 | If the TSC column does not make sense, then | ||
195 | the other numbers will also make no sense. | ||
196 | Turbostat is lightweight, and its data collection is not atomic. | ||
197 | These issues are usually caused by an extremely short measurement | ||
198 | interval (much less than 1 second), or system activity that prevents | ||
199 | turbostat from being able to run on all CPUS to quickly collect data. | ||
200 | |||
168 | The APERF, MPERF MSRs are defined to count non-halted cycles. | 201 | The APERF, MPERF MSRs are defined to count non-halted cycles. |
169 | Although it is not guaranteed by the architecture, turbostat assumes | 202 | Although it is not guaranteed by the architecture, turbostat assumes |
170 | that they count at TSC rate, which is true on all processors tested to date. | 203 | that they count at TSC rate, which is true on all processors tested to date. |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 861d7719020..2655ae9a3ad 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -35,9 +35,9 @@ | |||
35 | #include <ctype.h> | 35 | #include <ctype.h> |
36 | #include <sched.h> | 36 | #include <sched.h> |
37 | 37 | ||
38 | #define MSR_TSC 0x10 | ||
39 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE | 38 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE |
40 | #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD | 39 | #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD |
40 | #define MSR_IVT_TURBO_RATIO_LIMIT 0x1AE | ||
41 | #define MSR_APERF 0xE8 | 41 | #define MSR_APERF 0xE8 |
42 | #define MSR_MPERF 0xE7 | 42 | #define MSR_MPERF 0xE7 |
43 | #define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ | 43 | #define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ |
@@ -62,7 +62,11 @@ unsigned int genuine_intel; | |||
62 | unsigned int has_invariant_tsc; | 62 | unsigned int has_invariant_tsc; |
63 | unsigned int do_nehalem_platform_info; | 63 | unsigned int do_nehalem_platform_info; |
64 | unsigned int do_nehalem_turbo_ratio_limit; | 64 | unsigned int do_nehalem_turbo_ratio_limit; |
65 | unsigned int extra_msr_offset; | 65 | unsigned int do_ivt_turbo_ratio_limit; |
66 | unsigned int extra_msr_offset32; | ||
67 | unsigned int extra_msr_offset64; | ||
68 | unsigned int extra_delta_offset32; | ||
69 | unsigned int extra_delta_offset64; | ||
66 | double bclk; | 70 | double bclk; |
67 | unsigned int show_pkg; | 71 | unsigned int show_pkg; |
68 | unsigned int show_core; | 72 | unsigned int show_core; |
@@ -83,7 +87,10 @@ struct thread_data { | |||
83 | unsigned long long aperf; | 87 | unsigned long long aperf; |
84 | unsigned long long mperf; | 88 | unsigned long long mperf; |
85 | unsigned long long c1; /* derived */ | 89 | unsigned long long c1; /* derived */ |
86 | unsigned long long extra_msr; | 90 | unsigned long long extra_msr64; |
91 | unsigned long long extra_delta64; | ||
92 | unsigned long long extra_msr32; | ||
93 | unsigned long long extra_delta32; | ||
87 | unsigned int cpu_id; | 94 | unsigned int cpu_id; |
88 | unsigned int flags; | 95 | unsigned int flags; |
89 | #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 | 96 | #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 |
@@ -222,6 +229,14 @@ void print_header(void) | |||
222 | if (has_aperf) | 229 | if (has_aperf) |
223 | outp += sprintf(outp, " GHz"); | 230 | outp += sprintf(outp, " GHz"); |
224 | outp += sprintf(outp, " TSC"); | 231 | outp += sprintf(outp, " TSC"); |
232 | if (extra_delta_offset32) | ||
233 | outp += sprintf(outp, " count 0x%03X", extra_delta_offset32); | ||
234 | if (extra_delta_offset64) | ||
235 | outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64); | ||
236 | if (extra_msr_offset32) | ||
237 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32); | ||
238 | if (extra_msr_offset64) | ||
239 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64); | ||
225 | if (do_nhm_cstates) | 240 | if (do_nhm_cstates) |
226 | outp += sprintf(outp, " %%c1"); | 241 | outp += sprintf(outp, " %%c1"); |
227 | if (do_nhm_cstates) | 242 | if (do_nhm_cstates) |
@@ -238,8 +253,6 @@ void print_header(void) | |||
238 | outp += sprintf(outp, " %%pc6"); | 253 | outp += sprintf(outp, " %%pc6"); |
239 | if (do_snb_cstates) | 254 | if (do_snb_cstates) |
240 | outp += sprintf(outp, " %%pc7"); | 255 | outp += sprintf(outp, " %%pc7"); |
241 | if (extra_msr_offset) | ||
242 | outp += sprintf(outp, " MSR 0x%x ", extra_msr_offset); | ||
243 | 256 | ||
244 | outp += sprintf(outp, "\n"); | 257 | outp += sprintf(outp, "\n"); |
245 | } | 258 | } |
@@ -255,8 +268,14 @@ int dump_counters(struct thread_data *t, struct core_data *c, | |||
255 | fprintf(stderr, "aperf: %016llX\n", t->aperf); | 268 | fprintf(stderr, "aperf: %016llX\n", t->aperf); |
256 | fprintf(stderr, "mperf: %016llX\n", t->mperf); | 269 | fprintf(stderr, "mperf: %016llX\n", t->mperf); |
257 | fprintf(stderr, "c1: %016llX\n", t->c1); | 270 | fprintf(stderr, "c1: %016llX\n", t->c1); |
271 | fprintf(stderr, "msr0x%x: %08llX\n", | ||
272 | extra_delta_offset32, t->extra_delta32); | ||
258 | fprintf(stderr, "msr0x%x: %016llX\n", | 273 | fprintf(stderr, "msr0x%x: %016llX\n", |
259 | extra_msr_offset, t->extra_msr); | 274 | extra_delta_offset64, t->extra_delta64); |
275 | fprintf(stderr, "msr0x%x: %08llX\n", | ||
276 | extra_msr_offset32, t->extra_msr32); | ||
277 | fprintf(stderr, "msr0x%x: %016llX\n", | ||
278 | extra_msr_offset64, t->extra_msr64); | ||
260 | } | 279 | } |
261 | 280 | ||
262 | if (c) { | 281 | if (c) { |
@@ -360,6 +379,21 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
360 | /* TSC */ | 379 | /* TSC */ |
361 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); | 380 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); |
362 | 381 | ||
382 | /* delta */ | ||
383 | if (extra_delta_offset32) | ||
384 | outp += sprintf(outp, " %11llu", t->extra_delta32); | ||
385 | |||
386 | /* DELTA */ | ||
387 | if (extra_delta_offset64) | ||
388 | outp += sprintf(outp, " %11llu", t->extra_delta64); | ||
389 | /* msr */ | ||
390 | if (extra_msr_offset32) | ||
391 | outp += sprintf(outp, " 0x%08llx", t->extra_msr32); | ||
392 | |||
393 | /* MSR */ | ||
394 | if (extra_msr_offset64) | ||
395 | outp += sprintf(outp, " 0x%016llx", t->extra_msr64); | ||
396 | |||
363 | if (do_nhm_cstates) { | 397 | if (do_nhm_cstates) { |
364 | if (!skip_c1) | 398 | if (!skip_c1) |
365 | outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); | 399 | outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); |
@@ -391,8 +425,6 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
391 | if (do_snb_cstates) | 425 | if (do_snb_cstates) |
392 | outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); | 426 | outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); |
393 | done: | 427 | done: |
394 | if (extra_msr_offset) | ||
395 | outp += sprintf(outp, " 0x%016llx", t->extra_msr); | ||
396 | outp += sprintf(outp, "\n"); | 428 | outp += sprintf(outp, "\n"); |
397 | 429 | ||
398 | return 0; | 430 | return 0; |
@@ -502,10 +534,16 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
502 | old->mperf = 1; /* divide by 0 protection */ | 534 | old->mperf = 1; /* divide by 0 protection */ |
503 | } | 535 | } |
504 | 536 | ||
537 | old->extra_delta32 = new->extra_delta32 - old->extra_delta32; | ||
538 | old->extra_delta32 &= 0xFFFFFFFF; | ||
539 | |||
540 | old->extra_delta64 = new->extra_delta64 - old->extra_delta64; | ||
541 | |||
505 | /* | 542 | /* |
506 | * for "extra msr", just copy the latest w/o subtracting | 543 | * Extra MSR is just a snapshot, simply copy latest w/o subtracting |
507 | */ | 544 | */ |
508 | old->extra_msr = new->extra_msr; | 545 | old->extra_msr32 = new->extra_msr32; |
546 | old->extra_msr64 = new->extra_msr64; | ||
509 | } | 547 | } |
510 | 548 | ||
511 | int delta_cpu(struct thread_data *t, struct core_data *c, | 549 | int delta_cpu(struct thread_data *t, struct core_data *c, |
@@ -533,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data | |||
533 | t->mperf = 0; | 571 | t->mperf = 0; |
534 | t->c1 = 0; | 572 | t->c1 = 0; |
535 | 573 | ||
574 | t->extra_delta32 = 0; | ||
575 | t->extra_delta64 = 0; | ||
576 | |||
536 | /* tells format_counters to dump all fields from this set */ | 577 | /* tells format_counters to dump all fields from this set */ |
537 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; | 578 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; |
538 | 579 | ||
@@ -553,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c, | |||
553 | average.threads.mperf += t->mperf; | 594 | average.threads.mperf += t->mperf; |
554 | average.threads.c1 += t->c1; | 595 | average.threads.c1 += t->c1; |
555 | 596 | ||
597 | average.threads.extra_delta32 += t->extra_delta32; | ||
598 | average.threads.extra_delta64 += t->extra_delta64; | ||
599 | |||
556 | /* sum per-core values only for 1st thread in core */ | 600 | /* sum per-core values only for 1st thread in core */ |
557 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) | 601 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) |
558 | return 0; | 602 | return 0; |
@@ -588,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c, | |||
588 | average.threads.mperf /= topo.num_cpus; | 632 | average.threads.mperf /= topo.num_cpus; |
589 | average.threads.c1 /= topo.num_cpus; | 633 | average.threads.c1 /= topo.num_cpus; |
590 | 634 | ||
635 | average.threads.extra_delta32 /= topo.num_cpus; | ||
636 | average.threads.extra_delta32 &= 0xFFFFFFFF; | ||
637 | |||
638 | average.threads.extra_delta64 /= topo.num_cpus; | ||
639 | |||
591 | average.cores.c3 /= topo.num_cores; | 640 | average.cores.c3 /= topo.num_cores; |
592 | average.cores.c6 /= topo.num_cores; | 641 | average.cores.c6 /= topo.num_cores; |
593 | average.cores.c7 /= topo.num_cores; | 642 | average.cores.c7 /= topo.num_cores; |
@@ -629,8 +678,24 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |||
629 | return -4; | 678 | return -4; |
630 | } | 679 | } |
631 | 680 | ||
632 | if (extra_msr_offset) | 681 | if (extra_delta_offset32) { |
633 | if (get_msr(cpu, extra_msr_offset, &t->extra_msr)) | 682 | if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32)) |
683 | return -5; | ||
684 | t->extra_delta32 &= 0xFFFFFFFF; | ||
685 | } | ||
686 | |||
687 | if (extra_delta_offset64) | ||
688 | if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64)) | ||
689 | return -5; | ||
690 | |||
691 | if (extra_msr_offset32) { | ||
692 | if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32)) | ||
693 | return -5; | ||
694 | t->extra_msr32 &= 0xFFFFFFFF; | ||
695 | } | ||
696 | |||
697 | if (extra_msr_offset64) | ||
698 | if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) | ||
634 | return -5; | 699 | return -5; |
635 | 700 | ||
636 | /* collect core counters only for 1st thread in core */ | 701 | /* collect core counters only for 1st thread in core */ |
@@ -677,6 +742,9 @@ void print_verbose_header(void) | |||
677 | 742 | ||
678 | get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); | 743 | get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); |
679 | 744 | ||
745 | if (verbose > 1) | ||
746 | fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); | ||
747 | |||
680 | ratio = (msr >> 40) & 0xFF; | 748 | ratio = (msr >> 40) & 0xFF; |
681 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", | 749 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", |
682 | ratio, bclk, ratio * bclk); | 750 | ratio, bclk, ratio * bclk); |
@@ -685,14 +753,84 @@ void print_verbose_header(void) | |||
685 | fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", | 753 | fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", |
686 | ratio, bclk, ratio * bclk); | 754 | ratio, bclk, ratio * bclk); |
687 | 755 | ||
756 | if (!do_ivt_turbo_ratio_limit) | ||
757 | goto print_nhm_turbo_ratio_limits; | ||
758 | |||
759 | get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr); | ||
760 | |||
688 | if (verbose > 1) | 761 | if (verbose > 1) |
689 | fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); | 762 | fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr); |
763 | |||
764 | ratio = (msr >> 56) & 0xFF; | ||
765 | if (ratio) | ||
766 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n", | ||
767 | ratio, bclk, ratio * bclk); | ||
768 | |||
769 | ratio = (msr >> 48) & 0xFF; | ||
770 | if (ratio) | ||
771 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n", | ||
772 | ratio, bclk, ratio * bclk); | ||
773 | |||
774 | ratio = (msr >> 40) & 0xFF; | ||
775 | if (ratio) | ||
776 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n", | ||
777 | ratio, bclk, ratio * bclk); | ||
778 | |||
779 | ratio = (msr >> 32) & 0xFF; | ||
780 | if (ratio) | ||
781 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n", | ||
782 | ratio, bclk, ratio * bclk); | ||
783 | |||
784 | ratio = (msr >> 24) & 0xFF; | ||
785 | if (ratio) | ||
786 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n", | ||
787 | ratio, bclk, ratio * bclk); | ||
788 | |||
789 | ratio = (msr >> 16) & 0xFF; | ||
790 | if (ratio) | ||
791 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n", | ||
792 | ratio, bclk, ratio * bclk); | ||
793 | |||
794 | ratio = (msr >> 8) & 0xFF; | ||
795 | if (ratio) | ||
796 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n", | ||
797 | ratio, bclk, ratio * bclk); | ||
798 | |||
799 | ratio = (msr >> 0) & 0xFF; | ||
800 | if (ratio) | ||
801 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n", | ||
802 | ratio, bclk, ratio * bclk); | ||
803 | |||
804 | print_nhm_turbo_ratio_limits: | ||
690 | 805 | ||
691 | if (!do_nehalem_turbo_ratio_limit) | 806 | if (!do_nehalem_turbo_ratio_limit) |
692 | return; | 807 | return; |
693 | 808 | ||
694 | get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); | 809 | get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); |
695 | 810 | ||
811 | if (verbose > 1) | ||
812 | fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr); | ||
813 | |||
814 | ratio = (msr >> 56) & 0xFF; | ||
815 | if (ratio) | ||
816 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n", | ||
817 | ratio, bclk, ratio * bclk); | ||
818 | |||
819 | ratio = (msr >> 48) & 0xFF; | ||
820 | if (ratio) | ||
821 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n", | ||
822 | ratio, bclk, ratio * bclk); | ||
823 | |||
824 | ratio = (msr >> 40) & 0xFF; | ||
825 | if (ratio) | ||
826 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n", | ||
827 | ratio, bclk, ratio * bclk); | ||
828 | |||
829 | ratio = (msr >> 32) & 0xFF; | ||
830 | if (ratio) | ||
831 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n", | ||
832 | ratio, bclk, ratio * bclk); | ||
833 | |||
696 | ratio = (msr >> 24) & 0xFF; | 834 | ratio = (msr >> 24) & 0xFF; |
697 | if (ratio) | 835 | if (ratio) |
698 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", | 836 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", |
@@ -712,7 +850,6 @@ void print_verbose_header(void) | |||
712 | if (ratio) | 850 | if (ratio) |
713 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", | 851 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", |
714 | ratio, bclk, ratio * bclk); | 852 | ratio, bclk, ratio * bclk); |
715 | |||
716 | } | 853 | } |
717 | 854 | ||
718 | void free_all_buffers(void) | 855 | void free_all_buffers(void) |
@@ -1038,7 +1175,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1038 | case 0x2A: /* SNB */ | 1175 | case 0x2A: /* SNB */ |
1039 | case 0x2D: /* SNB Xeon */ | 1176 | case 0x2D: /* SNB Xeon */ |
1040 | case 0x3A: /* IVB */ | 1177 | case 0x3A: /* IVB */ |
1041 | case 0x3D: /* IVB Xeon */ | 1178 | case 0x3E: /* IVB Xeon */ |
1042 | return 1; | 1179 | return 1; |
1043 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ | 1180 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ |
1044 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ | 1181 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ |
@@ -1046,6 +1183,22 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1046 | return 0; | 1183 | return 0; |
1047 | } | 1184 | } |
1048 | } | 1185 | } |
1186 | int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) | ||
1187 | { | ||
1188 | if (!genuine_intel) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (family != 6) | ||
1192 | return 0; | ||
1193 | |||
1194 | switch (model) { | ||
1195 | case 0x3E: /* IVB Xeon */ | ||
1196 | return 1; | ||
1197 | default: | ||
1198 | return 0; | ||
1199 | } | ||
1200 | } | ||
1201 | |||
1049 | 1202 | ||
1050 | int is_snb(unsigned int family, unsigned int model) | 1203 | int is_snb(unsigned int family, unsigned int model) |
1051 | { | 1204 | { |
@@ -1056,7 +1209,7 @@ int is_snb(unsigned int family, unsigned int model) | |||
1056 | case 0x2A: | 1209 | case 0x2A: |
1057 | case 0x2D: | 1210 | case 0x2D: |
1058 | case 0x3A: /* IVB */ | 1211 | case 0x3A: /* IVB */ |
1059 | case 0x3D: /* IVB Xeon */ | 1212 | case 0x3E: /* IVB Xeon */ |
1060 | return 1; | 1213 | return 1; |
1061 | } | 1214 | } |
1062 | return 0; | 1215 | return 0; |
@@ -1145,12 +1298,13 @@ void check_cpuid() | |||
1145 | bclk = discover_bclk(family, model); | 1298 | bclk = discover_bclk(family, model); |
1146 | 1299 | ||
1147 | do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); | 1300 | do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); |
1301 | do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); | ||
1148 | } | 1302 | } |
1149 | 1303 | ||
1150 | 1304 | ||
1151 | void usage() | 1305 | void usage() |
1152 | { | 1306 | { |
1153 | fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n", | 1307 | fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", |
1154 | progname); | 1308 | progname); |
1155 | exit(1); | 1309 | exit(1); |
1156 | } | 1310 | } |
@@ -1440,15 +1594,15 @@ void cmdline(int argc, char **argv) | |||
1440 | 1594 | ||
1441 | progname = argv[0]; | 1595 | progname = argv[0]; |
1442 | 1596 | ||
1443 | while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) { | 1597 | while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) { |
1444 | switch (opt) { | 1598 | switch (opt) { |
1445 | case 'c': | 1599 | case 'p': |
1446 | show_core_only++; | 1600 | show_core_only++; |
1447 | break; | 1601 | break; |
1448 | case 'p': | 1602 | case 'P': |
1449 | show_pkg_only++; | 1603 | show_pkg_only++; |
1450 | break; | 1604 | break; |
1451 | case 's': | 1605 | case 'S': |
1452 | summary_only++; | 1606 | summary_only++; |
1453 | break; | 1607 | break; |
1454 | case 'v': | 1608 | case 'v': |
@@ -1457,10 +1611,20 @@ void cmdline(int argc, char **argv) | |||
1457 | case 'i': | 1611 | case 'i': |
1458 | interval_sec = atoi(optarg); | 1612 | interval_sec = atoi(optarg); |
1459 | break; | 1613 | break; |
1614 | case 'c': | ||
1615 | sscanf(optarg, "%x", &extra_delta_offset32); | ||
1616 | break; | ||
1617 | case 's': | ||
1618 | extra_delta_offset32 = 0x34; /* SMI counter */ | ||
1619 | break; | ||
1620 | case 'C': | ||
1621 | sscanf(optarg, "%x", &extra_delta_offset64); | ||
1622 | break; | ||
1623 | case 'm': | ||
1624 | sscanf(optarg, "%x", &extra_msr_offset32); | ||
1625 | break; | ||
1460 | case 'M': | 1626 | case 'M': |
1461 | sscanf(optarg, "%x", &extra_msr_offset); | 1627 | sscanf(optarg, "%x", &extra_msr_offset64); |
1462 | if (verbose > 1) | ||
1463 | fprintf(stderr, "MSR 0x%X\n", extra_msr_offset); | ||
1464 | break; | 1628 | break; |
1465 | default: | 1629 | default: |
1466 | usage(); | 1630 | usage(); |
@@ -1473,7 +1637,7 @@ int main(int argc, char **argv) | |||
1473 | cmdline(argc, argv); | 1637 | cmdline(argc, argv); |
1474 | 1638 | ||
1475 | if (verbose > 1) | 1639 | if (verbose > 1) |
1476 | fprintf(stderr, "turbostat v2.0 May 16, 2012" | 1640 | fprintf(stderr, "turbostat v2.1 October 6, 2012" |
1477 | " - Len Brown <lenb@kernel.org>\n"); | 1641 | " - Len Brown <lenb@kernel.org>\n"); |
1478 | 1642 | ||
1479 | turbostat_init(); | 1643 | turbostat_init(); |
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf index 323a552ce64..63a1a83f4f0 100644 --- a/tools/testing/ktest/examples/include/defaults.conf +++ b/tools/testing/ktest/examples/include/defaults.conf | |||
@@ -33,7 +33,7 @@ DEFAULTS | |||
33 | THIS_DIR := ${PWD} | 33 | THIS_DIR := ${PWD} |
34 | 34 | ||
35 | 35 | ||
36 | # to orginize your configs, having each machine save their configs | 36 | # to organize your configs, having each machine save their configs |
37 | # into a separate directly is useful. | 37 | # into a separate directly is useful. |
38 | CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE} | 38 | CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE} |
39 | 39 | ||
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf index 4fdb811bd81..60cedb1a115 100644 --- a/tools/testing/ktest/examples/include/tests.conf +++ b/tools/testing/ktest/examples/include/tests.conf | |||
@@ -47,7 +47,7 @@ BUILD_NOCLEAN = 1 | |||
47 | # Build, install, boot and test with a randconfg 10 times. | 47 | # Build, install, boot and test with a randconfg 10 times. |
48 | # It is important that you have set MIN_CONFIG in the config | 48 | # It is important that you have set MIN_CONFIG in the config |
49 | # that includes this file otherwise it is likely that the | 49 | # that includes this file otherwise it is likely that the |
50 | # randconfig will not have the neccessary configs needed to | 50 | # randconfig will not have the necessary configs needed to |
51 | # boot your box. This version of the test requires a min | 51 | # boot your box. This version of the test requires a min |
52 | # config that has enough to make sure the target has network | 52 | # config that has enough to make sure the target has network |
53 | # working. | 53 | # working. |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 52b7959cd51..b51d787176d 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -840,7 +840,9 @@ sub __read_config { | |||
840 | 840 | ||
841 | if ($rest =~ /\sIF\s+(.*)/) { | 841 | if ($rest =~ /\sIF\s+(.*)/) { |
842 | # May be a ELSE IF section. | 842 | # May be a ELSE IF section. |
843 | if (!process_if($name, $1)) { | 843 | if (process_if($name, $1)) { |
844 | $if_set = 1; | ||
845 | } else { | ||
844 | $skip = 1; | 846 | $skip = 1; |
845 | } | 847 | } |
846 | $rest = ""; | 848 | $rest = ""; |
@@ -1871,10 +1873,10 @@ sub make_oldconfig { | |||
1871 | apply_min_config; | 1873 | apply_min_config; |
1872 | } | 1874 | } |
1873 | 1875 | ||
1874 | if (!run_command "$make oldnoconfig") { | 1876 | if (!run_command "$make olddefconfig") { |
1875 | # Perhaps oldnoconfig doesn't exist in this version of the kernel | 1877 | # Perhaps olddefconfig doesn't exist in this version of the kernel |
1876 | # try a yes '' | oldconfig | 1878 | # try a yes '' | oldconfig |
1877 | doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; | 1879 | doprint "olddefconfig failed, trying yes '' | make oldconfig\n"; |
1878 | run_command "yes '' | $make oldconfig" or | 1880 | run_command "yes '' | $make oldconfig" or |
1879 | dodie "failed make config oldconfig"; | 1881 | dodie "failed make config oldconfig"; |
1880 | } | 1882 | } |
@@ -1927,7 +1929,7 @@ sub build { | |||
1927 | 1929 | ||
1928 | # old config can ask questions | 1930 | # old config can ask questions |
1929 | if ($type eq "oldconfig") { | 1931 | if ($type eq "oldconfig") { |
1930 | $type = "oldnoconfig"; | 1932 | $type = "olddefconfig"; |
1931 | 1933 | ||
1932 | # allow for empty configs | 1934 | # allow for empty configs |
1933 | run_command "touch $output_config"; | 1935 | run_command "touch $output_config"; |
@@ -1957,7 +1959,7 @@ sub build { | |||
1957 | load_force_config($minconfig); | 1959 | load_force_config($minconfig); |
1958 | } | 1960 | } |
1959 | 1961 | ||
1960 | if ($type ne "oldnoconfig") { | 1962 | if ($type ne "olddefconfig") { |
1961 | run_command "$make $type" or | 1963 | run_command "$make $type" or |
1962 | dodie "failed make config"; | 1964 | dodie "failed make config"; |
1963 | } | 1965 | } |
@@ -2456,8 +2458,7 @@ my %config_set; | |||
2456 | 2458 | ||
2457 | # config_off holds the set of configs that the bad config had disabled. | 2459 | # config_off holds the set of configs that the bad config had disabled. |
2458 | # We need to record them and set them in the .config when running | 2460 | # We need to record them and set them in the .config when running |
2459 | # oldnoconfig, because oldnoconfig does not turn off new symbols, but | 2461 | # olddefconfig, because olddefconfig keeps the defaults. |
2460 | # instead just keeps the defaults. | ||
2461 | my %config_off; | 2462 | my %config_off; |
2462 | 2463 | ||
2463 | # config_off_tmp holds a set of configs to turn off for now | 2464 | # config_off_tmp holds a set of configs to turn off for now |
@@ -3248,7 +3249,7 @@ sub test_this_config { | |||
3248 | } | 3249 | } |
3249 | 3250 | ||
3250 | # Remove this config from the list of configs | 3251 | # Remove this config from the list of configs |
3251 | # do a make oldnoconfig and then read the resulting | 3252 | # do a make olddefconfig and then read the resulting |
3252 | # .config to make sure it is missing the config that | 3253 | # .config to make sure it is missing the config that |
3253 | # we had before | 3254 | # we had before |
3254 | my %configs = %min_configs; | 3255 | my %configs = %min_configs; |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 85baf11e2ac..43480149119 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug | 1 | TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll |
2 | 2 | ||
3 | all: | 3 | all: |
4 | for TARGET in $(TARGETS); do \ | 4 | for TARGET in $(TARGETS); do \ |
diff --git a/tools/testing/selftests/epoll/Makefile b/tools/testing/selftests/epoll/Makefile new file mode 100644 index 00000000000..19806ed62f5 --- /dev/null +++ b/tools/testing/selftests/epoll/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for epoll selftests | ||
2 | |||
3 | all: test_epoll | ||
4 | %: %.c | ||
5 | gcc -pthread -g -o $@ $^ | ||
6 | |||
7 | run_tests: all | ||
8 | ./test_epoll | ||
9 | |||
10 | clean: | ||
11 | $(RM) test_epoll | ||
diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c new file mode 100644 index 00000000000..e0fcff1e833 --- /dev/null +++ b/tools/testing/selftests/epoll/test_epoll.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/epoll/test_epoll.c | ||
3 | * | ||
4 | * Copyright 2012 Adobe Systems Incorporated | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * Paton J. Lewis <palewis@adobe.com> | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <pthread.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <unistd.h> | ||
21 | #include <sys/epoll.h> | ||
22 | #include <sys/socket.h> | ||
23 | |||
24 | /* | ||
25 | * A pointer to an epoll_item_private structure will be stored in the epoll | ||
26 | * item's event structure so that we can get access to the epoll_item_private | ||
27 | * data after calling epoll_wait: | ||
28 | */ | ||
29 | struct epoll_item_private { | ||
30 | int index; /* Position of this struct within the epoll_items array. */ | ||
31 | int fd; | ||
32 | uint32_t events; | ||
33 | pthread_mutex_t mutex; /* Guards the following variables... */ | ||
34 | int stop; | ||
35 | int status; /* Stores any error encountered while handling item. */ | ||
36 | /* The following variable allows us to test whether we have encountered | ||
37 | a problem while attempting to cancel and delete the associated | ||
38 | event. When the test program exits, 'deleted' should be exactly | ||
39 | one. If it is greater than one, then the failed test reflects a real | ||
40 | world situation where we would have tried to access the epoll item's | ||
41 | private data after deleting it: */ | ||
42 | int deleted; | ||
43 | }; | ||
44 | |||
45 | struct epoll_item_private *epoll_items; | ||
46 | |||
47 | /* | ||
48 | * Delete the specified item from the epoll set. In a real-world secneario this | ||
49 | * is where we would free the associated data structure, but in this testing | ||
50 | * environment we retain the structure so that we can test for double-deletion: | ||
51 | */ | ||
52 | void delete_item(int index) | ||
53 | { | ||
54 | __sync_fetch_and_add(&epoll_items[index].deleted, 1); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * A pointer to a read_thread_data structure will be passed as the argument to | ||
59 | * each read thread: | ||
60 | */ | ||
61 | struct read_thread_data { | ||
62 | int stop; | ||
63 | int status; /* Indicates any error encountered by the read thread. */ | ||
64 | int epoll_set; | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * The function executed by the read threads: | ||
69 | */ | ||
70 | void *read_thread_function(void *function_data) | ||
71 | { | ||
72 | struct read_thread_data *thread_data = | ||
73 | (struct read_thread_data *)function_data; | ||
74 | struct epoll_event event_data; | ||
75 | struct epoll_item_private *item_data; | ||
76 | char socket_data; | ||
77 | |||
78 | /* Handle events until we encounter an error or this thread's 'stop' | ||
79 | condition is set: */ | ||
80 | while (1) { | ||
81 | int result = epoll_wait(thread_data->epoll_set, | ||
82 | &event_data, | ||
83 | 1, /* Number of desired events */ | ||
84 | 1000); /* Timeout in ms */ | ||
85 | if (result < 0) { | ||
86 | /* Breakpoints signal all threads. Ignore that while | ||
87 | debugging: */ | ||
88 | if (errno == EINTR) | ||
89 | continue; | ||
90 | thread_data->status = errno; | ||
91 | return 0; | ||
92 | } else if (thread_data->stop) | ||
93 | return 0; | ||
94 | else if (result == 0) /* Timeout */ | ||
95 | continue; | ||
96 | |||
97 | /* We need the mutex here because checking for the stop | ||
98 | condition and re-enabling the epoll item need to be done | ||
99 | together as one atomic operation when EPOLL_CTL_DISABLE is | ||
100 | available: */ | ||
101 | item_data = (struct epoll_item_private *)event_data.data.ptr; | ||
102 | pthread_mutex_lock(&item_data->mutex); | ||
103 | |||
104 | /* Remove the item from the epoll set if we want to stop | ||
105 | handling that event: */ | ||
106 | if (item_data->stop) | ||
107 | delete_item(item_data->index); | ||
108 | else { | ||
109 | /* Clear the data that was written to the other end of | ||
110 | our non-blocking socket: */ | ||
111 | do { | ||
112 | if (read(item_data->fd, &socket_data, 1) < 1) { | ||
113 | if ((errno == EAGAIN) || | ||
114 | (errno == EWOULDBLOCK)) | ||
115 | break; | ||
116 | else | ||
117 | goto error_unlock; | ||
118 | } | ||
119 | } while (item_data->events & EPOLLET); | ||
120 | |||
121 | /* The item was one-shot, so re-enable it: */ | ||
122 | event_data.events = item_data->events; | ||
123 | if (epoll_ctl(thread_data->epoll_set, | ||
124 | EPOLL_CTL_MOD, | ||
125 | item_data->fd, | ||
126 | &event_data) < 0) | ||
127 | goto error_unlock; | ||
128 | } | ||
129 | |||
130 | pthread_mutex_unlock(&item_data->mutex); | ||
131 | } | ||
132 | |||
133 | error_unlock: | ||
134 | thread_data->status = item_data->status = errno; | ||
135 | pthread_mutex_unlock(&item_data->mutex); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * A pointer to a write_thread_data structure will be passed as the argument to | ||
141 | * the write thread: | ||
142 | */ | ||
143 | struct write_thread_data { | ||
144 | int stop; | ||
145 | int status; /* Indicates any error encountered by the write thread. */ | ||
146 | int n_fds; | ||
147 | int *fds; | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * The function executed by the write thread. It writes a single byte to each | ||
152 | * socket in turn until the stop condition for this thread is set. If writing to | ||
153 | * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for | ||
154 | * the moment and just move on to the next socket in the list. We don't care | ||
155 | * about the order in which we deliver events to the epoll set. In fact we don't | ||
156 | * care about the data we're writing to the pipes at all; we just want to | ||
157 | * trigger epoll events: | ||
158 | */ | ||
159 | void *write_thread_function(void *function_data) | ||
160 | { | ||
161 | const char data = 'X'; | ||
162 | int index; | ||
163 | struct write_thread_data *thread_data = | ||
164 | (struct write_thread_data *)function_data; | ||
165 | while (!write_thread_data->stop) | ||
166 | for (index = 0; | ||
167 | !thread_data->stop && (index < thread_data->n_fds); | ||
168 | ++index) | ||
169 | if ((write(thread_data->fds[index], &data, 1) < 1) && | ||
170 | (errno != EAGAIN) && | ||
171 | (errno != EWOULDBLOCK)) { | ||
172 | write_thread_data->status = errno; | ||
173 | return; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Arguments are currently ignored: | ||
179 | */ | ||
180 | int main(int argc, char **argv) | ||
181 | { | ||
182 | const int n_read_threads = 100; | ||
183 | const int n_epoll_items = 500; | ||
184 | int index; | ||
185 | int epoll_set = epoll_create1(0); | ||
186 | struct write_thread_data write_thread_data = { | ||
187 | 0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int)) | ||
188 | }; | ||
189 | struct read_thread_data *read_thread_data = | ||
190 | malloc(n_read_threads * sizeof(struct read_thread_data)); | ||
191 | pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t)); | ||
192 | pthread_t write_thread; | ||
193 | |||
194 | printf("-----------------\n"); | ||
195 | printf("Runing test_epoll\n"); | ||
196 | printf("-----------------\n"); | ||
197 | |||
198 | epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private)); | ||
199 | |||
200 | if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 || | ||
201 | read_thread_data == 0 || read_threads == 0) | ||
202 | goto error; | ||
203 | |||
204 | if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { | ||
205 | printf("Error: please run this test on a multi-core system.\n"); | ||
206 | goto error; | ||
207 | } | ||
208 | |||
209 | /* Create the socket pairs and epoll items: */ | ||
210 | for (index = 0; index < n_epoll_items; ++index) { | ||
211 | int socket_pair[2]; | ||
212 | struct epoll_event event_data; | ||
213 | if (socketpair(AF_UNIX, | ||
214 | SOCK_STREAM | SOCK_NONBLOCK, | ||
215 | 0, | ||
216 | socket_pair) < 0) | ||
217 | goto error; | ||
218 | write_thread_data.fds[index] = socket_pair[0]; | ||
219 | epoll_items[index].index = index; | ||
220 | epoll_items[index].fd = socket_pair[1]; | ||
221 | if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0) | ||
222 | goto error; | ||
223 | /* We always use EPOLLONESHOT because this test is currently | ||
224 | structured to demonstrate the need for EPOLL_CTL_DISABLE, | ||
225 | which only produces useful information in the EPOLLONESHOT | ||
226 | case (without EPOLLONESHOT, calling epoll_ctl with | ||
227 | EPOLL_CTL_DISABLE will never return EBUSY). If support for | ||
228 | testing events without EPOLLONESHOT is desired, it should | ||
229 | probably be implemented in a separate unit test. */ | ||
230 | epoll_items[index].events = EPOLLIN | EPOLLONESHOT; | ||
231 | if (index < n_epoll_items / 2) | ||
232 | epoll_items[index].events |= EPOLLET; | ||
233 | epoll_items[index].stop = 0; | ||
234 | epoll_items[index].status = 0; | ||
235 | epoll_items[index].deleted = 0; | ||
236 | event_data.events = epoll_items[index].events; | ||
237 | event_data.data.ptr = &epoll_items[index]; | ||
238 | if (epoll_ctl(epoll_set, | ||
239 | EPOLL_CTL_ADD, | ||
240 | epoll_items[index].fd, | ||
241 | &event_data) < 0) | ||
242 | goto error; | ||
243 | } | ||
244 | |||
245 | /* Create and start the read threads: */ | ||
246 | for (index = 0; index < n_read_threads; ++index) { | ||
247 | read_thread_data[index].stop = 0; | ||
248 | read_thread_data[index].status = 0; | ||
249 | read_thread_data[index].epoll_set = epoll_set; | ||
250 | if (pthread_create(&read_threads[index], | ||
251 | NULL, | ||
252 | read_thread_function, | ||
253 | &read_thread_data[index]) != 0) | ||
254 | goto error; | ||
255 | } | ||
256 | |||
257 | if (pthread_create(&write_thread, | ||
258 | NULL, | ||
259 | write_thread_function, | ||
260 | &write_thread_data) != 0) | ||
261 | goto error; | ||
262 | |||
263 | /* Cancel all event pollers: */ | ||
264 | #ifdef EPOLL_CTL_DISABLE | ||
265 | for (index = 0; index < n_epoll_items; ++index) { | ||
266 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
267 | ++epoll_items[index].stop; | ||
268 | if (epoll_ctl(epoll_set, | ||
269 | EPOLL_CTL_DISABLE, | ||
270 | epoll_items[index].fd, | ||
271 | NULL) == 0) | ||
272 | delete_item(index); | ||
273 | else if (errno != EBUSY) { | ||
274 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
275 | goto error; | ||
276 | } | ||
277 | /* EBUSY means events were being handled; allow the other thread | ||
278 | to delete the item. */ | ||
279 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
280 | } | ||
281 | #else | ||
282 | for (index = 0; index < n_epoll_items; ++index) { | ||
283 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
284 | ++epoll_items[index].stop; | ||
285 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
286 | /* Wait in case a thread running read_thread_function is | ||
287 | currently executing code between epoll_wait and | ||
288 | pthread_mutex_lock with this item. Note that a longer delay | ||
289 | would make double-deletion less likely (at the expense of | ||
290 | performance), but there is no guarantee that any delay would | ||
291 | ever be sufficient. Note also that we delete all event | ||
292 | pollers at once for testing purposes, but in a real-world | ||
293 | environment we are likely to want to be able to cancel event | ||
294 | pollers at arbitrary times. Therefore we can't improve this | ||
295 | situation by just splitting this loop into two loops | ||
296 | (i.e. signal 'stop' for all items, sleep, and then delete all | ||
297 | items). We also can't fix the problem via EPOLL_CTL_DEL | ||
298 | because that command can't prevent the case where some other | ||
299 | thread is executing read_thread_function within the region | ||
300 | mentioned above: */ | ||
301 | usleep(1); | ||
302 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
303 | if (!epoll_items[index].deleted) | ||
304 | delete_item(index); | ||
305 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
306 | } | ||
307 | #endif | ||
308 | |||
309 | /* Shut down the read threads: */ | ||
310 | for (index = 0; index < n_read_threads; ++index) | ||
311 | __sync_fetch_and_add(&read_thread_data[index].stop, 1); | ||
312 | for (index = 0; index < n_read_threads; ++index) { | ||
313 | if (pthread_join(read_threads[index], NULL) != 0) | ||
314 | goto error; | ||
315 | if (read_thread_data[index].status) | ||
316 | goto error; | ||
317 | } | ||
318 | |||
319 | /* Shut down the write thread: */ | ||
320 | __sync_fetch_and_add(&write_thread_data.stop, 1); | ||
321 | if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status) | ||
322 | goto error; | ||
323 | |||
324 | /* Check for final error conditions: */ | ||
325 | for (index = 0; index < n_epoll_items; ++index) { | ||
326 | if (epoll_items[index].status != 0) | ||
327 | goto error; | ||
328 | if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0) | ||
329 | goto error; | ||
330 | } | ||
331 | for (index = 0; index < n_epoll_items; ++index) | ||
332 | if (epoll_items[index].deleted != 1) { | ||
333 | printf("Error: item data deleted %1d times.\n", | ||
334 | epoll_items[index].deleted); | ||
335 | goto error; | ||
336 | } | ||
337 | |||
338 | printf("[PASS]\n"); | ||
339 | return 0; | ||
340 | |||
341 | error: | ||
342 | printf("[FAIL]\n"); | ||
343 | return errno; | ||
344 | } | ||
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 8b40bd5e5cc..4c53cae6c27 100644 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests | |||
@@ -36,7 +36,7 @@ mkdir $mnt | |||
36 | mount -t hugetlbfs none $mnt | 36 | mount -t hugetlbfs none $mnt |
37 | 37 | ||
38 | echo "--------------------" | 38 | echo "--------------------" |
39 | echo "runing hugepage-mmap" | 39 | echo "running hugepage-mmap" |
40 | echo "--------------------" | 40 | echo "--------------------" |
41 | ./hugepage-mmap | 41 | ./hugepage-mmap |
42 | if [ $? -ne 0 ]; then | 42 | if [ $? -ne 0 ]; then |
@@ -50,7 +50,7 @@ shmall=`cat /proc/sys/kernel/shmall` | |||
50 | echo 268435456 > /proc/sys/kernel/shmmax | 50 | echo 268435456 > /proc/sys/kernel/shmmax |
51 | echo 4194304 > /proc/sys/kernel/shmall | 51 | echo 4194304 > /proc/sys/kernel/shmall |
52 | echo "--------------------" | 52 | echo "--------------------" |
53 | echo "runing hugepage-shm" | 53 | echo "running hugepage-shm" |
54 | echo "--------------------" | 54 | echo "--------------------" |
55 | ./hugepage-shm | 55 | ./hugepage-shm |
56 | if [ $? -ne 0 ]; then | 56 | if [ $? -ne 0 ]; then |
@@ -62,7 +62,7 @@ echo $shmmax > /proc/sys/kernel/shmmax | |||
62 | echo $shmall > /proc/sys/kernel/shmall | 62 | echo $shmall > /proc/sys/kernel/shmall |
63 | 63 | ||
64 | echo "--------------------" | 64 | echo "--------------------" |
65 | echo "runing map_hugetlb" | 65 | echo "running map_hugetlb" |
66 | echo "--------------------" | 66 | echo "--------------------" |
67 | ./map_hugetlb | 67 | ./map_hugetlb |
68 | if [ $? -ne 0 ]; then | 68 | if [ $? -ne 0 ]; then |
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index b0adb2710c0..68d0734b208 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c | |||
@@ -253,9 +253,6 @@ static int find_testdev(const char *name, const struct stat *sb, int flag) | |||
253 | 253 | ||
254 | if (flag != FTW_F) | 254 | if (flag != FTW_F) |
255 | return 0; | 255 | return 0; |
256 | /* ignore /proc/bus/usb/{devices,drivers} */ | ||
257 | if (strrchr(name, '/')[1] == 'd') | ||
258 | return 0; | ||
259 | 256 | ||
260 | fd = fopen(name, "rb"); | 257 | fd = fopen(name, "rb"); |
261 | if (!fd) { | 258 | if (!fd) { |
@@ -356,28 +353,8 @@ restart: | |||
356 | 353 | ||
357 | static const char *usbfs_dir_find(void) | 354 | static const char *usbfs_dir_find(void) |
358 | { | 355 | { |
359 | static char usbfs_path_0[] = "/dev/usb/devices"; | ||
360 | static char usbfs_path_1[] = "/proc/bus/usb/devices"; | ||
361 | static char udev_usb_path[] = "/dev/bus/usb"; | 356 | static char udev_usb_path[] = "/dev/bus/usb"; |
362 | 357 | ||
363 | static char *const usbfs_paths[] = { | ||
364 | usbfs_path_0, usbfs_path_1 | ||
365 | }; | ||
366 | |||
367 | static char *const * | ||
368 | end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths; | ||
369 | |||
370 | char *const *it = usbfs_paths; | ||
371 | do { | ||
372 | int fd = open(*it, O_RDONLY); | ||
373 | close(fd); | ||
374 | if (fd >= 0) { | ||
375 | strrchr(*it, '/')[0] = '\0'; | ||
376 | return *it; | ||
377 | } | ||
378 | } while (++it != end); | ||
379 | |||
380 | /* real device-nodes managed by udev */ | ||
381 | if (access(udev_usb_path, F_OK) == 0) | 358 | if (access(udev_usb_path, F_OK) == 0) |
382 | return udev_usb_path; | 359 | return udev_usb_path; |
383 | 360 | ||
@@ -489,7 +466,7 @@ usage: | |||
489 | goto usage; | 466 | goto usage; |
490 | if (!all && !device) { | 467 | if (!all && !device) { |
491 | fprintf (stderr, "must specify '-a' or '-D dev', " | 468 | fprintf (stderr, "must specify '-a' or '-D dev', " |
492 | "or DEVICE=/proc/bus/usb/BBB/DDD in env\n"); | 469 | "or DEVICE=/dev/bus/usb/BBB/DDD in env\n"); |
493 | goto usage; | 470 | goto usage; |
494 | } | 471 | } |
495 | 472 | ||
diff --git a/tools/virtio/virtio-trace/Makefile b/tools/virtio/virtio-trace/Makefile new file mode 100644 index 00000000000..0d238163347 --- /dev/null +++ b/tools/virtio/virtio-trace/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | CC = gcc | ||
2 | CFLAGS = -O2 -Wall -pthread | ||
3 | |||
4 | all: trace-agent | ||
5 | |||
6 | .c.o: | ||
7 | $(CC) $(CFLAGS) -c $^ -o $@ | ||
8 | |||
9 | trace-agent: trace-agent.o trace-agent-ctl.o trace-agent-rw.o | ||
10 | $(CC) $(CFLAGS) -o $@ $^ | ||
11 | |||
12 | clean: | ||
13 | rm -f *.o trace-agent | ||
diff --git a/tools/virtio/virtio-trace/README b/tools/virtio/virtio-trace/README new file mode 100644 index 00000000000..b64845b823a --- /dev/null +++ b/tools/virtio/virtio-trace/README | |||
@@ -0,0 +1,118 @@ | |||
1 | Trace Agent for virtio-trace | ||
2 | ============================ | ||
3 | |||
4 | Trace agent is a user tool for sending trace data of a guest to a Host in low | ||
5 | overhead. Trace agent has the following functions: | ||
6 | - splice a page of ring-buffer to read_pipe without memory copying | ||
7 | - splice the page from write_pipe to virtio-console without memory copying | ||
8 | - write trace data to stdout by using -o option | ||
9 | - controlled by start/stop orders from a Host | ||
10 | |||
11 | The trace agent operates as follows: | ||
12 | 1) Initialize all structures. | ||
13 | 2) Create a read/write thread per CPU. Each thread is bound to a CPU. | ||
14 | The read/write threads hold it. | ||
15 | 3) A controller thread does poll() for a start order of a host. | ||
16 | 4) After the controller of the trace agent receives a start order from a host, | ||
17 | the controller wake read/write threads. | ||
18 | 5) The read/write threads start to read trace data from ring-buffers and | ||
19 | write the data to virtio-serial. | ||
20 | 6) If the controller receives a stop order from a host, the read/write threads | ||
21 | stop to read trace data. | ||
22 | |||
23 | |||
24 | Files | ||
25 | ===== | ||
26 | |||
27 | README: this file | ||
28 | Makefile: Makefile of trace agent for virtio-trace | ||
29 | trace-agent.c: includes main function, sets up for operating trace agent | ||
30 | trace-agent.h: includes all structures and some macros | ||
31 | trace-agent-ctl.c: includes controller function for read/write threads | ||
32 | trace-agent-rw.c: includes read/write threads function | ||
33 | |||
34 | |||
35 | Setup | ||
36 | ===== | ||
37 | |||
38 | To use this trace agent for virtio-trace, we need to prepare some virtio-serial | ||
39 | I/Fs. | ||
40 | |||
41 | 1) Make FIFO in a host | ||
42 | virtio-trace uses virtio-serial pipe as trace data paths as to the number | ||
43 | of CPUs and a control path, so FIFO (named pipe) should be created as follows: | ||
44 | # mkdir /tmp/virtio-trace/ | ||
45 | # mkfifo /tmp/virtio-trace/trace-path-cpu{0,1,2,...,X}.{in,out} | ||
46 | # mkfifo /tmp/virtio-trace/agent-ctl-path.{in,out} | ||
47 | |||
48 | For example, if a guest use three CPUs, the names are | ||
49 | trace-path-cpu{0,1,2}.{in.out} | ||
50 | and | ||
51 | agent-ctl-path.{in,out}. | ||
52 | |||
53 | 2) Set up of virtio-serial pipe in a host | ||
54 | Add qemu option to use virtio-serial pipe. | ||
55 | |||
56 | ##virtio-serial device## | ||
57 | -device virtio-serial-pci,id=virtio-serial0\ | ||
58 | ##control path## | ||
59 | -chardev pipe,id=charchannel0,path=/tmp/virtio-trace/agent-ctl-path\ | ||
60 | -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,\ | ||
61 | id=channel0,name=agent-ctl-path\ | ||
62 | ##data path## | ||
63 | -chardev pipe,id=charchannel1,path=/tmp/virtio-trace/trace-path-cpu0\ | ||
64 | -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel0,\ | ||
65 | id=channel1,name=trace-path-cpu0\ | ||
66 | ... | ||
67 | |||
68 | If you manage guests with libvirt, add the following tags to domain XML files. | ||
69 | Then, libvirt passes the same command option to qemu. | ||
70 | |||
71 | <channel type='pipe'> | ||
72 | <source path='/tmp/virtio-trace/agent-ctl-path'/> | ||
73 | <target type='virtio' name='agent-ctl-path'/> | ||
74 | <address type='virtio-serial' controller='0' bus='0' port='0'/> | ||
75 | </channel> | ||
76 | <channel type='pipe'> | ||
77 | <source path='/tmp/virtio-trace/trace-path-cpu0'/> | ||
78 | <target type='virtio' name='trace-path-cpu0'/> | ||
79 | <address type='virtio-serial' controller='0' bus='0' port='1'/> | ||
80 | </channel> | ||
81 | ... | ||
82 | Here, chardev names are restricted to trace-path-cpuX and agent-ctl-path. For | ||
83 | example, if a guest use three CPUs, chardev names should be trace-path-cpu0, | ||
84 | trace-path-cpu1, trace-path-cpu2, and agent-ctl-path. | ||
85 | |||
86 | 3) Boot the guest | ||
87 | You can find some chardev in /dev/virtio-ports/ in the guest. | ||
88 | |||
89 | |||
90 | Run | ||
91 | === | ||
92 | |||
93 | 0) Build trace agent in a guest | ||
94 | $ make | ||
95 | |||
96 | 1) Enable ftrace in the guest | ||
97 | <Example> | ||
98 | # echo 1 > /sys/kernel/debug/tracing/events/sched/enable | ||
99 | |||
100 | 2) Run trace agent in the guest | ||
101 | This agent must be operated as root. | ||
102 | # ./trace-agent | ||
103 | read/write threads in the agent wait for start order from host. If you add -o | ||
104 | option, trace data are output via stdout in the guest. | ||
105 | |||
106 | 3) Open FIFO in a host | ||
107 | # cat /tmp/virtio-trace/trace-path-cpu0.out | ||
108 | If a host does not open these, trace data get stuck in buffers of virtio. Then, | ||
109 | the guest will stop by specification of chardev in QEMU. This blocking mode may | ||
110 | be solved in the future. | ||
111 | |||
112 | 4) Start to read trace data by ordering from a host | ||
113 | A host injects read start order to the guest via virtio-serial. | ||
114 | # echo 1 > /tmp/virtio-trace/agent-ctl-path.in | ||
115 | |||
116 | 5) Stop to read trace data by ordering from a host | ||
117 | A host injects read stop order to the guest via virtio-serial. | ||
118 | # echo 0 > /tmp/virtio-trace/agent-ctl-path.in | ||
diff --git a/tools/virtio/virtio-trace/trace-agent-ctl.c b/tools/virtio/virtio-trace/trace-agent-ctl.c new file mode 100644 index 00000000000..a2d0403c4f9 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent-ctl.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Controller of read/write threads for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <fcntl.h> | ||
14 | #include <poll.h> | ||
15 | #include <signal.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <unistd.h> | ||
19 | #include "trace-agent.h" | ||
20 | |||
21 | #define HOST_MSG_SIZE 256 | ||
22 | #define EVENT_WAIT_MSEC 100 | ||
23 | |||
24 | static volatile sig_atomic_t global_signal_val; | ||
25 | bool global_sig_receive; /* default false */ | ||
26 | bool global_run_operation; /* default false*/ | ||
27 | |||
28 | /* Handle SIGTERM/SIGINT/SIGQUIT to exit */ | ||
29 | static void signal_handler(int sig) | ||
30 | { | ||
31 | global_signal_val = sig; | ||
32 | } | ||
33 | |||
34 | int rw_ctl_init(const char *ctl_path) | ||
35 | { | ||
36 | int ctl_fd; | ||
37 | |||
38 | ctl_fd = open(ctl_path, O_RDONLY); | ||
39 | if (ctl_fd == -1) { | ||
40 | pr_err("Cannot open ctl_fd\n"); | ||
41 | goto error; | ||
42 | } | ||
43 | |||
44 | return ctl_fd; | ||
45 | |||
46 | error: | ||
47 | exit(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | static int wait_order(int ctl_fd) | ||
51 | { | ||
52 | struct pollfd poll_fd; | ||
53 | int ret = 0; | ||
54 | |||
55 | while (!global_sig_receive) { | ||
56 | poll_fd.fd = ctl_fd; | ||
57 | poll_fd.events = POLLIN; | ||
58 | |||
59 | ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC); | ||
60 | |||
61 | if (global_signal_val) { | ||
62 | global_sig_receive = true; | ||
63 | pr_info("Receive interrupt %d\n", global_signal_val); | ||
64 | |||
65 | /* Wakes rw-threads when they are sleeping */ | ||
66 | if (!global_run_operation) | ||
67 | pthread_cond_broadcast(&cond_wakeup); | ||
68 | |||
69 | ret = -1; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | if (ret < 0) { | ||
74 | pr_err("Polling error\n"); | ||
75 | goto error; | ||
76 | } | ||
77 | |||
78 | if (ret) | ||
79 | break; | ||
80 | }; | ||
81 | |||
82 | return ret; | ||
83 | |||
84 | error: | ||
85 | exit(EXIT_FAILURE); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * contol read/write threads by handling global_run_operation | ||
90 | */ | ||
91 | void *rw_ctl_loop(int ctl_fd) | ||
92 | { | ||
93 | ssize_t rlen; | ||
94 | char buf[HOST_MSG_SIZE]; | ||
95 | int ret; | ||
96 | |||
97 | /* Setup signal handlers */ | ||
98 | signal(SIGTERM, signal_handler); | ||
99 | signal(SIGINT, signal_handler); | ||
100 | signal(SIGQUIT, signal_handler); | ||
101 | |||
102 | while (!global_sig_receive) { | ||
103 | |||
104 | ret = wait_order(ctl_fd); | ||
105 | if (ret < 0) | ||
106 | break; | ||
107 | |||
108 | rlen = read(ctl_fd, buf, sizeof(buf)); | ||
109 | if (rlen < 0) { | ||
110 | pr_err("read data error in ctl thread\n"); | ||
111 | goto error; | ||
112 | } | ||
113 | |||
114 | if (rlen == 2 && buf[0] == '1') { | ||
115 | /* | ||
116 | * If host writes '1' to a control path, | ||
117 | * this controller wakes all read/write threads. | ||
118 | */ | ||
119 | global_run_operation = true; | ||
120 | pthread_cond_broadcast(&cond_wakeup); | ||
121 | pr_debug("Wake up all read/write threads\n"); | ||
122 | } else if (rlen == 2 && buf[0] == '0') { | ||
123 | /* | ||
124 | * If host writes '0' to a control path, read/write | ||
125 | * threads will wait for notification from Host. | ||
126 | */ | ||
127 | global_run_operation = false; | ||
128 | pr_debug("Stop all read/write threads\n"); | ||
129 | } else | ||
130 | pr_info("Invalid host notification: %s\n", buf); | ||
131 | } | ||
132 | |||
133 | return NULL; | ||
134 | |||
135 | error: | ||
136 | exit(EXIT_FAILURE); | ||
137 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent-rw.c b/tools/virtio/virtio-trace/trace-agent-rw.c new file mode 100644 index 00000000000..3aace5ea484 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent-rw.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Read/write thread of a guest agent for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <fcntl.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | #include <sys/syscall.h> | ||
18 | #include "trace-agent.h" | ||
19 | |||
20 | #define READ_WAIT_USEC 100000 | ||
21 | |||
22 | void *rw_thread_info_new(void) | ||
23 | { | ||
24 | struct rw_thread_info *rw_ti; | ||
25 | |||
26 | rw_ti = zalloc(sizeof(struct rw_thread_info)); | ||
27 | if (rw_ti == NULL) { | ||
28 | pr_err("rw_thread_info zalloc error\n"); | ||
29 | exit(EXIT_FAILURE); | ||
30 | } | ||
31 | |||
32 | rw_ti->cpu_num = -1; | ||
33 | rw_ti->in_fd = -1; | ||
34 | rw_ti->out_fd = -1; | ||
35 | rw_ti->read_pipe = -1; | ||
36 | rw_ti->write_pipe = -1; | ||
37 | rw_ti->pipe_size = PIPE_INIT; | ||
38 | |||
39 | return rw_ti; | ||
40 | } | ||
41 | |||
42 | void *rw_thread_init(int cpu, const char *in_path, const char *out_path, | ||
43 | bool stdout_flag, unsigned long pipe_size, | ||
44 | struct rw_thread_info *rw_ti) | ||
45 | { | ||
46 | int data_pipe[2]; | ||
47 | |||
48 | rw_ti->cpu_num = cpu; | ||
49 | |||
50 | /* set read(input) fd */ | ||
51 | rw_ti->in_fd = open(in_path, O_RDONLY); | ||
52 | if (rw_ti->in_fd == -1) { | ||
53 | pr_err("Could not open in_fd (CPU:%d)\n", cpu); | ||
54 | goto error; | ||
55 | } | ||
56 | |||
57 | /* set write(output) fd */ | ||
58 | if (!stdout_flag) { | ||
59 | /* virtio-serial output mode */ | ||
60 | rw_ti->out_fd = open(out_path, O_WRONLY); | ||
61 | if (rw_ti->out_fd == -1) { | ||
62 | pr_err("Could not open out_fd (CPU:%d)\n", cpu); | ||
63 | goto error; | ||
64 | } | ||
65 | } else | ||
66 | /* stdout mode */ | ||
67 | rw_ti->out_fd = STDOUT_FILENO; | ||
68 | |||
69 | if (pipe2(data_pipe, O_NONBLOCK) < 0) { | ||
70 | pr_err("Could not create pipe in rw-thread(%d)\n", cpu); | ||
71 | goto error; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Size of pipe is 64kB in default based on fs/pipe.c. | ||
76 | * To read/write trace data speedy, pipe size is changed. | ||
77 | */ | ||
78 | if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) { | ||
79 | pr_err("Could not change pipe size in rw-thread(%d)\n", cpu); | ||
80 | goto error; | ||
81 | } | ||
82 | |||
83 | rw_ti->read_pipe = data_pipe[1]; | ||
84 | rw_ti->write_pipe = data_pipe[0]; | ||
85 | rw_ti->pipe_size = pipe_size; | ||
86 | |||
87 | return NULL; | ||
88 | |||
89 | error: | ||
90 | exit(EXIT_FAILURE); | ||
91 | } | ||
92 | |||
93 | /* Bind a thread to a cpu */ | ||
94 | static void bind_cpu(int cpu_num) | ||
95 | { | ||
96 | cpu_set_t mask; | ||
97 | |||
98 | CPU_ZERO(&mask); | ||
99 | CPU_SET(cpu_num, &mask); | ||
100 | |||
101 | /* bind my thread to cpu_num by assigning zero to the first argument */ | ||
102 | if (sched_setaffinity(0, sizeof(mask), &mask) == -1) | ||
103 | pr_err("Could not set CPU#%d affinity\n", (int)cpu_num); | ||
104 | } | ||
105 | |||
106 | static void *rw_thread_main(void *thread_info) | ||
107 | { | ||
108 | ssize_t rlen, wlen; | ||
109 | ssize_t ret; | ||
110 | struct rw_thread_info *ts = (struct rw_thread_info *)thread_info; | ||
111 | |||
112 | bind_cpu(ts->cpu_num); | ||
113 | |||
114 | while (1) { | ||
115 | /* Wait for a read order of trace data by Host OS */ | ||
116 | if (!global_run_operation) { | ||
117 | pthread_mutex_lock(&mutex_notify); | ||
118 | pthread_cond_wait(&cond_wakeup, &mutex_notify); | ||
119 | pthread_mutex_unlock(&mutex_notify); | ||
120 | } | ||
121 | |||
122 | if (global_sig_receive) | ||
123 | break; | ||
124 | |||
125 | /* | ||
126 | * Each thread read trace_pipe_raw of each cpu bounding the | ||
127 | * thread, so contention of multi-threads does not occur. | ||
128 | */ | ||
129 | rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL, | ||
130 | ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE); | ||
131 | |||
132 | if (rlen < 0) { | ||
133 | pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num); | ||
134 | goto error; | ||
135 | } else if (rlen == 0) { | ||
136 | /* | ||
137 | * If trace data do not exist or are unreadable not | ||
138 | * for exceeding the page size, splice_read returns | ||
139 | * NULL. Then, this waits for being filled the data in a | ||
140 | * ring-buffer. | ||
141 | */ | ||
142 | usleep(READ_WAIT_USEC); | ||
143 | pr_debug("Read retry(cpu:%d)\n", ts->cpu_num); | ||
144 | continue; | ||
145 | } | ||
146 | |||
147 | wlen = 0; | ||
148 | |||
149 | do { | ||
150 | ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL, | ||
151 | rlen - wlen, | ||
152 | SPLICE_F_MOVE | SPLICE_F_MORE); | ||
153 | |||
154 | if (ret < 0) { | ||
155 | pr_err("Splice_write in rw-thread(%d)\n", | ||
156 | ts->cpu_num); | ||
157 | goto error; | ||
158 | } else if (ret == 0) | ||
159 | /* | ||
160 | * When host reader is not in time for reading | ||
161 | * trace data, guest will be stopped. This is | ||
162 | * because char dev in QEMU is not supported | ||
163 | * non-blocking mode. Then, writer might be | ||
164 | * sleep in that case. | ||
165 | * This sleep will be removed by supporting | ||
166 | * non-blocking mode. | ||
167 | */ | ||
168 | sleep(1); | ||
169 | wlen += ret; | ||
170 | } while (wlen < rlen); | ||
171 | } | ||
172 | |||
173 | return NULL; | ||
174 | |||
175 | error: | ||
176 | exit(EXIT_FAILURE); | ||
177 | } | ||
178 | |||
179 | |||
180 | pthread_t rw_thread_run(struct rw_thread_info *rw_ti) | ||
181 | { | ||
182 | int ret; | ||
183 | pthread_t rw_thread_per_cpu; | ||
184 | |||
185 | ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti); | ||
186 | if (ret != 0) { | ||
187 | pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num); | ||
188 | exit(EXIT_FAILURE); | ||
189 | } | ||
190 | |||
191 | return rw_thread_per_cpu; | ||
192 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent.c b/tools/virtio/virtio-trace/trace-agent.c new file mode 100644 index 00000000000..0a0a7dd4eff --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * Guest agent for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <limits.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | #include "trace-agent.h" | ||
18 | |||
19 | #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE)) | ||
20 | #define PIPE_DEF_BUFS 16 | ||
21 | #define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS) | ||
22 | #define PIPE_MAX_SIZE (1024*1024) | ||
23 | #define READ_PATH_FMT \ | ||
24 | "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw" | ||
25 | #define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d" | ||
26 | #define CTL_PATH "/dev/virtio-ports/agent-ctl-path" | ||
27 | |||
28 | pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER; | ||
29 | pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER; | ||
30 | |||
31 | static int get_total_cpus(void) | ||
32 | { | ||
33 | int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF); | ||
34 | |||
35 | if (nr_cpus <= 0) { | ||
36 | pr_err("Could not read cpus\n"); | ||
37 | goto error; | ||
38 | } else if (nr_cpus > MAX_CPUS) { | ||
39 | pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS); | ||
40 | goto error; | ||
41 | } | ||
42 | |||
43 | return nr_cpus; | ||
44 | |||
45 | error: | ||
46 | exit(EXIT_FAILURE); | ||
47 | } | ||
48 | |||
49 | static void *agent_info_new(void) | ||
50 | { | ||
51 | struct agent_info *s; | ||
52 | int i; | ||
53 | |||
54 | s = zalloc(sizeof(struct agent_info)); | ||
55 | if (s == NULL) { | ||
56 | pr_err("agent_info zalloc error\n"); | ||
57 | exit(EXIT_FAILURE); | ||
58 | } | ||
59 | |||
60 | s->pipe_size = PIPE_INIT; | ||
61 | s->use_stdout = false; | ||
62 | s->cpus = get_total_cpus(); | ||
63 | s->ctl_fd = -1; | ||
64 | |||
65 | /* read/write threads init */ | ||
66 | for (i = 0; i < s->cpus; i++) | ||
67 | s->rw_ti[i] = rw_thread_info_new(); | ||
68 | |||
69 | return s; | ||
70 | } | ||
71 | |||
72 | static unsigned long parse_size(const char *arg) | ||
73 | { | ||
74 | unsigned long value, round; | ||
75 | char *ptr; | ||
76 | |||
77 | value = strtoul(arg, &ptr, 10); | ||
78 | switch (*ptr) { | ||
79 | case 'K': case 'k': | ||
80 | value <<= 10; | ||
81 | break; | ||
82 | case 'M': case 'm': | ||
83 | value <<= 20; | ||
84 | break; | ||
85 | default: | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | if (value > PIPE_MAX_SIZE) { | ||
90 | pr_err("Pipe size must be less than 1MB\n"); | ||
91 | goto error; | ||
92 | } else if (value < PIPE_MIN_SIZE) { | ||
93 | pr_err("Pipe size must be over 64KB\n"); | ||
94 | goto error; | ||
95 | } | ||
96 | |||
97 | /* Align buffer size with page unit */ | ||
98 | round = value & (PAGE_SIZE - 1); | ||
99 | value = value - round; | ||
100 | |||
101 | return value; | ||
102 | error: | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void usage(char const *prg) | ||
107 | { | ||
108 | pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg); | ||
109 | } | ||
110 | |||
111 | static const char *make_path(int cpu_num, bool this_is_write_path) | ||
112 | { | ||
113 | int ret; | ||
114 | char *buf; | ||
115 | |||
116 | buf = zalloc(PATH_MAX); | ||
117 | if (buf == NULL) { | ||
118 | pr_err("Could not allocate buffer\n"); | ||
119 | goto error; | ||
120 | } | ||
121 | |||
122 | if (this_is_write_path) | ||
123 | /* write(output) path */ | ||
124 | ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num); | ||
125 | else | ||
126 | /* read(input) path */ | ||
127 | ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num); | ||
128 | |||
129 | if (ret <= 0) { | ||
130 | pr_err("Failed to generate %s path(CPU#%d):%d\n", | ||
131 | this_is_write_path ? "read" : "write", cpu_num, ret); | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | return buf; | ||
136 | |||
137 | error: | ||
138 | free(buf); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | static const char *make_input_path(int cpu_num) | ||
143 | { | ||
144 | return make_path(cpu_num, false); | ||
145 | } | ||
146 | |||
147 | static const char *make_output_path(int cpu_num) | ||
148 | { | ||
149 | return make_path(cpu_num, true); | ||
150 | } | ||
151 | |||
152 | static void *agent_info_init(struct agent_info *s) | ||
153 | { | ||
154 | int cpu; | ||
155 | const char *in_path = NULL; | ||
156 | const char *out_path = NULL; | ||
157 | |||
158 | /* init read/write threads */ | ||
159 | for (cpu = 0; cpu < s->cpus; cpu++) { | ||
160 | /* set read(input) path per read/write thread */ | ||
161 | in_path = make_input_path(cpu); | ||
162 | if (in_path == NULL) | ||
163 | goto error; | ||
164 | |||
165 | /* set write(output) path per read/write thread*/ | ||
166 | if (!s->use_stdout) { | ||
167 | out_path = make_output_path(cpu); | ||
168 | if (out_path == NULL) | ||
169 | goto error; | ||
170 | } else | ||
171 | /* stdout mode */ | ||
172 | pr_debug("stdout mode\n"); | ||
173 | |||
174 | rw_thread_init(cpu, in_path, out_path, s->use_stdout, | ||
175 | s->pipe_size, s->rw_ti[cpu]); | ||
176 | } | ||
177 | |||
178 | /* init controller of read/write threads */ | ||
179 | s->ctl_fd = rw_ctl_init((const char *)CTL_PATH); | ||
180 | |||
181 | return NULL; | ||
182 | |||
183 | error: | ||
184 | exit(EXIT_FAILURE); | ||
185 | } | ||
186 | |||
187 | static void *parse_args(int argc, char *argv[], struct agent_info *s) | ||
188 | { | ||
189 | int cmd; | ||
190 | unsigned long size; | ||
191 | |||
192 | while ((cmd = getopt(argc, argv, "hos:")) != -1) { | ||
193 | switch (cmd) { | ||
194 | /* stdout mode */ | ||
195 | case 'o': | ||
196 | s->use_stdout = true; | ||
197 | break; | ||
198 | /* size of pipe */ | ||
199 | case 's': | ||
200 | size = parse_size(optarg); | ||
201 | if (size == 0) | ||
202 | goto error; | ||
203 | s->pipe_size = size; | ||
204 | break; | ||
205 | case 'h': | ||
206 | default: | ||
207 | usage(argv[0]); | ||
208 | goto error; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | agent_info_init(s); | ||
213 | |||
214 | return NULL; | ||
215 | |||
216 | error: | ||
217 | exit(EXIT_FAILURE); | ||
218 | } | ||
219 | |||
220 | static void agent_main_loop(struct agent_info *s) | ||
221 | { | ||
222 | int cpu; | ||
223 | pthread_t rw_thread_per_cpu[MAX_CPUS]; | ||
224 | |||
225 | /* Start all read/write threads */ | ||
226 | for (cpu = 0; cpu < s->cpus; cpu++) | ||
227 | rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]); | ||
228 | |||
229 | rw_ctl_loop(s->ctl_fd); | ||
230 | |||
231 | /* Finish all read/write threads */ | ||
232 | for (cpu = 0; cpu < s->cpus; cpu++) { | ||
233 | int ret; | ||
234 | |||
235 | ret = pthread_join(rw_thread_per_cpu[cpu], NULL); | ||
236 | if (ret != 0) { | ||
237 | pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu); | ||
238 | exit(EXIT_FAILURE); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static void agent_info_free(struct agent_info *s) | ||
244 | { | ||
245 | int i; | ||
246 | |||
247 | close(s->ctl_fd); | ||
248 | for (i = 0; i < s->cpus; i++) { | ||
249 | close(s->rw_ti[i]->in_fd); | ||
250 | close(s->rw_ti[i]->out_fd); | ||
251 | close(s->rw_ti[i]->read_pipe); | ||
252 | close(s->rw_ti[i]->write_pipe); | ||
253 | free(s->rw_ti[i]); | ||
254 | } | ||
255 | free(s); | ||
256 | } | ||
257 | |||
258 | int main(int argc, char *argv[]) | ||
259 | { | ||
260 | struct agent_info *s = NULL; | ||
261 | |||
262 | s = agent_info_new(); | ||
263 | parse_args(argc, argv, s); | ||
264 | |||
265 | agent_main_loop(s); | ||
266 | |||
267 | agent_info_free(s); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent.h b/tools/virtio/virtio-trace/trace-agent.h new file mode 100644 index 00000000000..8de79bfeaa7 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent.h | |||
@@ -0,0 +1,75 @@ | |||
1 | #ifndef __TRACE_AGENT_H__ | ||
2 | #define __TRACE_AGENT_H__ | ||
3 | #include <pthread.h> | ||
4 | #include <stdbool.h> | ||
5 | |||
6 | #define MAX_CPUS 256 | ||
7 | #define PIPE_INIT (1024*1024) | ||
8 | |||
9 | /* | ||
10 | * agent_info - structure managing total information of guest agent | ||
11 | * @pipe_size: size of pipe (default 1MB) | ||
12 | * @use_stdout: set to true when o option is added (default false) | ||
13 | * @cpus: total number of CPUs | ||
14 | * @ctl_fd: fd of control path, /dev/virtio-ports/agent-ctl-path | ||
15 | * @rw_ti: structure managing information of read/write threads | ||
16 | */ | ||
17 | struct agent_info { | ||
18 | unsigned long pipe_size; | ||
19 | bool use_stdout; | ||
20 | int cpus; | ||
21 | int ctl_fd; | ||
22 | struct rw_thread_info *rw_ti[MAX_CPUS]; | ||
23 | }; | ||
24 | |||
25 | /* | ||
26 | * rw_thread_info - structure managing a read/write thread a cpu | ||
27 | * @cpu_num: cpu number operating this read/write thread | ||
28 | * @in_fd: fd of reading trace data path in cpu_num | ||
29 | * @out_fd: fd of writing trace data path in cpu_num | ||
30 | * @read_pipe: fd of read pipe | ||
31 | * @write_pipe: fd of write pipe | ||
32 | * @pipe_size: size of pipe (default 1MB) | ||
33 | */ | ||
34 | struct rw_thread_info { | ||
35 | int cpu_num; | ||
36 | int in_fd; | ||
37 | int out_fd; | ||
38 | int read_pipe; | ||
39 | int write_pipe; | ||
40 | unsigned long pipe_size; | ||
41 | }; | ||
42 | |||
43 | /* use for stopping rw threads */ | ||
44 | extern bool global_sig_receive; | ||
45 | |||
46 | /* use for notification */ | ||
47 | extern bool global_run_operation; | ||
48 | extern pthread_mutex_t mutex_notify; | ||
49 | extern pthread_cond_t cond_wakeup; | ||
50 | |||
51 | /* for controller of read/write threads */ | ||
52 | extern int rw_ctl_init(const char *ctl_path); | ||
53 | extern void *rw_ctl_loop(int ctl_fd); | ||
54 | |||
55 | /* for trace read/write thread */ | ||
56 | extern void *rw_thread_info_new(void); | ||
57 | extern void *rw_thread_init(int cpu, const char *in_path, const char *out_path, | ||
58 | bool stdout_flag, unsigned long pipe_size, | ||
59 | struct rw_thread_info *rw_ti); | ||
60 | extern pthread_t rw_thread_run(struct rw_thread_info *rw_ti); | ||
61 | |||
62 | static inline void *zalloc(size_t size) | ||
63 | { | ||
64 | return calloc(1, size); | ||
65 | } | ||
66 | |||
67 | #define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__) | ||
68 | #define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__) | ||
69 | #ifdef DEBUG | ||
70 | #define pr_debug(format, ...) fprintf(stderr, format, ## __VA_ARGS__) | ||
71 | #else | ||
72 | #define pr_debug(format, ...) do {} while (0) | ||
73 | #endif | ||
74 | |||
75 | #endif /*__TRACE_AGENT_H__*/ | ||
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index f576971f655..cd1b03e8089 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <sys/fcntl.h> | 34 | #include <sys/fcntl.h> |
35 | #include <sys/mount.h> | 35 | #include <sys/mount.h> |
36 | #include <sys/statfs.h> | 36 | #include <sys/statfs.h> |
37 | #include "../../include/linux/magic.h" | 37 | #include "../../include/uapi/linux/magic.h" |
38 | #include "../../include/linux/kernel-page-flags.h" | 38 | #include "../../include/linux/kernel-page-flags.h" |
39 | 39 | ||
40 | 40 | ||