From: jbeulich@novell.com
Subject: update tmem interface to v1
Patch-mainline: n/a

--- head-2010-10-05.orig/include/xen/interface/tmem.h	2010-01-04 11:56:34.000000000 +0100
+++ head-2010-10-05/include/xen/interface/tmem.h	2010-10-06 12:12:59.000000000 +0200
@@ -29,6 +29,9 @@
 
 #include "xen.h"
 
+/* version of ABI */
+#define TMEM_SPEC_VERSION          1
+
 /* Commands to HYPERVISOR_tmem_op() */
 #define TMEM_CONTROL               0
 #define TMEM_NEW_POOL              1
@@ -75,10 +78,12 @@
 /* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
 #define TMEM_POOL_PERSIST          1
 #define TMEM_POOL_SHARED           2
+#define TMEM_POOL_PRECOMPRESSED    4
 #define TMEM_POOL_PAGESIZE_SHIFT   4
 #define TMEM_POOL_PAGESIZE_MASK  0xf
 #define TMEM_POOL_VERSION_SHIFT   24
 #define TMEM_POOL_VERSION_MASK  0xff
+#define TMEM_POOL_RESERVED_BITS  0x00ffff00
 
 /* Bits for client flags (save/restore) */
 #define TMEM_CLIENT_COMPRESS       1
@@ -106,12 +111,12 @@ struct tmem_op {
             uint32_t cli_id;
             uint32_t arg1;
             uint32_t arg2;
-            uint64_t arg3;
+            uint64_t oid[3];
             tmem_cli_va_t buf;
         } ctrl; /* for cmd == TMEM_CONTROL */
         struct {
             
-            uint64_t object;
+            uint64_t oid[3];
             uint32_t index;
             uint32_t tmem_offset;
             uint32_t pfn_offset;
@@ -126,9 +131,8 @@ DEFINE_XEN_GUEST_HANDLE(tmem_op_t);
 struct tmem_handle {
     uint32_t pool_id;
     uint32_t index;
-    uint64_t oid;
+    uint64_t oid[3];
 };
-
 #endif
 
 #endif /* __XEN_PUBLIC_TMEM_H__ */
--- head-2010-10-05.orig/mm/precache.c	2010-10-08 16:25:45.000000000 +0200
+++ head-2010-10-05/mm/precache.c	2010-10-11 10:58:42.000000000 +0200
@@ -31,16 +31,57 @@
  */
 
 #include <linux/precache.h>
+#include <linux/exportfs.h>
 #include <linux/module.h>
 #include "tmem.h"
 
 static int precache_auto_allocate; /* set to 1 to auto_allocate */
 
+union precache_filekey {
+	struct tmem_oid oid;
+	u32 fh[0];
+};
+
+/*
+ * If the filesystem uses exportable filehandles, use the filehandle as
+ * the key, else use the inode number.
+ */
+static int precache_get_key(struct inode *inode, union precache_filekey *key)
+{
+#define PRECACHE_KEY_MAX (sizeof(key->oid) / sizeof(*key->fh))
+	struct super_block *sb = inode->i_sb;
+
+	memset(key, 0, sizeof(key));
+	if (sb->s_export_op) {
+		int (*fhfn)(struct dentry *, __u32 *fh, int *, int);
+
+		fhfn = sb->s_export_op->encode_fh;
+		if (fhfn) {
+			struct dentry *d;
+			int ret, maxlen = PRECACHE_KEY_MAX;
+
+			d = list_first_entry(&inode->i_dentry,
+					     struct dentry, d_alias);
+			ret = fhfn(d, key->fh, &maxlen, 0);
+			if (ret < 0)
+				return ret;
+			if (ret >= 255 || maxlen > PRECACHE_KEY_MAX)
+				return -EPERM;
+			if (maxlen > 0)
+				return 0;
+		}
+	}
+	key->oid.oid[0] = inode->i_ino;
+	key->oid.oid[1] = inode->i_generation;
+	return 0;
+#undef PRECACHE_KEY_MAX
+}
+
 int precache_put(struct address_space *mapping, unsigned long index,
 		 struct page *page)
 {
 	u32 tmem_pool = mapping->host->i_sb->precache_poolid;
-	u64 obj = (unsigned long) mapping->host->i_ino;
+	union precache_filekey key;
 	u32 ind = (u32) index;
 	unsigned long mfn = pfn_to_mfn(page_to_pfn(page));
 	int ret;
@@ -56,53 +97,53 @@ int precache_put(struct address_space *m
 			mapping->host->i_sb->s_id, tmem_pool);
 		mapping->host->i_sb->precache_poolid = tmem_pool;
 	}
-	if (ind != index)
+	if (ind != index || precache_get_key(mapping->host, &key))
 		return 0;
 	mb(); /* ensure page is quiescent; tmem may address it with an alias */
-	return tmem_put_page(tmem_pool, obj, ind, mfn);
+	return tmem_put_page(tmem_pool, key.oid, ind, mfn);
 }
 
 int precache_get(struct address_space *mapping, unsigned long index,
 		 struct page *empty_page)
 {
 	u32 tmem_pool = mapping->host->i_sb->precache_poolid;
-	u64 obj = (unsigned long) mapping->host->i_ino;
+	union precache_filekey key;
 	u32 ind = (u32) index;
 	unsigned long mfn = pfn_to_mfn(page_to_pfn(empty_page));
 
 	if ((s32)tmem_pool < 0)
 		return 0;
-	if (ind != index)
+	if (ind != index || precache_get_key(mapping->host, &key))
 		return 0;
 
-	return tmem_get_page(tmem_pool, obj, ind, mfn);
+	return tmem_get_page(tmem_pool, key.oid, ind, mfn);
 }
 EXPORT_SYMBOL(precache_get);
 
 int precache_flush(struct address_space *mapping, unsigned long index)
 {
 	u32 tmem_pool = mapping->host->i_sb->precache_poolid;
-	u64 obj = (unsigned long) mapping->host->i_ino;
+	union precache_filekey key;
 	u32 ind = (u32) index;
 
 	if ((s32)tmem_pool < 0)
 		return 0;
-	if (ind != index)
+	if (ind != index || precache_get_key(mapping->host, &key))
 		return 0;
 
-	return tmem_flush_page(tmem_pool, obj, ind);
+	return tmem_flush_page(tmem_pool, key.oid, ind);
 }
 EXPORT_SYMBOL(precache_flush);
 
 int precache_flush_inode(struct address_space *mapping)
 {
 	u32 tmem_pool = mapping->host->i_sb->precache_poolid;
-	u64 obj = (unsigned long) mapping->host->i_ino;
+	union precache_filekey key;
 
-	if ((s32)tmem_pool < 0)
+	if ((s32)tmem_pool < 0 || precache_get_key(mapping->host, &key))
 		return 0;
 
-	return tmem_flush_object(tmem_pool, obj);
+	return tmem_flush_object(tmem_pool, key.oid);
 }
 EXPORT_SYMBOL(precache_flush_inode);
 
