diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gpio/.gitignore | 4 | ||||
-rw-r--r-- | tools/gpio/gpio-hammer.c | 2 | ||||
-rw-r--r-- | tools/iio/iio_event_monitor.c | 2 | ||||
-rwxr-xr-x | tools/testing/selftests/drivers/gpu/drm_mm.sh | 15 | ||||
-rw-r--r-- | tools/testing/selftests/firmware/Makefile | 2 | ||||
-rwxr-xr-x | tools/testing/selftests/firmware/fw_fallback.sh | 224 | ||||
-rwxr-xr-x | tools/testing/selftests/firmware/fw_filesystem.sh | 25 | ||||
-rwxr-xr-x | tools/testing/selftests/firmware/fw_userhelper.sh | 99 | ||||
-rwxr-xr-x | tools/testing/selftests/lib/prime_numbers.sh | 15 | ||||
-rw-r--r-- | tools/testing/selftests/vm/Makefile | 8 | ||||
-rwxr-xr-x | tools/testing/selftests/vm/run_vmtests | 24 | ||||
-rw-r--r-- | tools/testing/selftests/vm/userfaultfd.c | 486 | ||||
-rw-r--r-- | tools/usb/ffs-test.c | 52 | ||||
-rw-r--r-- | tools/usb/usbip/README | 57 | ||||
-rwxr-xr-x | tools/usb/usbip/vudc/vudc_server_example.sh | 107 | ||||
-rw-r--r-- | tools/vm/Makefile | 8 |
16 files changed, 978 insertions, 152 deletions
diff --git a/tools/gpio/.gitignore b/tools/gpio/.gitignore new file mode 100644 index 000000000000..9e9dd4b681b2 --- /dev/null +++ b/tools/gpio/.gitignore @@ -0,0 +1,4 @@ +gpio-event-mon +gpio-hammer +lsgpio + diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index f1eab587dfea..4bcb234c0fca 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -38,7 +38,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, memset(&data.values, 0, sizeof(data.values)); ret = gpiotools_request_linehandle(device_name, lines, nlines, GPIOHANDLE_REQUEST_OUTPUT, &data, - "gpio-hammler"); + "gpio-hammer"); if (ret < 0) goto exit_error; else diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index d9b7e0f306c6..b61245e1181d 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -57,6 +57,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_RESISTANCE] = "resistance", [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", + [IIO_GRAVITY] = "gravity", }; static const char * const iio_ev_type_text[] = { @@ -149,6 +150,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_RESISTANCE: case IIO_PH: case IIO_UVINDEX: + case IIO_GRAVITY: break; default: return false; diff --git a/tools/testing/selftests/drivers/gpu/drm_mm.sh b/tools/testing/selftests/drivers/gpu/drm_mm.sh new file mode 100755 index 000000000000..96dd55c92799 --- /dev/null +++ b/tools/testing/selftests/drivers/gpu/drm_mm.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Runs API tests for struct drm_mm (DRM range manager) + +if ! /sbin/modprobe -n -q test-drm_mm; then + echo "drivers/gpu/drm_mm: [skip]" + exit 77 +fi + +if /sbin/modprobe -q test-drm_mm; then + /sbin/modprobe -q -r test-drm_mm + echo "drivers/gpu/drm_mm: ok" +else + echo "drivers/gpu/drm_mm: [FAIL]" + exit 1 +fi diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile index 9bf82234855b..1894d625af2d 100644 --- a/tools/testing/selftests/firmware/Makefile +++ b/tools/testing/selftests/firmware/Makefile @@ -3,7 +3,7 @@ # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" all: -TEST_PROGS := fw_filesystem.sh fw_userhelper.sh +TEST_PROGS := fw_filesystem.sh fw_fallback.sh include ../lib.mk diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh new file mode 100755 index 000000000000..2e4c22d5abf7 --- /dev/null +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -0,0 +1,224 @@ +#!/bin/sh +# This validates that the kernel will fall back to using the fallback mechanism +# to load firmware it can't find on disk itself. We must request a firmware +# that the kernel won't find, and any installed helper (e.g. udev) also +# won't find so that we can do the load ourself manually. +set -e + +modprobe test_firmware + +DIR=/sys/devices/virtual/misc/test_firmware + +# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ +# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that +# as an indicator for CONFIG_FW_LOADER_USER_HELPER. +HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) + +if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then + OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) +else + echo "usermode helper disabled so ignoring test" + exit 0 +fi + +FWPATH=$(mktemp -d) +FW="$FWPATH/test-firmware.bin" + +test_finish() +{ + echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout + rm -f "$FW" + rmdir "$FWPATH" +} + +load_fw() +{ + local name="$1" + local file="$2" + + # This will block until our load (below) has finished. + echo -n "$name" >"$DIR"/trigger_request & + + # Give kernel a chance to react. + local timeout=10 + while [ ! -e "$DIR"/"$name"/loading ]; do + sleep 0.1 + timeout=$(( $timeout - 1 )) + if [ "$timeout" -eq 0 ]; then + echo "$0: firmware interface never appeared" >&2 + exit 1 + fi + done + + echo 1 >"$DIR"/"$name"/loading + cat "$file" >"$DIR"/"$name"/data + echo 0 >"$DIR"/"$name"/loading + + # Wait for request to finish. + wait +} + +load_fw_cancel() +{ + local name="$1" + local file="$2" + + # This will block until our load (below) has finished. + echo -n "$name" >"$DIR"/trigger_request 2>/dev/null & + + # Give kernel a chance to react. + local timeout=10 + while [ ! -e "$DIR"/"$name"/loading ]; do + sleep 0.1 + timeout=$(( $timeout - 1 )) + if [ "$timeout" -eq 0 ]; then + echo "$0: firmware interface never appeared" >&2 + exit 1 + fi + done + + echo -1 >"$DIR"/"$name"/loading + + # Wait for request to finish. + wait +} + +load_fw_custom() +{ + local name="$1" + local file="$2" + + echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & + + # Give kernel a chance to react. + local timeout=10 + while [ ! -e "$DIR"/"$name"/loading ]; do + sleep 0.1 + timeout=$(( $timeout - 1 )) + if [ "$timeout" -eq 0 ]; then + echo "$0: firmware interface never appeared" >&2 + exit 1 + fi + done + + echo 1 >"$DIR"/"$name"/loading + cat "$file" >"$DIR"/"$name"/data + echo 0 >"$DIR"/"$name"/loading + + # Wait for request to finish. + wait +} + + +load_fw_custom_cancel() +{ + local name="$1" + local file="$2" + + echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & + + # Give kernel a chance to react. + local timeout=10 + while [ ! -e "$DIR"/"$name"/loading ]; do + sleep 0.1 + timeout=$(( $timeout - 1 )) + if [ "$timeout" -eq 0 ]; then + echo "$0: firmware interface never appeared" >&2 + exit 1 + fi + done + + echo -1 >"$DIR"/"$name"/loading + + # Wait for request to finish. + wait +} + + +trap "test_finish" EXIT + +# This is an unlikely real-world firmware content. :) +echo "ABCD0123" >"$FW" +NAME=$(basename "$FW") + +DEVPATH="$DIR"/"nope-$NAME"/loading + +# Test failure when doing nothing (timeout works). +echo -n 2 >/sys/class/firmware/timeout +echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & + +# Give the kernel some time to load the loading file, must be less +# than the timeout above. +sleep 1 +if [ ! -f $DEVPATH ]; then + echo "$0: fallback mechanism immediately cancelled" + echo "" + echo "The file never appeared: $DEVPATH" + echo "" + echo "This might be a distribution udev rule setup by your distribution" + echo "to immediately cancel all fallback requests, this must be" + echo "removed before running these tests. To confirm look for" + echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" + echo "and see if you have something like this:" + echo "" + echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" + echo "" + echo "If you do remove this file or comment out this line before" + echo "proceeding with these tests." + exit 1 +fi + +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not expected to match" >&2 + exit 1 +else + echo "$0: timeout works" +fi + +# Put timeout high enough for us to do work but not so long that failures +# slow down this test too much. +echo 4 >/sys/class/firmware/timeout + +# Load this script instead of the desired firmware. +load_fw "$NAME" "$0" +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not expected to match" >&2 + exit 1 +else + echo "$0: firmware comparison works" +fi + +# Do a proper load, which should work correctly. +load_fw "$NAME" "$FW" +if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not loaded" >&2 + exit 1 +else + echo "$0: fallback mechanism works" +fi + +load_fw_cancel "nope-$NAME" "$FW" +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was expected to be cancelled" >&2 + exit 1 +else + echo "$0: cancelling fallback mechanism works" +fi + +load_fw_custom "$NAME" "$FW" +if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not loaded" >&2 + exit 1 +else + echo "$0: custom fallback loading mechanism works" +fi + +load_fw_custom_cancel "nope-$NAME" "$FW" +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was expected to be cancelled" >&2 + exit 1 +else + echo "$0: cancelling custom fallback mechanism works" +fi + +exit 0 diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index 5c495ad7958a..e35691239350 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -5,9 +5,24 @@ # know so we can be sure we're not accidentally testing the user helper. set -e -modprobe test_firmware - DIR=/sys/devices/virtual/misc/test_firmware +TEST_DIR=$(dirname $0) + +test_modprobe() +{ + if [ ! -d $DIR ]; then + echo "$0: $DIR not present" + echo "You must have the following enabled in your kernel:" + cat $TEST_DIR/config + exit 1 + fi +} + +trap "test_modprobe" EXIT + +if [ ! -d $DIR ]; then + modprobe test_firmware +fi # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that @@ -48,18 +63,18 @@ echo "ABCD0123" >"$FW" NAME=$(basename "$FW") -if printf '\000' >"$DIR"/trigger_request; then +if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then echo "$0: empty filename should not succeed" >&2 exit 1 fi -if printf '\000' >"$DIR"/trigger_async_request; then +if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then echo "$0: empty filename should not succeed (async)" >&2 exit 1 fi # Request a firmware that doesn't exist, it should fail. -if echo -n "nope-$NAME" >"$DIR"/trigger_request; then +if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then echo "$0: firmware shouldn't have loaded" >&2 exit 1 fi diff --git a/tools/testing/selftests/firmware/fw_userhelper.sh b/tools/testing/selftests/firmware/fw_userhelper.sh deleted file mode 100755 index b9983f8e09f6..000000000000 --- a/tools/testing/selftests/firmware/fw_userhelper.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -# This validates that the kernel will fall back to using the user helper -# to load firmware it can't find on disk itself. We must request a firmware -# that the kernel won't find, and any installed helper (e.g. udev) also -# won't find so that we can do the load ourself manually. -set -e - -modprobe test_firmware - -DIR=/sys/devices/virtual/misc/test_firmware - -# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ -# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that -# as an indicator for CONFIG_FW_LOADER_USER_HELPER. -HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) - -if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then - OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) -else - echo "usermode helper disabled so ignoring test" - exit 0 -fi - -FWPATH=$(mktemp -d) -FW="$FWPATH/test-firmware.bin" - -test_finish() -{ - echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout - rm -f "$FW" - rmdir "$FWPATH" -} - -load_fw() -{ - local name="$1" - local file="$2" - - # This will block until our load (below) has finished. - echo -n "$name" >"$DIR"/trigger_request & - - # Give kernel a chance to react. - local timeout=10 - while [ ! -e "$DIR"/"$name"/loading ]; do - sleep 0.1 - timeout=$(( $timeout - 1 )) - if [ "$timeout" -eq 0 ]; then - echo "$0: firmware interface never appeared" >&2 - exit 1 - fi - done - - echo 1 >"$DIR"/"$name"/loading - cat "$file" >"$DIR"/"$name"/data - echo 0 >"$DIR"/"$name"/loading - - # Wait for request to finish. - wait -} - -trap "test_finish" EXIT - -# This is an unlikely real-world firmware content. :) -echo "ABCD0123" >"$FW" -NAME=$(basename "$FW") - -# Test failure when doing nothing (timeout works). -echo 1 >/sys/class/firmware/timeout -echo -n "$NAME" >"$DIR"/trigger_request -if diff -q "$FW" /dev/test_firmware >/dev/null ; then - echo "$0: firmware was not expected to match" >&2 - exit 1 -else - echo "$0: timeout works" -fi - -# Put timeout high enough for us to do work but not so long that failures -# slow down this test too much. -echo 4 >/sys/class/firmware/timeout - -# Load this script instead of the desired firmware. -load_fw "$NAME" "$0" -if diff -q "$FW" /dev/test_firmware >/dev/null ; then - echo "$0: firmware was not expected to match" >&2 - exit 1 -else - echo "$0: firmware comparison works" -fi - -# Do a proper load, which should work correctly. -load_fw "$NAME" "$FW" -if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then - echo "$0: firmware was not loaded" >&2 - exit 1 -else - echo "$0: user helper firmware loading works" -fi - -exit 0 diff --git a/tools/testing/selftests/lib/prime_numbers.sh b/tools/testing/selftests/lib/prime_numbers.sh new file mode 100755 index 000000000000..da4cbcd766f5 --- /dev/null +++ b/tools/testing/selftests/lib/prime_numbers.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Checks fast/slow prime_number generation for inconsistencies + +if ! /sbin/modprobe -q -r prime_numbers; then + echo "prime_numbers: [SKIP]" + exit 77 +fi + +if /sbin/modprobe -q prime_numbers selftest=65536; then + /sbin/modprobe -q -r prime_numbers + echo "prime_numbers: ok" +else + echo "prime_numbers: [FAIL]" + exit 1 +fi diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index bbab7f4664ac..900dfaf81051 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -10,6 +10,8 @@ BINARIES += on-fault-limit BINARIES += thuge-gen BINARIES += transhuge-stress BINARIES += userfaultfd +BINARIES += userfaultfd_hugetlb +BINARIES += userfaultfd_shmem BINARIES += mlock-random-test all: $(BINARIES) @@ -18,6 +20,12 @@ all: $(BINARIES) userfaultfd: userfaultfd.c ../../../../usr/include/linux/kernel.h $(CC) $(CFLAGS) -O2 -o $@ $< -lpthread +userfaultfd_hugetlb: userfaultfd.c ../../../../usr/include/linux/kernel.h + $(CC) $(CFLAGS) -DHUGETLB_TEST -O2 -o $@ $< -lpthread + +userfaultfd_shmem: userfaultfd.c ../../../../usr/include/linux/kernel.h + $(CC) $(CFLAGS) -DSHMEM_TEST -O2 -o $@ $< -lpthread + mlock-random-test: mlock-random-test.c $(CC) $(CFLAGS) -o $@ $< -lcap diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index e11968b3677e..c92f6cf31d0a 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -103,6 +103,30 @@ else echo "[PASS]" fi +echo "----------------------------" +echo "running userfaultfd_hugetlb" +echo "----------------------------" +# 258MB total huge pages == 128MB src and 128MB dst +./userfaultfd_hugetlb 128 32 $mnt/ufd_test_file +if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +else + echo "[PASS]" +fi +rm -f $mnt/ufd_test_file + +echo "----------------------------" +echo "running userfaultfd_shmem" +echo "----------------------------" +./userfaultfd_shmem 128 32 +if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +else + echo "[PASS]" +fi + #cleanup umount $mnt rm -rf $mnt diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index d77ed41b2094..5a840a605a16 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -63,6 +63,7 @@ #include <sys/mman.h> #include <sys/syscall.h> #include <sys/ioctl.h> +#include <sys/wait.h> #include <pthread.h> #include <linux/userfaultfd.h> @@ -76,8 +77,12 @@ static unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; #define BOUNCE_POLL (1<<3) static int bounces; +#ifdef HUGETLB_TEST +static int huge_fd; +static char *huge_fd_off0; +#endif static unsigned long long *count_verify; -static int uffd, finished, *pipefd; +static int uffd, uffd_flags, finished, *pipefd; static char *area_src, *area_dst; static char *zeropage; pthread_attr_t attr; @@ -97,6 +102,102 @@ pthread_attr_t attr; ~(unsigned long)(sizeof(unsigned long long) \ - 1))) +#if !defined(HUGETLB_TEST) && !defined(SHMEM_TEST) + +/* Anonymous memory */ +#define EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \ + (1 << _UFFDIO_COPY) | \ + (1 << _UFFDIO_ZEROPAGE)) + +static int release_pages(char *rel_area) +{ + int ret = 0; + + if (madvise(rel_area, nr_pages * page_size, MADV_DONTNEED)) { + perror("madvise"); + ret = 1; + } + + return ret; +} + +static void allocate_area(void **alloc_area) +{ + if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) { + fprintf(stderr, "out of memory\n"); + *alloc_area = NULL; + } +} + +#else /* HUGETLB_TEST or SHMEM_TEST */ + +#define EXPECTED_IOCTLS UFFD_API_RANGE_IOCTLS_BASIC + +#ifdef HUGETLB_TEST + +/* HugeTLB memory */ +static int release_pages(char *rel_area) +{ + int ret = 0; + + if (fallocate(huge_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + rel_area == huge_fd_off0 ? 0 : + nr_pages * page_size, + nr_pages * page_size)) { + perror("fallocate"); + ret = 1; + } + + return ret; +} + + +static void allocate_area(void **alloc_area) +{ + *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_HUGETLB, huge_fd, + *alloc_area == area_src ? 0 : + nr_pages * page_size); + if (*alloc_area == MAP_FAILED) { + fprintf(stderr, "mmap of hugetlbfs file failed\n"); + *alloc_area = NULL; + } + + if (*alloc_area == area_src) + huge_fd_off0 = *alloc_area; +} + +#elif defined(SHMEM_TEST) + +/* Shared memory */ +static int release_pages(char *rel_area) +{ + int ret = 0; + + if (madvise(rel_area, nr_pages * page_size, MADV_REMOVE)) { + perror("madvise"); + ret = 1; + } + + return ret; +} + +static void allocate_area(void **alloc_area) +{ + *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if (*alloc_area == MAP_FAILED) { + fprintf(stderr, "shared memory mmap failed\n"); + *alloc_area = NULL; + } +} + +#else /* SHMEM_TEST */ +#error "Undefined test type" +#endif /* HUGETLB_TEST */ + +#endif /* !defined(HUGETLB_TEST) && !defined(SHMEM_TEST) */ + static int my_bcmp(char *str1, char *str2, size_t n) { unsigned long i; @@ -217,7 +318,7 @@ static void *locking_thread(void *arg) return NULL; } -static int copy_page(unsigned long offset) +static int copy_page(int ufd, unsigned long offset) { struct uffdio_copy uffdio_copy; @@ -229,7 +330,7 @@ static int copy_page(unsigned long offset) uffdio_copy.len = page_size; uffdio_copy.mode = 0; uffdio_copy.copy = 0; - if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy)) { + if (ioctl(ufd, UFFDIO_COPY, &uffdio_copy)) { /* real retval in ufdio_copy.copy */ if (uffdio_copy.copy != -EEXIST) fprintf(stderr, "UFFDIO_COPY error %Ld\n", @@ -247,6 +348,7 @@ static void *uffd_poll_thread(void *arg) unsigned long cpu = (unsigned long) arg; struct pollfd pollfd[2]; struct uffd_msg msg; + struct uffdio_register uffd_reg; int ret; unsigned long offset; char tmp_chr; @@ -278,16 +380,35 @@ static void *uffd_poll_thread(void *arg) continue; perror("nonblocking read error"), exit(1); } - if (msg.event != UFFD_EVENT_PAGEFAULT) + switch (msg.event) { + default: fprintf(stderr, "unexpected msg event %u\n", msg.event), exit(1); - if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) - fprintf(stderr, "unexpected write fault\n"), exit(1); - offset = (char *)(unsigned long)msg.arg.pagefault.address - - area_dst; - offset &= ~(page_size-1); - if (copy_page(offset)) - userfaults++; + break; + case UFFD_EVENT_PAGEFAULT: + if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) + fprintf(stderr, "unexpected write fault\n"), exit(1); + offset = (char *)(unsigned long)msg.arg.pagefault.address - + area_dst; + offset &= ~(page_size-1); + if (copy_page(uffd, offset)) + userfaults++; + break; + case UFFD_EVENT_FORK: + uffd = msg.arg.fork.ufd; + pollfd[0].fd = uffd; + break; + case UFFD_EVENT_MADVDONTNEED: + uffd_reg.range.start = msg.arg.madv_dn.start; + uffd_reg.range.len = msg.arg.madv_dn.end - + msg.arg.madv_dn.start; + if (ioctl(uffd, UFFDIO_UNREGISTER, &uffd_reg.range)) + fprintf(stderr, "madv_dn failure\n"), exit(1); + break; + case UFFD_EVENT_REMAP: + area_dst = (char *)(unsigned long)msg.arg.remap.to; + break; + } } return (void *)userfaults; } @@ -324,7 +445,7 @@ static void *uffd_read_thread(void *arg) offset = (char *)(unsigned long)msg.arg.pagefault.address - area_dst; offset &= ~(page_size-1); - if (copy_page(offset)) + if (copy_page(uffd, offset)) (*this_cpu_userfaults)++; } return (void *)NULL; @@ -338,7 +459,7 @@ static void *background_thread(void *arg) for (page_nr = cpu * nr_pages_per_cpu; page_nr < (cpu+1) * nr_pages_per_cpu; page_nr++) - copy_page(page_nr * page_size); + copy_page(uffd, page_nr * page_size); return NULL; } @@ -384,10 +505,8 @@ static int stress(unsigned long *userfaults) * UFFDIO_COPY without writing zero pages into area_dst * because the background threads already completed). */ - if (madvise(area_src, nr_pages * page_size, MADV_DONTNEED)) { - perror("madvise"); + if (release_pages(area_src)) return 1; - } for (cpu = 0; cpu < nr_cpus; cpu++) { char c; @@ -414,27 +533,9 @@ static int stress(unsigned long *userfaults) return 0; } -static int userfaultfd_stress(void) +static int userfaultfd_open(int features) { - void *area; - char *tmp_area; - unsigned long nr; - struct uffdio_register uffdio_register; struct uffdio_api uffdio_api; - unsigned long cpu; - int uffd_flags, err; - unsigned long userfaults[nr_cpus]; - - if (posix_memalign(&area, page_size, nr_pages * page_size)) { - fprintf(stderr, "out of memory\n"); - return 1; - } - area_src = area; - if (posix_memalign(&area, page_size, nr_pages * page_size)) { - fprintf(stderr, "out of memory\n"); - return 1; - } - area_dst = area; uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd < 0) { @@ -445,7 +546,7 @@ static int userfaultfd_stress(void) uffd_flags = fcntl(uffd, F_GETFD, NULL); uffdio_api.api = UFFD_API; - uffdio_api.features = 0; + uffdio_api.features = features; if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { fprintf(stderr, "UFFDIO_API\n"); return 1; @@ -455,6 +556,235 @@ static int userfaultfd_stress(void) return 1; } + return 0; +} + +/* + * For non-cooperative userfaultfd test we fork() a process that will + * generate pagefaults, will mremap the area monitored by the + * userfaultfd and at last this process will release the monitored + * area. + * For the anonymous and shared memory the area is divided into two + * parts, the first part is accessed before mremap, and the second + * part is accessed after mremap. Since hugetlbfs does not support + * mremap, the entire monitored area is accessed in a single pass for + * HUGETLB_TEST. + * The release of the pages currently generates event only for + * anonymous memory (UFFD_EVENT_MADVDONTNEED), hence it is not checked + * for hugetlb and shmem. + */ +static int faulting_process(void) +{ + unsigned long nr; + unsigned long long count; + +#ifndef HUGETLB_TEST + unsigned long split_nr_pages = (nr_pages + 1) / 2; +#else + unsigned long split_nr_pages = nr_pages; +#endif + + for (nr = 0; nr < split_nr_pages; nr++) { + count = *area_count(area_dst, nr); + if (count != count_verify[nr]) { + fprintf(stderr, + "nr %lu memory corruption %Lu %Lu\n", + nr, count, + count_verify[nr]), exit(1); + } + } + +#ifndef HUGETLB_TEST + area_dst = mremap(area_dst, nr_pages * page_size, nr_pages * page_size, + MREMAP_MAYMOVE | MREMAP_FIXED, area_src); + if (area_dst == MAP_FAILED) + perror("mremap"), exit(1); + + for (; nr < nr_pages; nr++) { + count = *area_count(area_dst, nr); + if (count != count_verify[nr]) { + fprintf(stderr, + "nr %lu memory corruption %Lu %Lu\n", + nr, count, + count_verify[nr]), exit(1); + } + } + +#ifndef SHMEM_TEST + if (release_pages(area_dst)) + return 1; + + for (nr = 0; nr < nr_pages; nr++) { + if (my_bcmp(area_dst + nr * page_size, zeropage, page_size)) + fprintf(stderr, "nr %lu is not zero\n", nr), exit(1); + } +#endif /* SHMEM_TEST */ + +#endif /* HUGETLB_TEST */ + + return 0; +} + +static int uffdio_zeropage(int ufd, unsigned long offset) +{ + struct uffdio_zeropage uffdio_zeropage; + int ret; + unsigned long has_zeropage = EXPECTED_IOCTLS & (1 << _UFFDIO_ZEROPAGE); + + if (offset >= nr_pages * page_size) + fprintf(stderr, "unexpected offset %lu\n", + offset), exit(1); + uffdio_zeropage.range.start = (unsigned long) area_dst + offset; + uffdio_zeropage.range.len = page_size; + uffdio_zeropage.mode = 0; + ret = ioctl(ufd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + if (ret) { + /* real retval in ufdio_zeropage.zeropage */ + if (has_zeropage) { + if (uffdio_zeropage.zeropage == -EEXIST) + fprintf(stderr, "UFFDIO_ZEROPAGE -EEXIST\n"), + exit(1); + else + fprintf(stderr, "UFFDIO_ZEROPAGE error %Ld\n", + uffdio_zeropage.zeropage), exit(1); + } else { + if (uffdio_zeropage.zeropage != -EINVAL) + fprintf(stderr, + "UFFDIO_ZEROPAGE not -EINVAL %Ld\n", + uffdio_zeropage.zeropage), exit(1); + } + } else if (has_zeropage) { + if (uffdio_zeropage.zeropage != page_size) { + fprintf(stderr, "UFFDIO_ZEROPAGE unexpected %Ld\n", + uffdio_zeropage.zeropage), exit(1); + } else + return 1; + } else { + fprintf(stderr, + "UFFDIO_ZEROPAGE succeeded %Ld\n", + uffdio_zeropage.zeropage), exit(1); + } + + return 0; +} + +/* exercise UFFDIO_ZEROPAGE */ +static int userfaultfd_zeropage_test(void) +{ + struct uffdio_register uffdio_register; + unsigned long expected_ioctls; + + printf("testing UFFDIO_ZEROPAGE: "); + fflush(stdout); + + if (release_pages(area_dst)) + return 1; + + if (userfaultfd_open(0) < 0) + return 1; + uffdio_register.range.start = (unsigned long) area_dst; + uffdio_register.range.len = nr_pages * page_size; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) + fprintf(stderr, "register failure\n"), exit(1); + + expected_ioctls = EXPECTED_IOCTLS; + if ((uffdio_register.ioctls & expected_ioctls) != + expected_ioctls) + fprintf(stderr, + "unexpected missing ioctl for anon memory\n"), + exit(1); + + if (uffdio_zeropage(uffd, 0)) { + if (my_bcmp(area_dst, zeropage, page_size)) + fprintf(stderr, "zeropage is not zero\n"), exit(1); + } + + close(uffd); + printf("done.\n"); + return 0; +} + +static int userfaultfd_events_test(void) +{ + struct uffdio_register uffdio_register; + unsigned long expected_ioctls; + unsigned long userfaults; + pthread_t uffd_mon; + int err, features; + pid_t pid; + char c; + + printf("testing events (fork, remap, madv_dn): "); + fflush(stdout); + + if (release_pages(area_dst)) + return 1; + + features = UFFD_FEATURE_EVENT_FORK | UFFD_FEATURE_EVENT_REMAP | + UFFD_FEATURE_EVENT_MADVDONTNEED; + if (userfaultfd_open(features) < 0) + return 1; + fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK); + + uffdio_register.range.start = (unsigned long) area_dst; + uffdio_register.range.len = nr_pages * page_size; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) + fprintf(stderr, "register failure\n"), exit(1); + + expected_ioctls = EXPECTED_IOCTLS; + if ((uffdio_register.ioctls & expected_ioctls) != + expected_ioctls) + fprintf(stderr, + "unexpected missing ioctl for anon memory\n"), + exit(1); + + if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL)) + perror("uffd_poll_thread create"), exit(1); + + pid = fork(); + if (pid < 0) + perror("fork"), exit(1); + + if (!pid) + return faulting_process(); + + waitpid(pid, &err, 0); + if (err) + fprintf(stderr, "faulting process failed\n"), exit(1); + + if (write(pipefd[1], &c, sizeof(c)) != sizeof(c)) + perror("pipe write"), exit(1); + if (pthread_join(uffd_mon, (void **)&userfaults)) + return 1; + + close(uffd); + printf("userfaults: %ld\n", userfaults); + + return userfaults != nr_pages; +} + +static int userfaultfd_stress(void) +{ + void *area; + char *tmp_area; + unsigned long nr; + struct uffdio_register uffdio_register; + unsigned long cpu; + int err; + unsigned long userfaults[nr_cpus]; + + allocate_area((void **)&area_src); + if (!area_src) + return 1; + allocate_area((void **)&area_dst); + if (!area_dst) + return 1; + + if (userfaultfd_open(0) < 0) + return 1; + count_verify = malloc(nr_pages * sizeof(unsigned long long)); if (!count_verify) { perror("count_verify"); @@ -528,9 +858,7 @@ static int userfaultfd_stress(void) fprintf(stderr, "register failure\n"); return 1; } - expected_ioctls = (1 << _UFFDIO_WAKE) | - (1 << _UFFDIO_COPY) | - (1 << _UFFDIO_ZEROPAGE); + expected_ioctls = EXPECTED_IOCTLS; if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls) { fprintf(stderr, @@ -562,10 +890,8 @@ static int userfaultfd_stress(void) * MADV_DONTNEED only after the UFFDIO_REGISTER, so it's * required to MADV_DONTNEED here. */ - if (madvise(area_dst, nr_pages * page_size, MADV_DONTNEED)) { - perror("madvise 2"); + if (release_pages(area_dst)) return 1; - } /* bounce pass */ if (stress(userfaults)) @@ -603,9 +929,15 @@ static int userfaultfd_stress(void) printf("\n"); } - return err; + if (err) + return err; + + close(uffd); + return userfaultfd_zeropage_test() || userfaultfd_events_test(); } +#ifndef HUGETLB_TEST + int main(int argc, char **argv) { if (argc < 3) @@ -632,6 +964,74 @@ int main(int argc, char **argv) return userfaultfd_stress(); } +#else /* HUGETLB_TEST */ + +/* + * Copied from mlock2-tests.c + */ +unsigned long default_huge_page_size(void) +{ + unsigned long hps = 0; + char *line = NULL; + size_t linelen = 0; + FILE *f = fopen("/proc/meminfo", "r"); + + if (!f) + return 0; + while (getline(&line, &linelen, f) > 0) { + if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) { + hps <<= 10; + break; + } + } + + free(line); + fclose(f); + return hps; +} + +int main(int argc, char **argv) +{ + if (argc < 4) + fprintf(stderr, "Usage: <MiB> <bounces> <hugetlbfs_file>\n"), + exit(1); + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + page_size = default_huge_page_size(); + if (!page_size) + fprintf(stderr, "Unable to determine huge page size\n"), + exit(2); + if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2 + > page_size) + fprintf(stderr, "Impossible to run this test\n"), exit(2); + nr_pages_per_cpu = atol(argv[1]) * 1024*1024 / page_size / + nr_cpus; + if (!nr_pages_per_cpu) { + fprintf(stderr, "invalid MiB\n"); + fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); + } + bounces = atoi(argv[2]); + if (bounces <= 0) { + fprintf(stderr, "invalid bounces\n"); + fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); + } + nr_pages = nr_pages_per_cpu * nr_cpus; + huge_fd = open(argv[3], O_CREAT | O_RDWR, 0755); + if (huge_fd < 0) { + fprintf(stderr, "Open of %s failed", argv[3]); + perror("open"); + exit(1); + } + if (ftruncate(huge_fd, 0)) { + fprintf(stderr, "ftruncate %s to size 0 failed", argv[3]); + perror("ftruncate"); + exit(1); + } + printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n", + nr_pages, nr_pages_per_cpu); + return userfaultfd_stress(); +} + +#endif #else /* __NR_userfaultfd */ #warning "missing __NR_userfaultfd definition" diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c index 88d5e71be044..95dd14648ba5 100644 --- a/tools/usb/ffs-test.c +++ b/tools/usb/ffs-test.c @@ -22,7 +22,7 @@ /* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */ -#define _BSD_SOURCE /* for endian.h */ +#define _DEFAULT_SOURCE /* for endian.h */ #include <endian.h> #include <errno.h> @@ -110,16 +110,25 @@ static const struct { struct usb_functionfs_descs_head_v2 header; __le32 fs_count; __le32 hs_count; + __le32 ss_count; struct { struct usb_interface_descriptor intf; struct usb_endpoint_descriptor_no_audio sink; struct usb_endpoint_descriptor_no_audio source; } __attribute__((packed)) fs_descs, hs_descs; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio sink; + struct usb_ss_ep_comp_descriptor sink_comp; + struct usb_endpoint_descriptor_no_audio source; + struct usb_ss_ep_comp_descriptor source_comp; + } ss_descs; } __attribute__((packed)) descriptors = { .header = { .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC | - FUNCTIONFS_HAS_HS_DESC), + FUNCTIONFS_HAS_HS_DESC | + FUNCTIONFS_HAS_SS_DESC), .length = cpu_to_le32(sizeof descriptors), }, .fs_count = cpu_to_le32(3), @@ -171,6 +180,45 @@ static const struct { .bInterval = 1, /* NAK every 1 uframe */ }, }, + .ss_count = cpu_to_le32(5), + .ss_descs = { + .intf = { + .bLength = sizeof descriptors.fs_descs.intf, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .sink = { + .bLength = sizeof descriptors.hs_descs.sink, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), + }, + .sink_comp = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, + }, + .source = { + .bLength = sizeof descriptors.hs_descs.source, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 1, /* NAK every 1 uframe */ + }, + .source_comp = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, + }, + }, }; static size_t descs_to_legacy(void **legacy, const void *descriptors_v2) diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README index 831f49fea3ce..5eb2b6c7722b 100644 --- a/tools/usb/usbip/README +++ b/tools/usb/usbip/README @@ -4,10 +4,33 @@ # Copyright (C) 2011 matt mooney <mfm@muteddisk.com> # 2005-2008 Takahiro Hirofuchi +[Overview] +USB/IP protocol allows to pass USB device from server to client over the +network. Server is a machine which provides (shares) a USB device. Client is +a machine which uses USB device provided by server over the network. +The USB device may be either physical device connected to a server or +software entity created on a server using USB gadget subsystem. +Whole project consists of four parts: + + - usbip-vhci + A client side kernel module which provides a virtual USB Host Controller + and allows to import a USB device from a remote machine. + + - usbip-host (stub driver) + A server side module which provides a USB device driver which can be + bound to a physical USB device to make it exportable. + + - usbip-vudc + A server side module which provides a virtual USB Device Controller and allows + to export a USB device created using USB Gadget Subsystem. + + - usbip-utils + A set of userspace tools used to handle connection and management. + Used on both sides. [Requirements] - USB/IP device drivers - Found in the staging directory of the Linux kernel. + Found in the drivers/usb/usbip/ directory of the Linux kernel tree. - libudev >= 2.0 libudev library @@ -36,6 +59,10 @@ [Usage] +On a server side there are two entities which can be shared. +First of them is physical usb device connected to the machine. +To make it available below steps should be executed: + server:# (Physically attach your USB device.) server:# insmod usbip-core.ko @@ -52,6 +79,30 @@ - The USB device 1-2 is now exportable to other hosts! - Use `usbip unbind --busid 1-2' to stop exporting the device. +Second of shareable entities is USB Gadget created using USB Gadget Subsystem +on a server machine. To make it available below steps should be executed: + + server:# (Create your USB gadget) + - Currently the most preferable way of creating a new USB gadget + is ConfigFS Composite Gadget. Please refer to its documentation + for details. + - See vudc_server_example.sh for a short example of USB gadget creation + + server:# insmod usbip-core.ko + server:# insmod usbip-vudc.ko + - To create more than one instance of vudc use num module param + + server:# (Bind gadget to one of available vudc) + - Assign your new gadget to USB/IP UDC + - Using ConfigFS interface you may do this simply by: + server:# cd /sys/kernel/config/usb_gadget/<gadget_name> + server:# echo "usbip-vudc.0" > UDC + + server:# usbipd -D --device + - Start usbip daemon. + +To attach new device to client machine below commands should be used: + client:# insmod usbip-core.ko client:# insmod vhci-hcd.ko @@ -60,6 +111,8 @@ client:# usbip attach --remote <host> --busid 1-2 - Connect the remote USB device. + - When using vudc on a server side busid is really vudc instance name. + For example: usbip-vudc.0 client:# usbip port - Show virtual port status. @@ -192,6 +245,8 @@ Detach the imported device: - http://usbip.wiki.sourceforge.net/how-to-debug-usbip - usbip-host.ko must be bound to the target device. - See /proc/bus/usb/devices and find "Driver=..." lines of the device. + - Target USB gadget must be bound to vudc + (using USB gadget susbsys, not usbip bind command) - Shutdown firewall. - usbip now uses TCP port 3240. - Disable SELinux. diff --git a/tools/usb/usbip/vudc/vudc_server_example.sh b/tools/usb/usbip/vudc/vudc_server_example.sh new file mode 100755 index 000000000000..2736be64f203 --- /dev/null +++ b/tools/usb/usbip/vudc/vudc_server_example.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +################################################################################ +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to <http://unlicense.org/> +################################################################################ + +################################################################################ +# This is a sample script which shows how to use vUDC with ConfigFS gadgets +################################################################################ + +# Stop script on error +set -e + +################################################################################ +# Create your USB gadget +# You may use bare ConfigFS interface (as below) +# or libusbgx or gt toool +# Instead of ConfigFS gadgets you may use any of legacy gadgets. +################################################################################ +CONFIGFS_MOUNT_POINT="/sys/kernel/config" +GADGET_NAME="g1" +ID_VENDOR="0x1d6b" +ID_PRODUCT="0x0104" + +cd ${CONFIGFS_MOUNT_POINT}/usb_gadget +# Create a new USB gadget +mkdir ${GADGET_NAME} +cd ${GADGET_NAME} + +# This gadget contains one function - ACM (serial port over USB) +FUNC_DIR="functions/acm.ser0" +mkdir ${FUNC_DIR} + +# Just one configuration +mkdir configs/c.1 +ln -s ${FUNC_DIR} configs/c.1 + +# Set our gadget identity +echo ${ID_VENDOR} > idVendor +echo ${ID_PRODUCT} > idProduct + +################################################################################ +# Load vudc-module if vudc is not available +# You may change value of num param to get more than one vUDC instance +################################################################################ +[[ -d /sys/class/udc/usbip-vudc.0 ]] || modprobe usbip-vudc num=1 + +################################################################################ +# Bind gadget to our vUDC +# By default we bind to first one but you may change this if you would like +# to use more than one instance +################################################################################ +echo "usbip-vudc.0" > UDC + +################################################################################ +# Let's now run our usbip daemon in a USB device mode +################################################################################ +usbipd --device & + +################################################################################ +# Now your USB gadget is available using USB/IP protocol. +# To prepare your client, you should ensure that usbip-vhci module is inside +# your kernel. If it's not then you can load it: +# +# $ modprobe usbip-vhci +# +# To check availability of your gadget you may try to list devices exported +# on a remote server: +# +# $ modprobe usbip-vhci +# $ usbip list -r $SERVER_IP +# Exportable USB devices +# ====================== +# usbipd: info: request 0x8005(6): complete +# - 127.0.0.1 +# usbip-vudc.0: Linux Foundation : unknown product (1d6b:0104) +# : /sys/devices/platform/usbip-vudc.0 +# : (Defined at Interface level) (00/00/00) +# +# To attach this device to your client you may use: +# +# $ usbip attach -r $SERVER_IP -d usbip-vudc.0 +# +################################################################################ diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 93aadaf7ff63..006029456988 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile @@ -9,6 +9,8 @@ CC = $(CROSS_COMPILE)gcc CFLAGS = -Wall -Wextra -I../lib/ LDFLAGS = $(LIBS) +all: $(TARGETS) + $(TARGETS): $(LIBS) $(LIBS): @@ -20,3 +22,9 @@ $(LIBS): clean: $(RM) page-types slabinfo page_owner_sort make -C $(LIB_DIR) clean + +sbindir ?= /usr/sbin + +install: all + install -d $(DESTDIR)$(sbindir) + install -m 755 -p $(TARGETS) $(DESTDIR)$(sbindir) |