libceph: abstract message data

Group the types of message data into an abstract structure with a
type indicator and a union containing fields appropriate to the
type of data it represents.  Use this to represent the pages,
pagelist, bio, and trail in a ceph message.

Verify message data is of type NONE in ceph_msg_data_set_*()
routines.  Since information about message data of type NONE really
should not be interpreted, get rid of the other assertions in those
functions.

Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index fb2b18a..5860dd0 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -64,12 +64,55 @@
 	u32 required_features;
 };
 
-#define ceph_msg_has_pages(m)		((m)->p.pages != NULL)
-#define ceph_msg_has_pagelist(m)	((m)->l.pagelist != NULL)
+#define ceph_msg_has_pages(m)		((m)->p.type == CEPH_MSG_DATA_PAGES)
+#define ceph_msg_has_pagelist(m)	((m)->l.type == CEPH_MSG_DATA_PAGELIST)
 #ifdef CONFIG_BLOCK
-#define ceph_msg_has_bio(m)		((m)->b.bio != NULL)
+#define ceph_msg_has_bio(m)		((m)->b.type == CEPH_MSG_DATA_BIO)
 #endif /* CONFIG_BLOCK */
-#define ceph_msg_has_trail(m)		((m)->t.trail != NULL)
+#define ceph_msg_has_trail(m)		((m)->t.type == CEPH_MSG_DATA_PAGELIST)
+
+enum ceph_msg_data_type {
+	CEPH_MSG_DATA_NONE,	/* message contains no data payload */
+	CEPH_MSG_DATA_PAGES,	/* data source/destination is a page array */
+	CEPH_MSG_DATA_PAGELIST,	/* data source/destination is a pagelist */
+#ifdef CONFIG_BLOCK
+	CEPH_MSG_DATA_BIO,	/* data source/destination is a bio list */
+#endif /* CONFIG_BLOCK */
+};
+
+static __inline__ bool ceph_msg_data_type_valid(enum ceph_msg_data_type type)
+{
+	switch (type) {
+	case CEPH_MSG_DATA_NONE:
+	case CEPH_MSG_DATA_PAGES:
+	case CEPH_MSG_DATA_PAGELIST:
+#ifdef CONFIG_BLOCK
+	case CEPH_MSG_DATA_BIO:
+#endif /* CONFIG_BLOCK */
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct ceph_msg_data {
+	enum ceph_msg_data_type		type;
+	union {
+#ifdef CONFIG_BLOCK
+		struct {
+			struct bio	*bio_iter;	/* iterator */
+			struct bio	*bio;
+			unsigned int	bio_seg;	/* current seg in bio */
+		};
+#endif /* CONFIG_BLOCK */
+		struct {
+			struct page	**pages;	/* NOT OWNER. */
+			size_t		length;		/* total # bytes */
+			unsigned int	alignment;	/* first page */
+		};
+		struct ceph_pagelist	*pagelist;
+	};
+};
 
 /*
  * a single message.  it contains a header (src, dest, message type, etc.),
@@ -83,24 +126,12 @@
 	struct ceph_buffer *middle;
 
 	/* data payload */
-	struct {
-		struct page	**pages;	/* NOT OWNER. */
-		size_t		length;		/* # data bytes in array */
-		unsigned int	alignment;	/* first page */
-	} p;
-	struct {
-		struct ceph_pagelist	*pagelist;
-	} l;
+	struct ceph_msg_data	p;	/* pages */
+	struct ceph_msg_data	l;	/* pagelist */
 #ifdef CONFIG_BLOCK
-	struct {
-		struct bio	*bio_iter;	/* iterator */
-		struct bio	*bio;
-		unsigned int	bio_seg;	/* current seg in bio */
-	} b;
+	struct ceph_msg_data	b;	/* bio */
 #endif /* CONFIG_BLOCK */
-	struct {
-		struct ceph_pagelist *trail;	/* trailing part of data */
-	} t;
+	struct ceph_msg_data	t;	/* trail */
 
 	struct ceph_connection *con;
 	struct list_head list_head;	/* links for connection lists */