Commit b8cb5a54 authored by Tahsin Erdogan's avatar Tahsin Erdogan Committed by Theodore Ts'o

ext4: fix quota charging for shared xattr blocks

ext4_xattr_block_set() calls dquot_alloc_block() to charge for an xattr
block when new references are made. However if dquot_initialize() hasn't
been called on an inode, request for charging is effectively ignored
because ext4_inode_info->i_dquot is not initialized yet.

Add dquot_initialize() to call paths that lead to ext4_xattr_block_set().
Signed-off-by: default avatarTahsin Erdogan <tahsin@google.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
parent c41d342b
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
*/ */
#include <linux/quotaops.h>
#include "ext4_jbd2.h" #include "ext4_jbd2.h"
#include "ext4.h" #include "ext4.h"
#include "xattr.h" #include "xattr.h"
...@@ -232,6 +233,9 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -232,6 +233,9 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
handle_t *handle; handle_t *handle;
int error, retries = 0; int error, retries = 0;
error = dquot_initialize(inode);
if (error)
return error;
retry: retry:
handle = ext4_journal_start(inode, EXT4_HT_XATTR, handle = ext4_journal_start(inode, EXT4_HT_XATTR,
ext4_jbd2_credits_xattr(inode)); ext4_jbd2_credits_xattr(inode));
......
...@@ -1174,6 +1174,9 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len, ...@@ -1174,6 +1174,9 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
return res; return res;
} }
res = dquot_initialize(inode);
if (res)
return res;
retry: retry:
handle = ext4_journal_start(inode, EXT4_HT_MISC, handle = ext4_journal_start(inode, EXT4_HT_MISC,
ext4_jbd2_credits_xattr(inode)); ext4_jbd2_credits_xattr(inode));
......
...@@ -888,6 +888,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -888,6 +888,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
else { else {
u32 ref; u32 ref;
WARN_ON_ONCE(dquot_initialize_needed(inode));
/* The old block is released after updating /* The old block is released after updating
the inode. */ the inode. */
error = dquot_alloc_block(inode, error = dquot_alloc_block(inode,
...@@ -954,6 +956,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -954,6 +956,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
/* We need to allocate a new block */ /* We need to allocate a new block */
ext4_fsblk_t goal, block; ext4_fsblk_t goal, block;
WARN_ON_ONCE(dquot_initialize_needed(inode));
goal = ext4_group_first_block_no(sb, goal = ext4_group_first_block_no(sb,
EXT4_I(inode)->i_block_group); EXT4_I(inode)->i_block_group);
...@@ -1166,6 +1170,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, ...@@ -1166,6 +1170,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
return -EINVAL; return -EINVAL;
if (strlen(name) > 255) if (strlen(name) > 255)
return -ERANGE; return -ERANGE;
ext4_write_lock_xattr(inode, &no_expand); ext4_write_lock_xattr(inode, &no_expand);
error = ext4_reserve_inode_write(handle, inode, &is.iloc); error = ext4_reserve_inode_write(handle, inode, &is.iloc);
...@@ -1267,6 +1272,9 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, ...@@ -1267,6 +1272,9 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,
int error, retries = 0; int error, retries = 0;
int credits = ext4_jbd2_credits_xattr(inode); int credits = ext4_jbd2_credits_xattr(inode);
error = dquot_initialize(inode);
if (error)
return error;
retry: retry:
handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits);
if (IS_ERR(handle)) { if (IS_ERR(handle)) {
......
...@@ -1512,6 +1512,22 @@ int dquot_initialize(struct inode *inode) ...@@ -1512,6 +1512,22 @@ int dquot_initialize(struct inode *inode)
} }
EXPORT_SYMBOL(dquot_initialize); EXPORT_SYMBOL(dquot_initialize);
bool dquot_initialize_needed(struct inode *inode)
{
struct dquot **dquots;
int i;
if (!dquot_active(inode))
return false;
dquots = i_dquot(inode);
for (i = 0; i < MAXQUOTAS; i++)
if (!dquots[i] && sb_has_quota_active(inode->i_sb, i))
return true;
return false;
}
EXPORT_SYMBOL(dquot_initialize_needed);
/* /*
* Release all quotas referenced by inode. * Release all quotas referenced by inode.
* *
......
...@@ -44,6 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number); ...@@ -44,6 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
void inode_reclaim_rsv_space(struct inode *inode, qsize_t number); void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);
int dquot_initialize(struct inode *inode); int dquot_initialize(struct inode *inode);
bool dquot_initialize_needed(struct inode *inode);
void dquot_drop(struct inode *inode); void dquot_drop(struct inode *inode);
struct dquot *dqget(struct super_block *sb, struct kqid qid); struct dquot *dqget(struct super_block *sb, struct kqid qid);
static inline struct dquot *dqgrab(struct dquot *dquot) static inline struct dquot *dqgrab(struct dquot *dquot)
...@@ -207,6 +208,11 @@ static inline int dquot_initialize(struct inode *inode) ...@@ -207,6 +208,11 @@ static inline int dquot_initialize(struct inode *inode)
return 0; return 0;
} }
static inline bool dquot_initialize_needed(struct inode *inode)
{
return false;
}
static inline void dquot_drop(struct inode *inode) static inline void dquot_drop(struct inode *inode)
{ {
} }
......
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