One of the 'features' of overlayfs is that depending on whether a file
is on the upper or lower dir you get back a different device from stat.
That breaks our lxc_rmdir_onedev.

So at lxc_rmdir_ondev check the device of the directory being deleted.
If it is overlayfs, then skip the device check.

Note this is unrelated to overlayfs snapshots - in those cases when you
delete a container, /var/lib/lxc/$container/ does not actually have an
overlayfs under it.  Rather, to reproduce this you would

sudo mkdir /opt/{lower,upper,workdir}
sudo mount -t overlayfs -o lower=/opt/lower,upper=/opt/upper,workdir=/opt/workdir \
	lxc /var/lib/lxc
sudo lxc-create -t download -n c1 -- -d ubuntu -r trusty -a amd64
sudo lxc-destroy -n c1

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 src/lxc/utils.c | 39 ++++++++++++++++++++++++++++++++-------
 1 file changed, 32 insertions(+), 7 deletions(-)

--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -29,6 +29,7 @@
 #include <stddef.h>
 #include <string.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/param.h>
@@ -68,8 +69,8 @@
 
 lxc_log_define(lxc_utils, lxc);
 
-static int _recursive_rmdir_onedev(char *dirname, dev_t pdev,
-				   const char *exclude, int level)
+static int _recursive_rmdir(char *dirname, dev_t pdev,
+			    const char *exclude, int level, bool onedev)
 {
 	struct dirent dirent, *direntp;
 	DIR *dir;
@@ -106,7 +107,7 @@ static int _recursive_rmdir_onedev(char
 			if (ret < 0) {
 				switch(errno) {
 				case ENOTEMPTY:
-					INFO("Not deleting snapshots");
+					INFO("Not deleting snapshot %s", pathname);
 					hadexclude = true;
 					break;
 				case ENOTDIR:
@@ -129,14 +130,14 @@ static int _recursive_rmdir_onedev(char
 			failed=1;
 			continue;
 		}
-		if (mystat.st_dev != pdev)
+		if (onedev && mystat.st_dev != pdev)
 			continue;
 		if (S_ISDIR(mystat.st_mode)) {
-			if (_recursive_rmdir_onedev(pathname, pdev, exclude, level+1) < 0)
+			if (_recursive_rmdir(pathname, pdev, exclude, level+1, onedev) < 0)
 				failed=1;
 		} else {
 			if (unlink(pathname) < 0) {
-				ERROR("%s: failed to delete %s", __func__, pathname);
+				SYSERROR("%s: failed to delete %s", __func__, pathname);
 				failed=1;
 			}
 		}
@@ -158,17 +159,41 @@ static int _recursive_rmdir_onedev(char
 	return failed ? -1 : 0;
 }
 
+/* we have two different magic values for overlayfs, yay */
+#define OVERLAYFS_SUPER_MAGIC 0x794c764f
+#define OVERLAY_SUPER_MAGIC 0x794c7630
+/*
+ * In overlayfs, st_dev is unreliable.  so on overlayfs we don't do
+ * the lxc_rmdir_onedev()
+ */
+static bool is_native_overlayfs(const char *path)
+{
+	struct statfs sb;
+
+	if (statfs(path, &sb) < 0)
+		return false;
+	if (sb.f_type == OVERLAYFS_SUPER_MAGIC ||
+			sb.f_type == OVERLAY_SUPER_MAGIC)
+		return true;
+	return false;
+}
+
 /* returns 0 on success, -1 if there were any failures */
 extern int lxc_rmdir_onedev(char *path, const char *exclude)
 {
 	struct stat mystat;
+	bool onedev = true;
+
+	if (is_native_overlayfs(path)) {
+		onedev = false;
+	}
 
 	if (lstat(path, &mystat) < 0) {
 		ERROR("%s: failed to stat %s", __func__, path);
 		return -1;
 	}
 
-	return _recursive_rmdir_onedev(path, mystat.st_dev, exclude, 0);
+	return _recursive_rmdir(path, mystat.st_dev, exclude, 0, onedev);
 }
 
 static int mount_fs(const char *source, const char *target, const char *type)
