Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-08 Thread Ted Unangst
On Mon, Feb 8, 2010 at 11:11 AM, Owain Ainsworth  wrote:
> On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
>> I think this fixes the problem with sleeping and holding pseg_lck.
>
> This won't build on sparc64 (the only caller of valloc_align). If you
> fix that, then I am ok with this diff.

I was wondering about where it was used, thanks.



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-08 Thread Owain Ainsworth
On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
> I think this fixes the problem with sleeping and holding pseg_lck.
> 
> Index: uvm_extern.h
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> retrieving revision 1.82
> diff -u -r1.82 uvm_extern.h
> --- uvm_extern.h  11 Aug 2009 18:43:33 -  1.82
> +++ uvm_extern.h  2 Feb 2010 04:28:09 -
> @@ -517,8 +517,9 @@
>   vaddr_t *, vsize_t, int,
>   boolean_t, vm_map_t);
>  vaddr_t  uvm_km_valloc(vm_map_t, vsize_t);
> -vaddr_t  uvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> +vaddr_t  uvm_km_valloc_try(vm_map_t, vsize_t);
>  vaddr_t  uvm_km_valloc_wait(vm_map_t, vsize_t);
> +vaddr_t  uvm_km_valloc_align(struct vm_map *, vsize_t, 
> vsize_t, int);
>  vaddr_t  uvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
>   voff_t);
>  void *uvm_km_getpage(boolean_t, int *);
> Index: uvm_km.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> retrieving revision 1.75
> diff -u -r1.75 uvm_km.c
> --- uvm_km.c  25 Jul 2009 12:55:40 -  1.75
> +++ uvm_km.c  2 Feb 2010 04:27:35 -
> @@ -571,11 +571,17 @@
>  vaddr_t
>  uvm_km_valloc(struct vm_map *map, vsize_t size)
>  {
> - return(uvm_km_valloc_align(map, size, 0));
> + return(uvm_km_valloc_align(map, size, 0, 0));
>  }
>  
>  vaddr_t
> -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> +{
> + return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> +}
> +
> +vaddr_t
> +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> flags)
>  {
>   vaddr_t kva;
>   UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> @@ -592,7 +598,7 @@
>  
>   if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
>   UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> - UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> + UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
>   UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
>   return(0);
>   }
> Index: uvm_pager.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> retrieving revision 1.54
> diff -u -r1.54 uvm_pager.c
> --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
> +++ uvm_pager.c   2 Feb 2010 04:23:57 -
> @@ -138,7 +138,7 @@
>  {
>   KASSERT(pseg->start == 0);
>   KASSERT(pseg->use == 0);
> - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
>  }

This won't build on sparc64 (the only caller of valloc_align). If you
fix that, then I am ok with this diff.

Though to be honest, most of the valloc functions could mostly just be
replaced with uvm_km_kmemalloc (valloc_wait and valloc_align can't
without changes). The code called is equivalent in action to:

valloc() -> kmemalloc( VALLOC)
valloc_try() -> kmemalloc(TRYLOCK | VALLOC)

One thing at a time though. uvm_km.c has 3 or 4 allocators that are all
almost identical (some differ in flags, but not much else). I'll look
into clearing it up.

Reviewing that last paragraph, I notice that kmemalloc doesn't lock the
object that it is called with. I'll fix that soon...

Cheers,

