2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:59:41 +03:00
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* 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
*/
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include "xfs.h"
# include "xfs_fs.h"
2013-10-23 03:36:05 +04:00
# include "xfs_shared.h"
2013-10-23 03:50:10 +04:00
# include "xfs_format.h"
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# 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_mount.h"
# include "xfs_inode.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2005-04-17 02:20:36 +04:00
# include "xfs_error.h"
2013-10-23 03:51:50 +04:00
# include "xfs_quota.h"
2005-04-17 02:20:36 +04:00
# include "xfs_qm.h"
2009-12-15 02:14:59 +03:00
# include "xfs_trace.h"
2012-10-08 14:56:09 +04:00
# include "xfs_icache.h"
2005-04-17 02:20:36 +04:00
STATIC int xfs_qm_log_quotaoff ( xfs_mount_t * , xfs_qoff_logitem_t * * , uint ) ;
STATIC int xfs_qm_log_quotaoff_end ( xfs_mount_t * , xfs_qoff_logitem_t * ,
uint ) ;
STATIC uint xfs_qm_export_flags ( uint ) ;
STATIC uint xfs_qm_export_qtype_flags ( uint ) ;
/*
* Turn off quota accounting and / or enforcement for all udquots and / or
* gdquots . Called only at unmount time .
*
* This assumes that there are no dquots of this file system cached
* incore , and modifies the ondisk dquot directly . Therefore , for example ,
* it is an error to call this twice , without purging the cache .
*/
2009-02-09 10:47:34 +03:00
int
2005-04-17 02:20:36 +04:00
xfs_qm_scall_quotaoff (
xfs_mount_t * mp ,
2009-02-09 10:47:34 +03:00
uint flags )
2005-04-17 02:20:36 +04:00
{
2010-04-20 11:01:30 +04:00
struct xfs_quotainfo * q = mp - > m_quotainfo ;
2005-04-17 02:20:36 +04:00
uint dqtype ;
int error ;
uint inactivate_flags ;
xfs_qoff_logitem_t * qoffstart ;
/*
* No file system can have quotas enabled on disk but not in core .
* Note that quota utilities ( like quotaoff ) _expect_
* errno = = EEXIST here .
*/
if ( ( mp - > m_qflags & flags ) = = 0 )
return XFS_ERROR ( EEXIST ) ;
error = 0 ;
flags & = ( XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD ) ;
/*
* We don ' t want to deal with two quotaoffs messing up each other ,
* so we ' re going to serialize it . quotaoff isn ' t exactly a performance
* critical thing .
* If quotaoff , then we must be dealing with the root filesystem .
*/
2010-04-20 11:01:30 +04:00
ASSERT ( q ) ;
mutex_lock ( & q - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
/*
* If we ' re just turning off quota enforcement , change mp and go .
*/
if ( ( flags & XFS_ALL_QUOTA_ACCT ) = = 0 ) {
mp - > m_qflags & = ~ ( flags ) ;
2007-10-11 11:42:32 +04:00
spin_lock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
mp - > m_sb . sb_qflags = mp - > m_qflags ;
2007-10-11 11:42:32 +04:00
spin_unlock ( & mp - > m_sb_lock ) ;
2010-04-20 11:01:30 +04:00
mutex_unlock ( & q - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
/* XXX what to do if error ? Revert back to old vals incore ? */
error = xfs_qm_write_sb_changes ( mp , XFS_SB_QFLAGS ) ;
return ( error ) ;
}
dqtype = 0 ;
inactivate_flags = 0 ;
/*
* If accounting is off , we must turn enforcement off , clear the
* quota ' CHKD ' certificate to make it known that we have to
* do a quotacheck the next time this quota is turned on .
*/
if ( flags & XFS_UQUOTA_ACCT ) {
dqtype | = XFS_QMOPT_UQUOTA ;
flags | = ( XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD ) ;
inactivate_flags | = XFS_UQUOTA_ACTIVE ;
}
if ( flags & XFS_GQUOTA_ACCT ) {
dqtype | = XFS_QMOPT_GQUOTA ;
2013-06-28 02:25:10 +04:00
flags | = ( XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD ) ;
2005-04-17 02:20:36 +04:00
inactivate_flags | = XFS_GQUOTA_ACTIVE ;
2013-07-11 09:00:40 +04:00
}
if ( flags & XFS_PQUOTA_ACCT ) {
2005-06-21 09:38:48 +04:00
dqtype | = XFS_QMOPT_PQUOTA ;
2013-06-28 02:25:10 +04:00
flags | = ( XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD ) ;
2005-06-21 09:38:48 +04:00
inactivate_flags | = XFS_PQUOTA_ACTIVE ;
2005-04-17 02:20:36 +04:00
}
/*
* Nothing to do ? Don ' t complain . This happens when we ' re just
* turning off quota enforcement .
*/
2010-04-20 11:01:30 +04:00
if ( ( mp - > m_qflags & flags ) = = 0 )
goto out_unlock ;
2005-04-17 02:20:36 +04:00
/*
* Write the LI_QUOTAOFF log record , and do SB changes atomically ,
2008-04-10 06:20:45 +04:00
* and synchronously . If we fail to write , we should abort the
* operation as it cannot be recovered safely if we crash .
2005-04-17 02:20:36 +04:00
*/
2008-04-10 06:20:45 +04:00
error = xfs_qm_log_quotaoff ( mp , & qoffstart , flags ) ;
if ( error )
2010-04-20 11:01:30 +04:00
goto out_unlock ;
2005-04-17 02:20:36 +04:00
/*
* Next we clear the XFS_MOUNT_ * DQ_ACTIVE bit ( s ) in the mount struct
* to take care of the race between dqget and quotaoff . We don ' t take
* any special locks to reset these bits . All processes need to check
* these bits * after * taking inode lock ( s ) to see if the particular
* quota type is in the process of being turned off . If * ACTIVE , it is
* guaranteed that all dquot structures and all quotainode ptrs will all
* stay valid as long as that inode is kept locked .
*
* There is no turning back after this .
*/
mp - > m_qflags & = ~ inactivate_flags ;
/*
* Give back all the dquot reference ( s ) held by inodes .
* Here we go thru every single incore inode in this file system , and
* do a dqrele on the i_udquot / i_gdquot that it may have .
* Essentially , as long as somebody has an inode locked , this guarantees
* that quotas will not be turned off . This is handy because in a
* transaction once we lock the inode ( s ) and check for quotaon , we can
* depend on the quota inodes ( and other things ) being valid as long as
* we keep the lock ( s ) .
*/
xfs_qm_dqrele_all_inodes ( mp , flags ) ;
/*
* Next we make the changes in the quota flag in the mount struct .
* This isn ' t protected by a particular lock directly , because we
2011-03-31 05:57:33 +04:00
* don ' t want to take a mrlock every time we depend on quotas being on .
2005-04-17 02:20:36 +04:00
*/
2012-03-14 20:53:34 +04:00
mp - > m_qflags & = ~ flags ;
2005-04-17 02:20:36 +04:00
/*
* Go through all the dquots of this file system and purge them ,
2012-03-14 20:53:34 +04:00
* according to what was turned off .
2005-04-17 02:20:36 +04:00
*/
2012-03-14 20:53:34 +04:00
xfs_qm_dqpurge_all ( mp , dqtype ) ;
2005-04-17 02:20:36 +04:00
/*
* Transactions that had started before ACTIVE state bit was cleared
* could have logged many dquots , so they ' d have higher LSNs than
* the first QUOTAOFF log record does . If we happen to crash when
* the tail of the log has gone past the QUOTAOFF record , but
* before the last dquot modification , those dquots __will__
* recover , and that ' s not good .
*
* So , we have QUOTAOFF start and end logitems ; the start
* logitem won ' t get overwritten until the end logitem appears . . .
*/
2008-04-10 06:20:45 +04:00
error = xfs_qm_log_quotaoff_end ( mp , qoffstart , flags ) ;
if ( error ) {
/* We're screwed now. Shutdown is the only option. */
xfs_force_shutdown ( mp , SHUTDOWN_CORRUPT_INCORE ) ;
2010-04-20 11:01:30 +04:00
goto out_unlock ;
2008-04-10 06:20:45 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2013-07-11 03:00:36 +04:00
* If all quotas are completely turned off , close shop .
2005-04-17 02:20:36 +04:00
*/
2013-07-11 03:00:36 +04:00
if ( mp - > m_qflags = = 0 ) {
2010-04-20 11:01:30 +04:00
mutex_unlock ( & q - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
xfs_qm_destroy_quotainfo ( mp ) ;
return ( 0 ) ;
}
/*
2010-04-20 11:01:30 +04:00
* Release our quotainode references if we don ' t need them anymore .
2005-04-17 02:20:36 +04:00
*/
2010-04-20 11:01:30 +04:00
if ( ( dqtype & XFS_QMOPT_UQUOTA ) & & q - > qi_uquotaip ) {
IRELE ( q - > qi_uquotaip ) ;
q - > qi_uquotaip = NULL ;
2005-04-17 02:20:36 +04:00
}
2013-07-11 09:00:40 +04:00
if ( ( dqtype & XFS_QMOPT_GQUOTA ) & & q - > qi_gquotaip ) {
2010-04-20 11:01:30 +04:00
IRELE ( q - > qi_gquotaip ) ;
q - > qi_gquotaip = NULL ;
2005-04-17 02:20:36 +04:00
}
2013-07-11 09:00:40 +04:00
if ( ( dqtype & XFS_QMOPT_PQUOTA ) & & q - > qi_pquotaip ) {
IRELE ( q - > qi_pquotaip ) ;
q - > qi_pquotaip = NULL ;
}
2005-04-17 02:20:36 +04:00
2010-04-20 11:01:30 +04:00
out_unlock :
mutex_unlock ( & q - > qi_quotaofflock ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
2010-07-20 11:51:31 +04:00
STATIC int
xfs_qm_scall_trunc_qfile (
struct xfs_mount * mp ,
xfs_ino_t ino )
{
struct xfs_inode * ip ;
struct xfs_trans * tp ;
int error ;
if ( ino = = NULLFSINO )
return 0 ;
error = xfs_iget ( mp , NULL , ino , 0 , 0 , & ip ) ;
if ( error )
return error ;
xfs_ilock ( ip , XFS_IOLOCK_EXCL ) ;
tp = xfs_trans_alloc ( mp , XFS_TRANS_TRUNCATE_FILE ) ;
2013-08-12 14:49:59 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_itruncate , 0 , 0 ) ;
2010-07-20 11:51:31 +04:00
if ( error ) {
xfs_trans_cancel ( tp , 0 ) ;
xfs_iunlock ( ip , XFS_IOLOCK_EXCL ) ;
goto out_put ;
}
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
2011-09-19 19:00:54 +04:00
xfs_trans_ijoin ( tp , ip , 0 ) ;
2010-07-20 11:51:31 +04:00
2011-12-19 00:00:04 +04:00
ip - > i_d . di_size = 0 ;
xfs_trans_log_inode ( tp , ip , XFS_ILOG_CORE ) ;
error = xfs_itruncate_extents ( & tp , ip , XFS_DATA_FORK , 0 ) ;
2010-07-20 11:51:31 +04:00
if ( error ) {
xfs_trans_cancel ( tp , XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT ) ;
goto out_unlock ;
}
2011-12-19 00:00:04 +04:00
ASSERT ( ip - > i_d . di_nextents = = 0 ) ;
2010-09-28 06:27:25 +04:00
xfs_trans_ichgtime ( tp , ip , XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG ) ;
2010-07-20 11:51:31 +04:00
error = xfs_trans_commit ( tp , XFS_TRANS_RELEASE_LOG_RES ) ;
out_unlock :
xfs_iunlock ( ip , XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL ) ;
out_put :
IRELE ( ip ) ;
return error ;
}
2009-02-09 10:47:34 +03:00
int
2005-04-17 02:20:36 +04:00
xfs_qm_scall_trunc_qfiles (
xfs_mount_t * mp ,
uint flags )
{
2014-05-05 11:27:06 +04:00
int error = EINVAL ;
2005-04-17 02:20:36 +04:00
2014-05-05 11:27:06 +04:00
if ( ! xfs_sb_version_hasquota ( & mp - > m_sb ) | | flags = = 0 | |
( flags & ~ XFS_DQ_ALLTYPES ) ) {
2013-10-12 05:59:05 +04:00
xfs_debug ( mp , " %s: flags=%x m_qflags=%x " ,
2011-03-07 02:07:35 +03:00
__func__ , flags , mp - > m_qflags ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( EINVAL ) ;
}
2013-11-22 10:04:00 +04:00
if ( flags & XFS_DQ_USER ) {
2010-07-20 11:51:31 +04:00
error = xfs_qm_scall_trunc_qfile ( mp , mp - > m_sb . sb_uquotino ) ;
2013-11-22 10:04:00 +04:00
if ( error )
return error ;
}
if ( flags & XFS_DQ_GROUP ) {
error = xfs_qm_scall_trunc_qfile ( mp , mp - > m_sb . sb_gquotino ) ;
if ( error )
return error ;
}
2013-07-20 02:36:02 +04:00
if ( flags & XFS_DQ_PROJ )
2013-11-22 10:04:00 +04:00
error = xfs_qm_scall_trunc_qfile ( mp , mp - > m_sb . sb_pquotino ) ;
2005-04-17 02:20:36 +04:00
2013-11-22 10:04:00 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
/*
* Switch on ( a given ) quota enforcement for a filesystem . This takes
* effect immediately .
* ( Switching on quota accounting must be done at mount time . )
*/
2009-02-09 10:47:34 +03:00
int
2005-04-17 02:20:36 +04:00
xfs_qm_scall_quotaon (
xfs_mount_t * mp ,
uint flags )
{
int error ;
uint qf ;
__int64_t sbflags ;
flags & = ( XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD ) ;
/*
* Switching on quota accounting must be done at mount time .
*/
flags & = ~ ( XFS_ALL_QUOTA_ACCT ) ;
sbflags = 0 ;
if ( flags = = 0 ) {
2013-10-12 05:59:05 +04:00
xfs_debug ( mp , " %s: zero flags, m_qflags=%x " ,
2011-03-07 02:07:35 +03:00
__func__ , mp - > m_qflags ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( EINVAL ) ;
}
/* No fs can turn on quotas with a delayed effect */
ASSERT ( ( flags & XFS_ALL_QUOTA_ACCT ) = = 0 ) ;
/*
* Can ' t enforce without accounting . We check the superblock
* qflags here instead of m_qflags because rootfs can have
* quota acct on ondisk without m_qflags ' knowing .
*/
if ( ( ( flags & XFS_UQUOTA_ACCT ) = = 0 & &
2013-06-28 02:25:10 +04:00
( mp - > m_sb . sb_qflags & XFS_UQUOTA_ACCT ) = = 0 & &
( flags & XFS_UQUOTA_ENFD ) ) | |
( ( flags & XFS_GQUOTA_ACCT ) = = 0 & &
( mp - > m_sb . sb_qflags & XFS_GQUOTA_ACCT ) = = 0 & &
( flags & XFS_GQUOTA_ENFD ) ) | |
2005-06-21 09:38:48 +04:00
( ( flags & XFS_PQUOTA_ACCT ) = = 0 & &
2013-06-28 02:25:10 +04:00
( mp - > m_sb . sb_qflags & XFS_PQUOTA_ACCT ) = = 0 & &
( flags & XFS_PQUOTA_ENFD ) ) ) {
2011-03-07 02:07:35 +03:00
xfs_debug ( mp ,
2013-10-12 05:59:05 +04:00
" %s: Can't enforce without acct, flags=%x sbflags=%x " ,
2011-03-07 02:07:35 +03:00
__func__ , flags , mp - > m_sb . sb_qflags ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( EINVAL ) ;
}
/*
2011-03-31 05:57:33 +04:00
* If everything ' s up to - date incore , then don ' t waste time .
2005-04-17 02:20:36 +04:00
*/
if ( ( mp - > m_qflags & flags ) = = flags )
return XFS_ERROR ( EEXIST ) ;
/*
* Change sb_qflags on disk but not incore mp - > qflags
* if this is the root filesystem .
*/
2007-10-11 11:42:32 +04:00
spin_lock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
qf = mp - > m_sb . sb_qflags ;
mp - > m_sb . sb_qflags = qf | flags ;
2007-10-11 11:42:32 +04:00
spin_unlock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
/*
* There ' s nothing to change if it ' s the same .
*/
if ( ( qf & flags ) = = flags & & sbflags = = 0 )
return XFS_ERROR ( EEXIST ) ;
sbflags | = XFS_SB_QFLAGS ;
if ( ( error = xfs_qm_write_sb_changes ( mp , sbflags ) ) )
return ( error ) ;
/*
* If we aren ' t trying to switch on quota enforcement , we are done .
*/
if ( ( ( mp - > m_sb . sb_qflags & XFS_UQUOTA_ACCT ) ! =
( mp - > m_qflags & XFS_UQUOTA_ACCT ) ) | |
2005-06-21 09:38:48 +04:00
( ( mp - > m_sb . sb_qflags & XFS_PQUOTA_ACCT ) ! =
( mp - > m_qflags & XFS_PQUOTA_ACCT ) ) | |
( ( mp - > m_sb . sb_qflags & XFS_GQUOTA_ACCT ) ! =
( mp - > m_qflags & XFS_GQUOTA_ACCT ) ) | |
2005-04-17 02:20:36 +04:00
( flags & XFS_ALL_QUOTA_ENFD ) = = 0 )
return ( 0 ) ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return XFS_ERROR ( ESRCH ) ;
/*
* Switch on quota enforcement in core .
*/
2010-04-20 11:01:30 +04:00
mutex_lock ( & mp - > m_quotainfo - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
mp - > m_qflags | = ( flags & XFS_ALL_QUOTA_ENFD ) ;
2010-04-20 11:01:30 +04:00
mutex_unlock ( & mp - > m_quotainfo - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
return ( 0 ) ;
}
/*
* Return quota status information , such as uquota - off , enforcements , etc .
2013-08-07 02:27:08 +04:00
* for Q_XGETQSTAT command .
2005-04-17 02:20:36 +04:00
*/
2009-02-09 10:47:34 +03:00
int
2005-04-17 02:20:36 +04:00
xfs_qm_scall_getqstat (
2010-04-20 11:01:30 +04:00
struct xfs_mount * mp ,
struct fs_quota_stat * out )
2005-04-17 02:20:36 +04:00
{
2010-04-20 11:01:30 +04:00
struct xfs_quotainfo * q = mp - > m_quotainfo ;
2013-06-28 02:25:07 +04:00
struct xfs_inode * uip = NULL ;
struct xfs_inode * gip = NULL ;
2013-07-20 02:36:02 +04:00
struct xfs_inode * pip = NULL ;
2013-06-28 02:25:07 +04:00
bool tempuqip = false ;
bool tempgqip = false ;
2013-07-20 02:36:02 +04:00
bool temppqip = false ;
2005-04-17 02:20:36 +04:00
memset ( out , 0 , sizeof ( fs_quota_stat_t ) ) ;
out - > qs_version = FS_QSTAT_VERSION ;
2008-03-06 05:44:28 +03:00
if ( ! xfs_sb_version_hasquota ( & mp - > m_sb ) ) {
2005-04-17 02:20:36 +04:00
out - > qs_uquota . qfs_ino = NULLFSINO ;
out - > qs_gquota . qfs_ino = NULLFSINO ;
return ( 0 ) ;
}
2013-07-20 02:36:02 +04:00
2005-04-17 02:20:36 +04:00
out - > qs_flags = ( __uint16_t ) xfs_qm_export_flags ( mp - > m_qflags &
( XFS_ALL_QUOTA_ACCT |
XFS_ALL_QUOTA_ENFD ) ) ;
2010-04-20 11:01:30 +04:00
if ( q ) {
uip = q - > qi_uquotaip ;
gip = q - > qi_gquotaip ;
2013-07-20 02:36:02 +04:00
pip = q - > qi_pquotaip ;
2005-04-17 02:20:36 +04:00
}
if ( ! uip & & mp - > m_sb . sb_uquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_uquotino ,
2010-06-24 05:35:17 +04:00
0 , 0 , & uip ) = = 0 )
2012-11-13 03:32:59 +04:00
tempuqip = true ;
2005-04-17 02:20:36 +04:00
}
if ( ! gip & & mp - > m_sb . sb_gquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_gquotino ,
2010-06-24 05:35:17 +04:00
0 , 0 , & gip ) = = 0 )
2012-11-13 03:32:59 +04:00
tempgqip = true ;
2005-04-17 02:20:36 +04:00
}
2013-07-20 02:36:02 +04:00
/*
* Q_XGETQSTAT doesn ' t have room for both group and project quotas .
* So , allow the project quota values to be copied out only if
* there is no group quota information available .
*/
if ( ! gip ) {
if ( ! pip & & mp - > m_sb . sb_pquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_pquotino ,
0 , 0 , & pip ) = = 0 )
temppqip = true ;
}
} else
pip = NULL ;
2005-04-17 02:20:36 +04:00
if ( uip ) {
2013-07-20 02:36:02 +04:00
out - > qs_uquota . qfs_ino = mp - > m_sb . sb_uquotino ;
2005-04-17 02:20:36 +04:00
out - > qs_uquota . qfs_nblks = uip - > i_d . di_nblocks ;
out - > qs_uquota . qfs_nextents = uip - > i_d . di_nextents ;
if ( tempuqip )
2008-03-27 10:01:08 +03:00
IRELE ( uip ) ;
2005-04-17 02:20:36 +04:00
}
2013-07-20 02:36:02 +04:00
2005-04-17 02:20:36 +04:00
if ( gip ) {
2013-07-20 02:36:02 +04:00
out - > qs_gquota . qfs_ino = mp - > m_sb . sb_gquotino ;
2005-04-17 02:20:36 +04:00
out - > qs_gquota . qfs_nblks = gip - > i_d . di_nblocks ;
out - > qs_gquota . qfs_nextents = gip - > i_d . di_nextents ;
if ( tempgqip )
2008-03-27 10:01:08 +03:00
IRELE ( gip ) ;
2005-04-17 02:20:36 +04:00
}
2013-07-20 02:36:02 +04:00
if ( pip ) {
out - > qs_gquota . qfs_ino = mp - > m_sb . sb_gquotino ;
out - > qs_gquota . qfs_nblks = pip - > i_d . di_nblocks ;
out - > qs_gquota . qfs_nextents = pip - > i_d . di_nextents ;
if ( temppqip )
2013-08-07 02:27:08 +04:00
IRELE ( pip ) ;
}
if ( q ) {
out - > qs_incoredqs = q - > qi_dquots ;
out - > qs_btimelimit = q - > qi_btimelimit ;
out - > qs_itimelimit = q - > qi_itimelimit ;
out - > qs_rtbtimelimit = q - > qi_rtbtimelimit ;
out - > qs_bwarnlimit = q - > qi_bwarnlimit ;
out - > qs_iwarnlimit = q - > qi_iwarnlimit ;
}
return 0 ;
}
/*
* Return quota status information , such as uquota - off , enforcements , etc .
* for Q_XGETQSTATV command , to support separate project quota field .
*/
int
xfs_qm_scall_getqstatv (
struct xfs_mount * mp ,
struct fs_quota_statv * out )
{
struct xfs_quotainfo * q = mp - > m_quotainfo ;
struct xfs_inode * uip = NULL ;
struct xfs_inode * gip = NULL ;
struct xfs_inode * pip = NULL ;
bool tempuqip = false ;
bool tempgqip = false ;
bool temppqip = false ;
if ( ! xfs_sb_version_hasquota ( & mp - > m_sb ) ) {
out - > qs_uquota . qfs_ino = NULLFSINO ;
out - > qs_gquota . qfs_ino = NULLFSINO ;
out - > qs_pquota . qfs_ino = NULLFSINO ;
return ( 0 ) ;
}
out - > qs_flags = ( __uint16_t ) xfs_qm_export_flags ( mp - > m_qflags &
( XFS_ALL_QUOTA_ACCT |
XFS_ALL_QUOTA_ENFD ) ) ;
out - > qs_uquota . qfs_ino = mp - > m_sb . sb_uquotino ;
out - > qs_gquota . qfs_ino = mp - > m_sb . sb_gquotino ;
out - > qs_pquota . qfs_ino = mp - > m_sb . sb_pquotino ;
if ( q ) {
uip = q - > qi_uquotaip ;
gip = q - > qi_gquotaip ;
pip = q - > qi_pquotaip ;
}
if ( ! uip & & mp - > m_sb . sb_uquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_uquotino ,
0 , 0 , & uip ) = = 0 )
tempuqip = true ;
}
if ( ! gip & & mp - > m_sb . sb_gquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_gquotino ,
0 , 0 , & gip ) = = 0 )
tempgqip = true ;
}
if ( ! pip & & mp - > m_sb . sb_pquotino ! = NULLFSINO ) {
if ( xfs_iget ( mp , NULL , mp - > m_sb . sb_pquotino ,
0 , 0 , & pip ) = = 0 )
temppqip = true ;
}
if ( uip ) {
out - > qs_uquota . qfs_nblks = uip - > i_d . di_nblocks ;
out - > qs_uquota . qfs_nextents = uip - > i_d . di_nextents ;
if ( tempuqip )
IRELE ( uip ) ;
}
if ( gip ) {
out - > qs_gquota . qfs_nblks = gip - > i_d . di_nblocks ;
out - > qs_gquota . qfs_nextents = gip - > i_d . di_nextents ;
if ( tempgqip )
IRELE ( gip ) ;
}
if ( pip ) {
out - > qs_pquota . qfs_nblks = pip - > i_d . di_nblocks ;
out - > qs_pquota . qfs_nextents = pip - > i_d . di_nextents ;
if ( temppqip )
2013-07-20 02:36:02 +04:00
IRELE ( pip ) ;
}
2010-04-20 11:01:30 +04:00
if ( q ) {
out - > qs_incoredqs = q - > qi_dquots ;
out - > qs_btimelimit = q - > qi_btimelimit ;
out - > qs_itimelimit = q - > qi_itimelimit ;
out - > qs_rtbtimelimit = q - > qi_rtbtimelimit ;
out - > qs_bwarnlimit = q - > qi_bwarnlimit ;
out - > qs_iwarnlimit = q - > qi_iwarnlimit ;
2005-04-17 02:20:36 +04:00
}
2010-04-20 11:01:30 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-05-07 01:05:17 +04:00
# define XFS_DQ_MASK \
( FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK )
2005-04-17 02:20:36 +04:00
/*
* Adjust quota limits , and start / stop timers accordingly .
*/
2009-02-09 10:47:34 +03:00
int
2005-04-17 02:20:36 +04:00
xfs_qm_scall_setqlim (
2013-03-18 18:51:46 +04:00
struct xfs_mount * mp ,
2005-04-17 02:20:36 +04:00
xfs_dqid_t id ,
uint type ,
fs_disk_quota_t * newlim )
{
2010-04-20 11:01:30 +04:00
struct xfs_quotainfo * q = mp - > m_quotainfo ;
2013-03-18 18:51:46 +04:00
struct xfs_disk_dquot * ddq ;
struct xfs_dquot * dqp ;
struct xfs_trans * tp ;
2005-04-17 02:20:36 +04:00
int error ;
xfs_qcnt_t hard , soft ;
2010-05-07 01:05:17 +04:00
if ( newlim - > d_fieldmask & ~ XFS_DQ_MASK )
return EINVAL ;
if ( ( newlim - > d_fieldmask & XFS_DQ_MASK ) = = 0 )
return 0 ;
2005-04-17 02:20:36 +04:00
/*
* We don ' t want to race with a quotaoff so take the quotaoff lock .
2013-05-21 12:02:00 +04:00
* We don ' t hold an inode lock , so there ' s nothing else to stop
* a quotaoff from happening .
2005-04-17 02:20:36 +04:00
*/
2010-04-20 11:01:30 +04:00
mutex_lock ( & q - > qi_quotaofflock ) ;
2005-04-17 02:20:36 +04:00
/*
2013-05-21 12:02:00 +04:00
* Get the dquot ( locked ) before we start , as we need to do a
* transaction to allocate it if it doesn ' t exist . Once we have the
* dquot , unlock it so we can start the next transaction safely . We hold
* a reference to the dquot , so it ' s safe to do this unlock / lock without
* it being reclaimed in the mean time .
2005-04-17 02:20:36 +04:00
*/
2013-05-21 12:02:00 +04:00
error = xfs_qm_dqget ( mp , NULL , id , type , XFS_QMOPT_DQALLOC , & dqp ) ;
if ( error ) {
2005-04-17 02:20:36 +04:00
ASSERT ( error ! = ENOENT ) ;
2010-04-20 11:01:30 +04:00
goto out_unlock ;
2005-04-17 02:20:36 +04:00
}
2013-05-21 12:02:00 +04:00
xfs_dqunlock ( dqp ) ;
tp = xfs_trans_alloc ( mp , XFS_TRANS_QM_SETQLIM ) ;
2013-08-12 14:49:59 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_qm_setqlim , 0 , 0 ) ;
2013-05-21 12:02:00 +04:00
if ( error ) {
xfs_trans_cancel ( tp , 0 ) ;
goto out_rele ;
}
xfs_dqlock ( dqp ) ;
2005-04-17 02:20:36 +04:00
xfs_trans_dqjoin ( tp , dqp ) ;
ddq = & dqp - > q_core ;
/*
* Make sure that hardlimits are > = soft limits before changing .
*/
hard = ( newlim - > d_fieldmask & FS_DQ_BHARD ) ?
( xfs_qcnt_t ) XFS_BB_TO_FSB ( mp , newlim - > d_blk_hardlimit ) :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_blk_hardlimit ) ;
2005-04-17 02:20:36 +04:00
soft = ( newlim - > d_fieldmask & FS_DQ_BSOFT ) ?
( xfs_qcnt_t ) XFS_BB_TO_FSB ( mp , newlim - > d_blk_softlimit ) :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_blk_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( hard = = 0 | | hard > = soft ) {
2005-11-02 07:01:12 +03:00
ddq - > d_blk_hardlimit = cpu_to_be64 ( hard ) ;
ddq - > d_blk_softlimit = cpu_to_be64 ( soft ) ;
2013-03-18 18:51:46 +04:00
xfs_dquot_set_prealloc_limits ( dqp ) ;
2005-04-17 02:20:36 +04:00
if ( id = = 0 ) {
2010-04-20 11:01:30 +04:00
q - > qi_bhardlimit = hard ;
q - > qi_bsoftlimit = soft ;
2005-04-17 02:20:36 +04:00
}
} else {
2013-10-12 05:59:05 +04:00
xfs_debug ( mp , " blkhard %Ld < blksoft %Ld " , hard , soft ) ;
2005-04-17 02:20:36 +04:00
}
hard = ( newlim - > d_fieldmask & FS_DQ_RTBHARD ) ?
( xfs_qcnt_t ) XFS_BB_TO_FSB ( mp , newlim - > d_rtb_hardlimit ) :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_rtb_hardlimit ) ;
2005-04-17 02:20:36 +04:00
soft = ( newlim - > d_fieldmask & FS_DQ_RTBSOFT ) ?
( xfs_qcnt_t ) XFS_BB_TO_FSB ( mp , newlim - > d_rtb_softlimit ) :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_rtb_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( hard = = 0 | | hard > = soft ) {
2005-11-02 07:01:12 +03:00
ddq - > d_rtb_hardlimit = cpu_to_be64 ( hard ) ;
ddq - > d_rtb_softlimit = cpu_to_be64 ( soft ) ;
2005-04-17 02:20:36 +04:00
if ( id = = 0 ) {
2010-04-20 11:01:30 +04:00
q - > qi_rtbhardlimit = hard ;
q - > qi_rtbsoftlimit = soft ;
2005-04-17 02:20:36 +04:00
}
} else {
2013-10-12 05:59:05 +04:00
xfs_debug ( mp , " rtbhard %Ld < rtbsoft %Ld " , hard , soft ) ;
2005-04-17 02:20:36 +04:00
}
hard = ( newlim - > d_fieldmask & FS_DQ_IHARD ) ?
( xfs_qcnt_t ) newlim - > d_ino_hardlimit :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_ino_hardlimit ) ;
2005-04-17 02:20:36 +04:00
soft = ( newlim - > d_fieldmask & FS_DQ_ISOFT ) ?
( xfs_qcnt_t ) newlim - > d_ino_softlimit :
2005-11-02 07:01:12 +03:00
be64_to_cpu ( ddq - > d_ino_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( hard = = 0 | | hard > = soft ) {
2005-11-02 07:01:12 +03:00
ddq - > d_ino_hardlimit = cpu_to_be64 ( hard ) ;
ddq - > d_ino_softlimit = cpu_to_be64 ( soft ) ;
2005-04-17 02:20:36 +04:00
if ( id = = 0 ) {
2010-04-20 11:01:30 +04:00
q - > qi_ihardlimit = hard ;
q - > qi_isoftlimit = soft ;
2005-04-17 02:20:36 +04:00
}
} else {
2013-10-12 05:59:05 +04:00
xfs_debug ( mp , " ihard %Ld < isoft %Ld " , hard , soft ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-21 09:49:06 +04:00
/*
* Update warnings counter ( s ) if requested
*/
if ( newlim - > d_fieldmask & FS_DQ_BWARNS )
2005-11-02 07:01:12 +03:00
ddq - > d_bwarns = cpu_to_be16 ( newlim - > d_bwarns ) ;
2005-06-21 09:49:06 +04:00
if ( newlim - > d_fieldmask & FS_DQ_IWARNS )
2005-11-02 07:01:12 +03:00
ddq - > d_iwarns = cpu_to_be16 ( newlim - > d_iwarns ) ;
2005-06-21 09:49:06 +04:00
if ( newlim - > d_fieldmask & FS_DQ_RTBWARNS )
2005-11-02 07:01:12 +03:00
ddq - > d_rtbwarns = cpu_to_be16 ( newlim - > d_rtbwarns ) ;
2005-06-21 09:49:06 +04:00
2005-04-17 02:20:36 +04:00
if ( id = = 0 ) {
/*
* Timelimits for the super user set the relative time
* the other users can be over quota for this file system .
* If it is zero a default is used . Ditto for the default
2005-06-21 09:49:06 +04:00
* soft and hard limit values ( already done , above ) , and
* for warnings .
2005-04-17 02:20:36 +04:00
*/
if ( newlim - > d_fieldmask & FS_DQ_BTIMER ) {
2010-04-20 11:01:30 +04:00
q - > qi_btimelimit = newlim - > d_btimer ;
2005-11-02 07:01:12 +03:00
ddq - > d_btimer = cpu_to_be32 ( newlim - > d_btimer ) ;
2005-04-17 02:20:36 +04:00
}
if ( newlim - > d_fieldmask & FS_DQ_ITIMER ) {
2010-04-20 11:01:30 +04:00
q - > qi_itimelimit = newlim - > d_itimer ;
2005-11-02 07:01:12 +03:00
ddq - > d_itimer = cpu_to_be32 ( newlim - > d_itimer ) ;
2005-04-17 02:20:36 +04:00
}
if ( newlim - > d_fieldmask & FS_DQ_RTBTIMER ) {
2010-04-20 11:01:30 +04:00
q - > qi_rtbtimelimit = newlim - > d_rtbtimer ;
2005-11-02 07:01:12 +03:00
ddq - > d_rtbtimer = cpu_to_be32 ( newlim - > d_rtbtimer ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-21 09:49:06 +04:00
if ( newlim - > d_fieldmask & FS_DQ_BWARNS )
2010-04-20 11:01:30 +04:00
q - > qi_bwarnlimit = newlim - > d_bwarns ;
2005-06-21 09:49:06 +04:00
if ( newlim - > d_fieldmask & FS_DQ_IWARNS )
2010-04-20 11:01:30 +04:00
q - > qi_iwarnlimit = newlim - > d_iwarns ;
2005-06-21 09:49:06 +04:00
if ( newlim - > d_fieldmask & FS_DQ_RTBWARNS )
2010-04-20 11:01:30 +04:00
q - > qi_rtbwarnlimit = newlim - > d_rtbwarns ;
2005-06-21 09:49:06 +04:00
} else {
2005-04-17 02:20:36 +04:00
/*
* If the user is now over quota , start the timelimit .
* The user will not be ' warned ' .
* Note that we keep the timers ticking , whether enforcement
* is on or off . We don ' t really want to bother with iterating
* over all ondisk dquots and turning the timers on / off .
*/
xfs_qm_adjust_dqtimers ( mp , ddq ) ;
}
dqp - > dq_flags | = XFS_DQ_DIRTY ;
xfs_trans_log_dquot ( tp , dqp ) ;
2008-04-10 06:21:18 +04:00
error = xfs_trans_commit ( tp , 0 ) ;
2005-04-17 02:20:36 +04:00
2013-05-21 12:02:00 +04:00
out_rele :
xfs_qm_dqrele ( dqp ) ;
out_unlock :
2010-04-20 11:01:30 +04:00
mutex_unlock ( & q - > qi_quotaofflock ) ;
2008-04-10 06:21:18 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
STATIC int
xfs_qm_log_quotaoff_end (
xfs_mount_t * mp ,
xfs_qoff_logitem_t * startqoff ,
uint flags )
{
2005-06-21 09:38:48 +04:00
xfs_trans_t * tp ;
2005-04-17 02:20:36 +04:00
int error ;
2005-06-21 09:38:48 +04:00
xfs_qoff_logitem_t * qoffi ;
2005-04-17 02:20:36 +04:00
tp = xfs_trans_alloc ( mp , XFS_TRANS_QM_QUOTAOFF_END ) ;
2013-08-12 14:49:59 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_qm_equotaoff , 0 , 0 ) ;
2013-01-28 17:27:21 +04:00
if ( error ) {
2005-04-17 02:20:36 +04:00
xfs_trans_cancel ( tp , 0 ) ;
return ( error ) ;
}
qoffi = xfs_trans_get_qoff_item ( tp , startqoff ,
flags & XFS_ALL_QUOTA_ACCT ) ;
xfs_trans_log_quotaoff_item ( tp , qoffi ) ;
/*
* We have to make sure that the transaction is secure on disk before we
* return and actually stop quota accounting . So , make it synchronous .
* We don ' t care about quotoff ' s performance .
*/
xfs_trans_set_sync ( tp ) ;
2007-05-08 07:48:42 +04:00
error = xfs_trans_commit ( tp , 0 ) ;
2005-04-17 02:20:36 +04:00
return ( error ) ;
}
STATIC int
xfs_qm_log_quotaoff (
xfs_mount_t * mp ,
xfs_qoff_logitem_t * * qoffstartp ,
uint flags )
{
xfs_trans_t * tp ;
int error ;
xfs_qoff_logitem_t * qoffi = NULL ;
uint oldsbqflag = 0 ;
tp = xfs_trans_alloc ( mp , XFS_TRANS_QM_QUOTAOFF ) ;
2013-08-12 14:49:59 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_qm_quotaoff , 0 , 0 ) ;
2013-01-28 17:27:15 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
goto error0 ;
qoffi = xfs_trans_get_qoff_item ( tp , NULL , flags & XFS_ALL_QUOTA_ACCT ) ;
xfs_trans_log_quotaoff_item ( tp , qoffi ) ;
2007-10-11 11:42:32 +04:00
spin_lock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
oldsbqflag = mp - > m_sb . sb_qflags ;
mp - > m_sb . sb_qflags = ( mp - > m_qflags & ~ ( flags ) ) & XFS_MOUNT_QUOTA_ALL ;
2007-10-11 11:42:32 +04:00
spin_unlock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
xfs_mod_sb ( tp , XFS_SB_QFLAGS ) ;
/*
* We have to make sure that the transaction is secure on disk before we
* return and actually stop quota accounting . So , make it synchronous .
* We don ' t care about quotoff ' s performance .
*/
xfs_trans_set_sync ( tp ) ;
2007-05-08 07:48:42 +04:00
error = xfs_trans_commit ( tp , 0 ) ;
2005-04-17 02:20:36 +04:00
error0 :
if ( error ) {
xfs_trans_cancel ( tp , 0 ) ;
/*
* No one else is modifying sb_qflags , so this is OK .
* We still hold the quotaofflock .
*/
2007-10-11 11:42:32 +04:00
spin_lock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
mp - > m_sb . sb_qflags = oldsbqflag ;
2007-10-11 11:42:32 +04:00
spin_unlock ( & mp - > m_sb_lock ) ;
2005-04-17 02:20:36 +04:00
}
* qoffstartp = qoffi ;
return ( error ) ;
}
2012-02-20 06:28:16 +04:00
int
xfs_qm_scall_getquota (
struct xfs_mount * mp ,
xfs_dqid_t id ,
uint type ,
2005-04-17 02:20:36 +04:00
struct fs_disk_quota * dst )
{
2012-02-20 06:28:16 +04:00
struct xfs_dquot * dqp ;
int error ;
/*
* Try to get the dquot . We don ' t want it allocated on disk , so
* we aren ' t passing the XFS_QMOPT_DOALLOC flag . If it doesn ' t
* exist , we ' ll get ENOENT back .
*/
error = xfs_qm_dqget ( mp , NULL , id , type , 0 , & dqp ) ;
if ( error )
return error ;
/*
* If everything ' s NULL , this dquot doesn ' t quite exist as far as
* our utility programs are concerned .
*/
if ( XFS_IS_DQUOT_UNINITIALIZED ( dqp ) ) {
error = XFS_ERROR ( ENOENT ) ;
goto out_put ;
}
2005-04-17 02:20:36 +04:00
memset ( dst , 0 , sizeof ( * dst ) ) ;
2012-02-20 06:28:16 +04:00
dst - > d_version = FS_DQUOT_VERSION ;
dst - > d_flags = xfs_qm_export_qtype_flags ( dqp - > q_core . d_flags ) ;
dst - > d_id = be32_to_cpu ( dqp - > q_core . d_id ) ;
2005-11-02 07:01:12 +03:00
dst - > d_blk_hardlimit =
2012-02-20 06:28:16 +04:00
XFS_FSB_TO_BB ( mp , be64_to_cpu ( dqp - > q_core . d_blk_hardlimit ) ) ;
2005-11-02 07:01:12 +03:00
dst - > d_blk_softlimit =
2012-02-20 06:28:16 +04:00
XFS_FSB_TO_BB ( mp , be64_to_cpu ( dqp - > q_core . d_blk_softlimit ) ) ;
dst - > d_ino_hardlimit = be64_to_cpu ( dqp - > q_core . d_ino_hardlimit ) ;
dst - > d_ino_softlimit = be64_to_cpu ( dqp - > q_core . d_ino_softlimit ) ;
2012-02-20 06:28:17 +04:00
dst - > d_bcount = XFS_FSB_TO_BB ( mp , dqp - > q_res_bcount ) ;
dst - > d_icount = dqp - > q_res_icount ;
2012-02-20 06:28:16 +04:00
dst - > d_btimer = be32_to_cpu ( dqp - > q_core . d_btimer ) ;
dst - > d_itimer = be32_to_cpu ( dqp - > q_core . d_itimer ) ;
dst - > d_iwarns = be16_to_cpu ( dqp - > q_core . d_iwarns ) ;
dst - > d_bwarns = be16_to_cpu ( dqp - > q_core . d_bwarns ) ;
2005-11-02 07:01:12 +03:00
dst - > d_rtb_hardlimit =
2012-02-20 06:28:16 +04:00
XFS_FSB_TO_BB ( mp , be64_to_cpu ( dqp - > q_core . d_rtb_hardlimit ) ) ;
2005-11-02 07:01:12 +03:00
dst - > d_rtb_softlimit =
2012-02-20 06:28:16 +04:00
XFS_FSB_TO_BB ( mp , be64_to_cpu ( dqp - > q_core . d_rtb_softlimit ) ) ;
2012-02-20 06:28:17 +04:00
dst - > d_rtbcount = XFS_FSB_TO_BB ( mp , dqp - > q_res_rtbcount ) ;
2012-02-20 06:28:16 +04:00
dst - > d_rtbtimer = be32_to_cpu ( dqp - > q_core . d_rtbtimer ) ;
dst - > d_rtbwarns = be16_to_cpu ( dqp - > q_core . d_rtbwarns ) ;
2005-04-17 02:20:36 +04:00
/*
* Internally , we don ' t reset all the timers when quota enforcement
2006-03-29 02:55:14 +04:00
* gets turned off . No need to confuse the user level code ,
2005-04-17 02:20:36 +04:00
* so return zeroes in that case .
*/
2013-06-28 02:25:10 +04:00
if ( ( ! XFS_IS_UQUOTA_ENFORCED ( mp ) & &
dqp - > q_core . d_flags = = XFS_DQ_USER ) | |
( ! XFS_IS_GQUOTA_ENFORCED ( mp ) & &
dqp - > q_core . d_flags = = XFS_DQ_GROUP ) | |
( ! XFS_IS_PQUOTA_ENFORCED ( mp ) & &
dqp - > q_core . d_flags = = XFS_DQ_PROJ ) ) {
2005-04-17 02:20:36 +04:00
dst - > d_btimer = 0 ;
dst - > d_itimer = 0 ;
dst - > d_rtbtimer = 0 ;
}
# ifdef DEBUG
2010-06-04 12:56:01 +04:00
if ( ( ( XFS_IS_UQUOTA_ENFORCED ( mp ) & & dst - > d_flags = = FS_USER_QUOTA ) | |
2013-06-28 02:25:10 +04:00
( XFS_IS_GQUOTA_ENFORCED ( mp ) & & dst - > d_flags = = FS_GROUP_QUOTA ) | |
( XFS_IS_PQUOTA_ENFORCED ( mp ) & & dst - > d_flags = = FS_PROJ_QUOTA ) ) & &
2007-05-08 07:49:33 +04:00
dst - > d_id ! = 0 ) {
2012-12-21 19:45:17 +04:00
if ( ( dst - > d_bcount > dst - > d_blk_softlimit ) & &
2005-04-17 02:20:36 +04:00
( dst - > d_blk_softlimit > 0 ) ) {
ASSERT ( dst - > d_btimer ! = 0 ) ;
}
2012-12-21 19:45:17 +04:00
if ( ( dst - > d_icount > dst - > d_ino_softlimit ) & &
2005-04-17 02:20:36 +04:00
( dst - > d_ino_softlimit > 0 ) ) {
ASSERT ( dst - > d_itimer ! = 0 ) ;
}
}
# endif
2012-02-20 06:28:16 +04:00
out_put :
xfs_qm_dqput ( dqp ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
STATIC uint
xfs_qm_export_qtype_flags (
uint flags )
{
/*
2005-06-21 09:38:48 +04:00
* Can ' t be more than one , or none .
2005-04-17 02:20:36 +04:00
*/
2010-06-04 12:56:01 +04:00
ASSERT ( ( flags & ( FS_PROJ_QUOTA | FS_USER_QUOTA ) ) ! =
( FS_PROJ_QUOTA | FS_USER_QUOTA ) ) ;
ASSERT ( ( flags & ( FS_PROJ_QUOTA | FS_GROUP_QUOTA ) ) ! =
( FS_PROJ_QUOTA | FS_GROUP_QUOTA ) ) ;
ASSERT ( ( flags & ( FS_USER_QUOTA | FS_GROUP_QUOTA ) ) ! =
( FS_USER_QUOTA | FS_GROUP_QUOTA ) ) ;
ASSERT ( ( flags & ( FS_PROJ_QUOTA | FS_USER_QUOTA | FS_GROUP_QUOTA ) ) ! = 0 ) ;
2005-04-17 02:20:36 +04:00
return ( flags & XFS_DQ_USER ) ?
2010-06-04 12:56:01 +04:00
FS_USER_QUOTA : ( flags & XFS_DQ_PROJ ) ?
FS_PROJ_QUOTA : FS_GROUP_QUOTA ;
2005-04-17 02:20:36 +04:00
}
STATIC uint
xfs_qm_export_flags (
uint flags )
{
uint uflags ;
uflags = 0 ;
if ( flags & XFS_UQUOTA_ACCT )
2010-06-04 12:56:01 +04:00
uflags | = FS_QUOTA_UDQ_ACCT ;
2005-04-17 02:20:36 +04:00
if ( flags & XFS_GQUOTA_ACCT )
2010-06-04 12:56:01 +04:00
uflags | = FS_QUOTA_GDQ_ACCT ;
2013-06-28 02:25:10 +04:00
if ( flags & XFS_PQUOTA_ACCT )
uflags | = FS_QUOTA_PDQ_ACCT ;
2005-04-17 02:20:36 +04:00
if ( flags & XFS_UQUOTA_ENFD )
2010-06-04 12:56:01 +04:00
uflags | = FS_QUOTA_UDQ_ENFD ;
2013-06-28 02:25:10 +04:00
if ( flags & XFS_GQUOTA_ENFD )
uflags | = FS_QUOTA_GDQ_ENFD ;
if ( flags & XFS_PQUOTA_ENFD )
uflags | = FS_QUOTA_PDQ_ENFD ;
2005-04-17 02:20:36 +04:00
return ( uflags ) ;
}
2009-06-08 17:35:27 +04:00
STATIC int
xfs_dqrele_inode (
struct xfs_inode * ip ,
2012-11-06 18:50:39 +04:00
int flags ,
void * args )
2005-04-17 02:20:36 +04:00
{
2009-06-08 17:35:27 +04:00
/* skip quota inodes */
2010-04-20 11:01:30 +04:00
if ( ip = = ip - > i_mount - > m_quotainfo - > qi_uquotaip | |
2013-07-11 09:00:40 +04:00
ip = = ip - > i_mount - > m_quotainfo - > qi_gquotaip | |
ip = = ip - > i_mount - > m_quotainfo - > qi_pquotaip ) {
2009-06-08 17:35:27 +04:00
ASSERT ( ip - > i_udquot = = NULL ) ;
ASSERT ( ip - > i_gdquot = = NULL ) ;
2013-07-11 09:00:40 +04:00
ASSERT ( ip - > i_pdquot = = NULL ) ;
2009-06-08 17:35:27 +04:00
return 0 ;
}
2008-11-10 09:11:18 +03:00
2009-06-08 17:35:27 +04:00
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
if ( ( flags & XFS_UQUOTA_ACCT ) & & ip - > i_udquot ) {
xfs_qm_dqrele ( ip - > i_udquot ) ;
ip - > i_udquot = NULL ;
}
2013-07-11 09:00:40 +04:00
if ( ( flags & XFS_GQUOTA_ACCT ) & & ip - > i_gdquot ) {
2009-06-08 17:35:27 +04:00
xfs_qm_dqrele ( ip - > i_gdquot ) ;
ip - > i_gdquot = NULL ;
}
2013-07-11 09:00:40 +04:00
if ( ( flags & XFS_PQUOTA_ACCT ) & & ip - > i_pdquot ) {
xfs_qm_dqrele ( ip - > i_pdquot ) ;
ip - > i_pdquot = NULL ;
}
2010-06-24 05:52:50 +04:00
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2009-06-08 17:35:27 +04:00
return 0 ;
2008-10-30 09:08:03 +03:00
}
2009-06-08 17:35:27 +04:00
2008-10-30 09:08:03 +03:00
/*
* Go thru all the inodes in the file system , releasing their dquots .
2009-06-08 17:35:27 +04:00
*
2008-10-30 09:08:03 +03:00
* Note that the mount structure gets modified to indicate that quotas are off
2009-06-08 17:35:27 +04:00
* AFTER this , in the case of quotaoff .
2008-10-30 09:08:03 +03:00
*/
void
xfs_qm_dqrele_all_inodes (
struct xfs_mount * mp ,
uint flags )
{
ASSERT ( mp - > m_quotainfo ) ;
2012-11-06 18:50:39 +04:00
xfs_inode_ag_iterator ( mp , xfs_dqrele_inode , flags , NULL ) ;
2005-04-17 02:20:36 +04:00
}