--- head-2010-10-05.orig/mm/preswap.c	2010-08-24 11:19:44.000000000 +0200
+++ head-2010-10-05/mm/preswap.c	2010-10-06 13:08:11.000000000 +0200
@@ -46,7 +46,8 @@ const unsigned long preswap_zero = 0, pr
  */
 #define SWIZ_BITS		4
 #define SWIZ_MASK		((1 << SWIZ_BITS) - 1)
-#define oswiz(_type, _ind)	((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
+#define oswiz(_type, _ind)	((struct tmem_oid){ \
+	.oid[0] = (_type << SWIZ_BITS) | (_ind & SWIZ_MASK) })
 #define iswiz(_ind)		(_ind >> SWIZ_BITS)
 
 /*
--- head-2010-10-05.orig/mm/tmem.h	2010-08-24 11:19:44.000000000 +0200
+++ head-2010-10-05/mm/tmem.h	2010-10-06 14:27:10.000000000 +0200
@@ -14,71 +14,58 @@
 #define TMEM_POOL_MIN_PAGESHIFT   12
 #define TMEM_POOL_PAGEORDER       (PAGE_SHIFT - TMEM_POOL_MIN_PAGESHIFT)
 
-extern int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, u64 object, u32 index,
+struct tmem_pool_uuid {
+	u64 lo;
+	u64 hi;
+};
+
+struct tmem_oid {
+	u64 oid[3];
+};
+
+extern int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid, u32 index,
 	unsigned long gmfn, u32 tmem_offset, u32 pfn_offset, u32 len);
-extern int xen_tmem_new_pool(u32 tmem_cmd, u64 uuid_lo, u64 uuid_hi, u32 flags);
+extern int xen_tmem_new_pool(struct tmem_pool_uuid, u32 flags);
 
-static inline int tmem_put_page(u32 pool_id, u64 object, u32 index,
+static inline int tmem_put_page(u32 pool_id, struct tmem_oid oid, u32 index,
 	unsigned long gmfn)
 {
-	return xen_tmem_op(TMEM_PUT_PAGE, pool_id, object, index,
+	return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index,
 		gmfn, 0, 0, 0);
 }
 
-static inline int tmem_get_page(u32 pool_id, u64 object, u32 index,
+static inline int tmem_get_page(u32 pool_id, struct tmem_oid oid, u32 index,
 	unsigned long gmfn)
 {
-	return xen_tmem_op(TMEM_GET_PAGE, pool_id, object, index,
+	return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index,
 		gmfn, 0, 0, 0);
 }
 
-static inline int tmem_flush_page(u32 pool_id, u64 object, u32 index)
+static inline int tmem_flush_page(u32 pool_id, struct tmem_oid oid, u32 index)
 {
-	return xen_tmem_op(TMEM_FLUSH_PAGE, pool_id, object, index,
+	return xen_tmem_op(TMEM_FLUSH_PAGE, pool_id, oid, index,
 		0, 0, 0, 0);
 }
 
-static inline int tmem_flush_object(u32 pool_id, u64 object)
+static inline int tmem_flush_object(u32 pool_id, struct tmem_oid oid)
 {
-	return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, object, 0, 0, 0, 0, 0);
+	return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
 }
 
 static inline int tmem_new_pool(u64 uuid_lo, u64 uuid_hi, u32 flags)
 {
+	struct tmem_pool_uuid uuid = { .lo = uuid_lo, .hi = uuid_hi };
+
 	BUILD_BUG_ON((TMEM_POOL_PAGEORDER < 0) ||
 		(TMEM_POOL_PAGEORDER >= TMEM_POOL_PAGESIZE_MASK));
 	flags |= TMEM_POOL_PAGEORDER << TMEM_POOL_PAGESIZE_SHIFT;
-	return xen_tmem_new_pool(TMEM_NEW_POOL, uuid_lo, uuid_hi, flags);
+	return xen_tmem_new_pool(uuid, flags);
 }
 
 static inline int tmem_destroy_pool(u32 pool_id)
 {
-	return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, 0, 0, 0, 0, 0, 0);
+	static const struct tmem_oid oid = {};
+
+	return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
 }
-#else
-struct tmem_op {
-	u32 cmd;
-	s32 pool_id; /* private > 0; shared < 0; 0 is invalid */
-	union {
-		struct {  /* for cmd == TMEM_NEW_POOL */
-			u64 uuid[2];
-			u32 flags;
-		} new;
-		struct {  /* for cmd == TMEM_CONTROL */
-			u32 subop;
-			u32 cli_id;
-			u32 arg1;
-			u32 arg2;
-			void *buf;
-		} ctrl;
-		struct {
-			u64 object;
-			u32 index;
-			u32 tmem_offset;
-			u32 pfn_offset;
-			u32 len;
-			unsigned long pfn;  /* page frame */
-		} gen;
-	} u;
-};
 #endif
