Serious performance issues, broken initialization, and a likely
fix
Ade Lovett
ade at FreeBSD.org
Tue Aug 9 02:52:31 GMT 2005
Scott Long wrote:
> Ade Lovett wrote:
>> To cut a long story short, the order in which nswbuf is being
>> initialized is completely, totally, and utterly wrong -- this was
>> introduced by revision 1.132 of vm/vnode_pager.c just over 4 years ago.
>>
[snip]
> My vote is to revert rev 1.132 and replace the XXX comment with a more
> detailed explaination of the perils involved. Do you have any kind of
> easy to run regression test that could be used to quantify this problem
> and guard against it in the future? Thanks very very much for looking
> into it and providing such a good explaination.
It's not quite as easy as reverting 1.132, since we're talking about at
least two files here, vm/vnode_pager.c and kern/vfs_bio.c
How to handle it properly is a little more complicated since the code
that actually assigns a value to nswbuf is inside
kern_vfs_bio_buffer_alloc() which can be called multiple times as part
of the again goto loop in vm_ksubmap_init().
My personal preference would be to rip out lines 446-494 (RELENG_6) of
kern_vfs_bio_buffer_alloc() into a separate function, which sets nbuf
and nswbuf, and also have vnode_pager_init() call that routine.
As to an easy to run regression test, the code clearly states that there
is a minimum value of nswbuf:
* swbufs are used as temporary holders for I/O, such as paging I/O.
* We have no less then 16 and no more then 256.
However, the check for this is based on:
options NSWBUF_MIN=<somenumber>
being defined in the kernel configuration file (and propagated to
kernel/opt_swap.h as part of config(8).
Defining a couple of handy constants (in sys/conf.h ?):
#define NSWBUF_ABSOLUTE_MIN 16
#define NSWBUF_ABSOLUTE_MAX 256
The current check (based on NSWBUF_MIN) could be rewritten as follows:
#ifdef NSWBUF_MIN
if (nswbuf < NSWBUF_MIN)
nswbuf = NSWBUF_MIN;
#endif
if (nswbuf < NSWBUF_ABSOLUTE_MIN) {
printf("Warning: nswbuf too low (%d), setting to %d\n",
nswbuf, NSWBUF_ABSOLUTE_MIN);
nswbuf = NSWBUF_ABSOLUTE_MIN;
}
if (nswbuf > NSWBUF_ABSOLUTE_MAX) {
printf("Warning: nswbuf too high (%d), setting to %d\n",
nswbuf, NSWBUF_ABSOLUTE_MAX);
nswbuf = NSWBUF_ABSOLUTE_MAX;
}
and then, along with the code moving outlined above, having an undefined
value (or 0) of nswbuf could Never Happen[tm].
Indeed, at this point, where nswbuf is actually used in the RHS of an
assignment, one could even force a panic if it somehow it got missed in
future -- I believe in this case, a full blown panic would be justified,
given the massive loss of performance that occurs with only one swap buffer.
-aDe
More information about the freebsd-current
mailing list