2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:59:41 +03:00
* Copyright ( c ) 2000 - 2002 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
*/
# 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"
# include "xfs_ag.h"
# 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_attr_sf.h"
# include "xfs_dir2_sf.h"
# 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_attr.h"
# include "xfs_buf_item.h"
# include "xfs_trans_priv.h"
# include "xfs_qm.h"
STATIC void xfs_trans_alloc_dqinfo ( xfs_trans_t * ) ;
/*
* Add the locked dquot to the transaction .
* The dquot must be locked , and it cannot be associated with any
* transaction .
*/
void
xfs_trans_dqjoin (
xfs_trans_t * tp ,
xfs_dquot_t * dqp )
{
xfs_dq_logitem_t * lp ;
ASSERT ( ! XFS_DQ_IS_ADDEDTO_TRX ( tp , dqp ) ) ;
ASSERT ( XFS_DQ_IS_LOCKED ( dqp ) ) ;
ASSERT ( XFS_DQ_IS_LOGITEM_INITD ( dqp ) ) ;
lp = & dqp - > q_logitem ;
/*
* Get a log_item_desc to point at the new item .
*/
( void ) xfs_trans_add_item ( tp , ( xfs_log_item_t * ) ( lp ) ) ;
/*
* Initialize i_transp so we can later determine if this dquot is
* associated with this transaction .
*/
dqp - > q_transp = tp ;
}
/*
* This is called to mark the dquot as needing
* to be logged when the transaction is committed . The dquot must
* already be associated with the given transaction .
* Note that it marks the entire transaction as dirty . In the ordinary
* case , this gets called via xfs_trans_commit , after the transaction
* is already dirty . However , there ' s nothing stop this from getting
* called directly , as done by xfs_qm_scall_setqlim . Hence , the TRANS_DIRTY
* flag .
*/
void
xfs_trans_log_dquot (
xfs_trans_t * tp ,
xfs_dquot_t * dqp )
{
xfs_log_item_desc_t * lidp ;
ASSERT ( XFS_DQ_IS_ADDEDTO_TRX ( tp , dqp ) ) ;
ASSERT ( XFS_DQ_IS_LOCKED ( dqp ) ) ;
lidp = xfs_trans_find_item ( tp , ( xfs_log_item_t * ) ( & dqp - > q_logitem ) ) ;
ASSERT ( lidp ! = NULL ) ;
tp - > t_flags | = XFS_TRANS_DIRTY ;
lidp - > lid_flags | = XFS_LID_DIRTY ;
}
/*
* Carry forward whatever is left of the quota blk reservation to
* the spanky new transaction
*/
2009-06-08 17:33:32 +04:00
void
2005-04-17 02:20:36 +04:00
xfs_trans_dup_dqinfo (
xfs_trans_t * otp ,
xfs_trans_t * ntp )
{
xfs_dqtrx_t * oq , * nq ;
int i , j ;
xfs_dqtrx_t * oqa , * nqa ;
if ( ! otp - > t_dqinfo )
return ;
xfs_trans_alloc_dqinfo ( ntp ) ;
oqa = otp - > t_dqinfo - > dqa_usrdquots ;
nqa = ntp - > t_dqinfo - > dqa_usrdquots ;
/*
* Because the quota blk reservation is carried forward ,
* it is also necessary to carry forward the DQ_DIRTY flag .
*/
if ( otp - > t_flags & XFS_TRANS_DQ_DIRTY )
ntp - > t_flags | = XFS_TRANS_DQ_DIRTY ;
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = 0 ; i < XFS_QM_TRANS_MAXDQS ; i + + ) {
if ( oqa [ i ] . qt_dquot = = NULL )
break ;
oq = & oqa [ i ] ;
nq = & nqa [ i ] ;
nq - > qt_dquot = oq - > qt_dquot ;
nq - > qt_bcount_delta = nq - > qt_icount_delta = 0 ;
nq - > qt_rtbcount_delta = 0 ;
/*
* Transfer whatever is left of the reservations .
*/
nq - > qt_blk_res = oq - > qt_blk_res - oq - > qt_blk_res_used ;
oq - > qt_blk_res = oq - > qt_blk_res_used ;
nq - > qt_rtblk_res = oq - > qt_rtblk_res -
oq - > qt_rtblk_res_used ;
oq - > qt_rtblk_res = oq - > qt_rtblk_res_used ;
nq - > qt_ino_res = oq - > qt_ino_res - oq - > qt_ino_res_used ;
oq - > qt_ino_res = oq - > qt_ino_res_used ;
}
oqa = otp - > t_dqinfo - > dqa_grpdquots ;
nqa = ntp - > t_dqinfo - > dqa_grpdquots ;
}
}
/*
* Wrap around mod_dquot to account for both user and group quotas .
*/
2009-06-08 17:33:32 +04:00
void
2005-04-17 02:20:36 +04:00
xfs_trans_mod_dquot_byino (
xfs_trans_t * tp ,
xfs_inode_t * ip ,
uint field ,
long delta )
{
2009-06-08 17:33:32 +04:00
xfs_mount_t * mp = tp - > t_mountp ;
2005-04-17 02:20:36 +04:00
2009-06-08 17:33:32 +04:00
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) | |
! XFS_IS_QUOTA_ON ( mp ) | |
2005-04-17 02:20:36 +04:00
ip - > i_ino = = mp - > m_sb . sb_uquotino | |
ip - > i_ino = = mp - > m_sb . sb_gquotino )
return ;
if ( tp - > t_dqinfo = = NULL )
xfs_trans_alloc_dqinfo ( tp ) ;
2005-06-21 09:38:48 +04:00
if ( XFS_IS_UQUOTA_ON ( mp ) & & ip - > i_udquot )
2005-04-17 02:20:36 +04:00
( void ) xfs_trans_mod_dquot ( tp , ip - > i_udquot , field , delta ) ;
2005-06-21 09:38:48 +04:00
if ( XFS_IS_OQUOTA_ON ( mp ) & & ip - > i_gdquot )
2005-04-17 02:20:36 +04:00
( void ) xfs_trans_mod_dquot ( tp , ip - > i_gdquot , field , delta ) ;
}
STATIC xfs_dqtrx_t *
xfs_trans_get_dqtrx (
xfs_trans_t * tp ,
xfs_dquot_t * dqp )
{
int i ;
xfs_dqtrx_t * qa ;
for ( i = 0 ; i < XFS_QM_TRANS_MAXDQS ; i + + ) {
qa = XFS_QM_DQP_TO_DQACCT ( tp , dqp ) ;
if ( qa [ i ] . qt_dquot = = NULL | |
qa [ i ] . qt_dquot = = dqp ) {
return ( & qa [ i ] ) ;
}
}
return ( NULL ) ;
}
/*
* Make the changes in the transaction structure .
* The moral equivalent to xfs_trans_mod_sb ( ) .
* We don ' t touch any fields in the dquot , so we don ' t care
* if it ' s locked or not ( most of the time it won ' t be ) .
*/
void
xfs_trans_mod_dquot (
xfs_trans_t * tp ,
xfs_dquot_t * dqp ,
uint field ,
long delta )
{
xfs_dqtrx_t * qtrx ;
ASSERT ( tp ) ;
2009-06-08 17:33:32 +04:00
ASSERT ( XFS_IS_QUOTA_RUNNING ( tp - > t_mountp ) ) ;
2005-04-17 02:20:36 +04:00
qtrx = NULL ;
if ( tp - > t_dqinfo = = NULL )
xfs_trans_alloc_dqinfo ( tp ) ;
/*
* Find either the first free slot or the slot that belongs
* to this dquot .
*/
qtrx = xfs_trans_get_dqtrx ( tp , dqp ) ;
ASSERT ( qtrx ) ;
if ( qtrx - > qt_dquot = = NULL )
qtrx - > qt_dquot = dqp ;
switch ( field ) {
/*
* regular disk blk reservation
*/
case XFS_TRANS_DQ_RES_BLKS :
qtrx - > qt_blk_res + = ( ulong ) delta ;
break ;
/*
* inode reservation
*/
case XFS_TRANS_DQ_RES_INOS :
qtrx - > qt_ino_res + = ( ulong ) delta ;
break ;
/*
* disk blocks used .
*/
case XFS_TRANS_DQ_BCOUNT :
if ( qtrx - > qt_blk_res & & delta > 0 ) {
qtrx - > qt_blk_res_used + = ( ulong ) delta ;
ASSERT ( qtrx - > qt_blk_res > = qtrx - > qt_blk_res_used ) ;
}
qtrx - > qt_bcount_delta + = delta ;
break ;
case XFS_TRANS_DQ_DELBCOUNT :
qtrx - > qt_delbcnt_delta + = delta ;
break ;
/*
* Inode Count
*/
case XFS_TRANS_DQ_ICOUNT :
if ( qtrx - > qt_ino_res & & delta > 0 ) {
qtrx - > qt_ino_res_used + = ( ulong ) delta ;
ASSERT ( qtrx - > qt_ino_res > = qtrx - > qt_ino_res_used ) ;
}
qtrx - > qt_icount_delta + = delta ;
break ;
/*
* rtblk reservation
*/
case XFS_TRANS_DQ_RES_RTBLKS :
qtrx - > qt_rtblk_res + = ( ulong ) delta ;
break ;
/*
* rtblk count
*/
case XFS_TRANS_DQ_RTBCOUNT :
if ( qtrx - > qt_rtblk_res & & delta > 0 ) {
qtrx - > qt_rtblk_res_used + = ( ulong ) delta ;
ASSERT ( qtrx - > qt_rtblk_res > = qtrx - > qt_rtblk_res_used ) ;
}
qtrx - > qt_rtbcount_delta + = delta ;
break ;
case XFS_TRANS_DQ_DELRTBCOUNT :
qtrx - > qt_delrtb_delta + = delta ;
break ;
default :
ASSERT ( 0 ) ;
}
tp - > t_flags | = XFS_TRANS_DQ_DIRTY ;
}
/*
* Given an array of dqtrx structures , lock all the dquots associated
* and join them to the transaction , provided they have been modified .
* We know that the highest number of dquots ( of one type - usr OR grp ) ,
* involved in a transaction is 2 and that both usr and grp combined - 3.
* So , we don ' t attempt to make this very generic .
*/
STATIC void
xfs_trans_dqlockedjoin (
xfs_trans_t * tp ,
xfs_dqtrx_t * q )
{
ASSERT ( q [ 0 ] . qt_dquot ! = NULL ) ;
if ( q [ 1 ] . qt_dquot = = NULL ) {
xfs_dqlock ( q [ 0 ] . qt_dquot ) ;
xfs_trans_dqjoin ( tp , q [ 0 ] . qt_dquot ) ;
} else {
ASSERT ( XFS_QM_TRANS_MAXDQS = = 2 ) ;
xfs_dqlock2 ( q [ 0 ] . qt_dquot , q [ 1 ] . qt_dquot ) ;
xfs_trans_dqjoin ( tp , q [ 0 ] . qt_dquot ) ;
xfs_trans_dqjoin ( tp , q [ 1 ] . qt_dquot ) ;
}
}
/*
* Called by xfs_trans_commit ( ) and similar in spirit to
* xfs_trans_apply_sb_deltas ( ) .
* Go thru all the dquots belonging to this transaction and modify the
* INCORE dquot to reflect the actual usages .
* Unreserve just the reservations done by this transaction .
* dquot is still left locked at exit .
*/
2009-06-08 17:33:32 +04:00
void
2005-04-17 02:20:36 +04:00
xfs_trans_apply_dquot_deltas (
xfs_trans_t * tp )
{
int i , j ;
xfs_dquot_t * dqp ;
xfs_dqtrx_t * qtrx , * qa ;
xfs_disk_dquot_t * d ;
long totalbdelta ;
long totalrtbdelta ;
2009-06-08 17:33:32 +04:00
if ( ! ( tp - > t_flags & XFS_TRANS_DQ_DIRTY ) )
2005-04-17 02:20:36 +04:00
return ;
ASSERT ( tp - > t_dqinfo ) ;
qa = tp - > t_dqinfo - > dqa_usrdquots ;
for ( j = 0 ; j < 2 ; j + + ) {
if ( qa [ 0 ] . qt_dquot = = NULL ) {
qa = tp - > t_dqinfo - > dqa_grpdquots ;
continue ;
}
/*
* Lock all of the dquots and join them to the transaction .
*/
xfs_trans_dqlockedjoin ( tp , qa ) ;
for ( i = 0 ; i < XFS_QM_TRANS_MAXDQS ; i + + ) {
qtrx = & qa [ i ] ;
/*
* The array of dquots is filled
* sequentially , not sparsely .
*/
if ( ( dqp = qtrx - > qt_dquot ) = = NULL )
break ;
ASSERT ( XFS_DQ_IS_LOCKED ( dqp ) ) ;
ASSERT ( XFS_DQ_IS_ADDEDTO_TRX ( tp , dqp ) ) ;
/*
* adjust the actual number of blocks used
*/
d = & dqp - > q_core ;
/*
* The issue here is - sometimes we don ' t make a blkquota
* reservation intentionally to be fair to users
* ( when the amount is small ) . On the other hand ,
* delayed allocs do make reservations , but that ' s
* outside of a transaction , so we have no
* idea how much was really reserved .
* So , here we ' ve accumulated delayed allocation blks and
* non - delay blks . The assumption is that the
* delayed ones are always reserved ( outside of a
* transaction ) , and the others may or may not have
* quota reservations .
*/
totalbdelta = qtrx - > qt_bcount_delta +
qtrx - > qt_delbcnt_delta ;
totalrtbdelta = qtrx - > qt_rtbcount_delta +
qtrx - > qt_delrtb_delta ;
# ifdef QUOTADEBUG
if ( totalbdelta < 0 )
2005-11-02 07:01:12 +03:00
ASSERT ( be64_to_cpu ( d - > d_bcount ) > =
2005-04-17 02:20:36 +04:00
( xfs_qcnt_t ) - totalbdelta ) ;
if ( totalrtbdelta < 0 )
2005-11-02 07:01:12 +03:00
ASSERT ( be64_to_cpu ( d - > d_rtbcount ) > =
2005-04-17 02:20:36 +04:00
( xfs_qcnt_t ) - totalrtbdelta ) ;
if ( qtrx - > qt_icount_delta < 0 )
2005-11-02 07:01:12 +03:00
ASSERT ( be64_to_cpu ( d - > d_icount ) > =
2005-04-17 02:20:36 +04:00
( xfs_qcnt_t ) - qtrx - > qt_icount_delta ) ;
# endif
if ( totalbdelta )
2008-02-14 02:03:29 +03:00
be64_add_cpu ( & d - > d_bcount , ( xfs_qcnt_t ) totalbdelta ) ;
2005-04-17 02:20:36 +04:00
if ( qtrx - > qt_icount_delta )
2008-02-14 02:03:29 +03:00
be64_add_cpu ( & d - > d_icount , ( xfs_qcnt_t ) qtrx - > qt_icount_delta ) ;
2005-04-17 02:20:36 +04:00
if ( totalrtbdelta )
2008-02-14 02:03:29 +03:00
be64_add_cpu ( & d - > d_rtbcount , ( xfs_qcnt_t ) totalrtbdelta ) ;
2005-04-17 02:20:36 +04:00
/*
* Get any default limits in use .
* Start / reset the timer ( s ) if needed .
*/
if ( d - > d_id ) {
xfs_qm_adjust_dqlimits ( tp - > t_mountp , d ) ;
xfs_qm_adjust_dqtimers ( tp - > t_mountp , d ) ;
}
dqp - > dq_flags | = XFS_DQ_DIRTY ;
/*
* add this to the list of items to get logged
*/
xfs_trans_log_dquot ( tp , dqp ) ;
/*
* Take off what ' s left of the original reservation .
* In case of delayed allocations , there ' s no
* reservation that a transaction structure knows of .
*/
if ( qtrx - > qt_blk_res ! = 0 ) {
if ( qtrx - > qt_blk_res ! = qtrx - > qt_blk_res_used ) {
if ( qtrx - > qt_blk_res >
qtrx - > qt_blk_res_used )
dqp - > q_res_bcount - = ( xfs_qcnt_t )
( qtrx - > qt_blk_res -
qtrx - > qt_blk_res_used ) ;
else
dqp - > q_res_bcount - = ( xfs_qcnt_t )
( qtrx - > qt_blk_res_used -
qtrx - > qt_blk_res ) ;
}
} else {
/*
* These blks were never reserved , either inside
* a transaction or outside one ( in a delayed
* allocation ) . Also , this isn ' t always a
* negative number since we sometimes
* deliberately skip quota reservations .
*/
if ( qtrx - > qt_bcount_delta ) {
dqp - > q_res_bcount + =
( xfs_qcnt_t ) qtrx - > qt_bcount_delta ;
}
}
/*
* Adjust the RT reservation .
*/
if ( qtrx - > qt_rtblk_res ! = 0 ) {
2005-06-21 09:48:47 +04:00
if ( qtrx - > qt_rtblk_res ! = qtrx - > qt_rtblk_res_used ) {
2005-04-17 02:20:36 +04:00
if ( qtrx - > qt_rtblk_res >
qtrx - > qt_rtblk_res_used )
dqp - > q_res_rtbcount - = ( xfs_qcnt_t )
( qtrx - > qt_rtblk_res -
qtrx - > qt_rtblk_res_used ) ;
else
dqp - > q_res_rtbcount - = ( xfs_qcnt_t )
( qtrx - > qt_rtblk_res_used -
qtrx - > qt_rtblk_res ) ;
}
} else {
if ( qtrx - > qt_rtbcount_delta )
dqp - > q_res_rtbcount + =
( xfs_qcnt_t ) qtrx - > qt_rtbcount_delta ;
}
/*
* Adjust the inode reservation .
*/
if ( qtrx - > qt_ino_res ! = 0 ) {
ASSERT ( qtrx - > qt_ino_res > =
qtrx - > qt_ino_res_used ) ;
if ( qtrx - > qt_ino_res > qtrx - > qt_ino_res_used )
dqp - > q_res_icount - = ( xfs_qcnt_t )
( qtrx - > qt_ino_res -
qtrx - > qt_ino_res_used ) ;
} else {
if ( qtrx - > qt_icount_delta )
dqp - > q_res_icount + =
( xfs_qcnt_t ) qtrx - > qt_icount_delta ;
}
ASSERT ( dqp - > q_res_bcount > =
2005-11-02 07:01:12 +03:00
be64_to_cpu ( dqp - > q_core . d_bcount ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( dqp - > q_res_icount > =
2005-11-02 07:01:12 +03:00
be64_to_cpu ( dqp - > q_core . d_icount ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( dqp - > q_res_rtbcount > =
2005-11-02 07:01:12 +03:00
be64_to_cpu ( dqp - > q_core . d_rtbcount ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Do the group quotas next
*/
qa = tp - > t_dqinfo - > dqa_grpdquots ;
}
}
/*
* Release the reservations , and adjust the dquots accordingly .
* This is called only when the transaction is being aborted . If by
* any chance we have done dquot modifications incore ( ie . deltas ) already ,
* we simply throw those away , since that ' s the expected behavior
* when a transaction is curtailed without a commit .
*/
2009-06-08 17:33:32 +04:00
void
2005-04-17 02:20:36 +04:00
xfs_trans_unreserve_and_mod_dquots (
xfs_trans_t * tp )
{
int i , j ;
xfs_dquot_t * dqp ;
xfs_dqtrx_t * qtrx , * qa ;
boolean_t locked ;
if ( ! tp - > t_dqinfo | | ! ( tp - > t_flags & XFS_TRANS_DQ_DIRTY ) )
return ;
qa = tp - > t_dqinfo - > dqa_usrdquots ;
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = 0 ; i < XFS_QM_TRANS_MAXDQS ; i + + ) {
qtrx = & qa [ i ] ;
/*
* We assume that the array of dquots is filled
* sequentially , not sparsely .
*/
if ( ( dqp = qtrx - > qt_dquot ) = = NULL )
break ;
/*
* Unreserve the original reservation . We don ' t care
* about the number of blocks used field , or deltas .
* Also we don ' t bother to zero the fields .
*/
locked = B_FALSE ;
if ( qtrx - > qt_blk_res ) {
xfs_dqlock ( dqp ) ;
locked = B_TRUE ;
dqp - > q_res_bcount - =
( xfs_qcnt_t ) qtrx - > qt_blk_res ;
}
if ( qtrx - > qt_ino_res ) {
if ( ! locked ) {
xfs_dqlock ( dqp ) ;
locked = B_TRUE ;
}
dqp - > q_res_icount - =
( xfs_qcnt_t ) qtrx - > qt_ino_res ;
}
if ( qtrx - > qt_rtblk_res ) {
if ( ! locked ) {
xfs_dqlock ( dqp ) ;
locked = B_TRUE ;
}
dqp - > q_res_rtbcount - =
( xfs_qcnt_t ) qtrx - > qt_rtblk_res ;
}
if ( locked )
xfs_dqunlock ( dqp ) ;
}
qa = tp - > t_dqinfo - > dqa_grpdquots ;
}
}
2010-01-18 01:36:19 +03:00
STATIC void
xfs_quota_warn (
struct xfs_mount * mp ,
struct xfs_dquot * dqp ,
int type )
{
/* no warnings for project quotas - we just return ENOSPC later */
if ( dqp - > dq_flags & XFS_DQ_PROJ )
return ;
quota_send_warning ( ( dqp - > dq_flags & XFS_DQ_USER ) ? USRQUOTA : GRPQUOTA ,
be32_to_cpu ( dqp - > q_core . d_id ) , mp - > m_super - > s_dev ,
type ) ;
}
2005-04-17 02:20:36 +04:00
/*
* This reserves disk blocks and inodes against a dquot .
* Flags indicate if the dquot is to be locked here and also
* if the blk reservation is for RT or regular blocks .
* Sending in XFS_QMOPT_FORCE_RES flag skips the quota check .
*/
STATIC int
xfs_trans_dqresv (
xfs_trans_t * tp ,
xfs_mount_t * mp ,
xfs_dquot_t * dqp ,
long nblks ,
long ninos ,
uint flags )
{
xfs_qcnt_t hardlimit ;
xfs_qcnt_t softlimit ;
2005-06-21 09:48:47 +04:00
time_t timer ;
xfs_qwarncnt_t warns ;
xfs_qwarncnt_t warnlimit ;
xfs_qcnt_t count ;
2005-04-17 02:20:36 +04:00
xfs_qcnt_t * resbcountp ;
xfs_quotainfo_t * q = mp - > m_quotainfo ;
2009-02-08 23:51:42 +03:00
xfs_dqlock ( dqp ) ;
2005-04-17 02:20:36 +04:00
if ( flags & XFS_TRANS_DQ_RES_BLKS ) {
2005-11-02 07:01:12 +03:00
hardlimit = be64_to_cpu ( dqp - > q_core . d_blk_hardlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! hardlimit )
hardlimit = q - > qi_bhardlimit ;
2005-11-02 07:01:12 +03:00
softlimit = be64_to_cpu ( dqp - > q_core . d_blk_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! softlimit )
softlimit = q - > qi_bsoftlimit ;
2005-11-02 07:01:12 +03:00
timer = be32_to_cpu ( dqp - > q_core . d_btimer ) ;
warns = be16_to_cpu ( dqp - > q_core . d_bwarns ) ;
2010-04-20 11:01:30 +04:00
warnlimit = dqp - > q_mount - > m_quotainfo - > qi_bwarnlimit ;
2005-04-17 02:20:36 +04:00
resbcountp = & dqp - > q_res_bcount ;
} else {
ASSERT ( flags & XFS_TRANS_DQ_RES_RTBLKS ) ;
2005-11-02 07:01:12 +03:00
hardlimit = be64_to_cpu ( dqp - > q_core . d_rtb_hardlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! hardlimit )
hardlimit = q - > qi_rtbhardlimit ;
2005-11-02 07:01:12 +03:00
softlimit = be64_to_cpu ( dqp - > q_core . d_rtb_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! softlimit )
softlimit = q - > qi_rtbsoftlimit ;
2005-11-02 07:01:12 +03:00
timer = be32_to_cpu ( dqp - > q_core . d_rtbtimer ) ;
warns = be16_to_cpu ( dqp - > q_core . d_rtbwarns ) ;
2010-04-20 11:01:30 +04:00
warnlimit = dqp - > q_mount - > m_quotainfo - > qi_rtbwarnlimit ;
2005-04-17 02:20:36 +04:00
resbcountp = & dqp - > q_res_rtbcount ;
}
if ( ( flags & XFS_QMOPT_FORCE_RES ) = = 0 & &
dqp - > q_core . d_id & &
2007-05-08 07:49:33 +04:00
( ( XFS_IS_UQUOTA_ENFORCED ( dqp - > q_mount ) & & XFS_QM_ISUDQ ( dqp ) ) | |
( XFS_IS_OQUOTA_ENFORCED ( dqp - > q_mount ) & &
( XFS_QM_ISPDQ ( dqp ) | | XFS_QM_ISGDQ ( dqp ) ) ) ) ) {
2005-04-17 02:20:36 +04:00
# ifdef QUOTADEBUG
cmn_err ( CE_DEBUG , " BLK Res: nblks=%ld + resbcount=%Ld "
" > hardlimit=%Ld? " , nblks , * resbcountp , hardlimit ) ;
# endif
if ( nblks > 0 ) {
/*
* dquot is locked already . See if we ' d go over the
* hardlimit or exceed the timelimit if we allocate
* nblks .
*/
if ( hardlimit > 0ULL & &
2010-01-18 01:36:19 +03:00
hardlimit < = nblks + * resbcountp ) {
xfs_quota_warn ( mp , dqp , QUOTA_NL_BHARDWARN ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
2010-01-18 01:36:19 +03:00
}
2005-04-17 02:20:36 +04:00
if ( softlimit > 0ULL & &
2010-01-18 01:36:19 +03:00
softlimit < = nblks + * resbcountp ) {
if ( ( timer ! = 0 & & get_seconds ( ) > timer ) | |
( warns ! = 0 & & warns > = warnlimit ) ) {
xfs_quota_warn ( mp , dqp ,
QUOTA_NL_BSOFTLONGWARN ) ;
goto error_return ;
}
xfs_quota_warn ( mp , dqp , QUOTA_NL_BSOFTWARN ) ;
}
2005-04-17 02:20:36 +04:00
}
if ( ninos > 0 ) {
2005-11-02 07:01:12 +03:00
count = be64_to_cpu ( dqp - > q_core . d_icount ) ;
timer = be32_to_cpu ( dqp - > q_core . d_itimer ) ;
warns = be16_to_cpu ( dqp - > q_core . d_iwarns ) ;
2010-04-20 11:01:30 +04:00
warnlimit = dqp - > q_mount - > m_quotainfo - > qi_iwarnlimit ;
2005-11-02 07:01:12 +03:00
hardlimit = be64_to_cpu ( dqp - > q_core . d_ino_hardlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! hardlimit )
hardlimit = q - > qi_ihardlimit ;
2005-11-02 07:01:12 +03:00
softlimit = be64_to_cpu ( dqp - > q_core . d_ino_softlimit ) ;
2005-04-17 02:20:36 +04:00
if ( ! softlimit )
softlimit = q - > qi_isoftlimit ;
2010-01-14 01:05:49 +03:00
2010-01-18 01:36:19 +03:00
if ( hardlimit > 0ULL & & count > = hardlimit ) {
xfs_quota_warn ( mp , dqp , QUOTA_NL_IHARDWARN ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
2010-01-18 01:36:19 +03:00
}
if ( softlimit > 0ULL & & count > = softlimit ) {
if ( ( timer ! = 0 & & get_seconds ( ) > timer ) | |
( warns ! = 0 & & warns > = warnlimit ) ) {
xfs_quota_warn ( mp , dqp ,
QUOTA_NL_ISOFTLONGWARN ) ;
goto error_return ;
}
xfs_quota_warn ( mp , dqp , QUOTA_NL_ISOFTWARN ) ;
}
2005-04-17 02:20:36 +04:00
}
}
/*
* Change the reservation , but not the actual usage .
* Note that q_res_bcount = q_core . d_bcount + resv
*/
( * resbcountp ) + = ( xfs_qcnt_t ) nblks ;
if ( ninos ! = 0 )
dqp - > q_res_icount + = ( xfs_qcnt_t ) ninos ;
/*
* note the reservation amt in the trans struct too ,
* so that the transaction knows how much was reserved by
* it against this particular dquot .
* We don ' t do this when we are reserving for a delayed allocation ,
* because we don ' t have the luxury of a transaction envelope then .
*/
if ( tp ) {
ASSERT ( tp - > t_dqinfo ) ;
ASSERT ( flags & XFS_QMOPT_RESBLK_MASK ) ;
if ( nblks ! = 0 )
xfs_trans_mod_dquot ( tp , dqp ,
flags & XFS_QMOPT_RESBLK_MASK ,
nblks ) ;
if ( ninos ! = 0 )
xfs_trans_mod_dquot ( tp , dqp ,
XFS_TRANS_DQ_RES_INOS ,
ninos ) ;
}
2005-11-02 07:01:12 +03:00
ASSERT ( dqp - > q_res_bcount > = be64_to_cpu ( dqp - > q_core . d_bcount ) ) ;
ASSERT ( dqp - > q_res_rtbcount > = be64_to_cpu ( dqp - > q_core . d_rtbcount ) ) ;
ASSERT ( dqp - > q_res_icount > = be64_to_cpu ( dqp - > q_core . d_icount ) ) ;
2005-04-17 02:20:36 +04:00
2010-01-14 01:05:49 +03:00
xfs_dqunlock ( dqp ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
error_return :
2009-02-08 23:51:42 +03:00
xfs_dqunlock ( dqp ) ;
2010-01-14 01:05:49 +03:00
if ( flags & XFS_QMOPT_ENOSPC )
return ENOSPC ;
return EDQUOT ;
2005-04-17 02:20:36 +04:00
}
/*
2006-03-31 07:04:49 +04:00
* Given dquot ( s ) , make disk block and / or inode reservations against them .
2005-04-17 02:20:36 +04:00
* The fact that this does the reservation against both the usr and
2006-03-31 07:04:49 +04:00
* grp / prj quotas is important , because this follows a both - or - nothing
2005-04-17 02:20:36 +04:00
* approach .
*
2009-02-08 23:51:42 +03:00
* flags = XFS_QMOPT_FORCE_RES evades limit enforcement . Used by chown .
2006-03-31 07:04:49 +04:00
* XFS_QMOPT_ENOSPC returns ENOSPC not EDQUOT . Used by pquota .
2005-04-17 02:20:36 +04:00
* XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
* XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
* dquots are unlocked on return , if they were not locked by caller .
*/
int
xfs_trans_reserve_quota_bydquots (
xfs_trans_t * tp ,
xfs_mount_t * mp ,
xfs_dquot_t * udqp ,
xfs_dquot_t * gdqp ,
long nblks ,
long ninos ,
uint flags )
{
2006-03-31 07:04:49 +04:00
int resvd = 0 , error ;
2005-04-17 02:20:36 +04:00
2009-06-08 17:33:32 +04:00
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) | | ! XFS_IS_QUOTA_ON ( mp ) )
2006-03-31 07:04:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( tp & & tp - > t_dqinfo = = NULL )
xfs_trans_alloc_dqinfo ( tp ) ;
ASSERT ( flags & XFS_QMOPT_RESBLK_MASK ) ;
if ( udqp ) {
2006-03-31 07:04:49 +04:00
error = xfs_trans_dqresv ( tp , mp , udqp , nblks , ninos ,
( flags & ~ XFS_QMOPT_ENOSPC ) ) ;
if ( error )
return error ;
2005-04-17 02:20:36 +04:00
resvd = 1 ;
}
if ( gdqp ) {
2006-03-31 07:04:49 +04:00
error = xfs_trans_dqresv ( tp , mp , gdqp , nblks , ninos , flags ) ;
if ( error ) {
2005-04-17 02:20:36 +04:00
/*
* can ' t do it , so backout previous reservation
*/
if ( resvd ) {
flags | = XFS_QMOPT_FORCE_RES ;
xfs_trans_dqresv ( tp , mp , udqp ,
- nblks , - ninos , flags ) ;
}
2006-03-31 07:04:49 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
}
/*
2006-03-29 02:55:14 +04:00
* Didn ' t change anything critical , so , no need to log
2005-04-17 02:20:36 +04:00
*/
2006-03-31 07:04:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* Lock the dquot and change the reservation if we can .
* This doesn ' t change the actual usage , just the reservation .
* The inode sent in is locked .
*/
2009-06-08 17:33:32 +04:00
int
2005-04-17 02:20:36 +04:00
xfs_trans_reserve_quota_nblks (
2009-06-08 17:33:32 +04:00
struct xfs_trans * tp ,
struct xfs_inode * ip ,
long nblks ,
long ninos ,
uint flags )
2005-04-17 02:20:36 +04:00
{
2009-06-08 17:33:32 +04:00
struct xfs_mount * mp = ip - > i_mount ;
2005-04-17 02:20:36 +04:00
2009-06-08 17:33:32 +04:00
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) | | ! XFS_IS_QUOTA_ON ( mp ) )
2006-03-31 07:04:49 +04:00
return 0 ;
if ( XFS_IS_PQUOTA_ON ( mp ) )
flags | = XFS_QMOPT_ENOSPC ;
2005-04-17 02:20:36 +04:00
ASSERT ( ip - > i_ino ! = mp - > m_sb . sb_uquotino ) ;
ASSERT ( ip - > i_ino ! = mp - > m_sb . sb_gquotino ) ;
2008-04-22 11:34:00 +04:00
ASSERT ( xfs_isilocked ( ip , XFS_ILOCK_EXCL ) ) ;
2006-03-31 07:04:49 +04:00
ASSERT ( ( flags & ~ ( XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC ) ) = =
XFS_TRANS_DQ_RES_RTBLKS | |
( flags & ~ ( XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC ) ) = =
XFS_TRANS_DQ_RES_BLKS ) ;
2005-04-17 02:20:36 +04:00
/*
* Reserve nblks against these dquots , with trans as the mediator .
*/
2009-06-08 17:33:32 +04:00
return xfs_trans_reserve_quota_bydquots ( tp , mp ,
ip - > i_udquot , ip - > i_gdquot ,
nblks , ninos , flags ) ;
2005-04-17 02:20:36 +04:00
}
/*
* This routine is called to allocate a quotaoff log item .
*/
xfs_qoff_logitem_t *
xfs_trans_get_qoff_item (
xfs_trans_t * tp ,
xfs_qoff_logitem_t * startqoff ,
uint flags )
{
xfs_qoff_logitem_t * q ;
ASSERT ( tp ! = NULL ) ;
q = xfs_qm_qoff_logitem_init ( tp - > t_mountp , startqoff , flags ) ;
ASSERT ( q ! = NULL ) ;
/*
* Get a log_item_desc to point at the new item .
*/
( void ) xfs_trans_add_item ( tp , ( xfs_log_item_t * ) q ) ;
return ( q ) ;
}
/*
* This is called to mark the quotaoff logitem as needing
* to be logged when the transaction is committed . The logitem must
* already be associated with the given transaction .
*/
void
xfs_trans_log_quotaoff_item (
xfs_trans_t * tp ,
xfs_qoff_logitem_t * qlp )
{
xfs_log_item_desc_t * lidp ;
lidp = xfs_trans_find_item ( tp , ( xfs_log_item_t * ) qlp ) ;
ASSERT ( lidp ! = NULL ) ;
tp - > t_flags | = XFS_TRANS_DIRTY ;
lidp - > lid_flags | = XFS_LID_DIRTY ;
}
STATIC void
xfs_trans_alloc_dqinfo (
xfs_trans_t * tp )
{
2009-06-08 17:33:32 +04:00
tp - > t_dqinfo = kmem_zone_zalloc ( xfs_Gqm - > qm_dqtrxzone , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
}
2009-06-08 17:33:32 +04:00
void
2005-04-17 02:20:36 +04:00
xfs_trans_free_dqinfo (
xfs_trans_t * tp )
{
if ( ! tp - > t_dqinfo )
return ;
2009-06-08 17:33:32 +04:00
kmem_zone_free ( xfs_Gqm - > qm_dqtrxzone , tp - > t_dqinfo ) ;
tp - > t_dqinfo = NULL ;
2005-04-17 02:20:36 +04:00
}