Subject: pool_get(PR_NOWAIT) can lead to pool_get(PR_WAITOK)
To: None <tech-kern@netbsd.org>
From: Frank van der Linden <fvdl@wasabisystems.com>
List: tech-kern
Date: 08/05/2002 03:22:44
Greg Oster sent me the following trace of a LOCKDEBUG warning regarding
holding a spinlock while (possibly) going to sleep:


pool_get(PR_WAITOK) with held simple_lock 0xc0680238 CPU 0 /cheetah/current2/src/sys/arch/i386/compile/RAIDFRAME.ddb/../../../../kern/vfs_subr.c:460
pool_get(c06d1960,2,15f,c0764bc4,0) at pool_get+0x57
uvm_map(c069b700,c0764bdc,1000,c069b600,b355000,0,0,1727) at uvm_map+0x866
uvm_km_kmemalloc(c069b700,c069b600,1000,1,0) at uvm_km_kmemalloc+0x6d
uvm_km_alloc_poolpage1(c069b700,c069b600,0,c067f6d8,c05179c0) at uvm_km_alloc_poolpage1+0x3b
pool_page_alloc_nointr(c06bd6c0,0,c0100b64,e000ffe7) at pool_page_alloc_nointr+0x23
pool_allocator_alloc(c06bd6c0,0,c0764cc0,c0298a8e,c06bd72c) at pool_allocator_alloc+0x1f
pool_get(c06bd6c0,0,1cc,c038bee8,c04c6406) at pool_get+0x1eb
getnewvnode(0,0,c0a66300,c0764d2c) at getnewvnode+0xbb
getdevvp(403,c0764da8,3,282,c06e1f00) at getdevvp+0x2f
bdevvp(403,c0764da8,c0764dc0,0) at bdevvp+0x16
rf_find_raid_components(c04d7f60,5d,0,c0121567,c0679e74,c06b9cc0,c06b9ec8,c02a1797,9,4c0,c0764fa0,c027eae6,8,c06b9cc0,c0764fa0,c027eacc,c0762010,762000,769000,f00007ff,c07d,0,0,c0100331,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) at rf_find_raid_components+0x10a
raidattach(8,c06b9cc0,c0764fa0,c027eacc) at raidattach+0x2ea
main(0,0,0,0,0) at main+0x39a


The first pool_get (from getnewvnode()) is PR_NOWAIT, and it has to be,
since it's holding a spinlock at that time. A NOWAIT call of any kind
into UVM shouldn't lead to the process sleeping, but in this case it might.

The problem is the (inline) function uvm_mapent_alloc in uvm_map.c. It
always uses PR_WAITOK for non-static entries. Also, callers to
uvm_mapent_alloc don't check the return value.

The quickest solution I see is to pass a WAIT/NOWAIT flag to
uvm_mapent_alloc, have it use PR_NOWAIT/PR_WAITOK depending on that, and
return NULL properly if it fails. Callers will always pass in WAIT,
because that is the current default. For cases where a WAIT/NOWAIT flag
is passed down from above, it can be used appropriately (uvm_map() is
such a case), and the return value will be checked.

Comments?

- Frank

-- 
Frank van der Linden                                    fvdl@wasabisystems.com
==============================================================================
Quality NetBSD Development, Support & Service.   http://www.wasabisystems.com/