bionic: tests: add test for fallocate FALLOC_FL_PUNCH_HOLE

Bug: 28760453
Change-Id: I1a58d19bf45eac5f930b0f649cf9b8c9046302f3
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 0798686..275a5da 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -18,9 +18,16 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <string.h>
+#include <sys/utsname.h>
 
 #include "TemporaryFile.h"
 
+// Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
+#if !defined(FALLOC_FL_PUNCH_HOLE) || !defined(FALLOC_FL_KEEP_SIZE)
+#include <linux/falloc.h>
+#endif
+
 TEST(fcntl, fcntl_smoke) {
   int fd = open("/proc/version", O_RDONLY);
   ASSERT_TRUE(fd != -1);
@@ -260,3 +267,27 @@
   ASSERT_EQ(-1, sync_file_range(tf.fd, 0, 0, ~0));
   ASSERT_EQ(EINVAL, errno);
 }
+
+static bool parse_kernel_release(long* const major, long* const minor) {
+  struct utsname buf;
+  if (uname(&buf) == -1) {
+    return false;
+  }
+  return sscanf(buf.release, "%ld.%ld", major, minor) == 2;
+}
+
+/*
+ * Kernels less than 4.1 are affected.
+ * Devices that fail this test should include change id from Nexus:
+ * Commit: 9b431291a1fadbdbcca1485711b5bab145112293
+ */
+TEST(fcntl, falloc_punch) {
+  long major = 0, minor = 0;
+  ASSERT_TRUE(parse_kernel_release(&major, &minor));
+
+  if (major < 4 || (major == 4 && minor < 1)) {
+    TemporaryFile tf;
+    ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1));
+    ASSERT_EQ(errno, EOPNOTSUPP);
+  }
+}