Cachefiles: Refuse to cull a non-empty directory that is also a cache object
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index a9fb45d..3b14b36 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -1119,6 +1119,8 @@
 /*
  * cull an object if it's not in use
  * - called only by cache manager daemon
+ * - NB: This function is also used to cull non-cache objects,
+ *   if any sneak into the cache directory.
  */
 int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
 		    char *filename)
@@ -1144,13 +1146,23 @@
 
 	slot = cachefiles_read_cull_slot(cache, victim);
 
+	if (cachefiles_cx_validate_slot(cache, victim, slot) < 0)
+		slot = CACHEFILES_NO_CULL_SLOT;
+
+	/* Here's the cross-roads:
+	 * If this is a valid cache object, refuse to delete it if it is a non-empty dir.
+	 * If it is invalid, try to delete it regardless. */
+	if (slot == CACHEFILES_NO_CULL_SLOT &&
+	    S_ISDIR(victim->d_inode->i_mode) && !simple_empty(victim)) {
+		_debug("victim is a valid, non-empty dir. Refusing to cull.");
+		ret = -ENOTEMPTY;
+		goto error;
+	}
+
 	ret = cachefiles_remove_object_xattr(cache, victim);
 	if (ret < 0)
 		goto error_unlock;
 
-	if (cachefiles_cx_validate_slot(cache, victim, slot) < 0)
-		slot = CACHEFILES_NO_CULL_SLOT;
-
 	cachefiles_cx_clear_slot(cache, slot);
 
 	/*  actually remove the victim (drops the dir mutex) */
@@ -1168,6 +1180,12 @@
 	mutex_unlock(&dir->d_inode->i_mutex);
 error:
 	dput(victim);
+	if (ret == -ENOTEMPTY) {
+		/* Tried to delete a non-empty dir. */
+		_leave(" = -ENOTEMPTY");
+		return ret;
+	}
+
 	if (ret == -ENOENT) {
 		/* file or dir now absent - probably retired by netfs */
 		_leave(" = -ESTALE [absent]");