2009-02-09 10:47:34 +03:00
/*
* Copyright ( c ) 2008 , Christoph Hellwig
* All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation .
*
* 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 .
*
* 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
*/
# include "xfs.h"
2013-08-12 14:49:26 +04:00
# include "xfs_format.h"
2013-10-23 03:50:10 +04:00
# include "xfs_log_format.h"
2013-08-12 14:49:32 +04:00
# include "xfs_trans_resv.h"
2009-02-09 10:47:34 +03:00
# include "xfs_mount.h"
2013-10-23 03:51:50 +04:00
# include "xfs_inode.h"
2009-02-09 10:47:34 +03:00
# include "xfs_quota.h"
# include "xfs_trans.h"
2014-11-19 14:03:59 +03:00
# include "xfs_trace.h"
# include "xfs_icache.h"
2011-08-12 22:57:55 +04:00
# include "xfs_qm.h"
2009-02-09 10:47:34 +03:00
# include <linux/quota.h>
2014-11-19 14:03:59 +03:00
static void
xfs_qm_fill_state (
struct qc_type_state * tstate ,
struct xfs_mount * mp ,
struct xfs_inode * ip ,
xfs_ino_t ino )
2009-02-09 10:47:34 +03:00
{
2014-11-19 14:03:59 +03:00
struct xfs_quotainfo * q = mp - > m_quotainfo ;
bool tempqip = false ;
tstate - > ino = ino ;
if ( ! ip & & ino = = NULLFSINO )
return ;
if ( ! ip ) {
if ( xfs_iget ( mp , NULL , ino , 0 , 0 , & ip ) )
return ;
tempqip = true ;
2009-02-09 10:47:34 +03:00
}
2014-11-19 14:03:59 +03:00
tstate - > flags | = QCI_SYSFILE ;
tstate - > blocks = ip - > i_d . di_nblocks ;
tstate - > nextents = ip - > i_d . di_nextents ;
tstate - > spc_timelimit = q - > qi_btimelimit ;
tstate - > ino_timelimit = q - > qi_itimelimit ;
tstate - > rt_spc_timelimit = q - > qi_rtbtimelimit ;
tstate - > spc_warnlimit = q - > qi_bwarnlimit ;
tstate - > ino_warnlimit = q - > qi_iwarnlimit ;
tstate - > rt_spc_warnlimit = q - > qi_rtbwarnlimit ;
if ( tempqip )
IRELE ( ip ) ;
2009-02-09 10:47:34 +03:00
}
2014-11-19 14:03:59 +03:00
/*
* Return quota status information , such as enforcements , quota file inode
* numbers etc .
*/
static int
xfs_fs_get_quota_state (
2009-02-09 10:47:34 +03:00
struct super_block * sb ,
2014-11-19 14:03:59 +03:00
struct qc_state * state )
2009-02-09 10:47:34 +03:00
{
2014-11-19 14:03:59 +03:00
struct xfs_mount * mp = XFS_M ( sb ) ;
struct xfs_quotainfo * q = mp - > m_quotainfo ;
2009-02-09 10:47:34 +03:00
2014-11-19 14:03:59 +03:00
memset ( state , 0 , sizeof ( * state ) ) ;
2009-02-09 10:47:34 +03:00
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
2014-11-19 14:03:59 +03:00
return 0 ;
state - > s_incoredqs = q - > qi_dquots ;
if ( XFS_IS_UQUOTA_RUNNING ( mp ) )
state - > s_state [ USRQUOTA ] . flags | = QCI_ACCT_ENABLED ;
if ( XFS_IS_UQUOTA_ENFORCED ( mp ) )
state - > s_state [ USRQUOTA ] . flags | = QCI_LIMITS_ENFORCED ;
if ( XFS_IS_GQUOTA_RUNNING ( mp ) )
state - > s_state [ GRPQUOTA ] . flags | = QCI_ACCT_ENABLED ;
if ( XFS_IS_GQUOTA_ENFORCED ( mp ) )
state - > s_state [ GRPQUOTA ] . flags | = QCI_LIMITS_ENFORCED ;
if ( XFS_IS_PQUOTA_RUNNING ( mp ) )
state - > s_state [ PRJQUOTA ] . flags | = QCI_ACCT_ENABLED ;
if ( XFS_IS_PQUOTA_ENFORCED ( mp ) )
state - > s_state [ PRJQUOTA ] . flags | = QCI_LIMITS_ENFORCED ;
xfs_qm_fill_state ( & state - > s_state [ USRQUOTA ] , mp , q - > qi_uquotaip ,
mp - > m_sb . sb_uquotino ) ;
xfs_qm_fill_state ( & state - > s_state [ GRPQUOTA ] , mp , q - > qi_gquotaip ,
mp - > m_sb . sb_gquotino ) ;
xfs_qm_fill_state ( & state - > s_state [ PRJQUOTA ] , mp , q - > qi_pquotaip ,
mp - > m_sb . sb_pquotino ) ;
return 0 ;
2009-02-09 10:47:34 +03:00
}
2013-08-07 02:27:08 +04:00
STATIC int
2014-11-19 14:03:59 +03:00
xfs_quota_type ( int type )
2013-08-07 02:27:08 +04:00
{
2014-11-19 14:03:59 +03:00
switch ( type ) {
case USRQUOTA :
return XFS_DQ_USER ;
case GRPQUOTA :
return XFS_DQ_GROUP ;
default :
return XFS_DQ_PROJ ;
}
2013-08-07 02:27:08 +04:00
}
2014-12-16 15:07:45 +03:00
# define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK)
/*
* Adjust quota timers & warnings
*/
static int
xfs_fs_set_info (
struct super_block * sb ,
int type ,
struct qc_info * info )
{
struct xfs_mount * mp = XFS_M ( sb ) ;
struct qc_dqblk newlim ;
if ( sb - > s_flags & MS_RDONLY )
return - EROFS ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
if ( ! XFS_IS_QUOTA_ON ( mp ) )
return - ESRCH ;
if ( info - > i_fieldmask & ~ XFS_QC_SETINFO_MASK )
return - EINVAL ;
if ( ( info - > i_fieldmask & XFS_QC_SETINFO_MASK ) = = 0 )
return 0 ;
newlim . d_fieldmask = info - > i_fieldmask ;
newlim . d_spc_timer = info - > i_spc_timelimit ;
newlim . d_ino_timer = info - > i_ino_timelimit ;
newlim . d_rt_spc_timer = info - > i_rt_spc_timelimit ;
newlim . d_ino_warns = info - > i_ino_warnlimit ;
newlim . d_spc_warns = info - > i_spc_warnlimit ;
newlim . d_rt_spc_warns = info - > i_rt_spc_warnlimit ;
return xfs_qm_scall_setqlim ( mp , 0 , xfs_quota_type ( type ) , & newlim ) ;
}
2014-10-08 17:56:21 +04:00
static unsigned int
xfs_quota_flags ( unsigned int uflags )
2009-02-09 10:47:34 +03:00
{
2014-10-08 17:56:21 +04:00
unsigned int flags = 0 ;
2009-02-09 10:47:34 +03:00
2010-06-04 12:56:01 +04:00
if ( uflags & FS_QUOTA_UDQ_ACCT )
2009-02-09 10:47:34 +03:00
flags | = XFS_UQUOTA_ACCT ;
2010-06-04 12:56:01 +04:00
if ( uflags & FS_QUOTA_PDQ_ACCT )
2009-02-09 10:47:34 +03:00
flags | = XFS_PQUOTA_ACCT ;
2010-06-04 12:56:01 +04:00
if ( uflags & FS_QUOTA_GDQ_ACCT )
2009-02-09 10:47:34 +03:00
flags | = XFS_GQUOTA_ACCT ;
2010-06-04 12:56:01 +04:00
if ( uflags & FS_QUOTA_UDQ_ENFD )
2009-02-09 10:47:34 +03:00
flags | = XFS_UQUOTA_ENFD ;
2013-06-28 02:25:10 +04:00
if ( uflags & FS_QUOTA_GDQ_ENFD )
flags | = XFS_GQUOTA_ENFD ;
if ( uflags & FS_QUOTA_PDQ_ENFD )
flags | = XFS_PQUOTA_ENFD ;
2009-02-09 10:47:34 +03:00
2014-10-08 17:56:21 +04:00
return flags ;
}
STATIC int
xfs_quota_enable (
struct super_block * sb ,
unsigned int uflags )
{
struct xfs_mount * mp = XFS_M ( sb ) ;
if ( sb - > s_flags & MS_RDONLY )
return - EROFS ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
return xfs_qm_scall_quotaon ( mp , xfs_quota_flags ( uflags ) ) ;
}
STATIC int
xfs_quota_disable (
struct super_block * sb ,
unsigned int uflags )
{
struct xfs_mount * mp = XFS_M ( sb ) ;
if ( sb - > s_flags & MS_RDONLY )
return - EROFS ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
if ( ! XFS_IS_QUOTA_ON ( mp ) )
return - EINVAL ;
2009-02-09 10:47:34 +03:00
2014-10-08 17:56:21 +04:00
return xfs_qm_scall_quotaoff ( mp , xfs_quota_flags ( uflags ) ) ;
2009-02-09 10:47:34 +03:00
}
xfs: fix Q_XQUOTARM ioctl
The Q_XQUOTARM quotactl was not working properly, because
we weren't passing around proper flags. The xfs_fs_set_xstate()
ioctl handler used the same flags for Q_XQUOTAON/OFF as
well as for Q_XQUOTARM, but Q_XQUOTAON/OFF look for
XFS_UQUOTA_ACCT, XFS_UQUOTA_ENFD, XFS_GQUOTA_ACCT etc,
i.e. quota type + state, while Q_XQUOTARM looks only for
the type of quota, i.e. XFS_DQ_USER, XFS_DQ_GROUP etc.
Unfortunately these flag spaces overlap a bit, so we
got semi-random results for Q_XQUOTARM; i.e. the value
for XFS_DQ_USER == XFS_UQUOTA_ACCT, etc. yeargh.
Add a new quotactl op vector specifically for the QUOTARM
operation, since it operates with a different flag space.
This has been broken more or less forever, AFAICT.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-05-05 11:25:50 +04:00
STATIC int
xfs_fs_rm_xquota (
struct super_block * sb ,
unsigned int uflags )
{
struct xfs_mount * mp = XFS_M ( sb ) ;
unsigned int flags = 0 ;
2014-06-25 08:58:08 +04:00
xfs: fix Q_XQUOTARM ioctl
The Q_XQUOTARM quotactl was not working properly, because
we weren't passing around proper flags. The xfs_fs_set_xstate()
ioctl handler used the same flags for Q_XQUOTAON/OFF as
well as for Q_XQUOTARM, but Q_XQUOTAON/OFF look for
XFS_UQUOTA_ACCT, XFS_UQUOTA_ENFD, XFS_GQUOTA_ACCT etc,
i.e. quota type + state, while Q_XQUOTARM looks only for
the type of quota, i.e. XFS_DQ_USER, XFS_DQ_GROUP etc.
Unfortunately these flag spaces overlap a bit, so we
got semi-random results for Q_XQUOTARM; i.e. the value
for XFS_DQ_USER == XFS_UQUOTA_ACCT, etc. yeargh.
Add a new quotactl op vector specifically for the QUOTARM
operation, since it operates with a different flag space.
This has been broken more or less forever, AFAICT.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-05-05 11:25:50 +04:00
if ( sb - > s_flags & MS_RDONLY )
return - EROFS ;
if ( XFS_IS_QUOTA_ON ( mp ) )
return - EINVAL ;
if ( uflags & FS_USER_QUOTA )
flags | = XFS_DQ_USER ;
if ( uflags & FS_GROUP_QUOTA )
flags | = XFS_DQ_GROUP ;
2014-07-24 15:27:17 +04:00
if ( uflags & FS_PROJ_QUOTA )
xfs: fix Q_XQUOTARM ioctl
The Q_XQUOTARM quotactl was not working properly, because
we weren't passing around proper flags. The xfs_fs_set_xstate()
ioctl handler used the same flags for Q_XQUOTAON/OFF as
well as for Q_XQUOTARM, but Q_XQUOTAON/OFF look for
XFS_UQUOTA_ACCT, XFS_UQUOTA_ENFD, XFS_GQUOTA_ACCT etc,
i.e. quota type + state, while Q_XQUOTARM looks only for
the type of quota, i.e. XFS_DQ_USER, XFS_DQ_GROUP etc.
Unfortunately these flag spaces overlap a bit, so we
got semi-random results for Q_XQUOTARM; i.e. the value
for XFS_DQ_USER == XFS_UQUOTA_ACCT, etc. yeargh.
Add a new quotactl op vector specifically for the QUOTARM
operation, since it operates with a different flag space.
This has been broken more or less forever, AFAICT.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-05-05 11:25:50 +04:00
flags | = XFS_DQ_PROJ ;
2014-06-25 08:58:08 +04:00
return xfs_qm_scall_trunc_qfiles ( mp , flags ) ;
}
xfs: fix Q_XQUOTARM ioctl
The Q_XQUOTARM quotactl was not working properly, because
we weren't passing around proper flags. The xfs_fs_set_xstate()
ioctl handler used the same flags for Q_XQUOTAON/OFF as
well as for Q_XQUOTARM, but Q_XQUOTAON/OFF look for
XFS_UQUOTA_ACCT, XFS_UQUOTA_ENFD, XFS_GQUOTA_ACCT etc,
i.e. quota type + state, while Q_XQUOTARM looks only for
the type of quota, i.e. XFS_DQ_USER, XFS_DQ_GROUP etc.
Unfortunately these flag spaces overlap a bit, so we
got semi-random results for Q_XQUOTARM; i.e. the value
for XFS_DQ_USER == XFS_UQUOTA_ACCT, etc. yeargh.
Add a new quotactl op vector specifically for the QUOTARM
operation, since it operates with a different flag space.
This has been broken more or less forever, AFAICT.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-05-05 11:25:50 +04:00
2009-02-09 10:47:34 +03:00
STATIC int
2010-05-07 01:04:58 +04:00
xfs_fs_get_dqblk (
2009-02-09 10:47:34 +03:00
struct super_block * sb ,
2012-09-16 13:07:49 +04:00
struct kqid qid ,
2014-10-09 18:03:13 +04:00
struct qc_dqblk * qdq )
2009-02-09 10:47:34 +03:00
{
struct xfs_mount * mp = XFS_M ( sb ) ;
2016-02-08 03:27:38 +03:00
xfs_dqid_t id ;
2009-02-09 10:47:34 +03:00
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
if ( ! XFS_IS_QUOTA_ON ( mp ) )
return - ESRCH ;
2016-02-08 03:27:38 +03:00
id = from_kqid ( & init_user_ns , qid ) ;
return xfs_qm_scall_getquota ( mp , & id ,
xfs_quota_type ( qid . type ) , qdq , 0 ) ;
}
/* Return quota info for active quota >= this qid */
STATIC int
xfs_fs_get_nextdqblk (
struct super_block * sb ,
struct kqid * qid ,
struct qc_dqblk * qdq )
{
int ret ;
struct xfs_mount * mp = XFS_M ( sb ) ;
xfs_dqid_t id ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
if ( ! XFS_IS_QUOTA_ON ( mp ) )
return - ESRCH ;
id = from_kqid ( & init_user_ns , * qid ) ;
ret = xfs_qm_scall_getquota ( mp , & id ,
xfs_quota_type ( qid - > type ) , qdq ,
XFS_QMOPT_DQNEXT ) ;
if ( ret )
return ret ;
/* ID may be different, so convert back what we got */
* qid = make_kqid ( current_user_ns ( ) , qid - > type , id ) ;
return 0 ;
2009-02-09 10:47:34 +03:00
}
STATIC int
2010-05-07 01:05:17 +04:00
xfs_fs_set_dqblk (
2009-02-09 10:47:34 +03:00
struct super_block * sb ,
2012-09-16 13:07:49 +04:00
struct kqid qid ,
2014-10-09 18:03:13 +04:00
struct qc_dqblk * qdq )
2009-02-09 10:47:34 +03:00
{
struct xfs_mount * mp = XFS_M ( sb ) ;
if ( sb - > s_flags & MS_RDONLY )
return - EROFS ;
if ( ! XFS_IS_QUOTA_RUNNING ( mp ) )
return - ENOSYS ;
if ( ! XFS_IS_QUOTA_ON ( mp ) )
return - ESRCH ;
2014-06-25 08:58:08 +04:00
return xfs_qm_scall_setqlim ( mp , from_kqid ( & init_user_ns , qid ) ,
2014-10-09 18:03:13 +04:00
xfs_quota_type ( qid . type ) , qdq ) ;
2009-02-09 10:47:34 +03:00
}
2009-09-22 04:01:09 +04:00
const struct quotactl_ops xfs_quotactl_operations = {
2014-11-19 14:03:59 +03:00
. get_state = xfs_fs_get_quota_state ,
2014-12-16 15:07:45 +03:00
. set_info = xfs_fs_set_info ,
2014-10-08 17:56:21 +04:00
. quota_enable = xfs_quota_enable ,
. quota_disable = xfs_quota_disable ,
xfs: fix Q_XQUOTARM ioctl
The Q_XQUOTARM quotactl was not working properly, because
we weren't passing around proper flags. The xfs_fs_set_xstate()
ioctl handler used the same flags for Q_XQUOTAON/OFF as
well as for Q_XQUOTARM, but Q_XQUOTAON/OFF look for
XFS_UQUOTA_ACCT, XFS_UQUOTA_ENFD, XFS_GQUOTA_ACCT etc,
i.e. quota type + state, while Q_XQUOTARM looks only for
the type of quota, i.e. XFS_DQ_USER, XFS_DQ_GROUP etc.
Unfortunately these flag spaces overlap a bit, so we
got semi-random results for Q_XQUOTARM; i.e. the value
for XFS_DQ_USER == XFS_UQUOTA_ACCT, etc. yeargh.
Add a new quotactl op vector specifically for the QUOTARM
operation, since it operates with a different flag space.
This has been broken more or less forever, AFAICT.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-05-05 11:25:50 +04:00
. rm_xquota = xfs_fs_rm_xquota ,
2010-05-07 01:04:58 +04:00
. get_dqblk = xfs_fs_get_dqblk ,
2016-02-08 03:27:38 +03:00
. get_nextdqblk = xfs_fs_get_nextdqblk ,
2010-05-07 01:05:17 +04:00
. set_dqblk = xfs_fs_set_dqblk ,
2009-02-09 10:47:34 +03:00
} ;