diff options
Diffstat (limited to 'tools')
22 files changed, 665 insertions, 92 deletions
diff --git a/tools/Makefile b/tools/Makefile index feec3ad5fd09..bcae806b0c39 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,6 +7,7 @@ help: @echo ' cgroup - cgroup tools' @echo ' cpupower - a tool for all things x86 CPU power' @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' + @echo ' hv - tools used when in Hyper-V clients' @echo ' lguest - a minimal 32-bit x86 hypervisor' @echo ' perf - Linux performance measurement and analysis tool' @echo ' selftests - various kernel selftests' @@ -40,7 +41,7 @@ acpi: FORCE cpupower: FORCE $(call descend,power/$@) -cgroup firewire guest usb virtio vm net: FORCE +cgroup firewire hv guest usb virtio vm net: FORCE $(call descend,$@) libapikfs: FORCE @@ -64,7 +65,7 @@ acpi_install: cpupower_install: $(call descend,power/$(@:_install=),install) -cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install: +cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install: $(call descend,$(@:_install=),install) selftests_install: @@ -76,7 +77,7 @@ turbostat_install x86_energy_perf_policy_install: tmon_install: $(call descend,thermal/$(@:_install=),install) -install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \ +install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ perf_install selftests_install turbostat_install usb_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \ tmon @@ -87,7 +88,7 @@ acpi_clean: cpupower_clean: $(call descend,power/cpupower,clean) -cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: +cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: $(call descend,$(@:_clean=),clean) libapikfs_clean: @@ -105,7 +106,7 @@ turbostat_clean x86_energy_perf_policy_clean: tmon_clean: $(call descend,thermal/tmon,clean) -clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \ +clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ vm_clean net_clean x86_energy_perf_policy_clean tmon_clean diff --git a/tools/hv/Makefile b/tools/hv/Makefile new file mode 100644 index 000000000000..bd22f786a60c --- /dev/null +++ b/tools/hv/Makefile @@ -0,0 +1,13 @@ +# Makefile for Hyper-V tools + +CC = $(CROSS_COMPILE)gcc +PTHREAD_LIBS = -lpthread +WARNINGS = -Wall -Wextra +CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) + +all: hv_kvp_daemon hv_vss_daemon +%: %.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + $(RM) hv_kvp_daemon hv_vss_daemon diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c new file mode 100644 index 000000000000..4ecc4fd0bc1b --- /dev/null +++ b/tools/hv/hv_fcopy_daemon.c @@ -0,0 +1,195 @@ +/* + * An implementation of host to guest copy functionality for Linux. + * + * Copyright (C) 2014, Microsoft, Inc. + * + * Author : K. Y. Srinivasan <kys@microsoft.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <linux/types.h> +#include <linux/kdev_t.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <linux/hyperv.h> +#include <syslog.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> + +static int target_fd; +static char target_fname[W_MAX_PATH]; + +static int hv_start_fcopy(struct hv_start_fcopy *smsg) +{ + int error = HV_E_FAIL; + char *q, *p; + + /* + * If possile append a path seperator to the path. + */ + if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2)) + strcat((char *)smsg->path_name, "/"); + + p = (char *)smsg->path_name; + snprintf(target_fname, sizeof(target_fname), "%s/%s", + (char *)smsg->path_name, smsg->file_name); + + syslog(LOG_INFO, "Target file name: %s", target_fname); + /* + * Check to see if the path is already in place; if not, + * create if required. + */ + while ((q = strchr(p, '/')) != NULL) { + if (q == p) { + p++; + continue; + } + *q = '\0'; + if (access((char *)smsg->path_name, F_OK)) { + if (smsg->copy_flags & CREATE_PATH) { + if (mkdir((char *)smsg->path_name, 0755)) { + syslog(LOG_ERR, "Failed to create %s", + (char *)smsg->path_name); + goto done; + } + } else { + syslog(LOG_ERR, "Invalid path: %s", + (char *)smsg->path_name); + goto done; + } + } + p = q + 1; + *q = '/'; + } + + if (!access(target_fname, F_OK)) { + syslog(LOG_INFO, "File: %s exists", target_fname); + if (!smsg->copy_flags & OVER_WRITE) + goto done; + } + + target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744); + if (target_fd == -1) { + syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); + goto done; + } + + error = 0; +done: + return error; +} + +static int hv_copy_data(struct hv_do_fcopy *cpmsg) +{ + ssize_t bytes_written; + + bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, + cpmsg->offset); + + if (bytes_written != cpmsg->size) + return HV_E_FAIL; + + return 0; +} + +static int hv_copy_finished(void) +{ + close(target_fd); + return 0; +} +static int hv_copy_cancel(void) +{ + close(target_fd); + unlink(target_fname); + return 0; + +} + +int main(void) +{ + int fd, fcopy_fd, len; + int error; + int version = FCOPY_CURRENT_VERSION; + char *buffer[4096 * 2]; + struct hv_fcopy_hdr *in_msg; + + if (daemon(1, 0)) { + syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + openlog("HV_FCOPY", 0, LOG_USER); + syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); + + fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); + + if (fcopy_fd < 0) { + syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* + * Register with the kernel. + */ + if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) { + syslog(LOG_ERR, "Registration failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + while (1) { + /* + * In this loop we process fcopy messages after the + * handshake is complete. + */ + len = pread(fcopy_fd, buffer, (4096 * 2), 0); + if (len < 0) { + syslog(LOG_ERR, "pread failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + in_msg = (struct hv_fcopy_hdr *)buffer; + + switch (in_msg->operation) { + case START_FILE_COPY: + error = hv_start_fcopy((struct hv_start_fcopy *)in_msg); + break; + case WRITE_TO_FILE: + error = hv_copy_data((struct hv_do_fcopy *)in_msg); + break; + case COMPLETE_FCOPY: + error = hv_copy_finished(); + break; + case CANCEL_FCOPY: + error = hv_copy_cancel(); + break; + + default: + syslog(LOG_ERR, "Unknown operation: %d", + in_msg->operation); + + } + + if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) { + syslog(LOG_ERR, "pwrite failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + } +} diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 520de3304571..6a213b8cd7b9 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c @@ -87,6 +87,8 @@ static int vss_operate(int operation) continue; if (strcmp(ent->mnt_type, "iso9660") == 0) continue; + if (strcmp(ent->mnt_type, "vfat") == 0) + continue; if (strcmp(ent->mnt_dir, "/") == 0) { root_seen = 1; continue; diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c index 65dc757f7f7b..bb31813e43dd 100644 --- a/tools/net/bpf_dbg.c +++ b/tools/net/bpf_dbg.c @@ -87,9 +87,6 @@ __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs)))) #endif -#define CMD(_name, _func) { .name = _name, .func = _func, } -#define OP(_op, _name) [_op] = _name - enum { CMD_OK, CMD_ERR, @@ -145,32 +142,32 @@ static size_t pcap_map_size = 0; static char *pcap_ptr_va_start, *pcap_ptr_va_curr; static const char * const op_table[] = { - OP(BPF_ST, "st"), - OP(BPF_STX, "stx"), - OP(BPF_LD_B, "ldb"), - OP(BPF_LD_H, "ldh"), - OP(BPF_LD_W, "ld"), - OP(BPF_LDX, "ldx"), - OP(BPF_LDX_B, "ldxb"), - OP(BPF_JMP_JA, "ja"), - OP(BPF_JMP_JEQ, "jeq"), - OP(BPF_JMP_JGT, "jgt"), - OP(BPF_JMP_JGE, "jge"), - OP(BPF_JMP_JSET, "jset"), - OP(BPF_ALU_ADD, "add"), - OP(BPF_ALU_SUB, "sub"), - OP(BPF_ALU_MUL, "mul"), - OP(BPF_ALU_DIV, "div"), - OP(BPF_ALU_MOD, "mod"), - OP(BPF_ALU_NEG, "neg"), - OP(BPF_ALU_AND, "and"), - OP(BPF_ALU_OR, "or"), - OP(BPF_ALU_XOR, "xor"), - OP(BPF_ALU_LSH, "lsh"), - OP(BPF_ALU_RSH, "rsh"), - OP(BPF_MISC_TAX, "tax"), - OP(BPF_MISC_TXA, "txa"), - OP(BPF_RET, "ret"), + [BPF_ST] = "st", + [BPF_STX] = "stx", + [BPF_LD_B] = "ldb", + [BPF_LD_H] = "ldh", + [BPF_LD_W] = "ld", + [BPF_LDX] = "ldx", + [BPF_LDX_B] = "ldxb", + [BPF_JMP_JA] = "ja", + [BPF_JMP_JEQ] = "jeq", + [BPF_JMP_JGT] = "jgt", + [BPF_JMP_JGE] = "jge", + [BPF_JMP_JSET] = "jset", + [BPF_ALU_ADD] = "add", + [BPF_ALU_SUB] = "sub", + [BPF_ALU_MUL] = "mul", + [BPF_ALU_DIV] = "div", + [BPF_ALU_MOD] = "mod", + [BPF_ALU_NEG] = "neg", + [BPF_ALU_AND] = "and", + [BPF_ALU_OR] = "or", + [BPF_ALU_XOR] = "xor", + [BPF_ALU_LSH] = "lsh", + [BPF_ALU_RSH] = "rsh", + [BPF_MISC_TAX] = "tax", + [BPF_MISC_TXA] = "txa", + [BPF_RET] = "ret", }; static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) @@ -1127,7 +1124,6 @@ static int cmd_step(char *num) static int cmd_select(char *num) { unsigned int which, i; - struct pcap_pkthdr *hdr; bool have_next = true; if (!pcap_loaded() || strlen(num) == 0) @@ -1144,7 +1140,7 @@ static int cmd_select(char *num) for (i = 0; i < which && (have_next = pcap_next_pkt()); i++) /* noop */; - if (!have_next || (hdr = pcap_curr_pkt()) == NULL) { + if (!have_next || pcap_curr_pkt() == NULL) { rl_printf("no packet #%u available!\n", which); pcap_reset_pkt(); return CMD_ERR; @@ -1177,9 +1173,8 @@ static int cmd_breakpoint(char *subcmd) static int cmd_run(char *num) { static uint32_t pass = 0, fail = 0; - struct pcap_pkthdr *hdr; bool has_limit = true; - int ret, pkts = 0, i = 0; + int pkts = 0, i = 0; if (!bpf_prog_loaded() || !pcap_loaded()) return CMD_ERR; @@ -1189,10 +1184,10 @@ static int cmd_run(char *num) has_limit = false; do { - hdr = pcap_curr_pkt(); - ret = bpf_run_all(bpf_image, bpf_prog_len, - (uint8_t *) hdr + sizeof(*hdr), - hdr->caplen, hdr->len); + struct pcap_pkthdr *hdr = pcap_curr_pkt(); + int ret = bpf_run_all(bpf_image, bpf_prog_len, + (uint8_t *) hdr + sizeof(*hdr), + hdr->caplen, hdr->len); if (ret > 0) pass++; else if (ret == 0) @@ -1245,14 +1240,14 @@ static int cmd_quit(char *dontcare) } static const struct shell_cmd cmds[] = { - CMD("load", cmd_load), - CMD("select", cmd_select), - CMD("step", cmd_step), - CMD("run", cmd_run), - CMD("breakpoint", cmd_breakpoint), - CMD("disassemble", cmd_disassemble), - CMD("dump", cmd_dump), - CMD("quit", cmd_quit), + { .name = "load", .func = cmd_load }, + { .name = "select", .func = cmd_select }, + { .name = "step", .func = cmd_step }, + { .name = "run", .func = cmd_run }, + { .name = "breakpoint", .func = cmd_breakpoint }, + { .name = "disassemble", .func = cmd_disassemble }, + { .name = "dump", .func = cmd_dump }, + { .name = "quit", .func = cmd_quit }, }; static int execf(char *arg) @@ -1280,7 +1275,6 @@ out: static char *shell_comp_gen(const char *buf, int state) { static int list_index, len; - const char *name; if (!state) { list_index = 0; @@ -1288,9 +1282,9 @@ static char *shell_comp_gen(const char *buf, int state) } for (; list_index < array_size(cmds); ) { - name = cmds[list_index].name; - list_index++; + const char *name = cmds[list_index].name; + list_index++; if (strncmp(name, buf, len) == 0) return strdup(name); } @@ -1322,16 +1316,9 @@ static void init_shell(FILE *fin, FILE *fout) { char file[128]; - memset(file, 0, sizeof(file)); - snprintf(file, sizeof(file) - 1, - "%s/.bpf_dbg_history", getenv("HOME")); - + snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME")); read_history(file); - memset(file, 0, sizeof(file)); - snprintf(file, sizeof(file) - 1, - "%s/.bpf_dbg_init", getenv("HOME")); - rl_instream = fin; rl_outstream = fout; @@ -1348,37 +1335,41 @@ static void init_shell(FILE *fin, FILE *fout) rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap); + snprintf(file, sizeof(file), "%s/.bpf_dbg_init", getenv("HOME")); rl_read_init_file(file); + rl_prep_terminal(0); rl_set_signals(); signal(SIGINT, intr_shell); } -static void exit_shell(void) +static void exit_shell(FILE *fin, FILE *fout) { char file[128]; - memset(file, 0, sizeof(file)); - snprintf(file, sizeof(file) - 1, - "%s/.bpf_dbg_history", getenv("HOME")); - + snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME")); write_history(file); + clear_history(); rl_deprep_terminal(); try_close_pcap(); + + if (fin != stdin) + fclose(fin); + if (fout != stdout) + fclose(fout); } static int run_shell_loop(FILE *fin, FILE *fout) { char *buf; - int ret; init_shell(fin, fout); while ((buf = readline("> ")) != NULL) { - ret = execf(buf); + int ret = execf(buf); if (ret == CMD_EX) break; if (ret == CMD_OK && strlen(buf) > 0) @@ -1387,7 +1378,7 @@ static int run_shell_loop(FILE *fin, FILE *fout) free(buf); } - exit_shell(); + exit_shell(fin, fout); return 0; } diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch index fef8ae922800..4b06719ee984 100644 --- a/tools/perf/config/Makefile.arch +++ b/tools/perf/config/Makefile.arch @@ -5,7 +5,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/tile.*/tile/ ) # Additional ARCH settings for x86 ifeq ($(ARCH),i386) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index e18a8b5e6953..5c11ecad02a9 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -145,6 +145,14 @@ #define CPUINFO_PROC "core ID" #endif +#ifdef __tile__ +#define mb() asm volatile ("mf" ::: "memory") +#define wmb() asm volatile ("mf" ::: "memory") +#define rmb() asm volatile ("mf" ::: "memory") +#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory") +#define CPUINFO_PROC "model name" +#endif + #define barrier() asm volatile ("" ::: "memory") #ifndef cpu_relax diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf index 831c7c5395f1..fbc134f9ac6e 100644 --- a/tools/testing/ktest/examples/kvm.conf +++ b/tools/testing/ktest/examples/kvm.conf @@ -10,6 +10,10 @@ MACHINE = Guest # Use virsh to read the serial console of the guest CONSOLE = virsh console ${MACHINE} +# Use SIGKILL to terminate virsh console. We can't kill virsh console +# by the default signal, SIGINT. +CLOSE_CONSOLE_SIGNAL = KILL + #*************************************# # This part is the same as test.conf # #*************************************# diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index bd24ae5aaeab..316194f26ff4 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR export CC CFLAGS -TARGETS = pmu +TARGETS = pmu copyloops endif diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile new file mode 100644 index 000000000000..6f2d3be227f9 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -0,0 +1,29 @@ +# The loops are all 64-bit code +CFLAGS += -m64 +CFLAGS += -I$(CURDIR) +CFLAGS += -D SELFTEST + +# Use our CFLAGS for the implicit .S rule +ASFLAGS = $(CFLAGS) + +PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 +EXTRA_SOURCES := validate.c ../harness.c + +all: $(PROGS) + +copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base +copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7 +memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy +memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7 + +$(PROGS): $(EXTRA_SOURCES) + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) *.o + +.PHONY: all run_tests clean diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h new file mode 100644 index 000000000000..ccd9c84c4e3f --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -0,0 +1,86 @@ +#include <ppc-asm.h> + +#define CONFIG_ALTIVEC + +#define r1 1 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 + +#define R14 r14 +#define R15 r15 +#define R16 r16 +#define R17 r17 +#define R18 r18 +#define R19 r19 +#define R20 r20 +#define R21 r21 +#define R22 r22 + +#define STACKFRAMESIZE 256 +#define STK_PARAM(i) (48 + ((i)-3)*8) +#define STK_REG(i) (112 + ((i)-14)*8) + +#define _GLOBAL(A) FUNC_START(test_ ## A) + +#define PPC_MTOCRF(A, B) mtocrf A, B + +FUNC_START(enter_vmx_usercopy) + li r3,1 + blr + +FUNC_START(exit_vmx_usercopy) + li r3,0 + blr + +FUNC_START(enter_vmx_copy) + li r3,1 + blr + +FUNC_START(exit_vmx_copy) + blr + +FUNC_START(memcpy_power7) + blr + +FUNC_START(__copy_tofrom_user_power7) + blr + +FUNC_START(__copy_tofrom_user_base) + blr + +#define BEGIN_FTR_SECTION +#define FTR_SECTION_ELSE +#define ALT_FTR_SECTION_END_IFCLR(x) +#define ALT_FTR_SECTION_END(x, y) +#define END_FTR_SECTION_IFCLR(x) diff --git a/tools/testing/selftests/powerpc/copyloops/asm/processor.h b/tools/testing/selftests/powerpc/copyloops/asm/processor.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/asm/processor.h diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_64.S b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S new file mode 120000 index 000000000000..f1c418a2521a --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/copyuser_64.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S new file mode 120000 index 000000000000..478689598298 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/copyuser_power7.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_64.S b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S new file mode 120000 index 000000000000..cce33fb6f9d8 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcpy_64.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S new file mode 120000 index 000000000000..0d6fbfaf3d59 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcpy_power7.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/copyloops/validate.c b/tools/testing/selftests/powerpc/copyloops/validate.c new file mode 100644 index 000000000000..1750ff57ee58 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/validate.c @@ -0,0 +1,99 @@ +#include <malloc.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> + +#include "../utils.h" + +#define MAX_LEN 8192 +#define MAX_OFFSET 16 +#define MIN_REDZONE 128 +#define BUFLEN (MAX_LEN+MAX_OFFSET+2*MIN_REDZONE) +#define POISON 0xa5 + +unsigned long COPY_LOOP(void *to, const void *from, unsigned long size); + +static void do_one(char *src, char *dst, unsigned long src_off, + unsigned long dst_off, unsigned long len, void *redzone, + void *fill) +{ + char *srcp, *dstp; + unsigned long ret; + unsigned long i; + + srcp = src + MIN_REDZONE + src_off; + dstp = dst + MIN_REDZONE + dst_off; + + memset(src, POISON, BUFLEN); + memset(dst, POISON, BUFLEN); + memcpy(srcp, fill, len); + + ret = COPY_LOOP(dstp, srcp, len); + if (ret && ret != (unsigned long)dstp) { + printf("(%p,%p,%ld) returned %ld\n", dstp, srcp, len, ret); + abort(); + } + + if (memcmp(dstp, srcp, len)) { + printf("(%p,%p,%ld) miscompare\n", dstp, srcp, len); + printf("src: "); + for (i = 0; i < len; i++) + printf("%02x ", srcp[i]); + printf("\ndst: "); + for (i = 0; i < len; i++) + printf("%02x ", dstp[i]); + printf("\n"); + abort(); + } + + if (memcmp(dst, redzone, dstp - dst)) { + printf("(%p,%p,%ld) redzone before corrupted\n", + dstp, srcp, len); + abort(); + } + + if (memcmp(dstp+len, redzone, dst+BUFLEN-(dstp+len))) { + printf("(%p,%p,%ld) redzone after corrupted\n", + dstp, srcp, len); + abort(); + } +} + +int test_copy_loop(void) +{ + char *src, *dst, *redzone, *fill; + unsigned long len, src_off, dst_off; + unsigned long i; + + src = memalign(BUFLEN, BUFLEN); + dst = memalign(BUFLEN, BUFLEN); + redzone = malloc(BUFLEN); + fill = malloc(BUFLEN); + + if (!src || !dst || !redzone || !fill) { + fprintf(stderr, "malloc failed\n"); + exit(1); + } + + memset(redzone, POISON, BUFLEN); + + /* Fill with sequential bytes */ + for (i = 0; i < BUFLEN; i++) + fill[i] = i & 0xff; + + for (len = 1; len < MAX_LEN; len++) { + for (src_off = 0; src_off < MAX_OFFSET; src_off++) { + for (dst_off = 0; dst_off < MAX_OFFSET; dst_off++) { + do_one(src, dst, src_off, dst_off, len, + redzone, fill); + } + } + } + + return 0; +} + +int main(void) +{ + return test_harness(test_copy_loop, str(COPY_LOOP)); +} diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index 5851c4b0f553..0de064406dab 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -31,4 +31,7 @@ do { \ } \ } while (0) +#define _str(s) #s +#define str(s) _str(s) + #endif /* _SELFTESTS_POWERPC_UTILS_H */ diff --git a/tools/virtio/linux/kmemleak.h b/tools/virtio/linux/kmemleak.h new file mode 100644 index 000000000000..c07072270e2f --- /dev/null +++ b/tools/virtio/linux/kmemleak.h @@ -0,0 +1,3 @@ +static inline void kmemleak_ignore(const void *ptr) +{ +} diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index 844783040703..5a2d1f0f6bc7 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -63,7 +63,7 @@ int virtqueue_add_inbuf(struct virtqueue *vq, void *data, gfp_t gfp); -void virtqueue_kick(struct virtqueue *vq); +bool virtqueue_kick(struct virtqueue *vq); void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); @@ -79,7 +79,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, struct virtio_device *vdev, bool weak_barriers, void *pages, - void (*notify)(struct virtqueue *vq), + bool (*notify)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq), const char *name); void vring_del_virtqueue(struct virtqueue *vq); diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index bdb71a26ae35..00ea679b3826 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -172,7 +172,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, GFP_ATOMIC); if (likely(r == 0)) { ++started; - if (unlikely(!virtqueue_kick(vq->vq)) + if (unlikely(!virtqueue_kick(vq->vq))) r = -1; } } else diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index f9be24d9efac..05654f5e48d5 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -19,7 +19,8 @@ * Authors: Wu Fengguang <fengguang.wu@intel.com> */ -#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -29,11 +30,14 @@ #include <getopt.h> #include <limits.h> #include <assert.h> +#include <ftw.h> +#include <time.h> #include <sys/types.h> #include <sys/errno.h> #include <sys/fcntl.h> #include <sys/mount.h> #include <sys/statfs.h> +#include <sys/mman.h> #include "../../include/uapi/linux/magic.h" #include "../../include/uapi/linux/kernel-page-flags.h" #include <api/fs/debugfs.h> @@ -158,6 +162,7 @@ static int opt_raw; /* for kernel developers */ static int opt_list; /* list pages (in ranges) */ static int opt_no_summary; /* don't show summary */ static pid_t opt_pid; /* process to walk */ +const char * opt_file; #define MAX_ADDR_RANGES 1024 static int nr_addr_ranges; @@ -253,12 +258,7 @@ static unsigned long do_u64_read(int fd, char *name, if (index > ULONG_MAX / 8) fatal("index overflow: %lu\n", index); - if (lseek(fd, index * 8, SEEK_SET) < 0) { - perror(name); - exit(EXIT_FAILURE); - } - - bytes = read(fd, buf, count * 8); + bytes = pread(fd, buf, count * 8, (off_t)index * 8); if (bytes < 0) { perror(name); exit(EXIT_FAILURE); @@ -343,8 +343,8 @@ static char *page_flag_longname(uint64_t flags) * page list and summary */ -static void show_page_range(unsigned long voffset, - unsigned long offset, uint64_t flags) +static void show_page_range(unsigned long voffset, unsigned long offset, + unsigned long size, uint64_t flags) { static uint64_t flags0; static unsigned long voff; @@ -352,14 +352,16 @@ static void show_page_range(unsigned long voffset, static unsigned long count; if (flags == flags0 && offset == index + count && - (!opt_pid || voffset == voff + count)) { - count++; + size && voffset == voff + count) { + count += size; return; } if (count) { if (opt_pid) printf("%lx\t", voff); + if (opt_file) + printf("%lu\t", voff); printf("%lx\t%lx\t%s\n", index, count, page_flag_name(flags0)); } @@ -367,7 +369,12 @@ static void show_page_range(unsigned long voffset, flags0 = flags; index = offset; voff = voffset; - count = 1; + count = size; +} + +static void flush_page_range(void) +{ + show_page_range(0, 0, 0, 0); } static void show_page(unsigned long voffset, @@ -375,6 +382,8 @@ static void show_page(unsigned long voffset, { if (opt_pid) printf("%lx\t", voffset); + if (opt_file) + printf("%lu\t", voffset); printf("%lx\t%s\n", offset, page_flag_name(flags)); } @@ -565,7 +574,7 @@ static void add_page(unsigned long voffset, unpoison_page(offset); if (opt_list == 1) - show_page_range(voffset, offset, flags); + show_page_range(voffset, offset, 1, flags); else if (opt_list == 2) show_page(voffset, offset, flags); @@ -667,7 +676,7 @@ static void walk_addr_ranges(void) for (i = 0; i < nr_addr_ranges; i++) if (!opt_pid) - walk_pfn(0, opt_offset[i], opt_size[i], 0); + walk_pfn(opt_offset[i], opt_offset[i], opt_size[i], 0); else walk_task(opt_offset[i], opt_size[i]); @@ -699,9 +708,7 @@ static void usage(void) " -a|--addr addr-spec Walk a range of pages\n" " -b|--bits bits-spec Walk pages with specified bits\n" " -p|--pid pid Walk process address space\n" -#if 0 /* planned features */ " -f|--file filename Walk file address space\n" -#endif " -l|--list Show page details in ranges\n" " -L|--list-each Show page details one by one\n" " -N|--no-summary Don't show summary info\n" @@ -799,8 +806,130 @@ static void parse_pid(const char *str) fclose(file); } +static void show_file(const char *name, const struct stat *st) +{ + unsigned long long size = st->st_size; + char atime[64], mtime[64]; + long now = time(NULL); + + printf("%s\tInode: %u\tSize: %llu (%llu pages)\n", + name, (unsigned)st->st_ino, + size, (size + page_size - 1) / page_size); + + strftime(atime, sizeof(atime), "%c", localtime(&st->st_atime)); + strftime(mtime, sizeof(mtime), "%c", localtime(&st->st_mtime)); + + printf("Modify: %s (%ld seconds ago)\nAccess: %s (%ld seconds ago)\n", + mtime, now - st->st_mtime, + atime, now - st->st_atime); +} + +static void walk_file(const char *name, const struct stat *st) +{ + uint8_t vec[PAGEMAP_BATCH]; + uint64_t buf[PAGEMAP_BATCH], flags; + unsigned long nr_pages, pfn, i; + int fd; + off_t off; + ssize_t len; + void *ptr; + int first = 1; + + fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW); + + for (off = 0; off < st->st_size; off += len) { + nr_pages = (st->st_size - off + page_size - 1) / page_size; + if (nr_pages > PAGEMAP_BATCH) + nr_pages = PAGEMAP_BATCH; + len = nr_pages * page_size; + + ptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off); + if (ptr == MAP_FAILED) + fatal("mmap failed: %s", name); + + /* determine cached pages */ + if (mincore(ptr, len, vec)) + fatal("mincore failed: %s", name); + + /* turn off readahead */ + if (madvise(ptr, len, MADV_RANDOM)) + fatal("madvice failed: %s", name); + + /* populate ptes */ + for (i = 0; i < nr_pages ; i++) { + if (vec[i] & 1) + (void)*(volatile int *)(ptr + i * page_size); + } + + /* turn off harvesting reference bits */ + if (madvise(ptr, len, MADV_SEQUENTIAL)) + fatal("madvice failed: %s", name); + + if (pagemap_read(buf, (unsigned long)ptr / page_size, + nr_pages) != nr_pages) + fatal("cannot read pagemap"); + + munmap(ptr, len); + + for (i = 0; i < nr_pages; i++) { + pfn = pagemap_pfn(buf[i]); + if (!pfn) + continue; + if (!kpageflags_read(&flags, pfn, 1)) + continue; + if (first && opt_list) { + first = 0; + flush_page_range(); + show_file(name, st); + } + add_page(off / page_size + i, pfn, flags, buf[i]); + } + } + + close(fd); +} + +int walk_tree(const char *name, const struct stat *st, int type, struct FTW *f) +{ + (void)f; + switch (type) { + case FTW_F: + if (S_ISREG(st->st_mode)) + walk_file(name, st); + break; + case FTW_DNR: + fprintf(stderr, "cannot read dir: %s\n", name); + break; + } + return 0; +} + +static void walk_page_cache(void) +{ + struct stat st; + + kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); + pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY); + + if (stat(opt_file, &st)) + fatal("stat failed: %s\n", opt_file); + + if (S_ISREG(st.st_mode)) { + walk_file(opt_file, &st); + } else if (S_ISDIR(st.st_mode)) { + /* do not follow symlinks and mountpoints */ + if (nftw(opt_file, walk_tree, 64, FTW_MOUNT | FTW_PHYS) < 0) + fatal("nftw failed: %s\n", opt_file); + } else + fatal("unhandled file type: %s\n", opt_file); + + close(kpageflags_fd); + close(pagemap_fd); +} + static void parse_file(const char *name) { + opt_file = name; } static void parse_addr_range(const char *optarg) @@ -991,15 +1120,20 @@ int main(int argc, char *argv[]) if (opt_list && opt_pid) printf("voffset\t"); + if (opt_list && opt_file) + printf("foffset\t"); if (opt_list == 1) printf("offset\tlen\tflags\n"); if (opt_list == 2) printf("offset\tflags\n"); - walk_addr_ranges(); + if (opt_file) + walk_page_cache(); + else + walk_addr_ranges(); if (opt_list == 1) - show_page_range(0, 0, 0); /* drain the buffer */ + flush_page_range(); if (opt_no_summary) return 0; |