--- head-2010-10-05.orig/mm/tmem-xen.c	2009-06-23 09:28:21.000000000 +0200
+++ head-2010-10-05/mm/tmem-xen.c	2010-10-06 14:27:25.000000000 +0200
@@ -7,8 +7,9 @@
 #include <linux/types.h>
 #include <xen/interface/xen.h>
 #include <asm/hypervisor.h>
+#include "tmem.h"
 
-int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, u64 object, u32 index,
+int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid oid, u32 index,
 	unsigned long gmfn, u32 tmem_offset, u32 pfn_offset, u32 len)
 {
 	struct tmem_op op;
@@ -16,7 +17,8 @@ int xen_tmem_op(u32 tmem_cmd, u32 tmem_p
 
 	op.cmd = tmem_cmd;
 	op.pool_id = tmem_pool;
-	op.u.gen.object = object;
+	BUILD_BUG_ON(sizeof(op.u.gen.oid) != sizeof(oid.oid));
+	memcpy(op.u.gen.oid, oid.oid, sizeof(op.u.gen.oid));
 	op.u.gen.index = index;
 	op.u.gen.tmem_offset = tmem_offset;
 	op.u.gen.pfn_offset = pfn_offset;
@@ -26,15 +28,27 @@ int xen_tmem_op(u32 tmem_cmd, u32 tmem_p
 	return rc;
 }
 
-int xen_tmem_new_pool(uint32_t tmem_cmd, uint64_t uuid_lo,
-	uint64_t uuid_hi, uint32_t flags)
+int xen_tmem_new_pool(struct tmem_pool_uuid uuid, uint32_t flags)
 {
 	struct tmem_op op;
 	int rc = 0;
 
-	op.cmd = tmem_cmd;
-	op.u.new.uuid[0] = uuid_lo;
-	op.u.new.uuid[1] = uuid_hi;
+	op.cmd = TMEM_NEW_POOL;
+	op.u.new.uuid[0] = uuid.lo;
+	op.u.new.uuid[1] = uuid.hi;
+#ifdef TMEM_SPEC_VERSION
+	switch (flags >> TMEM_POOL_VERSION_SHIFT) {
+	case 0:
+		flags |= TMEM_SPEC_VERSION << TMEM_POOL_VERSION_SHIFT;
+		break;
+	case TMEM_SPEC_VERSION:
+		break;
+	default:
+		WARN(1, "TMEM: Bogus version %u, expecting %u\n",
+		     flags >> TMEM_POOL_VERSION_SHIFT, TMEM_SPEC_VERSION);
+		return -ENOSYS;
+	}
+#endif
 	op.u.new.flags = flags;
 	rc = HYPERVISOR_tmem_op(&op);
 	return rc;
