2005-04-16 15:20:36 -07:00
/*
2005-11-02 14:58:39 +11:00
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-16 15:20:36 -07:00
*
2005-11-02 14:58:39 +11:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-16 15:20:36 -07:00
* published by the Free Software Foundation .
*
2005-11-02 14:58:39 +11:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-16 15:20:36 -07:00
*
2005-11-02 14:58:39 +11:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-16 15:20:36 -07:00
*/
# include <linux/mm.h>
# include <linux/vmalloc.h>
# include <linux/highmem.h>
# include <linux/swap.h>
# include <linux/blkdev.h>
2006-10-19 23:28:16 -07:00
# include <linux/backing-dev.h>
2005-04-16 15:20:36 -07:00
# include "time.h"
# include "kmem.h"
# define MAX_VMALLOCS 6
# define MAX_SLAB_SIZE 0x20000
void *
2005-10-21 03:20:48 -04:00
kmem_alloc ( size_t size , unsigned int __nocast flags )
2005-04-16 15:20:36 -07:00
{
2005-10-21 03:20:48 -04:00
int retries = 0 ;
gfp_t lflags = kmem_flags_convert ( flags ) ;
void * ptr ;
2005-04-16 15:20:36 -07:00
2006-09-28 11:03:05 +10:00
# ifdef DEBUG
if ( unlikely ( ! ( flags & KM_LARGE ) & & ( size > PAGE_SIZE ) ) ) {
printk ( KERN_WARNING " Large %s attempt, size=%ld \n " ,
2008-04-10 12:19:21 +10:00
__func__ , ( long ) size ) ;
2006-09-28 11:03:05 +10:00
dump_stack ( ) ;
}
# endif
2005-04-16 15:20:36 -07:00
do {
if ( size < MAX_SLAB_SIZE | | retries > MAX_VMALLOCS )
ptr = kmalloc ( size , lflags ) ;
else
ptr = __vmalloc ( size , lflags , PAGE_KERNEL ) ;
if ( ptr | | ( flags & ( KM_MAYFAIL | KM_NOSLEEP ) ) )
return ptr ;
if ( ! ( + + retries % 100 ) )
printk ( KERN_ERR " XFS: possible memory allocation "
" deadlock in %s (mode:0x%x) \n " ,
2008-04-10 12:19:21 +10:00
__func__ , lflags ) ;
2006-10-19 23:28:16 -07:00
congestion_wait ( WRITE , HZ / 50 ) ;
2005-04-16 15:20:36 -07:00
} while ( 1 ) ;
}
void *
2005-10-21 03:20:48 -04:00
kmem_zalloc ( size_t size , unsigned int __nocast flags )
2005-04-16 15:20:36 -07:00
{
void * ptr ;
ptr = kmem_alloc ( size , flags ) ;
if ( ptr )
memset ( ( char * ) ptr , 0 , ( int ) size ) ;
return ptr ;
}
2006-09-28 11:03:27 +10:00
void *
kmem_zalloc_greedy ( size_t * size , size_t minsize , size_t maxsize ,
unsigned int __nocast flags )
{
2006-09-28 11:06:10 +10:00
void * ptr ;
size_t kmsize = maxsize ;
unsigned int kmflags = ( flags & ~ KM_SLEEP ) | KM_NOSLEEP ;
2006-09-28 11:03:27 +10:00
2006-09-28 11:06:10 +10:00
while ( ! ( ptr = kmem_zalloc ( kmsize , kmflags ) ) ) {
if ( ( kmsize < = minsize ) & & ( flags & KM_NOSLEEP ) )
break ;
if ( ( kmsize > > = 1 ) < = minsize ) {
kmsize = minsize ;
kmflags = flags ;
2006-09-28 11:03:27 +10:00
}
}
2006-09-28 11:06:10 +10:00
if ( ptr )
* size = kmsize ;
2006-09-28 11:03:27 +10:00
return ptr ;
}
2005-04-16 15:20:36 -07:00
void
kmem_free ( void * ptr , size_t size )
{
2008-02-04 22:28:34 -08:00
if ( ! is_vmalloc_addr ( ptr ) ) {
2005-04-16 15:20:36 -07:00
kfree ( ptr ) ;
} else {
vfree ( ptr ) ;
}
}
void *
2005-09-02 16:56:02 +10:00
kmem_realloc ( void * ptr , size_t newsize , size_t oldsize ,
2005-10-21 03:20:48 -04:00
unsigned int __nocast flags )
2005-04-16 15:20:36 -07:00
{
void * new ;
new = kmem_alloc ( newsize , flags ) ;
if ( ptr ) {
if ( new )
memcpy ( new , ptr ,
( ( oldsize < newsize ) ? oldsize : newsize ) ) ;
kmem_free ( ptr , oldsize ) ;
}
return new ;
}
void *
2005-10-21 03:20:48 -04:00
kmem_zone_alloc ( kmem_zone_t * zone , unsigned int __nocast flags )
2005-04-16 15:20:36 -07:00
{
2005-10-21 03:20:48 -04:00
int retries = 0 ;
gfp_t lflags = kmem_flags_convert ( flags ) ;
void * ptr ;
2005-04-16 15:20:36 -07:00
do {
ptr = kmem_cache_alloc ( zone , lflags ) ;
if ( ptr | | ( flags & ( KM_MAYFAIL | KM_NOSLEEP ) ) )
return ptr ;
if ( ! ( + + retries % 100 ) )
printk ( KERN_ERR " XFS: possible memory allocation "
" deadlock in %s (mode:0x%x) \n " ,
2008-04-10 12:19:21 +10:00
__func__ , lflags ) ;
2006-10-19 23:28:16 -07:00
congestion_wait ( WRITE , HZ / 50 ) ;
2005-04-16 15:20:36 -07:00
} while ( 1 ) ;
}
void *
2005-10-21 03:20:48 -04:00
kmem_zone_zalloc ( kmem_zone_t * zone , unsigned int __nocast flags )
2005-04-16 15:20:36 -07:00
{
void * ptr ;
ptr = kmem_zone_alloc ( zone , flags ) ;
if ( ptr )
memset ( ( char * ) ptr , 0 , kmem_cache_size ( zone ) ) ;
return ptr ;
}