It turns out this performance problem was inadvertently introduced by a
correction made to fs/buffer.c in the 2.0.21 patch. The addition of a missing
"++nr_buffers_size[isize];" revealed a latent problem in the load average
computations in maybe_shrink_lav_buffers, which caused shrink_specific_buffers
to be called inappropriately, wasting many cycles trying to reclaim buffers
where there were none to be had.
Specifically, the first calculation in the comparison
bdf_prm.b_un.lav_const * buffers_lav[nlist]*total_n_buffers <
total_lav * (nr_buffers_size[nlist] - nr_buffers_st[nlist][BUF_SHARED]))
can become negative or overflow. When it becomes negative, the comparison will
succeeed when it should not. One of the failures I logged was:
1884 * 73 * 21375 < 8812 * ( 57 - 0 )
The enclosed patch divides both sides of this comparison by total_lav *
total_n_buffers, which preserves the comparison while avoiding large
multiplications.
Leonard
--- linux/fs/buffer.c- Fri Sep 20 07:00:35 1996
+++ linux/fs/buffer.c Thu Feb 13 23:21:42 1997
@@ -1535,10 +1535,11 @@
if (n_sizes > 1)
for(nlist = 0; nlist < NR_SIZES; nlist++)
{
- if(nlist == isize) continue;
- if(nr_buffers_size[nlist] &&
- bdf_prm.b_un.lav_const * buffers_lav[nlist]*total_n_buffers <
- total_lav * (nr_buffers_size[nlist] - nr_buffers_st[nlist][BUF_SHARED]))
+ if (nlist == isize) continue;
+ if (nr_buffers_size[nlist] > 0 &&
+ total_lav > 0 && total_n_buffers > 0 &&
+ bdf_prm.b_un.lav_const * buffers_lav[nlist] / total_lav <
+ (nr_buffers_size[nlist] - nr_buffers_st[nlist][BUF_SHARED]) / total_n_buffers)
if(shrink_specific_buffers(6, bufferindex_size[nlist]))
return 1;
}