-0-
-- 
If you keep anything long enough, you can throw it away.



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-03 Thread Owain Ainsworth
On Wed, Feb 03, 2010 at 04:08:39PM +0100, Mark Kettenis wrote:
> > Date: Wed, 3 Feb 2010 14:41:04 +
> > From: Owain Ainsworth 
> > 
> > On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
> > > I think this fixes the problem with sleeping and holding pseg_lck.
> > > 
> > > Index: uvm_extern.h
> > > ===
> > > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> > > retrieving revision 1.82
> > > diff -u -r1.82 uvm_extern.h
> > > --- uvm_extern.h  11 Aug 2009 18:43:33 -  1.82
> > > +++ uvm_extern.h  2 Feb 2010 04:28:09 -
> > > @@ -517,8 +517,9 @@
> > >   vaddr_t *, vsize_t, int,
> > >   boolean_t, vm_map_t);
> > >  vaddr_t  uvm_km_valloc(vm_map_t, vsize_t);
> > > -vaddr_t  uvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> > > +vaddr_t  uvm_km_valloc_try(vm_map_t, vsize_t);
> > >  vaddr_t  uvm_km_valloc_wait(vm_map_t, vsize_t);
> > > +vaddr_t  uvm_km_valloc_align(struct vm_map *, vsize_t, 
> > > vsize_t, int);
> > >  vaddr_t  uvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
> > >   voff_t);
> > >  void *uvm_km_getpage(boolean_t, int *);
> > > Index: uvm_km.c
> > > ===
> > > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> > > retrieving revision 1.75
> > > diff -u -r1.75 uvm_km.c
> > > --- uvm_km.c  25 Jul 2009 12:55:40 -  1.75
> > > +++ uvm_km.c  2 Feb 2010 04:27:35 -
> > > @@ -571,11 +571,17 @@
> > >  vaddr_t
> > >  uvm_km_valloc(struct vm_map *map, vsize_t size)
> > >  {
> > > - return(uvm_km_valloc_align(map, size, 0));
> > > + return(uvm_km_valloc_align(map, size, 0, 0));
> > >  }
> > >  
> > >  vaddr_t
> > > -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> > > +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> > > +{
> > > + return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> > > +}
> > > +
> > > +vaddr_t
> > > +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> > > flags)
> > >  {
> > >   vaddr_t kva;
> > >   UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> > > @@ -592,7 +598,7 @@
> > >  
> > >   if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
> > >   UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> > > - UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> > > + UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
> > >   UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
> > >   return(0);
> > >   }
> > > Index: uvm_pager.c
> > > ===
> > > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> > > retrieving revision 1.54
> > > diff -u -r1.54 uvm_pager.c
> > > --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
> > > +++ uvm_pager.c   2 Feb 2010 04:23:57 -
> > > @@ -138,7 +138,7 @@
> > >  {
> > >   KASSERT(pseg->start == 0);
> > >   KASSERT(pseg->use == 0);
> > > - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> > > + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> > 
> > 
> > this doesn't take into account the fact that valloc_try may fail and
> > return 0.
> 
> That case is handled just fine.  In uvm_pseg_get() we have a check
> for pseg->start == 0 immediately after the uvm_pseg_init() call.

Ah yes, I missed that (also pointed out by ted). In which case this does
look correct. Will review more carefully when I get home from work.

-0-
-- 
I had to censor everything my sons watched ... even on the Mary Tyler
Moore show I heard the word "damn"!
-- Mary Lou Bax



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-03 Thread Mark Kettenis
> Date: Wed, 3 Feb 2010 06:10:09 +0100
> From: Ariane van der Steldt 
> 
> I think it'll only fix the problem partially though: uvm_km_free*
> doesn't have a trylock variant and may sleep just as well on the lock.

That's fairly easy to fix though.  You can simply save pseg->start in
a local variable, relase the lock and call uvm_km_free().



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-03 Thread Mark Kettenis
> Date: Wed, 3 Feb 2010 14:41:04 +
> From: Owain Ainsworth 
> 
> On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
> > I think this fixes the problem with sleeping and holding pseg_lck.
> > 
> > Index: uvm_extern.h
> > ===
> > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> > retrieving revision 1.82
> > diff -u -r1.82 uvm_extern.h
> > --- uvm_extern.h11 Aug 2009 18:43:33 -  1.82
> > +++ uvm_extern.h2 Feb 2010 04:28:09 -
> > @@ -517,8 +517,9 @@
> > vaddr_t *, vsize_t, int,
> > boolean_t, vm_map_t);
> >  vaddr_tuvm_km_valloc(vm_map_t, vsize_t);
> > -vaddr_tuvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> > +vaddr_tuvm_km_valloc_try(vm_map_t, vsize_t);
> >  vaddr_tuvm_km_valloc_wait(vm_map_t, vsize_t);
> > +vaddr_tuvm_km_valloc_align(struct vm_map *, vsize_t, 
> > vsize_t, int);
> >  vaddr_tuvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
> > voff_t);
> >  void   *uvm_km_getpage(boolean_t, int *);
> > Index: uvm_km.c
> > ===
> > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> > retrieving revision 1.75
> > diff -u -r1.75 uvm_km.c
> > --- uvm_km.c25 Jul 2009 12:55:40 -  1.75
> > +++ uvm_km.c2 Feb 2010 04:27:35 -
> > @@ -571,11 +571,17 @@
> >  vaddr_t
> >  uvm_km_valloc(struct vm_map *map, vsize_t size)
> >  {
> > -   return(uvm_km_valloc_align(map, size, 0));
> > +   return(uvm_km_valloc_align(map, size, 0, 0));
> >  }
> >  
> >  vaddr_t
> > -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> > +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> > +{
> > +   return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> > +}
> > +
> > +vaddr_t
> > +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> > flags)
> >  {
> > vaddr_t kva;
> > UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> > @@ -592,7 +598,7 @@
> >  
> > if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
> > UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> > -   UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> > +   UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
> > UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
> > return(0);
> > }
> > Index: uvm_pager.c
> > ===
> > RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> > retrieving revision 1.54
> > diff -u -r1.54 uvm_pager.c
> > --- uvm_pager.c 22 Jul 2009 21:05:37 -  1.54
> > +++ uvm_pager.c 2 Feb 2010 04:23:57 -
> > @@ -138,7 +138,7 @@
> >  {
> > KASSERT(pseg->start == 0);
> > KASSERT(pseg->use == 0);
> > -   pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> > +   pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> 
> 
> this doesn't take into account the fact that valloc_try may fail and
> return 0.

That case is handled just fine.  In uvm_pseg_get() we have a check
for pseg->start == 0 immediately after the uvm_pseg_init() call.



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-03 Thread Ted Unangst
On Wed, Feb 3, 2010 at 9:41 AM, Owain Ainsworth 
wrote:
>> Index: uvm_pager.c
>> ===
>> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
>> retrieving revision 1.54
>> diff -u -r1.54 uvm_pager.c
>> --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
>> +++ uvm_pager.c   2 Feb 2010 04:23:57 -
>> @@ -138,7 +138,7 @@
>>  {
>>   KASSERT(pseg->start == 0);
>>   KASSERT(pseg->use == 0);
>> - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
>> + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS *
MAXBSIZE);
>
>
> this doesn't take into account the fact that valloc_try may fail and
> return 0.

That appears to be the caller's concern.  There's no difference in
that regard between try and not try.  (only do :)).



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-03 Thread Owain Ainsworth
On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
> I think this fixes the problem with sleeping and holding pseg_lck.
> 
> Index: uvm_extern.h
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> retrieving revision 1.82
> diff -u -r1.82 uvm_extern.h
> --- uvm_extern.h  11 Aug 2009 18:43:33 -  1.82
> +++ uvm_extern.h  2 Feb 2010 04:28:09 -
> @@ -517,8 +517,9 @@
>   vaddr_t *, vsize_t, int,
>   boolean_t, vm_map_t);
>  vaddr_t  uvm_km_valloc(vm_map_t, vsize_t);
> -vaddr_t  uvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> +vaddr_t  uvm_km_valloc_try(vm_map_t, vsize_t);
>  vaddr_t  uvm_km_valloc_wait(vm_map_t, vsize_t);
> +vaddr_t  uvm_km_valloc_align(struct vm_map *, vsize_t, 
> vsize_t, int);
>  vaddr_t  uvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
>   voff_t);
>  void *uvm_km_getpage(boolean_t, int *);
> Index: uvm_km.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> retrieving revision 1.75
> diff -u -r1.75 uvm_km.c
> --- uvm_km.c  25 Jul 2009 12:55:40 -  1.75
> +++ uvm_km.c  2 Feb 2010 04:27:35 -
> @@ -571,11 +571,17 @@
>  vaddr_t
>  uvm_km_valloc(struct vm_map *map, vsize_t size)
>  {
> - return(uvm_km_valloc_align(map, size, 0));
> + return(uvm_km_valloc_align(map, size, 0, 0));
>  }
>  
>  vaddr_t
> -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> +{
> + return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> +}
> +
> +vaddr_t
> +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> flags)
>  {
>   vaddr_t kva;
>   UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> @@ -592,7 +598,7 @@
>  
>   if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
>   UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> - UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> + UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
>   UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
>   return(0);
>   }
> Index: uvm_pager.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> retrieving revision 1.54
> diff -u -r1.54 uvm_pager.c
> --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
> +++ uvm_pager.c   2 Feb 2010 04:23:57 -
> @@ -138,7 +138,7 @@
>  {
>   KASSERT(pseg->start == 0);
>   KASSERT(pseg->use == 0);
> - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);


