Commit f55abc0f authored by Jan Kara's avatar Jan Kara Committed by Mark Fasheh

quota: Allow to separately enable quota accounting and enforcing limits

Split DQUOT_USR_ENABLED (and DQUOT_GRP_ENABLED) into DQUOT_USR_USAGE_ENABLED
and DQUOT_USR_LIMITS_ENABLED. This way we are able to separately enable /
disable whether we should:
1) ignore quotas completely
2) just keep uptodate information about usage
3) actually enforce quota limits

This is going to be useful when quota is treated as filesystem metadata - we
then want to keep quota information uptodate all the time and just enable /
disable limits enforcement.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.com>
parent e4bc7b4b
This diff is collapsed.
...@@ -73,7 +73,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid ...@@ -73,7 +73,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid
case Q_SETQUOTA: case Q_SETQUOTA:
case Q_GETQUOTA: case Q_GETQUOTA:
/* This is just informative test so we are satisfied without a lock */ /* This is just informative test so we are satisfied without a lock */
if (!sb_has_quota_enabled(sb, type)) if (!sb_has_quota_active(sb, type))
return -ESRCH; return -ESRCH;
} }
...@@ -175,7 +175,7 @@ static void quota_sync_sb(struct super_block *sb, int type) ...@@ -175,7 +175,7 @@ static void quota_sync_sb(struct super_block *sb, int type)
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type) if (type != -1 && cnt != type)
continue; continue;
if (!sb_has_quota_enabled(sb, cnt)) if (!sb_has_quota_active(sb, cnt))
continue; continue;
mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA); mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA);
truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0);
...@@ -201,7 +201,7 @@ void sync_dquots(struct super_block *sb, int type) ...@@ -201,7 +201,7 @@ void sync_dquots(struct super_block *sb, int type)
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && type != cnt) if (type != -1 && type != cnt)
continue; continue;
if (!sb_has_quota_enabled(sb, cnt)) if (!sb_has_quota_active(sb, cnt))
continue; continue;
if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && if (!info_dirty(&sb_dqopt(sb)->info[cnt]) &&
list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list))
...@@ -245,7 +245,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void ...@@ -245,7 +245,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void
__u32 fmt; __u32 fmt;
down_read(&sb_dqopt(sb)->dqptr_sem); down_read(&sb_dqopt(sb)->dqptr_sem);
if (!sb_has_quota_enabled(sb, type)) { if (!sb_has_quota_active(sb, type)) {
up_read(&sb_dqopt(sb)->dqptr_sem); up_read(&sb_dqopt(sb)->dqptr_sem);
return -ESRCH; return -ESRCH;
} }
......
...@@ -318,12 +318,34 @@ struct quota_format_type { ...@@ -318,12 +318,34 @@ struct quota_format_type {
struct quota_format_type *qf_next; struct quota_format_type *qf_next;
}; };
#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ /* Quota state flags - they actually come in two flavors - for users and groups */
#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ enum {
#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but _DQUOT_USAGE_ENABLED = 0, /* Track disk usage for users */
_DQUOT_LIMITS_ENABLED, /* Enforce quota limits for users */
_DQUOT_SUSPENDED, /* User diskquotas are off, but
* we have necessary info in * we have necessary info in
* memory to turn them on */ * memory to turn them on */
#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */ _DQUOT_STATE_FLAGS
};
#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED)
#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED)
#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED)
#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \
DQUOT_SUSPENDED)
static inline unsigned int dquot_state_flag(unsigned int flags, int type)
{
if (type == USRQUOTA)
return flags;
return flags << _DQUOT_STATE_FLAGS;
}
static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
{
if (type == USRQUOTA)
return flags;
return flags >> _DQUOT_STATE_FLAGS;
}
struct quota_info { struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */ unsigned int flags; /* Flags for diskquotas on this device */
......
...@@ -40,11 +40,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot); ...@@ -40,11 +40,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
int vfs_quota_on(struct super_block *sb, int type, int format_id, int vfs_quota_on(struct super_block *sb, int type, int format_id,
char *path, int remount); char *path, int remount);
int vfs_quota_enable(struct inode *inode, int type, int format_id,
unsigned int flags);
int vfs_quota_on_path(struct super_block *sb, int type, int format_id, int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
struct path *path); struct path *path);
int vfs_quota_on_mount(struct super_block *sb, char *qf_name, int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
int format_id, int type); int format_id, int type);
int vfs_quota_off(struct super_block *sb, int type, int remount); int vfs_quota_off(struct super_block *sb, int type, int remount);
int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags);
int vfs_quota_sync(struct super_block *sb, int type); int vfs_quota_sync(struct super_block *sb, int type);
int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
...@@ -64,26 +67,22 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) ...@@ -64,26 +67,22 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
* Functions for checking status of quota * Functions for checking status of quota
*/ */
static inline int sb_has_quota_enabled(struct super_block *sb, int type) static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type)
{ {
if (type == USRQUOTA) return sb_dqopt(sb)->flags &
return (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) dquot_state_flag(DQUOT_USAGE_ENABLED, type);
&& !(sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED);
return (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED)
&& !(sb_dqopt(sb)->flags & DQUOT_GROUP_SUSPENDED);
} }
static inline int sb_any_quota_enabled(struct super_block *sb) static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type)
{ {
return sb_has_quota_enabled(sb, USRQUOTA) || return sb_dqopt(sb)->flags &
sb_has_quota_enabled(sb, GRPQUOTA); dquot_state_flag(DQUOT_LIMITS_ENABLED, type);
} }
static inline int sb_has_quota_suspended(struct super_block *sb, int type) static inline int sb_has_quota_suspended(struct super_block *sb, int type)
{ {
if (type == USRQUOTA) return sb_dqopt(sb)->flags &
return sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED; dquot_state_flag(DQUOT_SUSPENDED, type);
return sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED;
} }
static inline int sb_any_quota_suspended(struct super_block *sb) static inline int sb_any_quota_suspended(struct super_block *sb)
...@@ -92,6 +91,34 @@ static inline int sb_any_quota_suspended(struct super_block *sb) ...@@ -92,6 +91,34 @@ static inline int sb_any_quota_suspended(struct super_block *sb)
sb_has_quota_suspended(sb, GRPQUOTA); sb_has_quota_suspended(sb, GRPQUOTA);
} }
/* Does kernel know about any quota information for given sb + type? */
static inline int sb_has_quota_loaded(struct super_block *sb, int type)
{
/* Currently if anything is on, then quota usage is on as well */
return sb_has_quota_usage_enabled(sb, type);
}
static inline int sb_any_quota_loaded(struct super_block *sb)
{
return sb_has_quota_loaded(sb, USRQUOTA) ||
sb_has_quota_loaded(sb, GRPQUOTA);
}
static inline int sb_has_quota_active(struct super_block *sb, int type)
{
return sb_has_quota_loaded(sb, type) &&
!sb_has_quota_suspended(sb, type);
}
static inline int sb_any_quota_active(struct super_block *sb)
{
return sb_has_quota_active(sb, USRQUOTA) ||
sb_has_quota_active(sb, GRPQUOTA);
}
/* For backward compatibility until we remove all users */
#define sb_any_quota_enabled(sb) sb_any_quota_active(sb)
/* /*
* Operations supported for diskquotas. * Operations supported for diskquotas.
*/ */
...@@ -106,7 +133,7 @@ extern struct quotactl_ops vfs_quotactl_ops; ...@@ -106,7 +133,7 @@ extern struct quotactl_ops vfs_quotactl_ops;
static inline void vfs_dq_init(struct inode *inode) static inline void vfs_dq_init(struct inode *inode)
{ {
BUG_ON(!inode->i_sb); BUG_ON(!inode->i_sb);
if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode))
inode->i_sb->dq_op->initialize(inode, -1); inode->i_sb->dq_op->initialize(inode, -1);
} }
...@@ -114,7 +141,7 @@ static inline void vfs_dq_init(struct inode *inode) ...@@ -114,7 +141,7 @@ static inline void vfs_dq_init(struct inode *inode)
* a transaction (deadlocks possible otherwise) */ * a transaction (deadlocks possible otherwise) */
static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr) static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr)
{ {
if (sb_any_quota_enabled(inode->i_sb)) { if (sb_any_quota_active(inode->i_sb)) {
/* Used space is updated in alloc_space() */ /* Used space is updated in alloc_space() */
if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA)
return 1; return 1;
...@@ -134,7 +161,7 @@ static inline int vfs_dq_prealloc_space(struct inode *inode, qsize_t nr) ...@@ -134,7 +161,7 @@ static inline int vfs_dq_prealloc_space(struct inode *inode, qsize_t nr)
static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr) static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr)
{ {
if (sb_any_quota_enabled(inode->i_sb)) { if (sb_any_quota_active(inode->i_sb)) {
/* Used space is updated in alloc_space() */ /* Used space is updated in alloc_space() */
if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA)
return 1; return 1;
...@@ -154,7 +181,7 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr) ...@@ -154,7 +181,7 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr)
static inline int vfs_dq_alloc_inode(struct inode *inode) static inline int vfs_dq_alloc_inode(struct inode *inode)
{ {
if (sb_any_quota_enabled(inode->i_sb)) { if (sb_any_quota_active(inode->i_sb)) {
vfs_dq_init(inode); vfs_dq_init(inode);
if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA)
return 1; return 1;
...@@ -164,7 +191,7 @@ static inline int vfs_dq_alloc_inode(struct inode *inode) ...@@ -164,7 +191,7 @@ static inline int vfs_dq_alloc_inode(struct inode *inode)
static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
{ {
if (sb_any_quota_enabled(inode->i_sb)) if (sb_any_quota_active(inode->i_sb))
inode->i_sb->dq_op->free_space(inode, nr); inode->i_sb->dq_op->free_space(inode, nr);
else else
inode_sub_bytes(inode, nr); inode_sub_bytes(inode, nr);
...@@ -178,7 +205,7 @@ static inline void vfs_dq_free_space(struct inode *inode, qsize_t nr) ...@@ -178,7 +205,7 @@ static inline void vfs_dq_free_space(struct inode *inode, qsize_t nr)
static inline void vfs_dq_free_inode(struct inode *inode) static inline void vfs_dq_free_inode(struct inode *inode)
{ {
if (sb_any_quota_enabled(inode->i_sb)) if (sb_any_quota_active(inode->i_sb))
inode->i_sb->dq_op->free_inode(inode, 1); inode->i_sb->dq_op->free_inode(inode, 1);
} }
...@@ -199,12 +226,12 @@ static inline int vfs_dq_off(struct super_block *sb, int remount) ...@@ -199,12 +226,12 @@ static inline int vfs_dq_off(struct super_block *sb, int remount)
#else #else
static inline int sb_has_quota_enabled(struct super_block *sb, int type) static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type)
{ {
return 0; return 0;
} }
static inline int sb_any_quota_enabled(struct super_block *sb) static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type)
{ {
return 0; return 0;
} }
...@@ -219,6 +246,30 @@ static inline int sb_any_quota_suspended(struct super_block *sb) ...@@ -219,6 +246,30 @@ static inline int sb_any_quota_suspended(struct super_block *sb)
return 0; return 0;
} }
/* Does kernel know about any quota information for given sb + type? */
static inline int sb_has_quota_loaded(struct super_block *sb, int type)
{
return 0;
}
static inline int sb_any_quota_loaded(struct super_block *sb)
{
return 0;
}
static inline int sb_has_quota_active(struct super_block *sb, int type)
{
return 0;
}
static inline int sb_any_quota_active(struct super_block *sb)
{
return 0;
}
/* For backward compatibility until we remove all users */
#define sb_any_quota_enabled(sb) sb_any_quota_active(sb)
/* /*
* NO-OP when quota not configured. * NO-OP when quota not configured.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment