Allocate memory when dumping pipes with M_WAITOK flag.
On a system with huge number of pipes, M_NOWAIT failes almost always, because of memory fragmentation. My fix is different than the patch proposed by Pawel Malachowski, because in FreeBSD 5.x we cannot sleep while holding dummynet mutex (in 4.x there is no such lock). My fix is also ugly, but there is no easy way to prepare nice and clean fix. PR: kern/46557 Submitted by: Eugene Grosbein <eugen@grosbein.pp.ru> Reviewed by: mlaier
This commit is contained in:
parent
283ba8210a
commit
8c34a02cfb
@ -1867,17 +1867,14 @@ dn_copy_set(struct dn_flow_set *set, char *bp)
|
||||
return (char *)qp ;
|
||||
}
|
||||
|
||||
static int
|
||||
dummynet_get(struct sockopt *sopt)
|
||||
static size_t
|
||||
dn_calc_size(void)
|
||||
{
|
||||
char *buf, *bp ; /* bp is the "copy-pointer" */
|
||||
size_t size ;
|
||||
struct dn_flow_set *set ;
|
||||
struct dn_pipe *p ;
|
||||
int error=0 ;
|
||||
size_t size ;
|
||||
|
||||
/* XXX lock held too long */
|
||||
DUMMYNET_LOCK();
|
||||
DUMMYNET_LOCK_ASSERT();
|
||||
/*
|
||||
* compute size of data structures: list of pipes and flow_sets.
|
||||
*/
|
||||
@ -1887,8 +1884,35 @@ dummynet_get(struct sockopt *sopt)
|
||||
for (set = all_flow_sets ; set ; set = set->next )
|
||||
size += sizeof ( *set ) +
|
||||
set->rq_elements * sizeof(struct dn_flow_queue);
|
||||
buf = malloc(size, M_TEMP, M_NOWAIT);
|
||||
if (buf == 0) {
|
||||
return size ;
|
||||
}
|
||||
|
||||
static int
|
||||
dummynet_get(struct sockopt *sopt)
|
||||
{
|
||||
char *buf, *bp ; /* bp is the "copy-pointer" */
|
||||
size_t size ;
|
||||
struct dn_flow_set *set ;
|
||||
struct dn_pipe *p ;
|
||||
int error=0, i ;
|
||||
|
||||
/* XXX lock held too long */
|
||||
DUMMYNET_LOCK();
|
||||
/*
|
||||
* XXX: Ugly, but we need to allocate memory with M_WAITOK flag and we
|
||||
* cannot use this flag while holding a mutex.
|
||||
*/
|
||||
for (i = 0; i < 10; i++) {
|
||||
size = dn_calc_size();
|
||||
DUMMYNET_UNLOCK();
|
||||
buf = malloc(size, M_TEMP, M_WAITOK);
|
||||
DUMMYNET_LOCK();
|
||||
if (size == dn_calc_size())
|
||||
break;
|
||||
free(buf, M_TEMP);
|
||||
buf = NULL;
|
||||
}
|
||||
if (buf == NULL) {
|
||||
DUMMYNET_UNLOCK();
|
||||
return ENOBUFS ;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user