this doesn't take into account the fact that valloc_try may fail and
return 0.

The principle is good, but more is needed. Perhaps up to unlocking
everything and calling where we can sleep.

-0-
-- 
Fortune's Office Door Sign of the Week:

Incorrigible punster -- Do not incorrige.



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-02 Thread Ariane van der Steldt
On Mon, Feb 01, 2010 at 11:30:06PM -0500, Ted Unangst wrote:
> I think this fixes the problem with sleeping and holding pseg_lck.
> 
> Index: uvm_extern.h
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> retrieving revision 1.82
> diff -u -r1.82 uvm_extern.h
> --- uvm_extern.h  11 Aug 2009 18:43:33 -  1.82
> +++ uvm_extern.h  2 Feb 2010 04:28:09 -
> @@ -517,8 +517,9 @@
>   vaddr_t *, vsize_t, int,
>   boolean_t, vm_map_t);
>  vaddr_t  uvm_km_valloc(vm_map_t, vsize_t);
> -vaddr_t  uvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> +vaddr_t  uvm_km_valloc_try(vm_map_t, vsize_t);
>  vaddr_t  uvm_km_valloc_wait(vm_map_t, vsize_t);
> +vaddr_t  uvm_km_valloc_align(struct vm_map *, vsize_t, 
> vsize_t, int);
>  vaddr_t  uvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
>   voff_t);
>  void *uvm_km_getpage(boolean_t, int *);
> Index: uvm_km.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> retrieving revision 1.75
> diff -u -r1.75 uvm_km.c
> --- uvm_km.c  25 Jul 2009 12:55:40 -  1.75
> +++ uvm_km.c  2 Feb 2010 04:27:35 -
> @@ -571,11 +571,17 @@
>  vaddr_t
>  uvm_km_valloc(struct vm_map *map, vsize_t size)
>  {
> - return(uvm_km_valloc_align(map, size, 0));
> + return(uvm_km_valloc_align(map, size, 0, 0));
>  }
>  
>  vaddr_t
> -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> +{
> + return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> +}
> +
> +vaddr_t
> +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> flags)
>  {
>   vaddr_t kva;
>   UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> @@ -592,7 +598,7 @@
>  
>   if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
>   UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> - UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> + UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
>   UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
>   return(0);
>   }
> Index: uvm_pager.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> retrieving revision 1.54
> diff -u -r1.54 uvm_pager.c
> --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
> +++ uvm_pager.c   2 Feb 2010 04:23:57 -
> @@ -138,7 +138,7 @@
>  {
>   KASSERT(pseg->start == 0);
>   KASSERT(pseg->use == 0);
> - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);

