+ /*
+ * Dribble back the elements we are keeping.
+ */
+
+ if (++n >= 50 && keep != NULL) {
+ lock_zone(z);
+
+ tail->next = (void *)z->free_elements;
+ (void *)z->free_elements = keep;
+
+ unlock_zone(z);
+
+ n = 0; tail = keep = NULL;
+ }
+ }
+
+ /*
+ * Return any remaining elements.
+ */
+
+ if (keep != NULL) {
+ lock_zone(z);
+
+ tail->next = (void *)z->free_elements;
+ (void *)z->free_elements = keep;
+
+ unlock_zone(z);
+ }
+
+ /*
+ * Pass 2:
+ *
+ * Determine which pages we can reclaim and
+ * free those elements.
+ */
+
+ size_freed = 0;
+ prev = (void *)&scan;
+ elt = scan;
+ n = 0; tail = keep = NULL;
+ while (elt != NULL) {
+ if (zone_page_collectable((vm_offset_t)elt, elt_size)) {
+ size_freed += elt_size;
+ zone_page_free_element(&zone_free_pages,
+ (vm_offset_t)elt, elt_size);
+
+ elt = prev->next = elt->next;
+
+ ++zgc_stats.elems_freed;
+ }
+ else {
+ zone_page_keep((vm_offset_t)elt, elt_size);
+
+ if (keep == NULL)
+ keep = tail = elt;
+ else
+ tail = tail->next = elt;
+
+ elt = prev->next = elt->next;
+ tail->next = NULL;
+
+ ++zgc_stats.elems_kept;
+ }
+
+ /*
+ * Dribble back the elements we are keeping,
+ * and update the zone size info.
+ */
+
+ if (++n >= 50 && keep != NULL) {
+ lock_zone(z);
+
+ z->cur_size -= size_freed;
+ size_freed = 0;
+
+ tail->next = (void *)z->free_elements;
+ (void *)z->free_elements = keep;
+
+ unlock_zone(z);
+
+ n = 0; tail = keep = NULL;
+ }
+ }
+
+ /*
+ * Return any remaining elements, and update
+ * the zone size info.
+ */
+
+ if (size_freed > 0 || keep != NULL) {
+ lock_zone(z);
+
+ z->cur_size -= size_freed;
+
+ if (keep != NULL) {
+ tail->next = (void *)z->free_elements;
+ (void *)z->free_elements = keep;
+ }
+
+ unlock_zone(z);
+ }