2005-04-17 02:20:36 +04:00
/*
2006-06-09 09:29:58 +04:00
* Copyright ( c ) 2000 - 2006 Silicon Graphics , Inc .
2005-11-02 06:59:41 +03:00
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:59:41 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:59:41 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:59:41 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
# include "xfs_fs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# include "xfs_log.h"
2005-11-02 06:38:42 +03:00
# include "xfs_inum.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans.h"
# include "xfs_sb.h"
2005-11-02 06:38:42 +03:00
# include "xfs_ag.h"
2005-04-17 02:20:36 +04:00
# include "xfs_dir2.h"
# include "xfs_alloc.h"
# include "xfs_dmapi.h"
# include "xfs_quota.h"
# include "xfs_mount.h"
# include "xfs_bmap_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_alloc_btree.h"
2005-04-17 02:20:36 +04:00
# include "xfs_ialloc_btree.h"
# include "xfs_dir2_sf.h"
2005-11-02 06:38:42 +03:00
# include "xfs_attr_sf.h"
2005-04-17 02:20:36 +04:00
# include "xfs_dinode.h"
# include "xfs_inode.h"
2005-11-02 06:38:42 +03:00
# include "xfs_ialloc.h"
# include "xfs_itable.h"
# include "xfs_btree.h"
2005-04-17 02:20:36 +04:00
# include "xfs_bmap.h"
# include "xfs_rtalloc.h"
# include "xfs_error.h"
# include "xfs_rw.h"
# include "xfs_acl.h"
# include "xfs_attr.h"
# include "xfs_buf_item.h"
# include "xfs_qm.h"
2007-08-30 11:19:57 +04:00
STATIC void
xfs_fill_statvfs_from_dquot (
2008-11-28 06:23:36 +03:00
struct kstatfs * statp ,
2007-08-30 11:19:57 +04:00
xfs_disk_dquot_t * dp )
2006-06-09 09:29:58 +04:00
{
__uint64_t limit ;
2006-07-28 11:04:26 +04:00
limit = dp - > d_blk_softlimit ?
be64_to_cpu ( dp - > d_blk_softlimit ) :
be64_to_cpu ( dp - > d_blk_hardlimit ) ;
2006-06-09 09:29:58 +04:00
if ( limit & & statp - > f_blocks > limit ) {
statp - > f_blocks = limit ;
2006-07-28 11:04:26 +04:00
statp - > f_bfree =
( statp - > f_blocks > be64_to_cpu ( dp - > d_bcount ) ) ?
( statp - > f_blocks - be64_to_cpu ( dp - > d_bcount ) ) : 0 ;
2006-06-09 09:29:58 +04:00
}
2006-07-28 11:04:26 +04:00
limit = dp - > d_ino_softlimit ?
be64_to_cpu ( dp - > d_ino_softlimit ) :
be64_to_cpu ( dp - > d_ino_hardlimit ) ;
2006-06-09 09:29:58 +04:00
if ( limit & & statp - > f_files > limit ) {
statp - > f_files = limit ;
2006-07-28 11:04:26 +04:00
statp - > f_ffree =
( statp - > f_files > be64_to_cpu ( dp - > d_icount ) ) ?
( statp - > f_ffree - be64_to_cpu ( dp - > d_icount ) ) : 0 ;
2006-06-09 09:29:58 +04:00
}
}
2007-08-30 11:19:57 +04:00
/*
* Directory tree accounting is implemented using project quotas , where
* the project identifier is inherited from parent directories .
* A statvfs ( df , etc . ) of a directory that is using project quota should
* return a statvfs of the project , not the entire filesystem .
* This makes such trees appear as if they are filesystems in themselves .
*/
STATIC void
xfs_qm_statvfs (
xfs_inode_t * ip ,
2008-11-28 06:23:36 +03:00
struct kstatfs * statp )
2005-04-17 02:20:36 +04:00
{
2007-08-30 11:19:57 +04:00
xfs_mount_t * mp = ip - > i_mount ;
xfs_dquot_t * dqp ;
2005-04-17 02:20:36 +04:00
2007-08-30 11:19:57 +04:00
if ( ! ( ip - > i_d . di_flags & XFS_DIFLAG_PROJINHERIT ) | |
! ( ( mp - > m_qflags & ( XFS_PQUOTA_ACCT | XFS_OQUOTA_ENFD ) ) ) = =
( XFS_PQUOTA_ACCT | XFS_OQUOTA_ENFD ) )
return ;
if ( ! xfs_qm_dqget ( mp , NULL , ip - > i_d . di_projid , XFS_DQ_PROJ , 0 , & dqp ) ) {
xfs_disk_dquot_t * dp = & dqp - > q_core ;
xfs_fill_statvfs_from_dquot ( statp , dp ) ;
xfs_qm_dqput ( dqp ) ;
2005-04-17 02:20:36 +04:00
}
}
STATIC int
xfs_qm_newmount (
xfs_mount_t * mp ,
uint * needquotamount ,
uint * quotaflags )
{
uint quotaondisk ;
2005-06-21 09:38:48 +04:00
uint uquotaondisk = 0 , gquotaondisk = 0 , pquotaondisk = 0 ;
2005-04-17 02:20:36 +04:00
* quotaflags = 0 ;
* needquotamount = B_FALSE ;
2008-03-06 05:44:28 +03:00
quotaondisk = xfs_sb_version_hasquota ( & mp - > m_sb ) & &
2005-06-21 09:38:48 +04:00
( mp - > m_sb . sb_qflags & XFS_ALL_QUOTA_ACCT ) ;
2005-04-17 02:20:36 +04:00
if ( quotaondisk ) {
uquotaondisk = mp - > m_sb . sb_qflags & XFS_UQUOTA_ACCT ;
2005-06-21 09:38:48 +04:00
pquotaondisk = mp - > m_sb . sb_qflags & XFS_PQUOTA_ACCT ;
2005-04-17 02:20:36 +04:00
gquotaondisk = mp - > m_sb . sb_qflags & XFS_GQUOTA_ACCT ;
}
/*
* If the device itself is read - only , we can ' t allow
* the user to change the state of quota on the mount -
* this would generate a transaction on the ro device ,
* which would lead to an I / O error and shutdown
*/
if ( ( ( uquotaondisk & & ! XFS_IS_UQUOTA_ON ( mp ) ) | |
( ! uquotaondisk & & XFS_IS_UQUOTA_ON ( mp ) ) | |
2005-06-21 09:38:48 +04:00
( pquotaondisk & & ! XFS_IS_PQUOTA_ON ( mp ) ) | |
( ! pquotaondisk & & XFS_IS_PQUOTA_ON ( mp ) ) | |
2005-04-17 02:20:36 +04:00
( gquotaondisk & & ! XFS_IS_GQUOTA_ON ( mp ) ) | |
2005-06-21 09:38:48 +04:00
( ! gquotaondisk & & XFS_IS_OQUOTA_ON ( mp ) ) ) & &
2005-04-17 02:20:36 +04:00
xfs_dev_is_read_only ( mp , " changing quota state " ) ) {
cmn_err ( CE_WARN ,
2005-06-21 09:38:48 +04:00
" XFS: please mount with%s%s%s%s. " ,
2005-04-17 02:20:36 +04:00
( ! quotaondisk ? " out quota " : " " ) ,
( uquotaondisk ? " usrquota " : " " ) ,
2005-06-21 09:38:48 +04:00
( pquotaondisk ? " prjquota " : " " ) ,
2005-04-17 02:20:36 +04:00
( gquotaondisk ? " grpquota " : " " ) ) ;
return XFS_ERROR ( EPERM ) ;
}
if ( XFS_IS_QUOTA_ON ( mp ) | | quotaondisk ) {
/*
* Call mount_quotas at this point only if we won ' t have to do
* a quotacheck .
*/
if ( quotaondisk & & ! XFS_QM_NEED_QUOTACHECK ( mp ) ) {
/*
* If an error occured , qm_mount_quotas code
* has already disabled quotas . So , just finish
* mounting , and get on with the boring life
* without disk quotas .
*/
2008-08-13 10:49:32 +04:00
xfs_qm_mount_quotas ( mp ) ;
2005-04-17 02:20:36 +04:00
} else {
/*
* Clear the quota flags , but remember them . This
* is so that the quota code doesn ' t get invoked
* before we ' re ready . This can happen when an
* inode goes inactive and wants to free blocks ,
* or via xfs_log_mount_finish .
*/
* needquotamount = B_TRUE ;
* quotaflags = mp - > m_qflags ;
mp - > m_qflags = 0 ;
}
}
return 0 ;
}
STATIC int
xfs_qm_endmount (
xfs_mount_t * mp ,
uint needquotamount ,
2008-08-13 10:49:32 +04:00
uint quotaflags )
2005-04-17 02:20:36 +04:00
{
if ( needquotamount ) {
ASSERT ( mp - > m_qflags = = 0 ) ;
mp - > m_qflags = quotaflags ;
2008-08-13 10:49:32 +04:00
xfs_qm_mount_quotas ( mp ) ;
2005-04-17 02:20:36 +04:00
}
# if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
if ( ! ( XFS_IS_QUOTA_ON ( mp ) ) )
xfs_fs_cmn_err ( CE_NOTE , mp , " Disk quotas not turned on " ) ;
else
xfs_fs_cmn_err ( CE_NOTE , mp , " Disk quotas turned on " ) ;
# endif
# ifdef QUOTADEBUG
if ( XFS_IS_QUOTA_ON ( mp ) & & xfs_qm_internalqcheck ( mp ) )
cmn_err ( CE_WARN , " XFS: mount internalqcheck failed " ) ;
# endif
return 0 ;
}
STATIC void
xfs_qm_dqrele_null (
xfs_dquot_t * dq )
{
/*
* Called from XFS , where we always check first for a NULL dquot .
*/
if ( ! dq )
return ;
xfs_qm_dqrele ( dq ) ;
}
2007-08-30 11:19:57 +04:00
struct xfs_qmops xfs_qmcore_xfs = {
2005-04-17 02:20:36 +04:00
. xfs_qminit = xfs_qm_newmount ,
. xfs_qmdone = xfs_qm_unmount_quotadestroy ,
. xfs_qmmount = xfs_qm_endmount ,
. xfs_qmunmount = xfs_qm_unmount_quotas ,
. xfs_dqrele = xfs_qm_dqrele_null ,
. xfs_dqattach = xfs_qm_dqattach ,
. xfs_dqdetach = xfs_qm_dqdetach ,
. xfs_dqpurgeall = xfs_qm_dqpurge_all ,
. xfs_dqvopalloc = xfs_qm_vop_dqalloc ,
. xfs_dqvopcreate = xfs_qm_vop_dqattach_and_dqmod_newinode ,
. xfs_dqvoprename = xfs_qm_vop_rename_dqattach ,
. xfs_dqvopchown = xfs_qm_vop_chown ,
. xfs_dqvopchownresv = xfs_qm_vop_chown_reserve ,
2007-08-30 11:19:57 +04:00
. xfs_dqstatvfs = xfs_qm_statvfs ,
. xfs_dqsync = xfs_qm_sync ,
2005-04-17 02:20:36 +04:00
. xfs_dqtrxops = & xfs_trans_dquot_ops ,
} ;
2007-08-30 11:19:57 +04:00
EXPORT_SYMBOL ( xfs_qmcore_xfs ) ;
2005-04-17 02:20:36 +04:00
void __init
xfs_qm_init ( void )
{
2007-08-30 11:19:57 +04:00
printk ( KERN_INFO " SGI XFS Quota Management subsystem \n " ) ;
2006-01-10 02:59:21 +03:00
mutex_init ( & xfs_Gqm_lock ) ;
2005-04-17 02:20:36 +04:00
xfs_qm_init_procfs ( ) ;
}
void __exit
xfs_qm_exit ( void )
{
xfs_qm_cleanup_procfs ( ) ;
if ( qm_dqzone )
2006-03-22 04:47:28 +03:00
kmem_zone_destroy ( qm_dqzone ) ;
2005-04-17 02:20:36 +04:00
if ( qm_dqtrxzone )
2006-03-22 04:47:28 +03:00
kmem_zone_destroy ( qm_dqtrxzone ) ;
2005-04-17 02:20:36 +04:00
}