static int shrink_memcg(struct mem_cgroup *memcg)
 {
-       int nid, shrunk = 0;
+       int nid, shrunk = 0, scanned = 0;
 
        if (!mem_cgroup_zswap_writeback_enabled(memcg))
-               return -EINVAL;
+               return -ENOENT;
 
        /*
         * Skip zombies because their LRUs are reparented and we would be
 
                shrunk += list_lru_walk_one(&zswap_list_lru, nid, memcg,
                                            &shrink_memcg_cb, NULL, &nr_to_walk);
+               scanned += 1 - nr_to_walk;
        }
+
+       if (!scanned)
+               return -ENOENT;
+
        return shrunk ? 0 : -EAGAIN;
 }
 
 static void shrink_worker(struct work_struct *w)
 {
        struct mem_cgroup *memcg;
-       int ret, failures = 0;
+       int ret, failures = 0, attempts = 0;
        unsigned long thr;
 
        /* Reclaim down to the accept threshold */
        thr = zswap_accept_thr_pages();
 
        /*
-        * Global reclaim will select cgroup in a round-robin fashion.
+        * Global reclaim will select cgroup in a round-robin fashion from all
+        * online memcgs, but memcgs that have no pages in zswap and
+        * writeback-disabled memcgs (memory.zswap.writeback=0) are not
+        * candidates for shrinking.
+        *
+        * Shrinking will be aborted if we encounter the following
+        * MAX_RECLAIM_RETRIES times:
+        * - No writeback-candidate memcgs found in a memcg tree walk.
+        * - Shrinking a writeback-candidate memcg failed.
         *
         * We save iteration cursor memcg into zswap_next_shrink,
         * which can be modified by the offline memcg cleaner
                spin_unlock(&zswap_shrink_lock);
 
                if (!memcg) {
-                       if (++failures == MAX_RECLAIM_RETRIES)
+                       /*
+                        * Continue shrinking without incrementing failures if
+                        * we found candidate memcgs in the last tree walk.
+                        */
+                       if (!attempts && ++failures == MAX_RECLAIM_RETRIES)
                                break;
 
+                       attempts = 0;
                        goto resched;
                }
 
                /* drop the extra reference */
                mem_cgroup_put(memcg);
 
-               if (ret == -EINVAL)
-                       break;
+               /*
+                * There are no writeback-candidate pages in the memcg.
+                * This is not an issue as long as we can find another memcg
+                * with pages in zswap. Skip this without incrementing attempts
+                * and failures.
+                */
+               if (ret == -ENOENT)
+                       continue;
+               ++attempts;
+
                if (ret && ++failures == MAX_RECLAIM_RETRIES)
                        break;
 resched: