2008-02-07 11:13:49 +03:00
/*
* resource cgroups
*
* Copyright 2007 OpenVZ SWsoft Inc
*
* Author : Pavel Emelianov < xemul @ openvz . org >
*
*/
# include <linux/types.h>
# include <linux/parser.h>
# include <linux/fs.h>
2008-04-29 11:59:25 +04:00
# include <linux/slab.h>
2008-02-07 11:13:49 +03:00
# include <linux/res_counter.h>
# include <linux/uaccess.h>
void res_counter_init ( struct res_counter * counter )
{
spin_lock_init ( & counter - > lock ) ;
2008-02-07 11:13:57 +03:00
counter - > limit = ( unsigned long long ) LLONG_MAX ;
2008-02-07 11:13:49 +03:00
}
int res_counter_charge_locked ( struct res_counter * counter , unsigned long val )
{
if ( counter - > usage + val > counter - > limit ) {
counter - > failcnt + + ;
return - ENOMEM ;
}
counter - > usage + = val ;
2008-04-29 12:00:17 +04:00
if ( counter - > usage > counter - > max_usage )
counter - > max_usage = counter - > usage ;
2008-02-07 11:13:49 +03:00
return 0 ;
}
int res_counter_charge ( struct res_counter * counter , unsigned long val )
{
int ret ;
unsigned long flags ;
spin_lock_irqsave ( & counter - > lock , flags ) ;
ret = res_counter_charge_locked ( counter , val ) ;
spin_unlock_irqrestore ( & counter - > lock , flags ) ;
return ret ;
}
void res_counter_uncharge_locked ( struct res_counter * counter , unsigned long val )
{
if ( WARN_ON ( counter - > usage < val ) )
val = counter - > usage ;
counter - > usage - = val ;
}
void res_counter_uncharge ( struct res_counter * counter , unsigned long val )
{
unsigned long flags ;
spin_lock_irqsave ( & counter - > lock , flags ) ;
res_counter_uncharge_locked ( counter , val ) ;
spin_unlock_irqrestore ( & counter - > lock , flags ) ;
}
2008-02-07 11:13:57 +03:00
static inline unsigned long long *
res_counter_member ( struct res_counter * counter , int member )
2008-02-07 11:13:49 +03:00
{
switch ( member ) {
case RES_USAGE :
return & counter - > usage ;
2008-04-29 12:00:17 +04:00
case RES_MAX_USAGE :
return & counter - > max_usage ;
2008-02-07 11:13:49 +03:00
case RES_LIMIT :
return & counter - > limit ;
case RES_FAILCNT :
return & counter - > failcnt ;
} ;
BUG ( ) ;
return NULL ;
}
ssize_t res_counter_read ( struct res_counter * counter , int member ,
2008-02-07 11:13:57 +03:00
const char __user * userbuf , size_t nbytes , loff_t * pos ,
int ( * read_strategy ) ( unsigned long long val , char * st_buf ) )
2008-02-07 11:13:49 +03:00
{
2008-02-07 11:13:57 +03:00
unsigned long long * val ;
2008-02-07 11:13:49 +03:00
char buf [ 64 ] , * s ;
s = buf ;
val = res_counter_member ( counter , member ) ;
2008-02-07 11:13:57 +03:00
if ( read_strategy )
s + = read_strategy ( * val , s ) ;
else
s + = sprintf ( s , " %llu \n " , * val ) ;
2008-02-07 11:13:49 +03:00
return simple_read_from_buffer ( ( void __user * ) userbuf , nbytes ,
pos , buf , s - buf ) ;
}
2008-04-29 11:59:58 +04:00
u64 res_counter_read_u64 ( struct res_counter * counter , int member )
{
return * res_counter_member ( counter , member ) ;
}
2008-02-07 11:13:49 +03:00
ssize_t res_counter_write ( struct res_counter * counter , int member ,
2008-02-07 11:13:57 +03:00
const char __user * userbuf , size_t nbytes , loff_t * pos ,
int ( * write_strategy ) ( char * st_buf , unsigned long long * val ) )
2008-02-07 11:13:49 +03:00
{
int ret ;
char * buf , * end ;
2008-02-07 11:13:57 +03:00
unsigned long flags ;
unsigned long long tmp , * val ;
2008-02-07 11:13:49 +03:00
buf = kmalloc ( nbytes + 1 , GFP_KERNEL ) ;
ret = - ENOMEM ;
if ( buf = = NULL )
goto out ;
buf [ nbytes ] = ' \0 ' ;
ret = - EFAULT ;
if ( copy_from_user ( buf , userbuf , nbytes ) )
goto out_free ;
ret = - EINVAL ;
2008-03-05 01:28:24 +03:00
strstrip ( buf ) ;
2008-02-07 11:13:57 +03:00
if ( write_strategy ) {
if ( write_strategy ( buf , & tmp ) ) {
goto out_free ;
}
} else {
tmp = simple_strtoull ( buf , & end , 10 ) ;
if ( * end ! = ' \0 ' )
goto out_free ;
}
spin_lock_irqsave ( & counter - > lock , flags ) ;
2008-02-07 11:13:49 +03:00
val = res_counter_member ( counter , member ) ;
* val = tmp ;
2008-02-07 11:13:57 +03:00
spin_unlock_irqrestore ( & counter - > lock , flags ) ;
2008-02-07 11:13:49 +03:00
ret = nbytes ;
out_free :
kfree ( buf ) ;
out :
return ret ;
}