refill_freelist patch

Bill Hawes (whawes@star.net)
Thu, 03 Jul 1997 20:11:55 -0400


This is a multi-part message in MIME format.
--------------A8086473760B822617A55D21
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I've put together a very promising patch for refill_freelist that seems
to work very well under low memory, and which almost never has to wake
up bdflush. Instead of always trying to achieve the arbitrary needed
amount, it keeps track of how much memory has been obtained, and then
returns when the full amount, half of the amount, or any amount has been
obtained, depending on how difficult it is to get memory.

The rationale is that there's no point in making one task repeatedly try
to free up some fixed arbitrary amount, when all of the freed memory is
just being used up by other tasks. With this patch each call to
refill_freelist returns after a useful amount has been obtained. In
testing it with simultaneous compiles in 6M, I haven't yet seen the
"waking bdflush" message.

The patch is against 2.0.30 sources (back ported from my 2.1.42 test
version).

Regards,
Bill
--------------A8086473760B822617A55D21
Content-Type: text/plain; charset=us-ascii; name="buffer_ref30-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="buffer_ref30-patch"

--- fs/buffer.c.old Sun Apr 27 15:54:43 1997
+++ fs/buffer.c Thu Jul 3 19:27:50 1997
@@ -596,81 +596,103 @@
unsigned int best_time, winner;
int buffers[BUF_DIRTY];
int i;
- int needed;
+ int needed, obtained=0;

refilled = 1;
- /* If there are too many dirty buffers, we wake up the update process
- now so as to ensure that there are still clean buffers available
- for user processes to use (and dirty) */

- /* We are going to try to locate this much memory */
- needed =bdf_prm.b_un.nrefill * size;
+ /* We are going to try to locate this much memory. */
+ needed = bdf_prm.b_un.nrefill * size;

- while (nr_free_pages > min_free_pages*2 && needed > 0 &&
- grow_buffers(GFP_BUFFER, size)) {
- needed -= PAGE_SIZE;
- }
+ while ((nr_free_pages > min_free_pages*2) && (obtained < needed) &&
+ grow_buffers(GFP_BUFFER, size))
+ obtained += PAGE_SIZE;

repeat:
- /* OK, we cannot grow the buffer cache, now try to get some
- from the lru list */
-
- /* First set the candidate pointers to usable buffers. This
- should be quick nearly all of the time. */
+ if (obtained >= needed)
+ return;

- if(needed <= 0) return;
+ /* OK, we cannot grow the buffer cache, now try to get some
+ * from the lru list.
+ *
+ * First set the candidate pointers to usable buffers. This
+ * should be quick nearly all of the time.
+ */

- for(i=0; i<BUF_DIRTY; i++){
+ for(i=0; i<BUF_DIRTY; i++) {
buffers[i] = nr_buffers_type[i];
candidate[i] = find_candidate(lru_list[i], &buffers[i], size);
}

- /* Now see which candidate wins the election */
+ /* Now see which candidate wins the election. */

winner = best_time = UINT_MAX;
- for(i=0; i<BUF_DIRTY; i++){
- if(!candidate[i]) continue;
- if(candidate[i]->b_lru_time < best_time){
+ for(i=0; i<BUF_DIRTY; i++) {
+ if(!candidate[i])
+ continue;
+ if(candidate[i]->b_lru_time < best_time) {
best_time = candidate[i]->b_lru_time;
winner = i;
}
}

- /* If we have a winner, use it, and then get a new candidate from that list */
+ /* If we have a winner, use it, and then get a new candidate from that list. */
if(winner != UINT_MAX) {
i = winner;
- while (needed>0 && (bh=candidate[i])) {
+ while (obtained < needed && (bh=candidate[i])) {
candidate[i] = bh->b_next_free;
- if(candidate[i] == bh) candidate[i] = NULL; /* Got last one */
+
remove_from_queues(bh);
bh->b_dev = B_FREE;
put_last_free(bh);
- needed -= bh->b_size;
- buffers[i]--;
- if(buffers[i] == 0) candidate[i] = NULL;
+ obtained += bh->b_size;

- if (candidate[i] && !can_reclaim(candidate[i],size))
- candidate[i] = find_candidate(candidate[i],&buffers[i], size);
+ /*
+ * Validate the next node as a candidate
+ */
+ if(--buffers[i] == 0 || candidate[i] == bh)
+ candidate[i] = NULL; /* Got last one */
+ else
+ candidate[i] = find_candidate(candidate[i],
+ &buffers[i], size);
}
- if (needed >= 0)
- goto repeat;
+ goto repeat;
+ }
+
+ /*
+ * If we achieved at least half of our goal, return now.
+ */
+ if (obtained >= (needed >> 1)) {
+printk("refill_freelist: returning half obtained=%d\n", obtained);
+ return;
}
-
- if(needed <= 0) return;

/* Too bad, that was not enough. Try a little harder to grow some. */
-
if (nr_free_pages > min_free_pages + 5) {
if (grow_buffers(GFP_BUFFER, size)) {
- needed -= PAGE_SIZE;
+ obtained += PAGE_SIZE;
goto repeat;
- };
+ }
}

- /* and repeat until we find something good */
- if (!grow_buffers(GFP_ATOMIC, size))
- wakeup_bdflush(1);
- needed -= PAGE_SIZE;
+ /*
+ * Make one last attempt to allocate some buffers ...
+ */
+ if (grow_buffers(GFP_ATOMIC, size))
+ obtained += PAGE_SIZE;
+
+ /*
+ * If we got any buffers, return now to let this task proceed.
+ */
+ if (obtained) {
+printk("refill_freelist: returning some obtained=%d\n", obtained);
+ return;
+ }
+
+ /*
+ * System is _very_ low on memory ... wake up bdflush and wait.
+ */
+printk("refill_freelist: waking bdflush\n");
+ wakeup_bdflush(1);
goto repeat;
}

--------------A8086473760B822617A55D21--