2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2009-02-09 10:47:34 +03:00
/*
* Copyright ( c ) 2008 , Christoph Hellwig
* All Rights Reserved .
*/
# include "xfs.h"
2019-06-29 05:25:35 +03:00
# include "xfs_shared.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_icache.h"
2011-08-12 22:57:55 +04:00
# include "xfs_qm.h"
2009-02-09 10:47:34 +03:00
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 ,
2020-05-21 23:07:01 +03:00
xfs_ino_t ino ,
struct xfs_def_quota * defq )
2009-02-09 10:47:34 +03:00
{
2020-05-21 23:07:00 +03:00
bool tempqip = false ;
2014-11-19 14:03:59 +03:00
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 ;
2020-05-18 20:27:22 +03:00
tstate - > nextents = ip - > i_df . if_nextents ;
2020-05-21 23:07:01 +03:00
tstate - > spc_timelimit = ( u32 ) defq - > btimelimit ;
tstate - > ino_timelimit = ( u32 ) defq - > itimelimit ;
tstate - > rt_spc_timelimit = ( u32 ) defq - > rtbtimelimit ;
tstate - > spc_warnlimit = defq - > bwarnlimit ;
tstate - > ino_warnlimit = defq - > iwarnlimit ;
tstate - > rt_spc_warnlimit = defq - > rtbwarnlimit ;
2014-11-19 14:03:59 +03:00
if ( tempqip )
2018-07-25 22:52:32 +03:00
xfs_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 ,
2020-05-21 23:07:01 +03:00
mp - > m_sb . sb_uquotino , & q - > qi_usr_default ) ;
2014-11-19 14:03:59 +03:00
xfs_qm_fill_state ( & state - > s_state [ GRPQUOTA ] , mp , q - > qi_gquotaip ,
2020-05-21 23:07:01 +03:00
mp - > m_sb . sb_gquotino , & q - > qi_grp_default ) ;
2014-11-19 14:03:59 +03:00
xfs_qm_fill_state ( & state - > s_state [ PRJQUOTA ] , mp , q - > qi_pquotaip ,
2020-05-21 23:07:01 +03:00
mp - > m_sb . sb_pquotino , & q - > qi_prj_default ) ;
2014-11-19 14:03:59 +03:00
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 )
{
2020-05-21 23:07:00 +03:00
struct xfs_mount * mp = XFS_M ( sb ) ;
struct qc_dqblk newlim ;
2014-12-16 15:07:45 +03:00
2017-07-17 10:45:34 +03:00
if ( sb_rdonly ( sb ) )
2014-12-16 15:07:45 +03:00
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 ) ;
2017-07-17 10:45:34 +03:00
if ( sb_rdonly ( sb ) )
2014-10-08 17:56:21 +04:00
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 ) ;
2017-07-17 10:45:34 +03:00
if ( sb_rdonly ( sb ) )
2014-10-08 17:56:21 +04:00
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
2017-07-17 10:45:34 +03:00
if ( sb_rdonly ( sb ) )
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
return - EROFS ;
if ( XFS_IS_QUOTA_ON ( mp ) )
return - EINVAL ;
2019-10-24 03:00:45 +03:00
if ( uflags & ~ ( FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA ) )
return - EINVAL ;
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 ( uflags & FS_USER_QUOTA )
2020-07-14 20:36:09 +03:00
flags | = XFS_QMOPT_UQUOTA ;
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 ( uflags & FS_GROUP_QUOTA )
2020-07-14 20:36:09 +03:00
flags | = XFS_QMOPT_GQUOTA ;
2014-07-24 15:27:17 +04:00
if ( uflags & FS_PROJ_QUOTA )
2020-07-14 20:36:09 +03:00
flags | = XFS_QMOPT_PQUOTA ;
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
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 ) ;
2018-05-05 01:30:20 +03:00
return xfs_qm_scall_getquota ( mp , id , xfs_quota_type ( qid . type ) , qdq ) ;
2016-02-08 03:27:38 +03:00
}
/* 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 ) ;
2018-05-05 01:30:20 +03:00
ret = xfs_qm_scall_getquota_next ( mp , & id , xfs_quota_type ( qid - > type ) ,
qdq ) ;
2016-02-08 03:27:38 +03:00
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 ) ;
2017-07-17 10:45:34 +03:00
if ( sb_rdonly ( sb ) )
2009-02-09 10:47:34 +03:00
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
} ;