From: Li Dongyang <lidongyang@novell.com>
Subject: blkif: support discard
References: fate#309305
Patch-mainline: Never, SUSE-Xen specific

Now we use BLKIF_OP_DISCARD and add blkif_request_discard to blkif_request union,
the patch is taken from Owen Smith and Konrad, Thanks

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Owen Smith <owen.smith@citrix.com>
Signed-off-by: Li Dongyang <lidongyang@novell.com>

--- a/include/xen/blkif.h
+++ b/include/xen/blkif.h
@@ -33,6 +33,11 @@ struct blkif_common_request {
 	char dummy;
 };
 
+union __attribute__((transparent_union)) blkif_union {
+	struct blkif_request *generic;
+	struct blkif_request_discard *discard;
+};
+
 /* i386 protocol version */
 #pragma pack(push, 4)
 struct blkif_x86_32_request {
@@ -43,7 +48,18 @@ struct blkif_x86_32_request {
 	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
 	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 };
-typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+struct blkif_x86_32_discard {
+	uint8_t        operation;    /* BLKIF_OP_DISCARD                     */
+	uint8_t        reserved;     /*                                      */
+	blkif_vdev_t   handle;       /* same as for read/write requests      */
+	uint64_t       id;           /* private guest value, echoed in resp  */
+	blkif_sector_t sector_number;/* start sector idx on disk             */
+	uint64_t       nr_sectors;   /* number of contiguous sectors         */
+};
+union blkif_x86_32_union {
+	struct blkif_x86_32_request generic;
+	struct blkif_x86_32_discard discard;
+};
 #pragma pack(pop)
 
 /* x86_64 protocol version */
@@ -55,14 +71,25 @@ struct blkif_x86_64_request {
 	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
 	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 };
-typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+struct blkif_x86_64_discard {
+	uint8_t        operation;    /* BLKIF_OP_DISCARD                     */
+	uint8_t        reserved;     /*                                      */
+	blkif_vdev_t   handle;       /* sane as for read/write requests      */
+	uint64_t       __attribute__((__aligned__(8))) id;
+	blkif_sector_t sector_number;/* start sector idx on disk             */
+	uint64_t       nr_sectors;   /* number of contiguous sectors         */
+};
+union blkif_x86_64_union {
+	struct blkif_x86_64_request generic;
+	struct blkif_x86_64_discard discard;
+};
 
 #define blkif_native_sring blkif_sring
 DEFINE_RING_TYPES(blkif_common, struct blkif_common_request,
 		  struct blkif_response);
-DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request,
-		  struct blkif_response __attribute__((__packed__)));
-DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request,
+DEFINE_RING_TYPES(blkif_x86_32, union blkif_x86_32_union,
+		  struct blkif_response __packed);
+DEFINE_RING_TYPES(blkif_x86_64, union blkif_x86_64_union,
 		  struct blkif_response);
 
 union blkif_back_rings {
@@ -79,34 +106,62 @@ enum blkif_protocol {
 	BLKIF_PROTOCOL_X86_64 = 3,
 };
 
-static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+static void inline blkif_get_x86_32_req(union blkif_union dst,
+					const union blkif_x86_32_union *src)
 {
-	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-	dst->operation = src->operation;
-	dst->nr_segments = src->nr_segments;
-	dst->handle = src->handle;
-	dst->id = src->id;
-	dst->sector_number = src->sector_number;
+#ifdef __i386__
+	memcpy(dst.generic, src, sizeof(*dst.generic));
+#else
+	unsigned int i, n;
+
+	dst.generic->operation = src->generic.operation;
+	dst.generic->nr_segments = src->generic.nr_segments;
+	dst.generic->handle = src->generic.handle;
+	dst.generic->id = src->generic.id;
+	dst.generic->sector_number = src->generic.sector_number;
 	barrier();
-	if (n > dst->nr_segments)
-		n = dst->nr_segments;
-	for (i = 0; i < n; i++)
-		dst->seg[i] = src->seg[i];
+	switch (__builtin_expect(dst.generic->operation, BLKIF_OP_READ)) {
+	default:
+		n = min_t(unsigned int, dst.generic->nr_segments,
+			  BLKIF_MAX_SEGMENTS_PER_REQUEST);
+		for (i = 0; i < n; i++)
+			dst.generic->seg[i] = src->generic.seg[i];
+		break;
+	case BLKIF_OP_DISCARD:
+		/* All fields up to sector_number got copied above already. */
+		dst.discard->nr_sectors = src->discard.nr_sectors;
+		break;
+	}
+#endif
 }
 
-static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+static void inline blkif_get_x86_64_req(union blkif_union dst,
+					const union blkif_x86_64_union *src)
 {
-	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-	dst->operation = src->operation;
-	dst->nr_segments = src->nr_segments;
-	dst->handle = src->handle;
-	dst->id = src->id;
-	dst->sector_number = src->sector_number;
+#ifdef __x86_64__
+	memcpy(dst.generic, src, sizeof(*dst.generic));
+#else
+	unsigned int i, n;
+
+	dst.generic->operation = src->generic.operation;
+	dst.generic->nr_segments = src->generic.nr_segments;
+	dst.generic->handle = src->generic.handle;
+	dst.generic->id = src->generic.id;
+	dst.generic->sector_number = src->generic.sector_number;
 	barrier();
-	if (n > dst->nr_segments)
-		n = dst->nr_segments;
-	for (i = 0; i < n; i++)
-		dst->seg[i] = src->seg[i];
+	switch (__builtin_expect(dst.generic->operation, BLKIF_OP_READ)) {
+	default:
+		n = min_t(unsigned int, dst.generic->nr_segments,
+			  BLKIF_MAX_SEGMENTS_PER_REQUEST);
+		for (i = 0; i < n; i++)
+			dst.generic->seg[i] = src->generic.seg[i];
+		break;
+	case BLKIF_OP_DISCARD:
+		/* All fields up to sector_number got copied above already. */
+		dst.discard->nr_sectors = src->discard.nr_sectors;
+		break;
+	}
+#endif
 }
 
 #endif /* __XEN_BLKIF_H__ */
