2005-04-17 02:20:36 +04:00
/*
* Implementation of the diskquota system for the LINUX operating system . QUOTA
* is implemented using the BSD system call interface as the means of
* communication with the user level . This file contains the generic routines
* called by the different filesystems on allocation of an inode or block .
* These routines take care of the administration needed to have a consistent
* diskquota tracking system . The ideas of both user and group quotas are based
* on the Melbourne quota system as used on BSD derived systems . The internal
* implementation is based on one of the several variants of the LINUX
* inode - subsystem with added complexity of the diskquota system .
*
* Author : Marco van Wieringen < mvw @ planets . elm . net >
*
* Fixes : Dmitry Gorodchanin < pgmdsg @ ibi . com > , 11 Feb 96
*
* Revised list management to avoid races
* - - Bill Hawes , < whawes @ star . net > , 9 / 98
*
* Fixed races in dquot_transfer ( ) , dqget ( ) and dquot_alloc_ . . . ( ) .
* As the consequence the locking was moved from dquot_decr_ . . . ( ) ,
* dquot_incr_ . . . ( ) to calling functions .
* invalidate_dquots ( ) now writes modified dquots .
* Serialized quota_off ( ) and quota_on ( ) for mount point .
* Fixed a few bugs in grow_dquots ( ) .
* Fixed deadlock in write_dquot ( ) - we no longer account quotas on
* quota files
* remove_dquot_ref ( ) moved to inode . c - it now traverses through inodes
* add_dquot_ref ( ) restarts after blocking
* Added check for bogus uid and fixed check for group in quotactl .
* Jan Kara , < jack @ suse . cz > , sponsored by SuSE CR , 10 - 11 / 99
*
* Used struct list_head instead of own list struct
* Invalidation of referenced dquots is no longer possible
* Improved free_dquots list management
* Quota and i_blocks are now updated in one place to avoid races
* Warnings are now delayed so we won ' t block in critical section
* Write updated not to require dquot lock
* Jan Kara , < jack @ suse . cz > , 9 / 2000
*
* Added dynamic quota structure allocation
* Jan Kara < jack @ suse . cz > 12 / 2000
*
* Rewritten quota interface . Implemented new quota format and
* formats registering .
* Jan Kara , < jack @ suse . cz > , 2001 , 2002
*
* New SMP locking .
* Jan Kara , < jack @ suse . cz > , 10 / 2002
*
* Added journalled quota support , fix lock inversion problems
* Jan Kara , < jack @ suse . cz > , 2003 , 2004
*
* ( C ) Copyright 1994 - 1997 Marco van Wieringen
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/mount.h>
# include <linux/mm.h>
# include <linux/time.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/fcntl.h>
# include <linux/stat.h>
# include <linux/tty.h>
# include <linux/file.h>
# include <linux/slab.h>
# include <linux/sysctl.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/proc_fs.h>
# include <linux/security.h>
# include <linux/kmod.h>
# include <linux/namei.h>
# include <linux/buffer_head.h>
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-11-07 11:59:35 +03:00
# include <linux/quotaops.h>
2007-02-12 11:51:57 +03:00
# include <linux/writeback.h> /* for inode_lock, oddly enough.. */
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# define __DQUOT_PARANOIA
/*
2009-01-12 19:23:05 +03:00
* There are three quota SMP locks . dq_list_lock protects all lists with quotas
* and quota formats , dqstats structure containing statistics about the lists
* dq_data_lock protects data from dq_dqb and also mem_dqinfo structures and
* also guards consistency of dquot - > dq_dqb with inode - > i_blocks , i_bytes .
2005-04-17 02:20:36 +04:00
* i_blocks and i_bytes updates itself are guarded by i_lock acquired directly
2009-01-12 19:23:05 +03:00
* in inode_add_bytes ( ) and inode_sub_bytes ( ) . dq_state_lock protects
* modifications of quota state ( on quotaon and quotaoff ) and readers who care
* about latest values take it as well .
2005-04-17 02:20:36 +04:00
*
2009-01-12 19:23:05 +03:00
* The spinlock ordering is hence : dq_data_lock > dq_list_lock > i_lock ,
* dq_list_lock > dq_state_lock
2005-04-17 02:20:36 +04:00
*
* Note that some things ( eg . sb pointer , type , id ) doesn ' t change during
* the life of the dquot structure and so needn ' t to be protected by a lock
*
* Any operation working on dquots via inode pointers must hold dqptr_sem . If
* operation is just reading pointers from inode ( or not using them at all ) the
2010-01-06 19:20:35 +03:00
* read lock is enough . If pointers are altered function must hold write lock .
* Special care needs to be taken about S_NOQUOTA inode flag ( marking that
* inode is a quota file ) . Functions adding pointers from inode to dquots have
* to check this flag under dqptr_sem and then ( if S_NOQUOTA is not set ) they
* have to do all pointer modifications before dropping dqptr_sem . This makes
* sure they cannot race with quotaon which first sets S_NOQUOTA flag and
* then drops all pointers to dquots from an inode .
2005-04-17 02:20:36 +04:00
*
2006-03-23 14:00:29 +03:00
* Each dquot has its dq_lock mutex . Locked dquots might not be referenced
2005-04-17 02:20:36 +04:00
* from inodes ( dquot_alloc_space ( ) and such don ' t check the dq_lock ) .
* Currently dquot is locked only when it is being read to memory ( or space for
* it is being allocated ) on the first dqget ( ) and when it is being released on
* the last dqput ( ) . The allocation and release oparations are serialized by
* the dq_lock and by checking the use count in dquot_release ( ) . Write
* operations on dquots don ' t hold dq_lock as they copy data under dq_data_lock
* spinlock to internal buffers before writing .
*
* Lock ordering ( including related VFS locks ) is the following :
2006-03-23 14:00:29 +03:00
* i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot - > dq_lock >
* dqio_mutex
2009-01-12 19:23:05 +03:00
* The lock ordering of dqptr_sem imposed by quota code is only dqonoff_sem >
* dqptr_sem . But filesystem has to count with the fact that functions such as
* dquot_alloc_space ( ) acquire dqptr_sem and they usually have to be called
* from inside a transaction to keep filesystem consistency after a crash . Also
* filesystems usually want to do some IO on dquot from - > mark_dirty which is
* called with dqptr_sem held .
2006-03-23 14:00:29 +03:00
* i_mutex on quota files is special ( it ' s below dqio_mutex )
2005-04-17 02:20:36 +04:00
*/
2009-01-26 17:32:46 +03:00
static __cacheline_aligned_in_smp DEFINE_SPINLOCK ( dq_list_lock ) ;
static __cacheline_aligned_in_smp DEFINE_SPINLOCK ( dq_state_lock ) ;
__cacheline_aligned_in_smp DEFINE_SPINLOCK ( dq_data_lock ) ;
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dq_data_lock ) ;
2005-04-17 02:20:36 +04:00
static char * quotatypes [ ] = INITQFNAMES ;
static struct quota_format_type * quota_formats ; /* List of registered formats */
static struct quota_module_name module_names [ ] = INIT_QUOTA_MODULE_NAMES ;
/* SLAB cache for dquot structures */
2006-12-07 07:33:20 +03:00
static struct kmem_cache * dquot_cachep ;
2005-04-17 02:20:36 +04:00
int register_quota_format ( struct quota_format_type * fmt )
{
spin_lock ( & dq_list_lock ) ;
fmt - > qf_next = quota_formats ;
quota_formats = fmt ;
spin_unlock ( & dq_list_lock ) ;
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( register_quota_format ) ;
2005-04-17 02:20:36 +04:00
void unregister_quota_format ( struct quota_format_type * fmt )
{
struct quota_format_type * * actqf ;
spin_lock ( & dq_list_lock ) ;
2009-01-27 17:47:22 +03:00
for ( actqf = & quota_formats ; * actqf & & * actqf ! = fmt ;
actqf = & ( * actqf ) - > qf_next )
;
2005-04-17 02:20:36 +04:00
if ( * actqf )
* actqf = ( * actqf ) - > qf_next ;
spin_unlock ( & dq_list_lock ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( unregister_quota_format ) ;
2005-04-17 02:20:36 +04:00
static struct quota_format_type * find_quota_format ( int id )
{
struct quota_format_type * actqf ;
spin_lock ( & dq_list_lock ) ;
2009-01-27 17:47:22 +03:00
for ( actqf = quota_formats ; actqf & & actqf - > qf_fmt_id ! = id ;
actqf = actqf - > qf_next )
;
2005-04-17 02:20:36 +04:00
if ( ! actqf | | ! try_module_get ( actqf - > qf_owner ) ) {
int qm ;
spin_unlock ( & dq_list_lock ) ;
2009-01-27 17:47:22 +03:00
for ( qm = 0 ; module_names [ qm ] . qm_fmt_id & &
module_names [ qm ] . qm_fmt_id ! = id ; qm + + )
;
if ( ! module_names [ qm ] . qm_fmt_id | |
request_module ( module_names [ qm ] . qm_mod_name ) )
2005-04-17 02:20:36 +04:00
return NULL ;
spin_lock ( & dq_list_lock ) ;
2009-01-27 17:47:22 +03:00
for ( actqf = quota_formats ; actqf & & actqf - > qf_fmt_id ! = id ;
actqf = actqf - > qf_next )
;
2005-04-17 02:20:36 +04:00
if ( actqf & & ! try_module_get ( actqf - > qf_owner ) )
actqf = NULL ;
}
spin_unlock ( & dq_list_lock ) ;
return actqf ;
}
static void put_quota_format ( struct quota_format_type * fmt )
{
module_put ( fmt - > qf_owner ) ;
}
/*
* Dquot List Management :
* The quota code uses three lists for dquot management : the inuse_list ,
* free_dquots , and dquot_hash [ ] array . A single dquot structure may be
* on all three lists , depending on its current state .
*
* All dquots are placed to the end of inuse_list when first created , and this
* list is used for invalidate operation , which must look at every dquot .
*
* Unused dquots ( dq_count = = 0 ) are added to the free_dquots list when freed ,
* and this list is searched whenever we need an available dquot . Dquots are
* removed from the list as soon as they are used again , and
* dqstats . free_dquots gives the number of dquots on the list . When
* dquot is invalidated it ' s completely released from memory .
*
* Dquots with a specific identity ( device , type and id ) are placed on
* one of the dquot_hash [ ] hash chains . The provides an efficient search
* mechanism to locate a specific dquot .
*/
static LIST_HEAD ( inuse_list ) ;
static LIST_HEAD ( free_dquots ) ;
static unsigned int dq_hash_bits , dq_hash_mask ;
static struct hlist_head * dquot_hash ;
struct dqstats dqstats ;
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dqstats ) ;
2005-04-17 02:20:36 +04:00
2010-02-09 20:20:39 +03:00
static qsize_t inode_get_rsv_space ( struct inode * inode ) ;
2005-04-17 02:20:36 +04:00
static inline unsigned int
hashfn ( const struct super_block * sb , unsigned int id , int type )
{
unsigned long tmp ;
tmp = ( ( ( unsigned long ) sb > > L1_CACHE_SHIFT ) ^ id ) * ( MAXQUOTAS - type ) ;
return ( tmp + ( tmp > > dq_hash_bits ) ) & dq_hash_mask ;
}
/*
* Following list functions expect dq_list_lock to be held
*/
static inline void insert_dquot_hash ( struct dquot * dquot )
{
2009-01-27 17:47:22 +03:00
struct hlist_head * head ;
head = dquot_hash + hashfn ( dquot - > dq_sb , dquot - > dq_id , dquot - > dq_type ) ;
2005-04-17 02:20:36 +04:00
hlist_add_head ( & dquot - > dq_hash , head ) ;
}
static inline void remove_dquot_hash ( struct dquot * dquot )
{
hlist_del_init ( & dquot - > dq_hash ) ;
}
2009-01-27 03:47:11 +03:00
static struct dquot * find_dquot ( unsigned int hashent , struct super_block * sb ,
unsigned int id , int type )
2005-04-17 02:20:36 +04:00
{
struct hlist_node * node ;
struct dquot * dquot ;
hlist_for_each ( node , dquot_hash + hashent ) {
dquot = hlist_entry ( node , struct dquot , dq_hash ) ;
2009-01-27 17:47:22 +03:00
if ( dquot - > dq_sb = = sb & & dquot - > dq_id = = id & &
dquot - > dq_type = = type )
2005-04-17 02:20:36 +04:00
return dquot ;
}
2009-01-26 18:01:43 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
/* Add a dquot to the tail of the free list */
static inline void put_dquot_last ( struct dquot * dquot )
{
2006-06-26 11:24:37 +04:00
list_add_tail ( & dquot - > dq_free , & free_dquots ) ;
2005-04-17 02:20:36 +04:00
dqstats . free_dquots + + ;
}
static inline void remove_free_dquot ( struct dquot * dquot )
{
if ( list_empty ( & dquot - > dq_free ) )
return ;
list_del_init ( & dquot - > dq_free ) ;
dqstats . free_dquots - - ;
}
static inline void put_inuse ( struct dquot * dquot )
{
/* We add to the back of inuse list so we don't have to restart
* when traversing this list and we block */
2006-06-26 11:24:37 +04:00
list_add_tail ( & dquot - > dq_inuse , & inuse_list ) ;
2005-04-17 02:20:36 +04:00
dqstats . allocated_dquots + + ;
}
static inline void remove_inuse ( struct dquot * dquot )
{
dqstats . allocated_dquots - - ;
list_del ( & dquot - > dq_inuse ) ;
}
/*
* End of list functions needing dq_list_lock
*/
static void wait_on_dquot ( struct dquot * dquot )
{
2006-03-23 14:00:29 +03:00
mutex_lock ( & dquot - > dq_lock ) ;
mutex_unlock ( & dquot - > dq_lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-28 13:14:32 +04:00
static inline int dquot_dirty ( struct dquot * dquot )
{
return test_bit ( DQ_MOD_B , & dquot - > dq_flags ) ;
}
static inline int mark_dquot_dirty ( struct dquot * dquot )
{
return dquot - > dq_sb - > dq_op - > mark_dirty ( dquot ) ;
}
2005-04-17 02:20:36 +04:00
int dquot_mark_dquot_dirty ( struct dquot * dquot )
{
spin_lock ( & dq_list_lock ) ;
if ( ! test_and_set_bit ( DQ_MOD_B , & dquot - > dq_flags ) )
list_add ( & dquot - > dq_dirty , & sb_dqopt ( dquot - > dq_sb ) - >
info [ dquot - > dq_type ] . dqi_dirty_list ) ;
spin_unlock ( & dq_list_lock ) ;
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_mark_dquot_dirty ) ;
2005-04-17 02:20:36 +04:00
2009-12-14 15:21:15 +03:00
/* Dirtify all the dquots - this can block when journalling */
static inline int mark_all_dquot_dirty ( struct dquot * const * dquot )
{
int ret , err , cnt ;
ret = err = 0 ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
if ( dquot [ cnt ] )
/* Even in case of error we have to continue */
ret = mark_dquot_dirty ( dquot [ cnt ] ) ;
if ( ! err )
err = ret ;
}
return err ;
}
static inline void dqput_all ( struct dquot * * dquot )
{
unsigned int cnt ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
dqput ( dquot [ cnt ] ) ;
}
2005-04-17 02:20:36 +04:00
/* This function needs dq_list_lock */
static inline int clear_dquot_dirty ( struct dquot * dquot )
{
if ( ! test_and_clear_bit ( DQ_MOD_B , & dquot - > dq_flags ) )
return 0 ;
list_del_init ( & dquot - > dq_dirty ) ;
return 1 ;
}
void mark_info_dirty ( struct super_block * sb , int type )
{
set_bit ( DQF_INFO_DIRTY_B , & sb_dqopt ( sb ) - > info [ type ] . dqi_flags ) ;
}
EXPORT_SYMBOL ( mark_info_dirty ) ;
/*
* Read dquot from disk and alloc space for it
*/
int dquot_acquire ( struct dquot * dquot )
{
int ret = 0 , ret2 = 0 ;
struct quota_info * dqopt = sb_dqopt ( dquot - > dq_sb ) ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dquot - > dq_lock ) ;
mutex_lock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( ! test_bit ( DQ_READ_B , & dquot - > dq_flags ) )
ret = dqopt - > ops [ dquot - > dq_type ] - > read_dqblk ( dquot ) ;
if ( ret < 0 )
goto out_iolock ;
set_bit ( DQ_READ_B , & dquot - > dq_flags ) ;
/* Instantiate dquot if needed */
if ( ! test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) & & ! dquot - > dq_off ) {
ret = dqopt - > ops [ dquot - > dq_type ] - > commit_dqblk ( dquot ) ;
/* Write the info if needed */
2009-01-27 17:47:22 +03:00
if ( info_dirty ( & dqopt - > info [ dquot - > dq_type ] ) ) {
ret2 = dqopt - > ops [ dquot - > dq_type ] - > write_file_info (
dquot - > dq_sb , dquot - > dq_type ) ;
}
2005-04-17 02:20:36 +04:00
if ( ret < 0 )
goto out_iolock ;
if ( ret2 < 0 ) {
ret = ret2 ;
goto out_iolock ;
}
}
set_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) ;
out_iolock :
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
mutex_unlock ( & dquot - > dq_lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_acquire ) ;
2005-04-17 02:20:36 +04:00
/*
* Write dquot to disk
*/
int dquot_commit ( struct dquot * dquot )
{
int ret = 0 , ret2 = 0 ;
struct quota_info * dqopt = sb_dqopt ( dquot - > dq_sb ) ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dq_list_lock ) ;
if ( ! clear_dquot_dirty ( dquot ) ) {
spin_unlock ( & dq_list_lock ) ;
goto out_sem ;
}
spin_unlock ( & dq_list_lock ) ;
/* Inactive dquot can be only if there was error during read/init
* = > we have better not writing it */
if ( test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) ) {
ret = dqopt - > ops [ dquot - > dq_type ] - > commit_dqblk ( dquot ) ;
2009-01-27 17:47:22 +03:00
if ( info_dirty ( & dqopt - > info [ dquot - > dq_type ] ) ) {
ret2 = dqopt - > ops [ dquot - > dq_type ] - > write_file_info (
dquot - > dq_sb , dquot - > dq_type ) ;
}
2005-04-17 02:20:36 +04:00
if ( ret > = 0 )
ret = ret2 ;
}
out_sem :
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_commit ) ;
2005-04-17 02:20:36 +04:00
/*
* Release dquot
*/
int dquot_release ( struct dquot * dquot )
{
int ret = 0 , ret2 = 0 ;
struct quota_info * dqopt = sb_dqopt ( dquot - > dq_sb ) ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dquot - > dq_lock ) ;
2005-04-17 02:20:36 +04:00
/* Check whether we are not racing with some other dqget() */
if ( atomic_read ( & dquot - > dq_count ) > 1 )
goto out_dqlock ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( dqopt - > ops [ dquot - > dq_type ] - > release_dqblk ) {
ret = dqopt - > ops [ dquot - > dq_type ] - > release_dqblk ( dquot ) ;
/* Write the info */
2009-01-27 17:47:22 +03:00
if ( info_dirty ( & dqopt - > info [ dquot - > dq_type ] ) ) {
ret2 = dqopt - > ops [ dquot - > dq_type ] - > write_file_info (
dquot - > dq_sb , dquot - > dq_type ) ;
}
2005-04-17 02:20:36 +04:00
if ( ret > = 0 )
ret = ret2 ;
}
clear_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) ;
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
out_dqlock :
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dquot - > dq_lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_release ) ;
2005-04-17 02:20:36 +04:00
2008-11-25 17:31:32 +03:00
void dquot_destroy ( struct dquot * dquot )
2008-08-19 16:51:22 +04:00
{
kmem_cache_free ( dquot_cachep , dquot ) ;
}
2008-11-25 17:31:32 +03:00
EXPORT_SYMBOL ( dquot_destroy ) ;
2008-08-19 16:51:22 +04:00
static inline void do_destroy_dquot ( struct dquot * dquot )
{
dquot - > dq_sb - > dq_op - > destroy_dquot ( dquot ) ;
}
2005-04-17 02:20:36 +04:00
/* Invalidate all dquots on the list. Note that this function is called after
* quota is disabled and pointers from inodes removed so there cannot be new
2006-03-23 14:00:17 +03:00
* quota users . There can still be some users of quotas due to inodes being
* just deleted or pruned by prune_icache ( ) ( those are not attached to any
2009-01-12 19:23:05 +03:00
* list ) or parallel quotactl call . We have to wait for such users .
2006-03-23 14:00:17 +03:00
*/
2005-04-17 02:20:36 +04:00
static void invalidate_dquots ( struct super_block * sb , int type )
{
2005-06-26 01:59:36 +04:00
struct dquot * dquot , * tmp ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:17 +03:00
restart :
2005-04-17 02:20:36 +04:00
spin_lock ( & dq_list_lock ) ;
2005-06-26 01:59:36 +04:00
list_for_each_entry_safe ( dquot , tmp , & inuse_list , dq_inuse ) {
2005-04-17 02:20:36 +04:00
if ( dquot - > dq_sb ! = sb )
continue ;
if ( dquot - > dq_type ! = type )
continue ;
2006-03-23 14:00:17 +03:00
/* Wait for dquot users */
if ( atomic_read ( & dquot - > dq_count ) ) {
DEFINE_WAIT ( wait ) ;
atomic_inc ( & dquot - > dq_count ) ;
prepare_to_wait ( & dquot - > dq_wait_unused , & wait ,
TASK_UNINTERRUPTIBLE ) ;
spin_unlock ( & dq_list_lock ) ;
/* Once dqput() wakes us up, we know it's time to free
* the dquot .
* IMPORTANT : we rely on the fact that there is always
* at most one process waiting for dquot to free .
* Otherwise dq_count would be > 1 and we would never
* wake up .
*/
if ( atomic_read ( & dquot - > dq_count ) > 1 )
schedule ( ) ;
finish_wait ( & dquot - > dq_wait_unused , & wait ) ;
dqput ( dquot ) ;
/* At this moment dquot() need not exist (it could be
* reclaimed by prune_dqcache ( ) . Hence we must
* restart . */
goto restart ;
}
/*
* Quota now has no users and it has been written on last
* dqput ( )
*/
2005-04-17 02:20:36 +04:00
remove_dquot_hash ( dquot ) ;
remove_free_dquot ( dquot ) ;
remove_inuse ( dquot ) ;
2008-08-19 16:51:22 +04:00
do_destroy_dquot ( dquot ) ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & dq_list_lock ) ;
}
2008-10-20 19:05:00 +04:00
/* Call callback for every active dquot on given filesystem */
int dquot_scan_active ( struct super_block * sb ,
int ( * fn ) ( struct dquot * dquot , unsigned long priv ) ,
unsigned long priv )
{
struct dquot * dquot , * old_dquot = NULL ;
int ret = 0 ;
mutex_lock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
spin_lock ( & dq_list_lock ) ;
list_for_each_entry ( dquot , & inuse_list , dq_inuse ) {
if ( ! test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) )
continue ;
if ( dquot - > dq_sb ! = sb )
continue ;
/* Now we have active dquot so we can just increase use count */
atomic_inc ( & dquot - > dq_count ) ;
dqstats . lookups + + ;
spin_unlock ( & dq_list_lock ) ;
dqput ( old_dquot ) ;
old_dquot = dquot ;
ret = fn ( dquot , priv ) ;
if ( ret < 0 )
goto out ;
spin_lock ( & dq_list_lock ) ;
/* We are safe to continue now because our dquot could not
* be moved out of the inuse list while we hold the reference */
}
spin_unlock ( & dq_list_lock ) ;
out :
dqput ( old_dquot ) ;
mutex_unlock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_scan_active ) ;
2008-10-20 19:05:00 +04:00
2010-02-16 11:44:52 +03:00
int vfs_quota_sync ( struct super_block * sb , int type , int wait )
2005-04-17 02:20:36 +04:00
{
struct list_head * dirty ;
struct dquot * dquot ;
struct quota_info * dqopt = sb_dqopt ( sb ) ;
int cnt ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
if ( type ! = - 1 & & cnt ! = type )
continue ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_active ( sb , cnt ) )
2005-04-17 02:20:36 +04:00
continue ;
spin_lock ( & dq_list_lock ) ;
dirty = & dqopt - > info [ cnt ] . dqi_dirty_list ;
while ( ! list_empty ( dirty ) ) {
2009-01-27 17:47:22 +03:00
dquot = list_first_entry ( dirty , struct dquot ,
dq_dirty ) ;
2005-04-17 02:20:36 +04:00
/* Dirty and inactive can be only bad dquot... */
if ( ! test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) ) {
clear_dquot_dirty ( dquot ) ;
continue ;
}
/* Now we have active dquot from which someone is
* holding reference so we can safely just increase
* use count */
atomic_inc ( & dquot - > dq_count ) ;
dqstats . lookups + + ;
spin_unlock ( & dq_list_lock ) ;
sb - > dq_op - > write_dquot ( dquot ) ;
dqput ( dquot ) ;
spin_lock ( & dq_list_lock ) ;
}
spin_unlock ( & dq_list_lock ) ;
}
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2008-08-20 19:50:32 +04:00
if ( ( cnt = = type | | type = = - 1 ) & & sb_has_quota_active ( sb , cnt )
& & info_dirty ( & dqopt - > info [ cnt ] ) )
2005-04-17 02:20:36 +04:00
sb - > dq_op - > write_info ( sb , cnt ) ;
spin_lock ( & dq_list_lock ) ;
dqstats . syncs + + ;
spin_unlock ( & dq_list_lock ) ;
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
2010-02-16 11:44:52 +03:00
if ( ! wait | | ( sb_dqopt ( sb ) - > flags & DQUOT_QUOTA_SYS_FILE ) )
return 0 ;
/* This is not very clever (and fast) but currently I don't know about
* any other simple way of getting quota data to disk and we must get
* them there for userspace to be visible . . . */
if ( sb - > s_op - > sync_fs )
sb - > s_op - > sync_fs ( sb , 1 ) ;
sync_blockdev ( sb - > s_bdev ) ;
/*
* Now when everything is written we can discard the pagecache so
* that userspace sees the changes .
*/
mutex_lock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
if ( type ! = - 1 & & cnt ! = type )
continue ;
if ( ! sb_has_quota_active ( sb , cnt ) )
continue ;
mutex_lock_nested ( & sb_dqopt ( sb ) - > files [ cnt ] - > i_mutex ,
I_MUTEX_QUOTA ) ;
truncate_inode_pages ( & sb_dqopt ( sb ) - > files [ cnt ] - > i_data , 0 ) ;
mutex_unlock ( & sb_dqopt ( sb ) - > files [ cnt ] - > i_mutex ) ;
}
mutex_unlock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_sync ) ;
2005-04-17 02:20:36 +04:00
/* Free unused dquots from cache */
static void prune_dqcache ( int count )
{
struct list_head * head ;
struct dquot * dquot ;
head = free_dquots . prev ;
while ( head ! = & free_dquots & & count ) {
dquot = list_entry ( head , struct dquot , dq_free ) ;
remove_dquot_hash ( dquot ) ;
remove_free_dquot ( dquot ) ;
remove_inuse ( dquot ) ;
2008-08-19 16:51:22 +04:00
do_destroy_dquot ( dquot ) ;
2005-04-17 02:20:36 +04:00
count - - ;
head = free_dquots . prev ;
}
}
/*
* This is called from kswapd when we think we need some
* more memory
*/
2005-10-21 11:20:48 +04:00
static int shrink_dqcache_memory ( int nr , gfp_t gfp_mask )
2005-04-17 02:20:36 +04:00
{
if ( nr ) {
spin_lock ( & dq_list_lock ) ;
prune_dqcache ( nr ) ;
spin_unlock ( & dq_list_lock ) ;
}
return ( dqstats . free_dquots / 100 ) * sysctl_vfs_cache_pressure ;
}
2007-07-17 15:03:17 +04:00
static struct shrinker dqcache_shrinker = {
. shrink = shrink_dqcache_memory ,
. seeks = DEFAULT_SEEKS ,
} ;
2005-04-17 02:20:36 +04:00
/*
* Put reference to dquot
* NOTE : If you change this function please check whether dqput_blocks ( ) works right . . .
*/
2008-10-10 18:12:23 +04:00
void dqput ( struct dquot * dquot )
2005-04-17 02:20:36 +04:00
{
2008-07-25 12:46:49 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
if ( ! dquot )
return ;
# ifdef __DQUOT_PARANOIA
if ( ! atomic_read ( & dquot - > dq_count ) ) {
printk ( " VFS: dqput: trying to free free dquot \n " ) ;
printk ( " VFS: device %s, dquot of %s %d \n " ,
dquot - > dq_sb - > s_id ,
quotatypes [ dquot - > dq_type ] ,
dquot - > dq_id ) ;
BUG ( ) ;
}
# endif
spin_lock ( & dq_list_lock ) ;
dqstats . drops + + ;
spin_unlock ( & dq_list_lock ) ;
we_slept :
spin_lock ( & dq_list_lock ) ;
if ( atomic_read ( & dquot - > dq_count ) > 1 ) {
/* We have more than one user... nothing to do */
atomic_dec ( & dquot - > dq_count ) ;
2006-03-23 14:00:17 +03:00
/* Releasing dquot during quotaoff phase? */
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_active ( dquot - > dq_sb , dquot - > dq_type ) & &
2006-03-23 14:00:17 +03:00
atomic_read ( & dquot - > dq_count ) = = 1 )
wake_up ( & dquot - > dq_wait_unused ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_list_lock ) ;
return ;
}
/* Need to release dquot? */
if ( test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) & & dquot_dirty ( dquot ) ) {
spin_unlock ( & dq_list_lock ) ;
/* Commit dquot before releasing */
2008-07-25 12:46:49 +04:00
ret = dquot - > dq_sb - > dq_op - > write_dquot ( dquot ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " VFS: cannot write quota structure on "
" device %s (error %d). Quota may get out of "
" sync! \n " , dquot - > dq_sb - > s_id , ret ) ;
/*
* We clear dirty bit anyway , so that we avoid
* infinite loop here
*/
spin_lock ( & dq_list_lock ) ;
clear_dquot_dirty ( dquot ) ;
spin_unlock ( & dq_list_lock ) ;
}
2005-04-17 02:20:36 +04:00
goto we_slept ;
}
/* Clear flag in case dquot was inactive (something bad happened) */
clear_dquot_dirty ( dquot ) ;
if ( test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) ) {
spin_unlock ( & dq_list_lock ) ;
dquot - > dq_sb - > dq_op - > release_dquot ( dquot ) ;
goto we_slept ;
}
atomic_dec ( & dquot - > dq_count ) ;
# ifdef __DQUOT_PARANOIA
/* sanity check */
2006-04-02 15:36:13 +04:00
BUG_ON ( ! list_empty ( & dquot - > dq_free ) ) ;
2005-04-17 02:20:36 +04:00
# endif
put_dquot_last ( dquot ) ;
spin_unlock ( & dq_list_lock ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dqput ) ;
2005-04-17 02:20:36 +04:00
2008-11-25 17:31:32 +03:00
struct dquot * dquot_alloc ( struct super_block * sb , int type )
2008-08-19 16:51:22 +04:00
{
return kmem_cache_zalloc ( dquot_cachep , GFP_NOFS ) ;
}
2008-11-25 17:31:32 +03:00
EXPORT_SYMBOL ( dquot_alloc ) ;
2008-08-19 16:51:22 +04:00
2005-04-17 02:20:36 +04:00
static struct dquot * get_empty_dquot ( struct super_block * sb , int type )
{
struct dquot * dquot ;
2008-08-19 16:51:22 +04:00
dquot = sb - > dq_op - > alloc_dquot ( sb , type ) ;
2005-04-17 02:20:36 +04:00
if ( ! dquot )
2009-01-26 18:01:43 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
mutex_init ( & dquot - > dq_lock ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & dquot - > dq_free ) ;
INIT_LIST_HEAD ( & dquot - > dq_inuse ) ;
INIT_HLIST_NODE ( & dquot - > dq_hash ) ;
INIT_LIST_HEAD ( & dquot - > dq_dirty ) ;
2006-03-23 14:00:17 +03:00
init_waitqueue_head ( & dquot - > dq_wait_unused ) ;
2005-04-17 02:20:36 +04:00
dquot - > dq_sb = sb ;
dquot - > dq_type = type ;
atomic_set ( & dquot - > dq_count , 1 ) ;
return dquot ;
}
/*
* Get reference to dquot
2009-01-12 19:23:05 +03:00
*
* Locking is slightly tricky here . We are guarded from parallel quotaoff ( )
* destroying our dquot by :
* a ) checking for quota flags under dq_list_lock and
* b ) getting a reference to dquot before we release dq_list_lock
2005-04-17 02:20:36 +04:00
*/
2008-10-10 18:12:23 +04:00
struct dquot * dqget ( struct super_block * sb , unsigned int id , int type )
2005-04-17 02:20:36 +04:00
{
unsigned int hashent = hashfn ( sb , id , type ) ;
2009-01-26 18:01:43 +03:00
struct dquot * dquot = NULL , * empty = NULL ;
2005-04-17 02:20:36 +04:00
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_active ( sb , type ) )
2009-01-26 18:01:43 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
we_slept :
spin_lock ( & dq_list_lock ) ;
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
if ( ! sb_has_quota_active ( sb , type ) ) {
spin_unlock ( & dq_state_lock ) ;
spin_unlock ( & dq_list_lock ) ;
goto out ;
}
spin_unlock ( & dq_state_lock ) ;
2009-01-26 18:01:43 +03:00
dquot = find_dquot ( hashent , sb , id , type ) ;
if ( ! dquot ) {
if ( ! empty ) {
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_list_lock ) ;
2009-01-26 18:01:43 +03:00
empty = get_empty_dquot ( sb , type ) ;
if ( ! empty )
2005-04-17 02:20:36 +04:00
schedule ( ) ; /* Try to wait for a moment... */
goto we_slept ;
}
dquot = empty ;
2009-01-26 18:01:43 +03:00
empty = NULL ;
2005-04-17 02:20:36 +04:00
dquot - > dq_id = id ;
/* all dquots go on the inuse_list */
put_inuse ( dquot ) ;
/* hash it first so it can be found */
insert_dquot_hash ( dquot ) ;
dqstats . lookups + + ;
spin_unlock ( & dq_list_lock ) ;
} else {
if ( ! atomic_read ( & dquot - > dq_count ) )
remove_free_dquot ( dquot ) ;
atomic_inc ( & dquot - > dq_count ) ;
dqstats . cache_hits + + ;
dqstats . lookups + + ;
spin_unlock ( & dq_list_lock ) ;
}
2009-01-27 17:47:22 +03:00
/* Wait for dq_lock - after this we know that either dquot_release() is
* already finished or it will be canceled due to dq_count > 1 test */
2005-04-17 02:20:36 +04:00
wait_on_dquot ( dquot ) ;
2009-01-27 17:47:22 +03:00
/* Read the dquot / allocate space in quota file */
if ( ! test_bit ( DQ_ACTIVE_B , & dquot - > dq_flags ) & &
sb - > dq_op - > acquire_dquot ( dquot ) < 0 ) {
2005-04-17 02:20:36 +04:00
dqput ( dquot ) ;
2009-01-26 18:01:43 +03:00
dquot = NULL ;
2009-01-12 19:23:05 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
# ifdef __DQUOT_PARANOIA
2006-04-02 15:36:13 +04:00
BUG_ON ( ! dquot - > dq_sb ) ; /* Has somebody invalidated entry under us? */
2005-04-17 02:20:36 +04:00
# endif
2009-01-12 19:23:05 +03:00
out :
if ( empty )
do_destroy_dquot ( empty ) ;
2005-04-17 02:20:36 +04:00
return dquot ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dqget ) ;
2005-04-17 02:20:36 +04:00
static int dqinit_needed ( struct inode * inode , int type )
{
int cnt ;
if ( IS_NOQUOTA ( inode ) )
return 0 ;
if ( type ! = - 1 )
2009-01-26 18:01:43 +03:00
return ! inode - > i_dquot [ type ] ;
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
return 1 ;
return 0 ;
}
2006-03-23 14:00:29 +03:00
/* This routine is guarded by dqonoff_mutex mutex */
2005-04-17 02:20:36 +04:00
static void add_dquot_ref ( struct super_block * sb , int type )
{
2008-02-06 12:37:36 +03:00
struct inode * inode , * old_inode = NULL ;
2010-02-09 20:20:39 +03:00
int reserved = 0 ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:51:58 +03:00
spin_lock ( & inode_lock ) ;
list_for_each_entry ( inode , & sb - > s_inodes , i_sb_list ) {
2009-04-03 03:56:34 +04:00
if ( inode - > i_state & ( I_FREEING | I_CLEAR | I_WILL_FREE | I_NEW ) )
2009-03-11 23:17:36 +03:00
continue ;
2010-02-09 20:20:39 +03:00
if ( unlikely ( inode_get_rsv_space ( inode ) > 0 ) )
reserved = 1 ;
2007-02-12 11:51:58 +03:00
if ( ! atomic_read ( & inode - > i_writecount ) )
continue ;
if ( ! dqinit_needed ( inode , type ) )
continue ;
__iget ( inode ) ;
spin_unlock ( & inode_lock ) ;
2008-02-06 12:37:36 +03:00
iput ( old_inode ) ;
2007-02-12 11:51:58 +03:00
sb - > dq_op - > initialize ( inode , type ) ;
2008-02-06 12:37:36 +03:00
/* We hold a reference to 'inode' so it couldn't have been
* removed from s_inodes list while we dropped the inode_lock .
* We cannot iput the inode now as we can be holding the last
* reference and we cannot iput it under inode_lock . So we
* keep the reference and iput it later . */
old_inode = inode ;
spin_lock ( & inode_lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:51:58 +03:00
spin_unlock ( & inode_lock ) ;
2008-02-06 12:37:36 +03:00
iput ( old_inode ) ;
2010-02-09 20:20:39 +03:00
if ( reserved ) {
printk ( KERN_WARNING " VFS (%s): Writes happened before quota "
" was turned on thus quota information is probably "
" inconsistent. Please run quotacheck(8). \n " , sb - > s_id ) ;
}
2005-04-17 02:20:36 +04:00
}
2009-01-27 17:47:22 +03:00
/*
* Return 0 if dqput ( ) won ' t block .
* ( note that 1 doesn ' t necessarily mean blocking )
*/
2005-04-17 02:20:36 +04:00
static inline int dqput_blocks ( struct dquot * dquot )
{
if ( atomic_read ( & dquot - > dq_count ) < = 1 )
return 1 ;
return 0 ;
}
2009-01-27 17:47:22 +03:00
/*
* Remove references to dquots from inode and add dquot to list for freeing
* if we have the last referece to dquot
* We can ' t race with anybody because we hold dqptr_sem for writing . . .
*/
2007-05-08 11:27:22 +04:00
static int remove_inode_dquot_ref ( struct inode * inode , int type ,
struct list_head * tofree_head )
2005-04-17 02:20:36 +04:00
{
struct dquot * dquot = inode - > i_dquot [ type ] ;
2009-01-26 18:01:43 +03:00
inode - > i_dquot [ type ] = NULL ;
if ( dquot ) {
2005-04-17 02:20:36 +04:00
if ( dqput_blocks ( dquot ) ) {
# ifdef __DQUOT_PARANOIA
if ( atomic_read ( & dquot - > dq_count ) ! = 1 )
printk ( KERN_WARNING " VFS: Adding dquot with dq_count %d to dispose list. \n " , atomic_read ( & dquot - > dq_count ) ) ;
# endif
spin_lock ( & dq_list_lock ) ;
2009-01-27 17:47:22 +03:00
/* As dquot must have currently users it can't be on
* the free list . . . */
list_add ( & dquot - > dq_free , tofree_head ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_list_lock ) ;
return 1 ;
}
else
dqput ( dquot ) ; /* We have guaranteed we won't block */
}
return 0 ;
}
2009-01-27 17:47:22 +03:00
/*
* Free list of dquots
* Dquots are removed from inodes and no new references can be got so we are
* the only ones holding reference
*/
2005-04-17 02:20:36 +04:00
static void put_dquot_list ( struct list_head * tofree_head )
{
struct list_head * act_head ;
struct dquot * dquot ;
act_head = tofree_head - > next ;
while ( act_head ! = tofree_head ) {
dquot = list_entry ( act_head , struct dquot , dq_free ) ;
act_head = act_head - > next ;
2009-01-27 17:47:22 +03:00
/* Remove dquot from the list so we won't have problems... */
list_del_init ( & dquot - > dq_free ) ;
2005-04-17 02:20:36 +04:00
dqput ( dquot ) ;
}
}
2007-02-12 11:51:57 +03:00
static void remove_dquot_ref ( struct super_block * sb , int type ,
struct list_head * tofree_head )
{
struct inode * inode ;
spin_lock ( & inode_lock ) ;
list_for_each_entry ( inode , & sb - > s_inodes , i_sb_list ) {
2009-03-11 23:17:36 +03:00
/*
* We have to scan also I_NEW inodes because they can already
* have quota pointer initialized . Luckily , we need to touch
* only quota pointers and these have separate locking
* ( dqptr_sem ) .
*/
2007-02-12 11:51:57 +03:00
if ( ! IS_NOQUOTA ( inode ) )
remove_inode_dquot_ref ( inode , type , tofree_head ) ;
}
spin_unlock ( & inode_lock ) ;
}
2005-04-17 02:20:36 +04:00
/* Gather all references from inodes and drop them */
static void drop_dquot_ref ( struct super_block * sb , int type )
{
LIST_HEAD ( tofree_head ) ;
2007-02-12 11:51:57 +03:00
if ( sb - > dq_op ) {
down_write ( & sb_dqopt ( sb ) - > dqptr_sem ) ;
remove_dquot_ref ( sb , type , & tofree_head ) ;
up_write ( & sb_dqopt ( sb ) - > dqptr_sem ) ;
put_dquot_list ( & tofree_head ) ;
}
2005-04-17 02:20:36 +04:00
}
2008-08-20 16:45:12 +04:00
static inline void dquot_incr_inodes ( struct dquot * dquot , qsize_t number )
2005-04-17 02:20:36 +04:00
{
dquot - > dq_dqb . dqb_curinodes + = number ;
}
static inline void dquot_incr_space ( struct dquot * dquot , qsize_t number )
{
dquot - > dq_dqb . dqb_curspace + = number ;
}
2009-01-13 18:43:09 +03:00
static inline void dquot_resv_space ( struct dquot * dquot , qsize_t number )
{
dquot - > dq_dqb . dqb_rsvspace + = number ;
}
2009-01-13 18:43:14 +03:00
/*
* Claim reserved quota space
*/
2010-02-09 20:20:39 +03:00
static void dquot_claim_reserved_space ( struct dquot * dquot , qsize_t number )
2009-01-13 18:43:14 +03:00
{
2010-02-09 20:20:39 +03:00
if ( dquot - > dq_dqb . dqb_rsvspace < number ) {
WARN_ON_ONCE ( 1 ) ;
number = dquot - > dq_dqb . dqb_rsvspace ;
}
2009-01-13 18:43:14 +03:00
dquot - > dq_dqb . dqb_curspace + = number ;
dquot - > dq_dqb . dqb_rsvspace - = number ;
}
static inline
void dquot_free_reserved_space ( struct dquot * dquot , qsize_t number )
{
2010-02-09 20:20:39 +03:00
if ( dquot - > dq_dqb . dqb_rsvspace > = number )
dquot - > dq_dqb . dqb_rsvspace - = number ;
else {
WARN_ON_ONCE ( 1 ) ;
dquot - > dq_dqb . dqb_rsvspace = 0 ;
}
2009-01-13 18:43:14 +03:00
}
2009-01-27 03:47:11 +03:00
static void dquot_decr_inodes ( struct dquot * dquot , qsize_t number )
2005-04-17 02:20:36 +04:00
{
2008-10-01 20:21:39 +04:00
if ( sb_dqopt ( dquot - > dq_sb ) - > flags & DQUOT_NEGATIVE_USAGE | |
dquot - > dq_dqb . dqb_curinodes > = number )
2005-04-17 02:20:36 +04:00
dquot - > dq_dqb . dqb_curinodes - = number ;
else
dquot - > dq_dqb . dqb_curinodes = 0 ;
if ( dquot - > dq_dqb . dqb_curinodes < = dquot - > dq_dqb . dqb_isoftlimit )
dquot - > dq_dqb . dqb_itime = ( time_t ) 0 ;
clear_bit ( DQ_INODES_B , & dquot - > dq_flags ) ;
}
2009-01-27 03:47:11 +03:00
static void dquot_decr_space ( struct dquot * dquot , qsize_t number )
2005-04-17 02:20:36 +04:00
{
2008-10-01 20:21:39 +04:00
if ( sb_dqopt ( dquot - > dq_sb ) - > flags & DQUOT_NEGATIVE_USAGE | |
dquot - > dq_dqb . dqb_curspace > = number )
2005-04-17 02:20:36 +04:00
dquot - > dq_dqb . dqb_curspace - = number ;
else
dquot - > dq_dqb . dqb_curspace = 0 ;
2008-08-20 16:45:12 +04:00
if ( dquot - > dq_dqb . dqb_curspace < = dquot - > dq_dqb . dqb_bsoftlimit )
2005-04-17 02:20:36 +04:00
dquot - > dq_dqb . dqb_btime = ( time_t ) 0 ;
clear_bit ( DQ_BLKS_B , & dquot - > dq_flags ) ;
}
2007-12-23 01:03:25 +03:00
static int warning_issued ( struct dquot * dquot , const int warntype )
{
int flag = ( warntype = = QUOTA_NL_BHARDWARN | |
warntype = = QUOTA_NL_BSOFTLONGWARN ) ? DQ_BLKS_B :
( ( warntype = = QUOTA_NL_IHARDWARN | |
warntype = = QUOTA_NL_ISOFTLONGWARN ) ? DQ_INODES_B : 0 ) ;
if ( ! flag )
return 0 ;
return test_and_set_bit ( flag , & dquot - > dq_flags ) ;
}
2007-10-17 10:29:31 +04:00
# ifdef CONFIG_PRINT_QUOTA_WARNING
2005-04-17 02:20:36 +04:00
static int flag_print_warnings = 1 ;
2009-01-27 03:47:11 +03:00
static int need_print_warning ( struct dquot * dquot )
2005-04-17 02:20:36 +04:00
{
if ( ! flag_print_warnings )
return 0 ;
switch ( dquot - > dq_type ) {
case USRQUOTA :
2008-11-14 02:39:05 +03:00
return current_fsuid ( ) = = dquot - > dq_id ;
2005-04-17 02:20:36 +04:00
case GRPQUOTA :
return in_group_p ( dquot - > dq_id ) ;
}
return 0 ;
}
/* Print warning to user which exceeded quota */
2007-12-23 01:03:25 +03:00
static void print_warning ( struct dquot * dquot , const int warntype )
2005-04-17 02:20:36 +04:00
{
char * msg = NULL ;
2006-12-08 13:36:04 +03:00
struct tty_struct * tty ;
2005-04-17 02:20:36 +04:00
2008-07-25 12:46:52 +04:00
if ( warntype = = QUOTA_NL_IHARDBELOW | |
warntype = = QUOTA_NL_ISOFTBELOW | |
warntype = = QUOTA_NL_BHARDBELOW | |
warntype = = QUOTA_NL_BSOFTBELOW | | ! need_print_warning ( dquot ) )
2005-04-17 02:20:36 +04:00
return ;
2006-12-08 13:36:04 +03:00
tty = get_current_tty ( ) ;
if ( ! tty )
2008-10-13 13:39:13 +04:00
return ;
2006-12-08 13:36:04 +03:00
tty_write_message ( tty , dquot - > dq_sb - > s_id ) ;
2007-10-17 10:29:31 +04:00
if ( warntype = = QUOTA_NL_ISOFTWARN | | warntype = = QUOTA_NL_BSOFTWARN )
2006-12-08 13:36:04 +03:00
tty_write_message ( tty , " : warning, " ) ;
2005-04-17 02:20:36 +04:00
else
2006-12-08 13:36:04 +03:00
tty_write_message ( tty , " : write failed, " ) ;
tty_write_message ( tty , quotatypes [ dquot - > dq_type ] ) ;
2005-04-17 02:20:36 +04:00
switch ( warntype ) {
2007-10-17 10:29:31 +04:00
case QUOTA_NL_IHARDWARN :
2005-04-17 02:20:36 +04:00
msg = " file limit reached. \r \n " ;
break ;
2007-10-17 10:29:31 +04:00
case QUOTA_NL_ISOFTLONGWARN :
2005-04-17 02:20:36 +04:00
msg = " file quota exceeded too long. \r \n " ;
break ;
2007-10-17 10:29:31 +04:00
case QUOTA_NL_ISOFTWARN :
2005-04-17 02:20:36 +04:00
msg = " file quota exceeded. \r \n " ;
break ;
2007-10-17 10:29:31 +04:00
case QUOTA_NL_BHARDWARN :
2005-04-17 02:20:36 +04:00
msg = " block limit reached. \r \n " ;
break ;
2007-10-17 10:29:31 +04:00
case QUOTA_NL_BSOFTLONGWARN :
2005-04-17 02:20:36 +04:00
msg = " block quota exceeded too long. \r \n " ;
break ;
2007-10-17 10:29:31 +04:00
case QUOTA_NL_BSOFTWARN :
2005-04-17 02:20:36 +04:00
msg = " block quota exceeded. \r \n " ;
break ;
}
2006-12-08 13:36:04 +03:00
tty_write_message ( tty , msg ) ;
2008-10-13 13:39:13 +04:00
tty_kref_put ( tty ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-17 10:29:31 +04:00
# endif
2009-01-13 18:43:09 +03:00
/*
* Write warnings to the console and send warning messages over netlink .
*
* Note that this function can sleep .
*/
2009-01-27 03:47:11 +03:00
static void flush_warnings ( struct dquot * const * dquots , char * warntype )
2005-04-17 02:20:36 +04:00
{
2009-09-28 15:35:17 +04:00
struct dquot * dq ;
2005-04-17 02:20:36 +04:00
int i ;
2009-09-28 15:35:17 +04:00
for ( i = 0 ; i < MAXQUOTAS ; i + + ) {
dq = dquots [ i ] ;
if ( dq & & warntype [ i ] ! = QUOTA_NL_NOWARN & &
! warning_issued ( dq , warntype [ i ] ) ) {
2007-10-17 10:29:31 +04:00
# ifdef CONFIG_PRINT_QUOTA_WARNING
2009-09-28 15:35:17 +04:00
print_warning ( dq , warntype [ i ] ) ;
2007-10-17 10:29:31 +04:00
# endif
2009-09-28 15:35:17 +04:00
quota_send_warning ( dq - > dq_type , dq - > dq_id ,
dq - > dq_sb - > s_dev , warntype [ i ] ) ;
2007-10-17 10:29:31 +04:00
}
2009-09-28 15:35:17 +04:00
}
2005-04-17 02:20:36 +04:00
}
2009-01-27 03:47:11 +03:00
static int ignore_hardlimit ( struct dquot * dquot )
2005-04-17 02:20:36 +04:00
{
struct mem_dqinfo * info = & sb_dqopt ( dquot - > dq_sb ) - > info [ dquot - > dq_type ] ;
return capable ( CAP_SYS_RESOURCE ) & &
2009-01-27 17:47:22 +03:00
( info - > dqi_format - > qf_fmt_id ! = QFMT_VFS_OLD | |
! ( info - > dqi_flags & V1_DQF_RSQUASH ) ) ;
2005-04-17 02:20:36 +04:00
}
/* needs dq_data_lock */
2008-08-20 16:45:12 +04:00
static int check_idq ( struct dquot * dquot , qsize_t inodes , char * warntype )
2005-04-17 02:20:36 +04:00
{
2009-01-27 17:47:22 +03:00
qsize_t newinodes = dquot - > dq_dqb . dqb_curinodes + inodes ;
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_NOWARN ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_limits_enabled ( dquot - > dq_sb , dquot - > dq_type ) | |
test_bit ( DQ_FAKE_B , & dquot - > dq_flags ) )
2005-04-17 02:20:36 +04:00
return QUOTA_OK ;
if ( dquot - > dq_dqb . dqb_ihardlimit & &
2009-01-27 17:47:22 +03:00
newinodes > dquot - > dq_dqb . dqb_ihardlimit & &
2005-04-17 02:20:36 +04:00
! ignore_hardlimit ( dquot ) ) {
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_IHARDWARN ;
2005-04-17 02:20:36 +04:00
return NO_QUOTA ;
}
if ( dquot - > dq_dqb . dqb_isoftlimit & &
2009-01-27 17:47:22 +03:00
newinodes > dquot - > dq_dqb . dqb_isoftlimit & &
dquot - > dq_dqb . dqb_itime & &
get_seconds ( ) > = dquot - > dq_dqb . dqb_itime & &
2005-04-17 02:20:36 +04:00
! ignore_hardlimit ( dquot ) ) {
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_ISOFTLONGWARN ;
2005-04-17 02:20:36 +04:00
return NO_QUOTA ;
}
if ( dquot - > dq_dqb . dqb_isoftlimit & &
2009-01-27 17:47:22 +03:00
newinodes > dquot - > dq_dqb . dqb_isoftlimit & &
2005-04-17 02:20:36 +04:00
dquot - > dq_dqb . dqb_itime = = 0 ) {
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_ISOFTWARN ;
2009-01-27 17:47:22 +03:00
dquot - > dq_dqb . dqb_itime = get_seconds ( ) +
sb_dqopt ( dquot - > dq_sb ) - > info [ dquot - > dq_type ] . dqi_igrace ;
2005-04-17 02:20:36 +04:00
}
return QUOTA_OK ;
}
/* needs dq_data_lock */
static int check_bdq ( struct dquot * dquot , qsize_t space , int prealloc , char * warntype )
{
2009-01-13 18:43:09 +03:00
qsize_t tspace ;
2009-01-27 17:47:22 +03:00
struct super_block * sb = dquot - > dq_sb ;
2009-01-13 18:43:09 +03:00
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_NOWARN ;
2009-01-27 17:47:22 +03:00
if ( ! sb_has_quota_limits_enabled ( sb , dquot - > dq_type ) | |
2008-08-20 19:50:32 +04:00
test_bit ( DQ_FAKE_B , & dquot - > dq_flags ) )
2005-04-17 02:20:36 +04:00
return QUOTA_OK ;
2009-01-13 18:43:09 +03:00
tspace = dquot - > dq_dqb . dqb_curspace + dquot - > dq_dqb . dqb_rsvspace
+ space ;
2005-04-17 02:20:36 +04:00
if ( dquot - > dq_dqb . dqb_bhardlimit & &
2009-01-13 18:43:09 +03:00
tspace > dquot - > dq_dqb . dqb_bhardlimit & &
2005-04-17 02:20:36 +04:00
! ignore_hardlimit ( dquot ) ) {
if ( ! prealloc )
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_BHARDWARN ;
2005-04-17 02:20:36 +04:00
return NO_QUOTA ;
}
if ( dquot - > dq_dqb . dqb_bsoftlimit & &
2009-01-13 18:43:09 +03:00
tspace > dquot - > dq_dqb . dqb_bsoftlimit & &
2009-01-27 17:47:22 +03:00
dquot - > dq_dqb . dqb_btime & &
get_seconds ( ) > = dquot - > dq_dqb . dqb_btime & &
2005-04-17 02:20:36 +04:00
! ignore_hardlimit ( dquot ) ) {
if ( ! prealloc )
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_BSOFTLONGWARN ;
2005-04-17 02:20:36 +04:00
return NO_QUOTA ;
}
if ( dquot - > dq_dqb . dqb_bsoftlimit & &
2009-01-13 18:43:09 +03:00
tspace > dquot - > dq_dqb . dqb_bsoftlimit & &
2005-04-17 02:20:36 +04:00
dquot - > dq_dqb . dqb_btime = = 0 ) {
if ( ! prealloc ) {
2007-10-17 10:29:31 +04:00
* warntype = QUOTA_NL_BSOFTWARN ;
2009-01-27 17:47:22 +03:00
dquot - > dq_dqb . dqb_btime = get_seconds ( ) +
sb_dqopt ( sb ) - > info [ dquot - > dq_type ] . dqi_bgrace ;
2005-04-17 02:20:36 +04:00
}
else
/*
* We don ' t allow preallocation to exceed softlimit so exceeding will
* be always printed
*/
return NO_QUOTA ;
}
return QUOTA_OK ;
}
2008-08-20 16:45:12 +04:00
static int info_idq_free ( struct dquot * dquot , qsize_t inodes )
2008-07-25 12:46:52 +04:00
{
2009-01-27 17:47:22 +03:00
qsize_t newinodes ;
2008-07-25 12:46:52 +04:00
if ( test_bit ( DQ_FAKE_B , & dquot - > dq_flags ) | |
2008-08-20 19:50:32 +04:00
dquot - > dq_dqb . dqb_curinodes < = dquot - > dq_dqb . dqb_isoftlimit | |
! sb_has_quota_limits_enabled ( dquot - > dq_sb , dquot - > dq_type ) )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_NOWARN ;
2009-01-27 17:47:22 +03:00
newinodes = dquot - > dq_dqb . dqb_curinodes - inodes ;
if ( newinodes < = dquot - > dq_dqb . dqb_isoftlimit )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_ISOFTBELOW ;
if ( dquot - > dq_dqb . dqb_curinodes > = dquot - > dq_dqb . dqb_ihardlimit & &
2009-01-27 17:47:22 +03:00
newinodes < dquot - > dq_dqb . dqb_ihardlimit )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_IHARDBELOW ;
return QUOTA_NL_NOWARN ;
}
static int info_bdq_free ( struct dquot * dquot , qsize_t space )
{
if ( test_bit ( DQ_FAKE_B , & dquot - > dq_flags ) | |
2008-08-20 16:45:12 +04:00
dquot - > dq_dqb . dqb_curspace < = dquot - > dq_dqb . dqb_bsoftlimit )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_NOWARN ;
2008-08-20 16:45:12 +04:00
if ( dquot - > dq_dqb . dqb_curspace - space < = dquot - > dq_dqb . dqb_bsoftlimit )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_BSOFTBELOW ;
2008-08-20 16:45:12 +04:00
if ( dquot - > dq_dqb . dqb_curspace > = dquot - > dq_dqb . dqb_bhardlimit & &
dquot - > dq_dqb . dqb_curspace - space < dquot - > dq_dqb . dqb_bhardlimit )
2008-07-25 12:46:52 +04:00
return QUOTA_NL_BHARDBELOW ;
return QUOTA_NL_NOWARN ;
}
2010-02-09 20:20:39 +03:00
2005-04-17 02:20:36 +04:00
/*
* Initialize quota pointers in inode
2009-01-12 19:23:05 +03:00
* We do things in a bit complicated way but by that we avoid calling
* dqget ( ) and thus filesystem callbacks under dqptr_sem .
2005-04-17 02:20:36 +04:00
*/
int dquot_initialize ( struct inode * inode , int type )
{
unsigned int id = 0 ;
int cnt , ret = 0 ;
2009-01-26 18:01:43 +03:00
struct dquot * got [ MAXQUOTAS ] = { NULL , NULL } ;
2009-01-12 19:23:05 +03:00
struct super_block * sb = inode - > i_sb ;
2010-02-09 20:20:39 +03:00
qsize_t rsv ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
/* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex */
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) )
return 0 ;
2009-01-12 19:23:05 +03:00
/* First get references to structures we might need. */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
if ( type ! = - 1 & & cnt ! = type )
continue ;
switch ( cnt ) {
case USRQUOTA :
id = inode - > i_uid ;
break ;
case GRPQUOTA :
id = inode - > i_gid ;
break ;
}
got [ cnt ] = dqget ( sb , id , cnt ) ;
}
down_write ( & sb_dqopt ( sb ) - > dqptr_sem ) ;
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) )
goto out_err ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
if ( type ! = - 1 & & cnt ! = type )
continue ;
2009-01-12 19:23:05 +03:00
/* Avoid races with quotaoff() */
if ( ! sb_has_quota_active ( sb , cnt ) )
continue ;
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] ) {
2009-01-12 19:23:05 +03:00
inode - > i_dquot [ cnt ] = got [ cnt ] ;
2009-01-26 18:01:43 +03:00
got [ cnt ] = NULL ;
2010-02-09 20:20:39 +03:00
/*
* Make quota reservation system happy if someone
* did a write before quota was turned on
*/
rsv = inode_get_rsv_space ( inode ) ;
if ( unlikely ( rsv ) )
dquot_resv_space ( inode - > i_dquot [ cnt ] , rsv ) ;
2005-04-17 02:20:36 +04:00
}
}
out_err :
2009-01-12 19:23:05 +03:00
up_write ( & sb_dqopt ( sb ) - > dqptr_sem ) ;
/* Drop unused references */
2009-12-14 15:21:15 +03:00
dqput_all ( got ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_initialize ) ;
2005-04-17 02:20:36 +04:00
/*
* Release all quotas referenced by inode
*/
2009-01-12 19:23:05 +03:00
int dquot_drop ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
int cnt ;
2009-01-12 19:23:05 +03:00
struct dquot * put [ MAXQUOTAS ] ;
2005-04-17 02:20:36 +04:00
2009-01-12 19:23:05 +03:00
down_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-12 19:23:05 +03:00
put [ cnt ] = inode - > i_dquot [ cnt ] ;
2009-01-26 18:01:43 +03:00
inode - > i_dquot [ cnt ] = NULL ;
2005-04-17 02:20:36 +04:00
}
up_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
2009-12-14 15:21:15 +03:00
dqput_all ( put ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_drop ) ;
2005-04-17 02:20:36 +04:00
2008-07-25 12:46:50 +04:00
/* Wrapper to remove references to quota structures from inode */
void vfs_dq_drop ( struct inode * inode )
{
/* Here we can get arbitrary inode from clear_inode() so we have
* to be careful . OTOH we don ' t need locking as quota operations
* are allowed to change only at mount time */
if ( ! IS_NOQUOTA ( inode ) & & inode - > i_sb & & inode - > i_sb - > dq_op
& & inode - > i_sb - > dq_op - > drop ) {
int cnt ;
/* Test before calling to rule out calls from proc and such
* where we are not allowed to block . Note that this is
* actually reliable test even without the lock - the caller
* must assure that nobody can come after the DQUOT_DROP and
* add quota pointers back anyway */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2009-01-26 18:01:43 +03:00
if ( inode - > i_dquot [ cnt ] )
2008-07-25 12:46:50 +04:00
break ;
if ( cnt < MAXQUOTAS )
inode - > i_sb - > dq_op - > drop ( inode ) ;
}
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_dq_drop ) ;
2008-07-25 12:46:50 +04:00
2009-12-14 15:21:13 +03:00
/*
* inode_reserved_space is managed internally by quota , and protected by
* i_lock similar to i_blocks + i_bytes .
*/
static qsize_t * inode_reserved_space ( struct inode * inode )
{
/* Filesystem must explicitly define it's own method in order to use
* quota reservation interface */
BUG_ON ( ! inode - > i_sb - > dq_op - > get_reserved_space ) ;
return inode - > i_sb - > dq_op - > get_reserved_space ( inode ) ;
}
2010-02-09 19:53:36 +03:00
void inode_add_rsv_space ( struct inode * inode , qsize_t number )
2009-12-14 15:21:13 +03:00
{
spin_lock ( & inode - > i_lock ) ;
* inode_reserved_space ( inode ) + = number ;
spin_unlock ( & inode - > i_lock ) ;
}
2010-02-09 19:53:36 +03:00
EXPORT_SYMBOL ( inode_add_rsv_space ) ;
2009-12-14 15:21:13 +03:00
2010-02-09 19:53:36 +03:00
void inode_claim_rsv_space ( struct inode * inode , qsize_t number )
2009-12-14 15:21:13 +03:00
{
spin_lock ( & inode - > i_lock ) ;
* inode_reserved_space ( inode ) - = number ;
__inode_add_bytes ( inode , number ) ;
spin_unlock ( & inode - > i_lock ) ;
}
2010-02-09 19:53:36 +03:00
EXPORT_SYMBOL ( inode_claim_rsv_space ) ;
2009-12-14 15:21:13 +03:00
2010-02-09 19:53:36 +03:00
void inode_sub_rsv_space ( struct inode * inode , qsize_t number )
2009-12-14 15:21:13 +03:00
{
spin_lock ( & inode - > i_lock ) ;
* inode_reserved_space ( inode ) - = number ;
spin_unlock ( & inode - > i_lock ) ;
}
2010-02-09 19:53:36 +03:00
EXPORT_SYMBOL ( inode_sub_rsv_space ) ;
2009-12-14 15:21:13 +03:00
static qsize_t inode_get_rsv_space ( struct inode * inode )
{
qsize_t ret ;
2010-01-06 20:03:36 +03:00
if ( ! inode - > i_sb - > dq_op - > get_reserved_space )
return 0 ;
2009-12-14 15:21:13 +03:00
spin_lock ( & inode - > i_lock ) ;
ret = * inode_reserved_space ( inode ) ;
spin_unlock ( & inode - > i_lock ) ;
return ret ;
}
static void inode_incr_space ( struct inode * inode , qsize_t number ,
int reserve )
{
if ( reserve )
inode_add_rsv_space ( inode , number ) ;
else
inode_add_bytes ( inode , number ) ;
}
static void inode_decr_space ( struct inode * inode , qsize_t number , int reserve )
{
if ( reserve )
inode_sub_rsv_space ( inode , number ) ;
else
inode_sub_bytes ( inode , number ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Following four functions update i_blocks + i_bytes fields and
* quota information ( together with appropriate checks )
* NOTE : We absolutely rely on the fact that caller dirties
* the inode ( usually macros in quotaops . h care about this ) and
* holds a handle for the current transaction so that dquot write and
* inode write go into the same transaction .
*/
/*
* This operation can block , but only after everything is updated
*/
2009-01-13 18:43:09 +03:00
int __dquot_alloc_space ( struct inode * inode , qsize_t number ,
int warn , int reserve )
2005-04-17 02:20:36 +04:00
{
2009-01-13 18:43:09 +03:00
int cnt , ret = QUOTA_OK ;
2005-04-17 02:20:36 +04:00
char warntype [ MAXQUOTAS ] ;
2009-12-14 15:21:13 +03:00
/*
* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex
*/
if ( IS_NOQUOTA ( inode ) ) {
inode_incr_space ( inode , number , reserve ) ;
goto out ;
}
down_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2007-10-17 10:29:31 +04:00
warntype [ cnt ] = QUOTA_NL_NOWARN ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dq_data_lock ) ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
2009-01-13 18:43:09 +03:00
if ( check_bdq ( inode - > i_dquot [ cnt ] , number , warn , warntype + cnt )
= = NO_QUOTA ) {
ret = NO_QUOTA ;
2009-12-14 15:21:13 +03:00
spin_unlock ( & dq_data_lock ) ;
goto out_flush_warn ;
2009-01-13 18:43:09 +03:00
}
2005-04-17 02:20:36 +04:00
}
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
2009-01-13 18:43:09 +03:00
if ( reserve )
dquot_resv_space ( inode - > i_dquot [ cnt ] , number ) ;
else
dquot_incr_space ( inode - > i_dquot [ cnt ] , number ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-14 15:21:13 +03:00
inode_incr_space ( inode , number , reserve ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_data_lock ) ;
2009-01-13 18:43:09 +03:00
2009-12-14 15:21:13 +03:00
if ( reserve )
goto out_flush_warn ;
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( inode - > i_dquot ) ;
2009-12-14 15:21:13 +03:00
out_flush_warn :
flush_warnings ( inode - > i_dquot , warntype ) ;
2005-04-17 02:20:36 +04:00
up_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
2009-01-13 18:43:09 +03:00
out :
return ret ;
}
2009-12-14 15:21:13 +03:00
int dquot_alloc_space ( struct inode * inode , qsize_t number , int warn )
{
return __dquot_alloc_space ( inode , number , warn , 0 ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_alloc_space ) ;
2009-01-13 18:43:09 +03:00
int dquot_reserve_space ( struct inode * inode , qsize_t number , int warn )
{
2009-12-14 15:21:13 +03:00
return __dquot_alloc_space ( inode , number , warn , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-13 18:43:09 +03:00
EXPORT_SYMBOL ( dquot_reserve_space ) ;
2005-04-17 02:20:36 +04:00
/*
* This operation can block , but only after everything is updated
*/
2008-08-20 16:45:12 +04:00
int dquot_alloc_inode ( const struct inode * inode , qsize_t number )
2005-04-17 02:20:36 +04:00
{
int cnt , ret = NO_QUOTA ;
char warntype [ MAXQUOTAS ] ;
2006-03-23 14:00:29 +03:00
/* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex */
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) )
return QUOTA_OK ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2007-10-17 10:29:31 +04:00
warntype [ cnt ] = QUOTA_NL_NOWARN ;
2005-04-17 02:20:36 +04:00
down_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
spin_lock ( & dq_data_lock ) ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
2009-01-27 17:47:22 +03:00
if ( check_idq ( inode - > i_dquot [ cnt ] , number , warntype + cnt )
= = NO_QUOTA )
2005-04-17 02:20:36 +04:00
goto warn_put_all ;
}
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
dquot_incr_inodes ( inode - > i_dquot [ cnt ] , number ) ;
}
ret = QUOTA_OK ;
warn_put_all :
spin_unlock ( & dq_data_lock ) ;
if ( ret = = QUOTA_OK )
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( inode - > i_dquot ) ;
2007-12-18 03:20:26 +03:00
flush_warnings ( inode - > i_dquot , warntype ) ;
2005-04-17 02:20:36 +04:00
up_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_alloc_inode ) ;
2005-04-17 02:20:36 +04:00
2009-01-13 18:43:14 +03:00
int dquot_claim_space ( struct inode * inode , qsize_t number )
{
int cnt ;
int ret = QUOTA_OK ;
if ( IS_NOQUOTA ( inode ) ) {
2009-12-14 15:21:13 +03:00
inode_claim_rsv_space ( inode , number ) ;
2009-01-13 18:43:14 +03:00
goto out ;
}
down_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
spin_lock ( & dq_data_lock ) ;
/* Claim reserved quotas to allocated quotas */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( inode - > i_dquot [ cnt ] )
2009-01-13 18:43:14 +03:00
dquot_claim_reserved_space ( inode - > i_dquot [ cnt ] ,
number ) ;
}
/* Update inode bytes */
2009-12-14 15:21:13 +03:00
inode_claim_rsv_space ( inode , number ) ;
2009-01-13 18:43:14 +03:00
spin_unlock ( & dq_data_lock ) ;
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( inode - > i_dquot ) ;
2009-01-13 18:43:14 +03:00
up_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
out :
return ret ;
}
EXPORT_SYMBOL ( dquot_claim_space ) ;
2005-04-17 02:20:36 +04:00
/*
* This operation can block , but only after everything is updated
*/
2009-12-14 15:21:13 +03:00
int __dquot_free_space ( struct inode * inode , qsize_t number , int reserve )
2005-04-17 02:20:36 +04:00
{
unsigned int cnt ;
2008-07-25 12:46:52 +04:00
char warntype [ MAXQUOTAS ] ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
/* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex */
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) ) {
2009-12-14 15:21:13 +03:00
inode_decr_space ( inode , number , reserve ) ;
2005-04-17 02:20:36 +04:00
return QUOTA_OK ;
}
2008-07-25 12:46:52 +04:00
2005-04-17 02:20:36 +04:00
down_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
spin_lock ( & dq_data_lock ) ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
2008-07-25 12:46:52 +04:00
warntype [ cnt ] = info_bdq_free ( inode - > i_dquot [ cnt ] , number ) ;
2009-12-14 15:21:13 +03:00
if ( reserve )
dquot_free_reserved_space ( inode - > i_dquot [ cnt ] , number ) ;
else
dquot_decr_space ( inode - > i_dquot [ cnt ] , number ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-14 15:21:13 +03:00
inode_decr_space ( inode , number , reserve ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_data_lock ) ;
2009-12-14 15:21:13 +03:00
if ( reserve )
goto out_unlock ;
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( inode - > i_dquot ) ;
2009-12-14 15:21:13 +03:00
out_unlock :
2008-07-25 12:46:52 +04:00
flush_warnings ( inode - > i_dquot , warntype ) ;
2005-04-17 02:20:36 +04:00
up_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
return QUOTA_OK ;
}
2009-12-14 15:21:13 +03:00
int dquot_free_space ( struct inode * inode , qsize_t number )
{
return __dquot_free_space ( inode , number , 0 ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_free_space ) ;
2005-04-17 02:20:36 +04:00
2009-12-14 15:21:13 +03:00
/*
* Release reserved quota space
*/
void dquot_release_reserved_space ( struct inode * inode , qsize_t number )
{
__dquot_free_space ( inode , number , 1 ) ;
}
EXPORT_SYMBOL ( dquot_release_reserved_space ) ;
2005-04-17 02:20:36 +04:00
/*
* This operation can block , but only after everything is updated
*/
2008-08-20 16:45:12 +04:00
int dquot_free_inode ( const struct inode * inode , qsize_t number )
2005-04-17 02:20:36 +04:00
{
unsigned int cnt ;
2008-07-25 12:46:52 +04:00
char warntype [ MAXQUOTAS ] ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
/* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex */
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) )
return QUOTA_OK ;
2008-07-25 12:46:52 +04:00
2005-04-17 02:20:36 +04:00
down_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
spin_lock ( & dq_data_lock ) ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! inode - > i_dquot [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
2008-07-25 12:46:52 +04:00
warntype [ cnt ] = info_idq_free ( inode - > i_dquot [ cnt ] , number ) ;
2005-04-17 02:20:36 +04:00
dquot_decr_inodes ( inode - > i_dquot [ cnt ] , number ) ;
}
spin_unlock ( & dq_data_lock ) ;
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( inode - > i_dquot ) ;
2008-07-25 12:46:52 +04:00
flush_warnings ( inode - > i_dquot , warntype ) ;
2005-04-17 02:20:36 +04:00
up_read ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
return QUOTA_OK ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_free_inode ) ;
2005-04-17 02:20:36 +04:00
/*
* Transfer the number of inode and blocks from one diskquota to an other .
*
* This operation can block , but only after everything is updated
* A transaction must be started when entering this function .
*/
int dquot_transfer ( struct inode * inode , struct iattr * iattr )
{
2009-01-13 18:43:14 +03:00
qsize_t space , cur_space ;
qsize_t rsv_space = 0 ;
2005-04-17 02:20:36 +04:00
struct dquot * transfer_from [ MAXQUOTAS ] ;
struct dquot * transfer_to [ MAXQUOTAS ] ;
2009-01-12 19:23:05 +03:00
int cnt , ret = QUOTA_OK ;
int chuid = iattr - > ia_valid & ATTR_UID & & inode - > i_uid ! = iattr - > ia_uid ,
chgid = iattr - > ia_valid & ATTR_GID & & inode - > i_gid ! = iattr - > ia_gid ;
2008-07-25 12:46:52 +04:00
char warntype_to [ MAXQUOTAS ] ;
char warntype_from_inodes [ MAXQUOTAS ] , warntype_from_space [ MAXQUOTAS ] ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
/* First test before acquiring mutex - solves deadlocks when we
* re - enter the quota code and are already holding the mutex */
2005-04-17 02:20:36 +04:00
if ( IS_NOQUOTA ( inode ) )
return QUOTA_OK ;
2009-01-12 19:23:05 +03:00
/* Initialize the arrays */
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
transfer_from [ cnt ] = NULL ;
transfer_to [ cnt ] = NULL ;
2008-07-25 12:46:52 +04:00
warntype_to [ cnt ] = QUOTA_NL_NOWARN ;
2005-04-17 02:20:36 +04:00
}
2009-01-27 17:47:22 +03:00
if ( chuid )
transfer_to [ USRQUOTA ] = dqget ( inode - > i_sb , iattr - > ia_uid ,
USRQUOTA ) ;
if ( chgid )
transfer_to [ GRPQUOTA ] = dqget ( inode - > i_sb , iattr - > ia_gid ,
GRPQUOTA ) ;
2009-01-12 19:23:05 +03:00
down_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
if ( IS_NOQUOTA ( inode ) ) { /* File without quota accounting? */
up_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
goto put_all ;
}
2005-04-17 02:20:36 +04:00
spin_lock ( & dq_data_lock ) ;
2009-01-13 18:43:14 +03:00
cur_space = inode_get_bytes ( inode ) ;
2009-12-14 15:21:13 +03:00
rsv_space = inode_get_rsv_space ( inode ) ;
2009-01-13 18:43:14 +03:00
space = cur_space + rsv_space ;
2005-04-17 02:20:36 +04:00
/* Build the transfer_from list and check the limits */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
2009-01-26 18:01:43 +03:00
if ( ! transfer_to [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
transfer_from [ cnt ] = inode - > i_dquot [ cnt ] ;
2008-07-25 12:46:52 +04:00
if ( check_idq ( transfer_to [ cnt ] , 1 , warntype_to + cnt ) = =
NO_QUOTA | | check_bdq ( transfer_to [ cnt ] , space , 0 ,
warntype_to + cnt ) = = NO_QUOTA )
2009-01-12 19:23:05 +03:00
goto over_quota ;
2005-04-17 02:20:36 +04:00
}
/*
* Finally perform the needed transfer from transfer_from to transfer_to
*/
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
/*
* Skip changes for same uid or gid or for turned off quota - type .
*/
2009-01-26 18:01:43 +03:00
if ( ! transfer_to [ cnt ] )
2005-04-17 02:20:36 +04:00
continue ;
/* Due to IO error we might not have transfer_from[] structure */
if ( transfer_from [ cnt ] ) {
2008-07-25 12:46:52 +04:00
warntype_from_inodes [ cnt ] =
info_idq_free ( transfer_from [ cnt ] , 1 ) ;
warntype_from_space [ cnt ] =
info_bdq_free ( transfer_from [ cnt ] , space ) ;
2005-04-17 02:20:36 +04:00
dquot_decr_inodes ( transfer_from [ cnt ] , 1 ) ;
2009-01-13 18:43:14 +03:00
dquot_decr_space ( transfer_from [ cnt ] , cur_space ) ;
dquot_free_reserved_space ( transfer_from [ cnt ] ,
rsv_space ) ;
2005-04-17 02:20:36 +04:00
}
dquot_incr_inodes ( transfer_to [ cnt ] , 1 ) ;
2009-01-13 18:43:14 +03:00
dquot_incr_space ( transfer_to [ cnt ] , cur_space ) ;
dquot_resv_space ( transfer_to [ cnt ] , rsv_space ) ;
2005-04-17 02:20:36 +04:00
inode - > i_dquot [ cnt ] = transfer_to [ cnt ] ;
}
spin_unlock ( & dq_data_lock ) ;
2009-01-12 19:23:05 +03:00
up_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
2009-12-14 15:21:15 +03:00
mark_all_dquot_dirty ( transfer_from ) ;
mark_all_dquot_dirty ( transfer_to ) ;
/* The reference we got is transferred to the inode */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
transfer_to [ cnt ] = NULL ;
2009-01-12 19:23:05 +03:00
warn_put_all :
2008-07-25 12:46:52 +04:00
flush_warnings ( transfer_to , warntype_to ) ;
flush_warnings ( transfer_from , warntype_from_inodes ) ;
flush_warnings ( transfer_from , warntype_from_space ) ;
2009-01-12 19:23:05 +03:00
put_all :
2009-12-14 15:21:15 +03:00
dqput_all ( transfer_from ) ;
dqput_all ( transfer_to ) ;
2005-04-17 02:20:36 +04:00
return ret ;
2009-01-12 19:23:05 +03:00
over_quota :
spin_unlock ( & dq_data_lock ) ;
up_write ( & sb_dqopt ( inode - > i_sb ) - > dqptr_sem ) ;
/* Clear dquot pointers we don't want to dqput() */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
2009-01-26 18:01:43 +03:00
transfer_from [ cnt ] = NULL ;
2009-01-12 19:23:05 +03:00
ret = NO_QUOTA ;
goto warn_put_all ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_transfer ) ;
2005-04-17 02:20:36 +04:00
2008-07-25 12:46:50 +04:00
/* Wrapper for transferring ownership of an inode */
int vfs_dq_transfer ( struct inode * inode , struct iattr * iattr )
{
2008-08-20 19:50:32 +04:00
if ( sb_any_quota_active ( inode - > i_sb ) & & ! IS_NOQUOTA ( inode ) ) {
2008-07-25 12:46:50 +04:00
vfs_dq_init ( inode ) ;
if ( inode - > i_sb - > dq_op - > transfer ( inode , iattr ) = = NO_QUOTA )
return 1 ;
}
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_dq_transfer ) ;
2008-07-25 12:46:50 +04:00
2005-04-17 02:20:36 +04:00
/*
* Write info of quota file to disk
*/
int dquot_commit_info ( struct super_block * sb , int type )
{
int ret ;
struct quota_info * dqopt = sb_dqopt ( sb ) ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
ret = dqopt - > ops [ type ] - > write_file_info ( sb , type ) ;
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( dquot_commit_info ) ;
2005-04-17 02:20:36 +04:00
/*
* Definitions of diskquota operations .
*/
2009-09-22 04:01:08 +04:00
const struct dquot_operations dquot_operations = {
2005-04-17 02:20:36 +04:00
. initialize = dquot_initialize ,
. drop = dquot_drop ,
. alloc_space = dquot_alloc_space ,
. alloc_inode = dquot_alloc_inode ,
. free_space = dquot_free_space ,
. free_inode = dquot_free_inode ,
. transfer = dquot_transfer ,
. write_dquot = dquot_commit ,
. acquire_dquot = dquot_acquire ,
. release_dquot = dquot_release ,
. mark_dirty = dquot_mark_dquot_dirty ,
2008-08-19 16:51:22 +04:00
. write_info = dquot_commit_info ,
. alloc_dquot = dquot_alloc ,
. destroy_dquot = dquot_destroy ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Turn quota off on a device . type = = - 1 = = > quotaoff for all types ( umount )
*/
2008-08-20 19:50:32 +04:00
int vfs_quota_disable ( struct super_block * sb , int type , unsigned int flags )
2005-04-17 02:20:36 +04:00
{
2008-04-28 13:14:33 +04:00
int cnt , ret = 0 ;
2005-04-17 02:20:36 +04:00
struct quota_info * dqopt = sb_dqopt ( sb ) ;
struct inode * toputinode [ MAXQUOTAS ] ;
2008-08-20 19:50:32 +04:00
/* Cannot turn off usage accounting without turning off limits, or
* suspend quotas and simultaneously turn quotas off . */
if ( ( flags & DQUOT_USAGE_ENABLED & & ! ( flags & DQUOT_LIMITS_ENABLED ) )
| | ( flags & DQUOT_SUSPENDED & & flags & ( DQUOT_LIMITS_ENABLED |
DQUOT_USAGE_ENABLED ) ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* We need to serialize quota_off() for device */
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
2008-05-13 01:02:08 +04:00
/*
* Skip everything if there ' s nothing to do . We have to do this because
* sometimes we are called when fill_super ( ) failed and calling
* sync_fs ( ) in such cases does no good .
*/
2008-08-20 19:50:32 +04:00
if ( ! sb_any_quota_loaded ( sb ) ) {
2008-05-13 01:02:08 +04:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
toputinode [ cnt ] = NULL ;
if ( type ! = - 1 & & cnt ! = type )
continue ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_loaded ( sb , cnt ) )
2008-04-28 13:14:33 +04:00
continue ;
2008-08-20 19:50:32 +04:00
if ( flags & DQUOT_SUSPENDED ) {
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
dqopt - > flags | =
dquot_state_flag ( DQUOT_SUSPENDED , cnt ) ;
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
} else {
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
dqopt - > flags & = ~ dquot_state_flag ( flags , cnt ) ;
/* Turning off suspended quotas? */
if ( ! sb_has_quota_loaded ( sb , cnt ) & &
sb_has_quota_suspended ( sb , cnt ) ) {
dqopt - > flags & = ~ dquot_state_flag (
DQUOT_SUSPENDED , cnt ) ;
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
iput ( dqopt - > files [ cnt ] ) ;
dqopt - > files [ cnt ] = NULL ;
continue ;
}
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2008-04-28 13:14:33 +04:00
}
2008-08-20 19:50:32 +04:00
/* We still have to keep quota loaded? */
if ( sb_has_quota_loaded ( sb , cnt ) & & ! ( flags & DQUOT_SUSPENDED ) )
2005-04-17 02:20:36 +04:00
continue ;
/* Note: these are blocking operations */
drop_dquot_ref ( sb , cnt ) ;
invalidate_dquots ( sb , cnt ) ;
/*
2009-01-27 17:47:22 +03:00
* Now all dquots should be invalidated , all writes done so we
* should be only users of the info . No locks needed .
2005-04-17 02:20:36 +04:00
*/
if ( info_dirty ( & dqopt - > info [ cnt ] ) )
sb - > dq_op - > write_info ( sb , cnt ) ;
if ( dqopt - > ops [ cnt ] - > free_file_info )
dqopt - > ops [ cnt ] - > free_file_info ( sb , cnt ) ;
put_quota_format ( dqopt - > info [ cnt ] . dqi_format ) ;
toputinode [ cnt ] = dqopt - > files [ cnt ] ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_loaded ( sb , cnt ) )
2008-04-28 13:14:33 +04:00
dqopt - > files [ cnt ] = NULL ;
2005-04-17 02:20:36 +04:00
dqopt - > info [ cnt ] . dqi_flags = 0 ;
dqopt - > info [ cnt ] . dqi_igrace = 0 ;
dqopt - > info [ cnt ] . dqi_bgrace = 0 ;
dqopt - > ops [ cnt ] = NULL ;
}
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2008-09-30 19:53:37 +04:00
/* Skip syncing and setting flags if quota files are hidden */
if ( dqopt - > flags & DQUOT_QUOTA_SYS_FILE )
goto put_inodes ;
2005-04-17 02:20:36 +04:00
/* Sync the superblock so that buffers with quota data are written to
2005-11-08 01:13:39 +03:00
* disk ( and so userspace sees correct data afterwards ) . */
2005-04-17 02:20:36 +04:00
if ( sb - > s_op - > sync_fs )
sb - > s_op - > sync_fs ( sb , 1 ) ;
sync_blockdev ( sb - > s_bdev ) ;
/* Now the quota files are just ordinary files and we can set the
* inode flags back . Moreover we discard the pagecache so that
* userspace sees the writes we did bypassing the pagecache . We
* must also discard the blockdev buffers so that we see the
* changes done by userspace on the next quotaon ( ) */
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
if ( toputinode [ cnt ] ) {
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
/* If quota was reenabled in the meantime, we have
* nothing to do */
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_loaded ( sb , cnt ) ) {
2009-01-27 17:47:22 +03:00
mutex_lock_nested ( & toputinode [ cnt ] - > i_mutex ,
I_MUTEX_QUOTA ) ;
2005-04-17 02:20:36 +04:00
toputinode [ cnt ] - > i_flags & = ~ ( S_IMMUTABLE |
S_NOATIME | S_NOQUOTA ) ;
2009-01-27 17:47:22 +03:00
truncate_inode_pages ( & toputinode [ cnt ] - > i_data ,
0 ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & toputinode [ cnt ] - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( toputinode [ cnt ] ) ;
}
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2008-09-30 19:53:37 +04:00
}
if ( sb - > s_bdev )
invalidate_bdev ( sb - > s_bdev ) ;
put_inodes :
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + )
if ( toputinode [ cnt ] ) {
2008-04-28 13:14:33 +04:00
/* On remount RO, we keep the inode pointer so that we
2008-08-20 19:50:32 +04:00
* can reenable quota on the subsequent remount RW . We
* have to check ' flags ' variable and not use sb_has_
* function because another quotaon / quotaoff could
* change global state before we got here . We refuse
* to suspend quotas when there is pending delete on
* the quota file . . . */
if ( ! ( flags & DQUOT_SUSPENDED ) )
2008-04-28 13:14:33 +04:00
iput ( toputinode [ cnt ] ) ;
else if ( ! toputinode [ cnt ] - > i_nlink )
ret = - EBUSY ;
2005-04-17 02:20:36 +04:00
}
2008-04-28 13:14:33 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_disable ) ;
2005-04-17 02:20:36 +04:00
2008-08-20 19:50:32 +04:00
int vfs_quota_off ( struct super_block * sb , int type , int remount )
{
return vfs_quota_disable ( sb , type , remount ? DQUOT_SUSPENDED :
( DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED ) ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_off ) ;
2005-04-17 02:20:36 +04:00
/*
* Turn quotas on on a device
*/
2008-08-20 19:50:32 +04:00
/*
* Helper function to turn quotas on when we already have the inode of
* quota file and no quota information is loaded .
*/
static int vfs_load_quota_inode ( struct inode * inode , int type , int format_id ,
unsigned int flags )
2005-04-17 02:20:36 +04:00
{
struct quota_format_type * fmt = find_quota_format ( format_id ) ;
struct super_block * sb = inode - > i_sb ;
struct quota_info * dqopt = sb_dqopt ( sb ) ;
int error ;
int oldflags = - 1 ;
if ( ! fmt )
return - ESRCH ;
if ( ! S_ISREG ( inode - > i_mode ) ) {
error = - EACCES ;
goto out_fmt ;
}
if ( IS_RDONLY ( inode ) ) {
error = - EROFS ;
goto out_fmt ;
}
if ( ! sb - > s_op - > quota_write | | ! sb - > s_op - > quota_read ) {
error = - EINVAL ;
goto out_fmt ;
}
2008-08-20 19:50:32 +04:00
/* Usage always has to be set... */
if ( ! ( flags & DQUOT_USAGE_ENABLED ) ) {
error = - EINVAL ;
goto out_fmt ;
}
2005-04-17 02:20:36 +04:00
2008-09-30 19:53:37 +04:00
if ( ! ( dqopt - > flags & DQUOT_QUOTA_SYS_FILE ) ) {
/* As we bypass the pagecache we must now flush the inode so
* that we see all the changes from userspace . . . */
write_inode_now ( inode , 1 ) ;
/* And now flush the block cache so that kernel sees the
* changes */
invalidate_bdev ( sb - > s_bdev ) ;
}
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
2008-08-20 19:50:32 +04:00
if ( sb_has_quota_loaded ( sb , type ) ) {
2005-04-17 02:20:36 +04:00
error = - EBUSY ;
goto out_lock ;
}
2008-09-30 19:53:37 +04:00
if ( ! ( dqopt - > flags & DQUOT_QUOTA_SYS_FILE ) ) {
/* We don't want quota and atime on quota files (deadlocks
* possible ) Also nobody should write to the file - we use
* special IO operations which ignore the immutable bit . */
2009-07-22 20:12:17 +04:00
mutex_lock_nested ( & inode - > i_mutex , I_MUTEX_QUOTA ) ;
2009-01-27 17:47:22 +03:00
oldflags = inode - > i_flags & ( S_NOATIME | S_IMMUTABLE |
S_NOQUOTA ) ;
2008-09-30 19:53:37 +04:00
inode - > i_flags | = S_NOQUOTA | S_NOATIME | S_IMMUTABLE ;
2009-07-22 20:12:17 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-01-06 19:20:35 +03:00
/*
* When S_NOQUOTA is set , remove dquot references as no more
* references can be added
*/
2008-09-30 19:53:37 +04:00
sb - > dq_op - > drop ( inode ) ;
}
2005-04-17 02:20:36 +04:00
error = - EIO ;
dqopt - > files [ type ] = igrab ( inode ) ;
if ( ! dqopt - > files [ type ] )
goto out_lock ;
error = - EINVAL ;
if ( ! fmt - > qf_ops - > check_quota_file ( sb , type ) )
goto out_file_init ;
dqopt - > ops [ type ] = fmt - > qf_ops ;
dqopt - > info [ type ] . dqi_format = fmt ;
2008-04-28 13:14:33 +04:00
dqopt - > info [ type ] . dqi_fmt_id = format_id ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & dqopt - > info [ type ] . dqi_dirty_list ) ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & dqopt - > dqio_mutex ) ;
2009-01-27 17:47:22 +03:00
error = dqopt - > ops [ type ] - > read_file_info ( sb , type ) ;
if ( error < 0 ) {
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
2005-04-17 02:20:36 +04:00
goto out_file_init ;
}
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqio_mutex ) ;
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
dqopt - > flags | = dquot_state_flag ( flags , type ) ;
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2005-04-17 02:20:36 +04:00
add_dquot_ref ( sb , type ) ;
2006-03-23 14:00:29 +03:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out_file_init :
dqopt - > files [ type ] = NULL ;
iput ( inode ) ;
out_lock :
if ( oldflags ! = - 1 ) {
2009-07-22 20:12:17 +04:00
mutex_lock_nested ( & inode - > i_mutex , I_MUTEX_QUOTA ) ;
2005-04-17 02:20:36 +04:00
/* Set the flags back (in the case of accidental quotaon()
* on a wrong file we don ' t want to mess up the flags ) */
inode - > i_flags & = ~ ( S_NOATIME | S_NOQUOTA | S_IMMUTABLE ) ;
inode - > i_flags | = oldflags ;
2009-07-22 20:12:17 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2009-07-07 20:15:21 +04:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
out_fmt :
put_quota_format ( fmt ) ;
return error ;
}
2008-04-28 13:14:33 +04:00
/* Reenable quotas on remount RW */
static int vfs_quota_on_remount ( struct super_block * sb , int type )
{
struct quota_info * dqopt = sb_dqopt ( sb ) ;
struct inode * inode ;
int ret ;
2008-08-20 19:50:32 +04:00
unsigned int flags ;
2008-04-28 13:14:33 +04:00
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
if ( ! sb_has_quota_suspended ( sb , type ) ) {
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
return 0 ;
}
inode = dqopt - > files [ type ] ;
dqopt - > files [ type ] = NULL ;
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
flags = dqopt - > flags & dquot_state_flag ( DQUOT_USAGE_ENABLED |
DQUOT_LIMITS_ENABLED , type ) ;
dqopt - > flags & = ~ dquot_state_flag ( DQUOT_STATE_FLAGS , type ) ;
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2008-04-28 13:14:33 +04:00
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
2008-08-20 19:50:32 +04:00
flags = dquot_generic_flag ( flags , type ) ;
ret = vfs_load_quota_inode ( inode , type , dqopt - > info [ type ] . dqi_fmt_id ,
flags ) ;
2008-04-28 13:14:33 +04:00
iput ( inode ) ;
return ret ;
}
2008-08-01 12:29:18 +04:00
int vfs_quota_on_path ( struct super_block * sb , int type , int format_id ,
struct path * path )
{
int error = security_quota_on ( path - > dentry ) ;
if ( error )
return error ;
/* Quota file not on the same filesystem? */
if ( path - > mnt - > mnt_sb ! = sb )
error = - EXDEV ;
else
2008-08-20 19:50:32 +04:00
error = vfs_load_quota_inode ( path - > dentry - > d_inode , type ,
format_id , DQUOT_USAGE_ENABLED |
DQUOT_LIMITS_ENABLED ) ;
2008-08-01 12:29:18 +04:00
return error ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_on_path ) ;
2008-08-01 12:29:18 +04:00
2008-08-02 08:57:06 +04:00
int vfs_quota_on ( struct super_block * sb , int type , int format_id , char * name ,
2008-04-28 13:14:33 +04:00
int remount )
2005-04-17 02:20:36 +04:00
{
2008-08-02 08:57:06 +04:00
struct path path ;
2005-04-17 02:20:36 +04:00
int error ;
2008-04-28 13:14:33 +04:00
if ( remount )
return vfs_quota_on_remount ( sb , type ) ;
2008-08-02 08:57:06 +04:00
error = kern_path ( name , LOOKUP_FOLLOW , & path ) ;
2008-08-01 12:29:18 +04:00
if ( ! error ) {
2008-08-02 08:57:06 +04:00
error = vfs_quota_on_path ( sb , type , format_id , & path ) ;
path_put ( & path ) ;
2008-08-01 12:29:18 +04:00
}
2005-04-17 02:20:36 +04:00
return error ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_on ) ;
2005-04-17 02:20:36 +04:00
2008-08-20 19:50:32 +04:00
/*
* More powerful function for turning on quotas allowing setting
* of individual quota flags
*/
int vfs_quota_enable ( struct inode * inode , int type , int format_id ,
unsigned int flags )
{
int ret = 0 ;
struct super_block * sb = inode - > i_sb ;
struct quota_info * dqopt = sb_dqopt ( sb ) ;
/* Just unsuspend quotas? */
if ( flags & DQUOT_SUSPENDED )
return vfs_quota_on_remount ( sb , type ) ;
if ( ! flags )
return 0 ;
/* Just updating flags needed? */
if ( sb_has_quota_loaded ( sb , type ) ) {
mutex_lock ( & dqopt - > dqonoff_mutex ) ;
/* Now do a reliable test... */
if ( ! sb_has_quota_loaded ( sb , type ) ) {
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
goto load_quota ;
}
if ( flags & DQUOT_USAGE_ENABLED & &
sb_has_quota_usage_enabled ( sb , type ) ) {
ret = - EBUSY ;
goto out_lock ;
}
if ( flags & DQUOT_LIMITS_ENABLED & &
sb_has_quota_limits_enabled ( sb , type ) ) {
ret = - EBUSY ;
goto out_lock ;
}
2009-01-12 19:23:05 +03:00
spin_lock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
sb_dqopt ( sb ) - > flags | = dquot_state_flag ( flags , type ) ;
2009-01-12 19:23:05 +03:00
spin_unlock ( & dq_state_lock ) ;
2008-08-20 19:50:32 +04:00
out_lock :
mutex_unlock ( & dqopt - > dqonoff_mutex ) ;
return ret ;
}
load_quota :
return vfs_load_quota_inode ( inode , type , format_id , flags ) ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_enable ) ;
2008-08-20 19:50:32 +04:00
2005-04-17 02:20:36 +04:00
/*
* This function is used when filesystem needs to initialize quotas
* during mount time .
*/
2005-06-23 11:09:16 +04:00
int vfs_quota_on_mount ( struct super_block * sb , char * qf_name ,
int format_id , int type )
2005-04-17 02:20:36 +04:00
{
2005-06-23 11:09:16 +04:00
struct dentry * dentry ;
2005-04-17 02:20:36 +04:00
int error ;
2009-11-12 17:42:08 +03:00
mutex_lock ( & sb - > s_root - > d_inode - > i_mutex ) ;
2005-06-23 11:09:16 +04:00
dentry = lookup_one_len ( qf_name , sb - > s_root , strlen ( qf_name ) ) ;
2009-11-12 17:42:08 +03:00
mutex_unlock ( & sb - > s_root - > d_inode - > i_mutex ) ;
2005-06-23 11:09:16 +04:00
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
2005-11-29 00:44:14 +03:00
if ( ! dentry - > d_inode ) {
error = - ENOENT ;
goto out ;
}
2005-04-17 02:20:36 +04:00
error = security_quota_on ( dentry ) ;
2005-06-23 11:09:16 +04:00
if ( ! error )
2008-08-20 19:50:32 +04:00
error = vfs_load_quota_inode ( dentry - > d_inode , type , format_id ,
DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED ) ;
2005-06-23 11:09:16 +04:00
2005-11-29 00:44:14 +03:00
out :
2005-06-23 11:09:16 +04:00
dput ( dentry ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_quota_on_mount ) ;
2005-04-17 02:20:36 +04:00
2008-07-25 12:46:50 +04:00
/* Wrapper to turn on quotas when remounting rw */
int vfs_dq_quota_on_remount ( struct super_block * sb )
{
int cnt ;
int ret = 0 , err ;
if ( ! sb - > s_qcop | | ! sb - > s_qcop - > quota_on )
return - ENOSYS ;
for ( cnt = 0 ; cnt < MAXQUOTAS ; cnt + + ) {
err = sb - > s_qcop - > quota_on ( sb , cnt , 0 , NULL , 1 ) ;
if ( err < 0 & & ! ret )
ret = err ;
}
return ret ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_dq_quota_on_remount ) ;
2008-07-25 12:46:50 +04:00
2008-08-20 16:45:12 +04:00
static inline qsize_t qbtos ( qsize_t blocks )
{
return blocks < < QIF_DQBLKSIZE_BITS ;
}
static inline qsize_t stoqb ( qsize_t space )
{
return ( space + QIF_DQBLKSIZE - 1 ) > > QIF_DQBLKSIZE_BITS ;
}
2005-04-17 02:20:36 +04:00
/* Generic routine for getting common part of quota structure */
static void do_get_dqblk ( struct dquot * dquot , struct if_dqblk * di )
{
struct mem_dqblk * dm = & dquot - > dq_dqb ;
spin_lock ( & dq_data_lock ) ;
2008-08-20 16:45:12 +04:00
di - > dqb_bhardlimit = stoqb ( dm - > dqb_bhardlimit ) ;
di - > dqb_bsoftlimit = stoqb ( dm - > dqb_bsoftlimit ) ;
2009-01-13 18:43:09 +03:00
di - > dqb_curspace = dm - > dqb_curspace + dm - > dqb_rsvspace ;
2005-04-17 02:20:36 +04:00
di - > dqb_ihardlimit = dm - > dqb_ihardlimit ;
di - > dqb_isoftlimit = dm - > dqb_isoftlimit ;
di - > dqb_curinodes = dm - > dqb_curinodes ;
di - > dqb_btime = dm - > dqb_btime ;
di - > dqb_itime = dm - > dqb_itime ;
di - > dqb_valid = QIF_ALL ;
spin_unlock ( & dq_data_lock ) ;
}
2009-01-27 17:47:22 +03:00
int vfs_get_dqblk ( struct super_block * sb , int type , qid_t id ,
struct if_dqblk * di )
2005-04-17 02:20:36 +04:00
{
struct dquot * dquot ;
2009-01-12 19:23:05 +03:00
dquot = dqget ( sb , id , type ) ;
2009-01-26 18:01:43 +03:00
if ( ! dquot )
2005-04-17 02:20:36 +04:00
return - ESRCH ;
do_get_dqblk ( dquot , di ) ;
dqput ( dquot ) ;
2009-01-12 19:23:05 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_get_dqblk ) ;
2005-04-17 02:20:36 +04:00
/* Generic routine for setting common part of quota structure */
2008-04-28 13:14:31 +04:00
static int do_set_dqblk ( struct dquot * dquot , struct if_dqblk * di )
2005-04-17 02:20:36 +04:00
{
struct mem_dqblk * dm = & dquot - > dq_dqb ;
int check_blim = 0 , check_ilim = 0 ;
2008-04-28 13:14:31 +04:00
struct mem_dqinfo * dqi = & sb_dqopt ( dquot - > dq_sb ) - > info [ dquot - > dq_type ] ;
if ( ( di - > dqb_valid & QIF_BLIMITS & &
( di - > dqb_bhardlimit > dqi - > dqi_maxblimit | |
di - > dqb_bsoftlimit > dqi - > dqi_maxblimit ) ) | |
( di - > dqb_valid & QIF_ILIMITS & &
( di - > dqb_ihardlimit > dqi - > dqi_maxilimit | |
di - > dqb_isoftlimit > dqi - > dqi_maxilimit ) ) )
return - ERANGE ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dq_data_lock ) ;
if ( di - > dqb_valid & QIF_SPACE ) {
2009-01-13 18:43:09 +03:00
dm - > dqb_curspace = di - > dqb_curspace - dm - > dqb_rsvspace ;
2005-04-17 02:20:36 +04:00
check_blim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_SPACE_B , & dquot - > dq_flags ) ;
2005-04-17 02:20:36 +04:00
}
if ( di - > dqb_valid & QIF_BLIMITS ) {
2008-08-20 16:45:12 +04:00
dm - > dqb_bsoftlimit = qbtos ( di - > dqb_bsoftlimit ) ;
dm - > dqb_bhardlimit = qbtos ( di - > dqb_bhardlimit ) ;
2005-04-17 02:20:36 +04:00
check_blim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_BLIMITS_B , & dquot - > dq_flags ) ;
2005-04-17 02:20:36 +04:00
}
if ( di - > dqb_valid & QIF_INODES ) {
dm - > dqb_curinodes = di - > dqb_curinodes ;
check_ilim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_INODES_B , & dquot - > dq_flags ) ;
2005-04-17 02:20:36 +04:00
}
if ( di - > dqb_valid & QIF_ILIMITS ) {
dm - > dqb_isoftlimit = di - > dqb_isoftlimit ;
dm - > dqb_ihardlimit = di - > dqb_ihardlimit ;
check_ilim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_ILIMITS_B , & dquot - > dq_flags ) ;
2005-04-17 02:20:36 +04:00
}
2008-10-02 18:48:10 +04:00
if ( di - > dqb_valid & QIF_BTIME ) {
2005-04-17 02:20:36 +04:00
dm - > dqb_btime = di - > dqb_btime ;
2009-01-08 05:07:29 +03:00
check_blim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_BTIME_B , & dquot - > dq_flags ) ;
}
if ( di - > dqb_valid & QIF_ITIME ) {
2005-04-17 02:20:36 +04:00
dm - > dqb_itime = di - > dqb_itime ;
2009-01-08 05:07:29 +03:00
check_ilim = 1 ;
2008-10-02 18:48:10 +04:00
__set_bit ( DQ_LASTSET_B + QIF_ITIME_B , & dquot - > dq_flags ) ;
}
2005-04-17 02:20:36 +04:00
if ( check_blim ) {
2009-01-27 17:47:22 +03:00
if ( ! dm - > dqb_bsoftlimit | |
dm - > dqb_curspace < dm - > dqb_bsoftlimit ) {
2005-04-17 02:20:36 +04:00
dm - > dqb_btime = 0 ;
clear_bit ( DQ_BLKS_B , & dquot - > dq_flags ) ;
2009-01-27 17:47:22 +03:00
} else if ( ! ( di - > dqb_valid & QIF_BTIME ) )
/* Set grace only if user hasn't provided his own... */
2008-04-28 13:14:31 +04:00
dm - > dqb_btime = get_seconds ( ) + dqi - > dqi_bgrace ;
2005-04-17 02:20:36 +04:00
}
if ( check_ilim ) {
2009-01-27 17:47:22 +03:00
if ( ! dm - > dqb_isoftlimit | |
dm - > dqb_curinodes < dm - > dqb_isoftlimit ) {
2005-04-17 02:20:36 +04:00
dm - > dqb_itime = 0 ;
clear_bit ( DQ_INODES_B , & dquot - > dq_flags ) ;
2009-01-27 17:47:22 +03:00
} else if ( ! ( di - > dqb_valid & QIF_ITIME ) )
/* Set grace only if user hasn't provided his own... */
2008-04-28 13:14:31 +04:00
dm - > dqb_itime = get_seconds ( ) + dqi - > dqi_igrace ;
2005-04-17 02:20:36 +04:00
}
2009-01-27 17:47:22 +03:00
if ( dm - > dqb_bhardlimit | | dm - > dqb_bsoftlimit | | dm - > dqb_ihardlimit | |
dm - > dqb_isoftlimit )
2005-04-17 02:20:36 +04:00
clear_bit ( DQ_FAKE_B , & dquot - > dq_flags ) ;
else
set_bit ( DQ_FAKE_B , & dquot - > dq_flags ) ;
spin_unlock ( & dq_data_lock ) ;
mark_dquot_dirty ( dquot ) ;
2008-04-28 13:14:31 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-01-27 17:47:22 +03:00
int vfs_set_dqblk ( struct super_block * sb , int type , qid_t id ,
struct if_dqblk * di )
2005-04-17 02:20:36 +04:00
{
struct dquot * dquot ;
2008-04-28 13:14:31 +04:00
int rc ;
2005-04-17 02:20:36 +04:00
2008-08-20 19:50:32 +04:00
dquot = dqget ( sb , id , type ) ;
if ( ! dquot ) {
rc = - ESRCH ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-04-28 13:14:31 +04:00
rc = do_set_dqblk ( dquot , di ) ;
2005-04-17 02:20:36 +04:00
dqput ( dquot ) ;
2008-08-20 19:50:32 +04:00
out :
2008-04-28 13:14:31 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_set_dqblk ) ;
2005-04-17 02:20:36 +04:00
/* Generic routine for getting common part of quota file information */
int vfs_get_dqinfo ( struct super_block * sb , int type , struct if_dqinfo * ii )
{
struct mem_dqinfo * mi ;
2006-03-23 14:00:29 +03:00
mutex_lock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_active ( sb , type ) ) {
2006-03-23 14:00:29 +03:00
mutex_unlock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
return - ESRCH ;
}
mi = sb_dqopt ( sb ) - > info + type ;
spin_lock ( & dq_data_lock ) ;
ii - > dqi_bgrace = mi - > dqi_bgrace ;
ii - > dqi_igrace = mi - > dqi_igrace ;
ii - > dqi_flags = mi - > dqi_flags & DQF_MASK ;
ii - > dqi_valid = IIF_ALL ;
spin_unlock ( & dq_data_lock ) ;
2006-03-23 14:00:29 +03:00
mutex_unlock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_get_dqinfo ) ;
2005-04-17 02:20:36 +04:00
/* Generic routine for setting common part of quota file information */
int vfs_set_dqinfo ( struct super_block * sb , int type , struct if_dqinfo * ii )
{
struct mem_dqinfo * mi ;
2008-08-20 19:50:32 +04:00
int err = 0 ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:29 +03:00
mutex_lock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2008-08-20 19:50:32 +04:00
if ( ! sb_has_quota_active ( sb , type ) ) {
err = - ESRCH ;
goto out ;
2005-04-17 02:20:36 +04:00
}
mi = sb_dqopt ( sb ) - > info + type ;
spin_lock ( & dq_data_lock ) ;
if ( ii - > dqi_valid & IIF_BGRACE )
mi - > dqi_bgrace = ii - > dqi_bgrace ;
if ( ii - > dqi_valid & IIF_IGRACE )
mi - > dqi_igrace = ii - > dqi_igrace ;
if ( ii - > dqi_valid & IIF_FLAGS )
2009-01-27 17:47:22 +03:00
mi - > dqi_flags = ( mi - > dqi_flags & ~ DQF_MASK ) |
( ii - > dqi_flags & DQF_MASK ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dq_data_lock ) ;
mark_info_dirty ( sb , type ) ;
/* Force write to disk */
sb - > dq_op - > write_info ( sb , type ) ;
2008-08-20 19:50:32 +04:00
out :
2006-03-23 14:00:29 +03:00
mutex_unlock ( & sb_dqopt ( sb ) - > dqonoff_mutex ) ;
2008-08-20 19:50:32 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 18:19:32 +03:00
EXPORT_SYMBOL ( vfs_set_dqinfo ) ;
2005-04-17 02:20:36 +04:00
2009-09-22 04:01:09 +04:00
const struct quotactl_ops vfs_quotactl_ops = {
2005-04-17 02:20:36 +04:00
. quota_on = vfs_quota_on ,
. quota_off = vfs_quota_off ,
. quota_sync = vfs_quota_sync ,
. get_info = vfs_get_dqinfo ,
. set_info = vfs_set_dqinfo ,
. get_dqblk = vfs_get_dqblk ,
. set_dqblk = vfs_set_dqblk
} ;
static ctl_table fs_dqstats_table [ ] = {
{
. procname = " lookups " ,
. data = & dqstats . lookups ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " drops " ,
. data = & dqstats . drops ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " reads " ,
. data = & dqstats . reads ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " writes " ,
. data = & dqstats . writes ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " cache_hits " ,
. data = & dqstats . cache_hits ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " allocated_dquots " ,
. data = & dqstats . allocated_dquots ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " free_dquots " ,
. data = & dqstats . free_dquots ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " syncs " ,
. data = & dqstats . syncs ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
2007-10-17 10:29:31 +04:00
# ifdef CONFIG_PRINT_QUOTA_WARNING
2005-04-17 02:20:36 +04:00
{
. procname = " warnings " ,
. data = & flag_print_warnings ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
2007-10-17 10:29:31 +04:00
# endif
2009-11-06 01:25:10 +03:00
{ } ,
2005-04-17 02:20:36 +04:00
} ;
static ctl_table fs_table [ ] = {
{
. procname = " quota " ,
. mode = 0555 ,
. child = fs_dqstats_table ,
} ,
2009-11-06 01:25:10 +03:00
{ } ,
2005-04-17 02:20:36 +04:00
} ;
static ctl_table sys_table [ ] = {
{
. procname = " fs " ,
. mode = 0555 ,
. child = fs_table ,
} ,
2009-11-06 01:25:10 +03:00
{ } ,
2005-04-17 02:20:36 +04:00
} ;
static int __init dquot_init ( void )
{
int i ;
unsigned long nr_hash , order ;
printk ( KERN_NOTICE " VFS: Disk quotas %s \n " , __DQUOT_VERSION__ ) ;
2007-02-14 11:34:09 +03:00
register_sysctl_table ( sys_table ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 05:11:58 +04:00
dquot_cachep = kmem_cache_create ( " dquot " ,
2005-04-17 02:20:36 +04:00
sizeof ( struct dquot ) , sizeof ( unsigned long ) * 4 ,
2006-03-24 14:16:06 +03:00
( SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD | SLAB_PANIC ) ,
2007-07-20 05:11:58 +04:00
NULL ) ;
2005-04-17 02:20:36 +04:00
order = 0 ;
dquot_hash = ( struct hlist_head * ) __get_free_pages ( GFP_ATOMIC , order ) ;
if ( ! dquot_hash )
panic ( " Cannot create dquot hash table " ) ;
/* Find power-of-two hlist_heads which can fit into allocation */
nr_hash = ( 1UL < < order ) * PAGE_SIZE / sizeof ( struct hlist_head ) ;
dq_hash_bits = 0 ;
do {
dq_hash_bits + + ;
} while ( nr_hash > > dq_hash_bits ) ;
dq_hash_bits - - ;
nr_hash = 1UL < < dq_hash_bits ;
dq_hash_mask = nr_hash - 1 ;
for ( i = 0 ; i < nr_hash ; i + + )
INIT_HLIST_HEAD ( dquot_hash + i ) ;
printk ( " Dquot-cache hash table entries: %ld (order %ld, %ld bytes) \n " ,
nr_hash , order , ( PAGE_SIZE < < order ) ) ;
2007-07-17 15:03:17 +04:00
register_shrinker ( & dqcache_shrinker ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
module_init ( dquot_init ) ;