References: FATE#316071
Subject: libxl: add option for discard support to xl disk configuration

Handle new boolean option discard/no-discard for disk configuration. It
is supposed to disable discard support if file based backing storage was
intentionally created non-sparse to avoid fragmentation of the file.

The option intended for the backend driver. A new boolean property
"discard-enable" is written to the backend node. An upcoming patch for
qemu will make use of this property. The kernel blkback driver may be
updated as well to disable discard for phy based backing storage.

This change does not break ABI. Instead of adding a new member
discard_enable to struct libxl_device_disk the existing readwrite member
is reused.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 docs/misc/xl-disk-configuration.txt |   17 +++++++++++++++++
 tools/libxl/libxl.c                 |    2 ++
 tools/libxl/libxl.h                 |   12 ++++++++++++
 tools/libxl/libxlu_disk.c           |    3 +++
 tools/libxl/libxlu_disk_i.h         |    2 +-
 tools/libxl/libxlu_disk_l.l         |    2 ++
 6 files changed, 37 insertions(+), 1 deletion(-)

Index: xen-4.4.3-testing/docs/misc/xl-disk-configuration.txt
===================================================================
--- xen-4.4.3-testing.orig/docs/misc/xl-disk-configuration.txt
+++ xen-4.4.3-testing/docs/misc/xl-disk-configuration.txt
@@ -179,6 +179,23 @@ These scripts are normally called "block
 
 
 
+discard / no-discard
+---------------
+
+Description:           Request backend to advertise discard support to frontend
+Supported values:      discard
+                       no-discard
+Mandatory:             No
+Default value:         discard
+
+An advisory setting for the backend driver, specifying whether, to
+advertise discard support (TRIM, UNMAP) to the frontend.  The real
+benefit of this option is to be able to force it off rather than on.  It
+can be used to disable "hole punching" for file based backends which
+were intentionally created non-sparse to avoid fragmentation of the
+file.
+
+
 ============================================
 DEPRECATED PARAMETERS, PREFIXES AND SYNTAXES
 ============================================
Index: xen-4.4.3-testing/tools/libxl/libxl.c
===================================================================
--- xen-4.4.3-testing.orig/tools/libxl/libxl.c
+++ xen-4.4.3-testing/tools/libxl/libxl.c
@@ -2497,6 +2497,8 @@ static void device_disk_add(libxl__egc *
         flexarray_append(back, disk->readwrite ? "w" : "r");
         flexarray_append(back, "device-type");
         flexarray_append(back, disk->is_cdrom ? "cdrom" : "disk");
+        if ((disk->readwrite & ~LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MASK) == LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MAGIC)
+            flexarray_append_pair(back, "discard-enable", "0");
 
         flexarray_append(front, "backend-id");
         flexarray_append(front, libxl__sprintf(gc, "%d", disk->backend_domid));
Index: xen-4.4.3-testing/tools/libxl/libxl.h
===================================================================
--- xen-4.4.3-testing.orig/tools/libxl/libxl.h
+++ xen-4.4.3-testing/tools/libxl/libxl.h
@@ -95,6 +95,18 @@
 #define LIBXL_HAVE_BUILDINFO_EVENT_CHANNELS 1
 
 /*
+ * The libxl_device_disk lacks discard_enable field, disabling discard
+ * is supported without breaking the ABI. This is done by overloading
+ * struct libxl_device_disk->readwrite:
+ * readwrite == 0: disk is readonly, no discard
+ * readwrite == 1: disk is readwrite, backend driver may enable discard
+ * readwrite == MAGIC: disk is readwrite, backend driver should not offer
+ * discard to the frontend driver.
+ */
+#define LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MAGIC 0x00000060U
+#define LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MASK  0xffffff0fU
+
+/*
  * libxl ABI compatibility
  *
  * The only guarantee which libxl makes regarding ABI compatibility
Index: xen-4.4.3-testing/tools/libxl/libxlu_disk.c
===================================================================
--- xen-4.4.3-testing.orig/tools/libxl/libxlu_disk.c
+++ xen-4.4.3-testing/tools/libxl/libxlu_disk.c
@@ -80,6 +80,9 @@ int xlu_disk_parse(XLU_Config *cfg,
             disk->format = LIBXL_DISK_FORMAT_EMPTY;
     }
 
+    if (disk->readwrite && dpc.disable_discard)
+        disk->readwrite = (disk->readwrite & LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MASK) | LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_DISABLE_MAGIC;
+
     if (!disk->vdev) {
         xlu__disk_err(&dpc,0, "no vdev specified");
         goto x_err;
Index: xen-4.4.3-testing/tools/libxl/libxlu_disk_i.h
===================================================================
--- xen-4.4.3-testing.orig/tools/libxl/libxlu_disk_i.h
+++ xen-4.4.3-testing/tools/libxl/libxlu_disk_i.h
@@ -10,7 +10,7 @@ typedef struct {
     void *scanner;
     YY_BUFFER_STATE buf;
     libxl_device_disk *disk;
-    int access_set, had_depr_prefix;
+    int access_set, disable_discard, had_depr_prefix;
     const char *spec;
 } DiskParseContext;
 
Index: xen-4.4.3-testing/tools/libxl/libxlu_disk_l.l
===================================================================
--- xen-4.4.3-testing.orig/tools/libxl/libxlu_disk_l.l
+++ xen-4.4.3-testing/tools/libxl/libxlu_disk_l.l
@@ -173,6 +173,8 @@ backendtype=[^,]*,? { STRIP(','); setbac
 
 vdev=[^,]*,?	{ STRIP(','); SAVESTRING("vdev", vdev, FROMEQUALS); }
 script=[^,]*,?	{ STRIP(','); SAVESTRING("script", script, FROMEQUALS); }
+discard,?	{ DPC->disable_discard = 0; }
+no-discard,?	{ DPC->disable_discard = 1; }
 
  /* the target magic parameter, eats the rest of the string */
 
