$(call RPM_TO_USERSPACE,./sbin/fdisk,$(RPM_DIR)/util-linux-ng)
$(call RPM_TO_USERSPACE,./sbin/losetup,$(RPM_DIR)/util-linux-ng)
$(call RPM_TO_USERSPACE,./sbin/pivot_root,$(RPM_DIR)/util-linux-ng)
- $(call RPM_TO_USERSPACE,./sbin/swapon,$(RPM_DIR)/util-linux-ng)
- $(call RPM_TO_USERSPACE,./sbin/swapoff,$(RPM_DIR)/util-linux-ng)
- $(call RPM_TO_USERSPACE,./sbin/mkswap,$(RPM_DIR)/util-linux-ng)
$(call RPM_TO_USERSPACE,./usr/bin/hexdump,$(RPM_DIR)/util-linux-ng)
$(call RPM_TO_USERSPACE,./usr/bin/flock,$(RPM_DIR)/util-linux-ng)
$(call RPM_TO_USERSPACE,./usr/bin/time,$(RPM_DIR)/time)
LDLIBS="-L$(shell pwd)/userspace/$(LIBSDIR)" $(MAKE) -j$$(($(NCPUS) * 2)) $(MFLAGS) -C tools/drfb_test
$(INSTALL_PROG) tools/drfb_test/dfbtest_fillrect userspace/usr/bin/
+.PHONY: xtt-tools-install-eatmem
+xtt-tools-install-eatmem:
+ LDLIBS="-L$(shell pwd)/userspace/$(LIBSDIR)" $(MAKE) -j$$(($(NCPUS) * 2)) $(MFLAGS) -C tools/eatmem
+ $(call RPM_TO_USERSPACE,./sbin/mkswap,$(RPM_DIR)/util-linux-ng)
+ $(call RPM_TO_USERSPACE,./sbin/swapon,$(RPM_DIR)/util-linux-ng)
+ $(call RPM_TO_USERSPACE,./sbin/swapoff,$(RPM_DIR)/util-linux-ng)
+ $(INSTALL_PROG) tools/eatmem/eatmem userspace/usr/bin/
+
.PHONY: xtt-tools-install
-xtt-tools-install:
+xtt-tools-install: xtt-tools-install-eatmem
LDLIBS="-L$(shell pwd)/userspace/$(LIBSDIR)" $(MAKE) -j$$(($(NCPUS) * 2)) $(MFLAGS) -C tools
$(INSTALL_PROG) tools/ssh_support/ssh-shadowgen userspace/usr/sbin/
$(INSTALL_SCRIPT) tools/ssh_support/sshd_server userspace/usr/bin/
$(INSTALL_PROG) tools/read_intr/read_intr userspace/usr/bin/
$(INSTALL_PROG) tools/debug/fb_test userspace/usr/bin/
$(INSTALL_PROG) tools/crashme/crashme userspace/usr/bin/
- $(INSTALL_PROG) tools/eatmem/eatmem userspace/usr/bin/
$(INSTALL_PROG) tools/discard_io/discard_io userspace/usr/bin/
fio/fio: fio/fio
--- /dev/null
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <xen/xen.h>
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/tmem.h>
+
+
+#define TMEM_TEST "0.1"
+
+MODULE_AUTHOR("Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>");
+MODULE_DESCRIPTION("tmem_test");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(TMEM_TEST);
+
+static bool shared __read_mostly = true;
+module_param(shared, bool, S_IRUGO);
+
+#define MAX_PAGES 20
+struct tmem_oid {
+ u64 oid[3];
+};
+struct tmem_pool_uuid {
+ u64 lo;
+ u64 hi;
+};
+struct _arg {
+ int flags;
+ int pool;
+ int rc;
+ struct tmem_oid oid;
+ struct tmem_pool_uuid uuid;
+};
+
+
+#define TMEM_CONTROL 0
+#define TMEM_NEW_POOL 1
+#define TMEM_DESTROY_POOL 2
+#define TMEM_NEW_PAGE 3
+#define TMEM_PUT_PAGE 4
+#define TMEM_GET_PAGE 5
+
+#define TMEM_FLUSH_PAGE 6
+#define TMEM_FLUSH_OBJECT 7
+#define TMEM_READ 8
+#define TMEM_WRITE 9
+#define TMEM_XCHG 10
+
+/* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
+#define TMEM_POOL_PERSIST 1
+#define TMEM_POOL_SHARED 2
+#define TMEM_POOL_PAGESIZE_SHIFT 4
+#define TMEM_VERSION_SHIFT 24
+
+#define EFROZEN 1000
+#define EEMPTY 1001
+static inline int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid oid,
+ u32 index, unsigned long gmfn)
+{
+ struct tmem_op op;
+ int rc = 0;
+
+ op.cmd = tmem_cmd;
+ op.pool_id = tmem_pool;
+ op.u.gen.oid[0] = oid.oid[0];
+ op.u.gen.oid[1] = oid.oid[1];
+ op.u.gen.oid[2] = oid.oid[2];
+ op.u.gen.index = index;
+ op.u.gen.tmem_offset = 0;
+ op.u.gen.pfn_offset = 0;
+ op.u.gen.len = 0;
+ set_xen_guest_handle(op.u.gen.gmfn, (void *)gmfn);
+ rc = HYPERVISOR_tmem_op(&op);
+ return rc;
+}
+static int xen_tmem_new_pool(struct tmem_pool_uuid uuid, u32 flags, unsigned long pagesize)
+{
+ struct tmem_op op;
+ int rc = 0, pageshift;
+
+ for (pageshift = 0; pagesize != 1; pageshift++)
+ pagesize >>= 1;
+ flags |= (pageshift - 12) << TMEM_POOL_PAGESIZE_SHIFT;
+ flags |= TMEM_SPEC_VERSION << TMEM_VERSION_SHIFT;
+ op.cmd = TMEM_NEW_POOL;
+ op.u.new.uuid[0] = uuid.lo;
+ op.u.new.uuid[1] = uuid.hi;
+ op.u.new.flags = flags;
+ rc = HYPERVISOR_tmem_op(&op);
+ return rc;
+}
+
+/* xen generic tmem ops */
+
+static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid,
+ u32 index, unsigned long pfn)
+{
+ unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn;
+
+ return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index, gmfn);
+}
+static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid,
+ u32 index, unsigned long pfn)
+{
+ unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn;
+
+ return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index, gmfn);
+}
+
+static int xen_tmem_destroy_pool(u32 pool_id)
+{
+ struct tmem_oid oid = { { 0 } };
+
+ return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0);
+}
+
+static int thread(void *_arg)
+{
+ struct _arg *arg = (struct _arg *)_arg;
+ struct page *a[MAX_PAGES];
+ struct tmem_oid oid[MAX_PAGES];
+ unsigned int i, j;
+ int rc = 0;
+
+ if (!_arg) {
+ pr_warn("No arguments passed in thread!\n");
+ return -EINVAL;
+ }
+ pr_info("pool=%d, flags=%d, uuid=%lx:%lx\n", arg->pool, arg->flags,
+ (unsigned long)arg->uuid.lo, (unsigned long)arg->uuid.hi);
+ arg->rc = 0;
+ do {
+ for (j = 0, i = 0;i < MAX_PAGES; i++, j++) {
+ a[i] = alloc_page(GFP_KERNEL);
+ if (!a[i])
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout_interruptible(HZ);
+ for (i = 0; i < j; i++) {
+ unsigned long *addr = page_address(a[i]);
+ if (addr) {
+ memset(addr, 0xc2, PAGE_SIZE);
+ }
+ oid[i].oid[0] = arg->oid.oid[0];
+ oid[i].oid[1] = arg->oid.oid[1];
+ oid[i].oid[2] = (u64)addr;
+ }
+again:
+ /* Do the tmem operation. */
+ for (i = 0; i < j; i++) {
+ struct page *page = a[i];
+ unsigned long pfn = page_to_pfn(page);
+
+ rc = xen_tmem_put_page(arg->pool, oid[i], 0, pfn);
+
+ if (rc != 1) {
+ pr_warn("pool=%d i=%d PUT PFN=0x%lx, rc=%d!\n", arg->pool,i, pfn, rc);
+ if (rc == -EFROZEN || rc == -ENOMEM) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout_interruptible(HZ);
+ goto again;
+ }
+ arg->rc = rc;
+ break;
+ }
+ }
+ if (rc != 1)
+ break;
+ rc = 0;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout_interruptible(HZ);
+ for (i = 0; i < j; i++) {
+ struct page *page = a[i];
+ unsigned long pfn = page_to_pfn(page);
+ unsigned long *addr = page_address(page);
+
+ rc = xen_tmem_get_page(arg->pool, oid[i], 0, pfn);
+
+ if (rc != 1) {
+ pr_warn("pool=%d i=%d GET PFN=0x%lx, rc=%d!\n", arg->pool, i, pfn, rc);
+ arg->rc = rc;
+ break;
+ }
+ if (addr) {
+ unsigned long v;
+ for (v = 0; v < PAGE_SIZE / sizeof(*addr); v += sizeof(*addr))
+ {
+ if (addr[v] != 0xc2c2c2c2c2c2c2c2) {
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, addr, PAGE_SIZE);
+ pr_warn("pool=%d i=%d UUID=%lx:%lx failed! Have: [0x%lx]\n", arg->pool, i,
+ (unsigned long)arg->uuid.lo, (unsigned long)arg->uuid.hi,
+ addr[v]);
+ BUG();
+ }
+ }
+ }
+ }
+ if (rc != 1)
+ break;
+ rc = 0;
+ for (i = 0; i< MAX_PAGES; i++) {
+ if (a[i])
+ __free_page(a[i]);
+ a[i] = NULL;
+ }
+ } while (!kthread_should_stop());
+ return rc;
+}
+#define MAX_THREADS 4
+static struct task_struct *t[MAX_THREADS];
+static struct _arg a[MAX_THREADS];
+
+static int __init tmem_test_init(void)
+{
+ unsigned int i;
+ int rc;
+
+ /* First is TMEM_POOL_PERSIST */
+ i = 0;
+ a[i].uuid.lo = 0;
+ a[i].uuid.hi = 0;
+ a[i].flags = TMEM_POOL_PERSIST;
+ a[i].pool = -1;
+ a[i].oid.oid[0] = 0x1000+i;
+
+ if (shared) {
+ i++;
+ a[i].uuid.lo = 0xdeadbeef;
+ a[i].uuid.hi = 0;
+ a[i].flags = TMEM_POOL_SHARED;
+ a[i].pool = -1;
+ a[i].oid.oid[0] = 0x1000+i;
+
+ i++;
+ a[i].uuid.lo = 0xdeadbeef;
+ a[i].uuid.hi = 0;
+ a[i].flags = TMEM_POOL_SHARED;
+ a[i].pool = -1;
+ a[i].oid.oid[0] = 0x1000+i;
+ } else {
+ i++;
+ a[i].oid.oid[0] = 0;
+ a[i].pool = -1;
+ i++;
+ a[i].oid.oid[0] = 0;
+ a[i].pool = -1;
+ }
+ i++;
+ a[i].uuid.lo = 0xbad;
+ a[i].uuid.hi = 0xf00d;
+ a[i].flags = 0;
+ a[i].pool = -1;
+ a[i].oid.oid[0] = 0x1000+i;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ a[i].rc = 0;
+ if (!a[i].oid.oid[0])
+ continue;
+
+ rc = xen_tmem_new_pool(a[i].uuid, a[i].flags, PAGE_SIZE);
+ if (rc < 0) {
+ pr_warn("%d UUID=%lx:%lx flags=0x%x failed with rc=%d\n",
+ i, (unsigned long)a[i].uuid.lo, (unsigned long)a[i].uuid.hi, a[i].flags, rc);
+ rc = -EINVAL;
+ goto exit;
+ }
+ a[i].pool = rc;
+ }
+ pr_info("Pools allocated.\n");
+ for (i = 0; i < MAX_THREADS; i++) {
+ if (!a[i].oid.oid[0])
+ continue;
+ t[i] = kthread_run(thread, &a[i], "tmem_test");
+ if (!t[i]) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ }
+
+ pr_info("Threads running.\n");
+ return 0;
+exit:
+ for (i = 0; i < MAX_THREADS; i++)
+ {
+ if (!a[i].oid.oid[0])
+ continue;
+ if (t[i])
+ kthread_stop(t[i]);
+ }
+ /* Two of the pools are shared so we need to stop workers first.*/
+ for (i = 0; i < MAX_THREADS; i++)
+ if (a[i].pool != -1)
+ xen_tmem_destroy_pool(a[i].pool);
+ return rc;
+}
+static void __exit tmem_test_exit(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ if (!a[i].oid.oid[0])
+ continue;
+ if (t[i] && a[i].rc == 0)
+ kthread_stop(t[i]);
+ }
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ if (a[i].pool != -1)
+ xen_tmem_destroy_pool(a[i].pool);
+ }
+}
+module_init(tmem_test_init);
+module_exit(tmem_test_exit);
--- /dev/null
+#!/bin/bash
+
+ . /etc/init.d/functions
+
+SWAP_SIZE="+768M"
+FS_SIZE="+256M"
+FIO_TEST="/tmp/read.fio"
+
+tmem_check()
+{
+ local _rc=$1
+ if [ $_rc -ne 0 ]; then
+ echo "Failed with $_rc"
+ exit $rc
+ fi
+}
+tmem_setup ()
+{
+ local disk=$1
+ echo "Erasing $disk"
+
+ (echo o; echo w) | fdisk $disk
+ rc=$?
+ tmem_check $rc
+ echo "-----------------------------------"
+ echo "Creating swap fs with $SWAP_SIZE"
+ (echo n; echo p;echo 1; echo 1; echo $SWAP_SIZE; echo w) | fdisk $disk
+ rc=$?
+ tmem_check $rc
+ echo "-----------------------------------"
+ echo "Creating fs partition"
+ echo -e "n\np\n2\n\n\nw" | fdisk $disk
+ #(echo n; echo p; echo 2; echo 1; echo $FS_SIZE; echo w) | fdisk $disk
+ rc=$?
+ tmem_check $rc
+
+ sync
+ sleep 5
+ echo "-----------------------------------"
+ echo "Formating swap partition"
+
+ mkswap ${disk}1
+ rc=$?
+ tmem_check $rc
+
+ echo "-----------------------------------"
+ echo "Formating FS partition"
+ mkfs.ext3 ${disk}2
+ rc=$?
+ tmem_check $rc
+
+ echo "sync"
+
+ sync
+
+
+ mkdir /TEST
+ mount ${disk}2 /TEST
+ rc=$?
+ tmem_check $rc
+
+ swapon ${disk}1
+ rc=$?
+ tmem_check $rc
+
+ return 0;
+}
+
+tmem_missing()
+{
+ echo "Missing binaries. Disabling tmem tests."
+ exit 1;
+}
+
+which mkswap 1>/dev/null 2>/dev/null
+if [ $? -eq 1 ]; then
+ tmem_missing
+fi
+which swapon 1>/dev/null 2>/dev/null
+if [ $? -eq 1 ]; then
+ tmem_missing
+fi
+
+# This should be figured by some boot parameters, but for now just assume
+# xvda
+tmem_setup /dev/xvda
+rc=$?
+if [ $rc -ne 0 ]; then
+ echo "Test failed with $rc!"
+ exit $rc
+fi
+modprobe tmem
+# Now the kernel will start pushing pages in swap..
+echo "Kicking off eatmem."
+
+echo "while (true); do eatmem 100M 10; echo '+'; done" > /tmp/tmem.sh
+
+echo "[/TEST/test]" > $FIO_TEST
+echo "buffered=1" >> $FIO_TEST
+echo "rw=read" >> $FIO_TEST
+echo "runtime=360" >> $FIO_TEST
+echo "size=250M" >> $FIO_TEST
+echo "directory=/TEST" >> $FIO_TEST
+
+chmod 755 /tmp/tmem.sh
+nohup bash /tmp/tmem.sh &
+nohup bash fio $FIO_TEST &
+
+modprobe tmem-test