I'd prefer
 uvm_km_kmemalloc(kernel_map, NULL, MAX_PAGER_SEGS * MAXBSIZE,
UVM_KMF_TRYLOCK|UVM_KMF_VALLOC)
instead of introducing a new uvm_km_valloc_* function. There are plenty
of those already and most of them can be rewritten to uvm_km_kmemalloc
with suitable flags.

Apart from that, the diff looks fine to me.

>  }
>  
>  /*
> 

I think it'll only fix the problem partially though: uvm_km_free*
doesn't have a trylock variant and may sleep just as well on the lock.

I think what happens is that another uvm_km_pgremove is sleeping on
the wanted flag, holding the rwlock. I.e. another uvm_km_free is in
progress somewhere else, waiting for a busy kernelpage (which hopefully
is busy because of a 3rd kernel thread, possibly the pagedaemon).

To summarize:
[1] aiodone needs pseg mutex
[2] mutex is held by pagedaemon thread which illegally sleeps
[3] because the pagedaemon wants access to the uvm_map
[4] which is held by another kernel thread sleeping while locking uvm_map
[5] because another thread has its page marked busy

The thread in [5] could be the pagedaemon, in which case we have a
deadlock. However, making the allocation in [2] try-lock instead may
indeed remove the deadlock (assuming no other process would try to mark
pages busy that don't belong to it).
But I think the deadlock would still resurface, simply because this is a
kernel page and some other kernel thread may try to free its memory
between the pagedaemon starting a page-out and the aiodone daemon
cleaning up.
To make matters worse, it could be that a uvm object decided it needed
to be synced to disk: if memory serves me right any uvm_object io goes
through this code.

The only fix I can think of at the moment is not to use uvm_km_alloc and
uvm_km_free at all for the pseg code.

Ciao,
-- 
Ariane



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-02 Thread Mike Belopuhov
On Mon, Feb 01, 2010 at 23:30 -0500, Ted Unangst wrote:
> I think this fixes the problem with sleeping and holding pseg_lck.
> 

perhaps it also makes sense to honour UVMPAGER_MAPIN_WAITOK flag.
what do you think?

> Index: uvm_extern.h
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
> retrieving revision 1.82
> diff -u -r1.82 uvm_extern.h
> --- uvm_extern.h  11 Aug 2009 18:43:33 -  1.82
> +++ uvm_extern.h  2 Feb 2010 04:28:09 -
> @@ -517,8 +517,9 @@
>   vaddr_t *, vsize_t, int,
>   boolean_t, vm_map_t);
>  vaddr_t  uvm_km_valloc(vm_map_t, vsize_t);
> -vaddr_t  uvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
> +vaddr_t  uvm_km_valloc_try(vm_map_t, vsize_t);
>  vaddr_t  uvm_km_valloc_wait(vm_map_t, vsize_t);
> +vaddr_t  uvm_km_valloc_align(struct vm_map *, vsize_t, 
> vsize_t, int);
>  vaddr_t  uvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
>   voff_t);
>  void *uvm_km_getpage(boolean_t, int *);
> Index: uvm_km.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
> retrieving revision 1.75
> diff -u -r1.75 uvm_km.c
> --- uvm_km.c  25 Jul 2009 12:55:40 -  1.75
> +++ uvm_km.c  2 Feb 2010 04:27:35 -
> @@ -571,11 +571,17 @@
>  vaddr_t
>  uvm_km_valloc(struct vm_map *map, vsize_t size)
>  {
> - return(uvm_km_valloc_align(map, size, 0));
> + return(uvm_km_valloc_align(map, size, 0, 0));
>  }
>  
>  vaddr_t
> -uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
> +uvm_km_valloc_try(struct vm_map *map, vsize_t size)
> +{
> + return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
> +}
> +
> +vaddr_t
> +uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int 
> flags)
>  {
>   vaddr_t kva;
>   UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
> @@ -592,7 +598,7 @@
>  
>   if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
>   UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
> - UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
> + UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
>   UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
>   return(0);
>   }
> Index: uvm_pager.c
> ===
> RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
> retrieving revision 1.54
> diff -u -r1.54 uvm_pager.c
> --- uvm_pager.c   22 Jul 2009 21:05:37 -  1.54
> +++ uvm_pager.c   2 Feb 2010 04:23:57 -
> @@ -138,7 +138,7 @@
>  {
>   KASSERT(pseg->start == 0);
>   KASSERT(pseg->use == 0);
> - pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
> + pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
>  }
>  
>  /*



Re: uvm_pseg_get & uvm_pseg_lck fix

2010-02-02 Thread Mike Belopuhov
On Tue, Feb 02, 2010 at 15:21 +0300, Mike Belopuhov wrote:
> On Mon, Feb 01, 2010 at 23:30 -0500, Ted Unangst wrote:
> > I think this fixes the problem with sleeping and holding pseg_lck.
> > 
> 
> perhaps it also makes sense to honour UVMPAGER_MAPIN_WAITOK flag.
> what do you think?
> 

no, i'm sorry, this is wrong.



uvm_pseg_get & uvm_pseg_lck fix

2010-02-01 Thread Ted Unangst
I think this fixes the problem with sleeping and holding pseg_lck.

Index: uvm_extern.h
===
RCS file: /home/tedu/cvs/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.82
diff -u -r1.82 uvm_extern.h
--- uvm_extern.h11 Aug 2009 18:43:33 -  1.82
+++ uvm_extern.h2 Feb 2010 04:28:09 -
@@ -517,8 +517,9 @@
vaddr_t *, vsize_t, int,
boolean_t, vm_map_t);
 vaddr_tuvm_km_valloc(vm_map_t, vsize_t);
-vaddr_tuvm_km_valloc_align(vm_map_t, vsize_t, vsize_t);
+vaddr_tuvm_km_valloc_try(vm_map_t, vsize_t);
 vaddr_tuvm_km_valloc_wait(vm_map_t, vsize_t);
+vaddr_tuvm_km_valloc_align(struct vm_map *, vsize_t, 
vsize_t, int);
 vaddr_tuvm_km_valloc_prefer_wait(vm_map_t, vsize_t,
voff_t);
 void   *uvm_km_getpage(boolean_t, int *);
Index: uvm_km.c
===
RCS file: /home/tedu/cvs/src/sys/uvm/uvm_km.c,v
retrieving revision 1.75
diff -u -r1.75 uvm_km.c
--- uvm_km.c25 Jul 2009 12:55:40 -  1.75
+++ uvm_km.c2 Feb 2010 04:27:35 -
@@ -571,11 +571,17 @@
 vaddr_t
 uvm_km_valloc(struct vm_map *map, vsize_t size)
 {
-   return(uvm_km_valloc_align(map, size, 0));
+   return(uvm_km_valloc_align(map, size, 0, 0));
 }
 
 vaddr_t
-uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align)
+uvm_km_valloc_try(struct vm_map *map, vsize_t size)
+{
+   return(uvm_km_valloc_align(map, size, 0, UVM_FLAG_TRYLOCK));
+}
+
+vaddr_t
+uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align, int flags)
 {
vaddr_t kva;
UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist);
@@ -592,7 +598,7 @@
 
if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
-   UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) {
+   UVM_INH_NONE, UVM_ADV_RANDOM, flags)) != 0)) {
UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
return(0);
}
Index: uvm_pager.c
===
RCS file: /home/tedu/cvs/src/sys/uvm/uvm_pager.c,v
retrieving revision 1.54
diff -u -r1.54 uvm_pager.c
--- uvm_pager.c 22 Jul 2009 21:05:37 -  1.54
+++ uvm_pager.c 2 Feb 2010 04:23:57 -
@@ -138,7 +138,7 @@
 {
KASSERT(pseg->start == 0);
KASSERT(pseg->use == 0);
-   pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
+   pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
 }
 
 /*



Re: uvm_pseg_get & uvm_pseg_lck

2010-01-31 Thread Owain Ainsworth
On Sun, Jan 31, 2010 at 02:05:35PM +0100, Mark Kettenis wrote:
> > Date: Thu, 28 Jan 2010 18:55:55 +0300
> > From: Mike Belopuhov 
> > 
> > Hi all,
> > 
> > could someone please enlighten me how this uvm_pseg_get is supposed
> > to work?
> > 
> > uvm_pseg_get
> > mtx_enter(&uvm_pseg_lck);
> > `-> uvm_pseg_init
> > `-> uvm_km_valloc
> > `-> uvm_km_valloc_align
> > `-> uvm_map
> > `-> vm_map_lock <-- sleeping lock
> > 
> > Debugger(10,d73eeeac,d03e0ee2,d06ab9a0,0) at Debugger+0x4
> > panic(d020319c,d73eeecc,d03ad948,d06ab980,d51c8000) at panic+0x61
> > mtx_enter(d06ab980,d51c8000,d51d8000,d02f70c5,1) at mtx_enter+0x5c
> > uvm_pseg_release(d51c8000,10,d73eeefc,d02f41d4,50) at uvm_pseg_release+0x64
> > uvm_aio_aiodone(d0f422e4,0,d11c1c3c,d73eef90,d02e763d) at 
> > uvm_aio_aiodone+0xba
> > uvm_aiodone_daemon(d11c1c3c) at uvm_aiodone_daemon+0x97
> > Bad frame pointer: 0xd079ceb8
> > 
> > OpenBSD 4.6.
> > 
> > Or am I missing something?
> 
> No, I think you're right.  I think uvm_pseg_init() should use a memory
> allocation function that can't sleep.
> 
> I think I brought this up before questioning whether uvm_km_valloc()
> was allowed to sleep (since we also have uvm_km_valloc_wait()).  To
> that question art@ answered that uvm_km_valloc() still was allowed to
> sleep.

Yes, correct.

valloc_wait is special and only used for the limited maps (phys and exec
iirc).

uvm_km_valloc_try or something would be trivial to write which is a
valloc that only does a trylock on the map.

-0-
-- 
In order to make an apple pie from scratch, you must first create the
universe.
-- Carl Sagan, Cosmos



Re: uvm_pseg_get & uvm_pseg_lck

2010-01-31 Thread Mark Kettenis
> Date: Thu, 28 Jan 2010 18:55:55 +0300
> From: Mike Belopuhov 
> 
> Hi all,
> 
> could someone please enlighten me how this uvm_pseg_get is supposed
> to work?
> 
> uvm_pseg_get
> mtx_enter(&uvm_pseg_lck);
> `-> uvm_pseg_init
> `-> uvm_km_valloc
> `-> uvm_km_valloc_align
> `-> uvm_map
> `-> vm_map_lock <-- sleeping lock
> 
> Debugger(10,d73eeeac,d03e0ee2,d06ab9a0,0) at Debugger+0x4
> panic(d020319c,d73eeecc,d03ad948,d06ab980,d51c8000) at panic+0x61
> mtx_enter(d06ab980,d51c8000,d51d8000,d02f70c5,1) at mtx_enter+0x5c
> uvm_pseg_release(d51c8000,10,d73eeefc,d02f41d4,50) at uvm_pseg_release+0x64
> uvm_aio_aiodone(d0f422e4,0,d11c1c3c,d73eef90,d02e763d) at uvm_aio_aiodone+0xba
> uvm_aiodone_daemon(d11c1c3c) at uvm_aiodone_daemon+0x97
> Bad frame pointer: 0xd079ceb8
> 
> OpenBSD 4.6.
> 
> Or am I missing something?

No, I think you're right.  I think uvm_pseg_init() should use a memory
allocation function that can't sleep.

I think I brought this up before questioning whether uvm_km_valloc()
was allowed to sleep (since we also have uvm_km_valloc_wait()).  To
that question art@ answered that uvm_km_valloc() still was allowed to
sleep.



Re: uvm_pseg_get & uvm_pseg_lck

2010-01-28 Thread Ariane van der Steldt
On Thu, Jan 28, 2010 at 06:55:55PM +0300, Mike Belopuhov wrote:
> could someone please enlighten me how this uvm_pseg_get is supposed
> to work?
> 
> uvm_pseg_get
> mtx_enter(&uvm_pseg_lck);
> `-> uvm_pseg_init
> `-> uvm_km_valloc
> `-> uvm_km_valloc_align
> `-> uvm_map
> `-> vm_map_lock <-- sleeping lock

It's supposed to work like that, except for the sleeping on the lock (if
the lock is busy, it should fail instead).

pseg was written to remove a deadlock during (heavy) paging. The system
works by holding on to a number of virtual addresses, each containing an
area of MAXBSIZE size. The first of these areas is always populated, so
that paging never fails (this was an issue when the diff was created).
The next are allocated when needed and freed when no longer needed, so
that the pager can speed up io (by queueing more) without holding on to
that memory when not doing anything.

uvm_km_valloc probably needs to be replaced by uvm_km_kmemalloc using
flags = UVM_KMF_TRYLOCK|UVM_KMF_VALLOC.
It is important that these are only virtual addresses, with no physical
memory backing them, so that pages from userland processes can be mapped
in to perform the IO for paging out.

> Debugger(10,d73eeeac,d03e0ee2,d06ab9a0,0) at Debugger+0x4
> panic(d020319c,d73eeecc,d03ad948,d06ab980,d51c8000) at panic+0x61
> mtx_enter(d06ab980,d51c8000,d51d8000,d02f70c5,1) at mtx_enter+0x5c
> uvm_pseg_release(d51c8000,10,d73eeefc,d02f41d4,50) at uvm_pseg_release+0x64
> uvm_aio_aiodone(d0f422e4,0,d11c1c3c,d73eef90,d02e763d) at uvm_aio_aiodone+0xba
> uvm_aiodone_daemon(d11c1c3c) at uvm_aiodone_daemon+0x97
> Bad frame pointer: 0xd079ceb8
> 
> OpenBSD 4.6.
> 
> Or am I missing something?

You're not missing anything. My fault for misinterpreting the
distinction between uvm_km_valloc{,_wait}.

I don't have a reproducable case. How did you hit the panic?

Ciao,
-- 
Ariane



uvm_pseg_get & uvm_pseg_lck

2010-01-28 Thread Mike Belopuhov
Hi all,

could someone please enlighten me how this uvm_pseg_get is supposed
to work?

uvm_pseg_get
mtx_enter(&uvm_pseg_lck);
`-> uvm_pseg_init
`-> uvm_km_valloc
`-> uvm_km_valloc_align
`-> uvm_map
`-> vm_map_lock <-- sleeping lock

Debugger(10,d73eeeac,d03e0ee2,d06ab9a0,0) at Debugger+0x4
panic(d020319c,d73eeecc,d03ad948,d06ab980,d51c8000) at panic+0x61
mtx_enter(d06ab980,d51c8000,d51d8000,d02f70c5,1) at mtx_enter+0x5c
uvm_pseg_release(d51c8000,10,d73eeefc,d02f41d4,50) at uvm_pseg_release+0x64
uvm_aio_aiodone(d0f422e4,0,d11c1c3c,d73eef90,d02e763d) at uvm_aio_aiodone+0xba
uvm_aiodone_daemon(d11c1c3c) at uvm_aiodone_daemon+0x97
Bad frame pointer: 0xd079ceb8

OpenBSD 4.6.

Or am I missing something?