Skip to content

Commit

Permalink
quota: Fix warning when a delayed write happens before quota is enabled
Browse files Browse the repository at this point in the history
If a delayed-allocation write happens before quota is enabled, the
kernel spits out a warning:
WARNING: at fs/quota/dquot.c:988 dquot_claim_space+0x77/0x112()

because the fact that user has some delayed allocation is not recorded
in quota structure.

Make dquot_initialize() update amount of reserved space for user if it sees
inode has some space reserved. Also make sure that reserved quota space does
not go negative and we warn about the filesystem bug just once.

Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
Jan Kara committed Mar 4, 2010
1 parent c469070 commit 0a5a9c7
Showing 1 changed file with 31 additions and 4 deletions.
35 changes: 31 additions & 4 deletions fs/quota/dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ static struct hlist_head *dquot_hash;
struct dqstats dqstats;
EXPORT_SYMBOL(dqstats);

static qsize_t inode_get_rsv_space(struct inode *inode);

static inline unsigned int
hashfn(const struct super_block *sb, unsigned int id, int type)
{
Expand Down Expand Up @@ -844,11 +846,14 @@ static int dqinit_needed(struct inode *inode, int type)
static void add_dquot_ref(struct super_block *sb, int type)
{
struct inode *inode, *old_inode = NULL;
int reserved = 0;

spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
continue;
if (unlikely(inode_get_rsv_space(inode) > 0))
reserved = 1;
if (!atomic_read(&inode->i_writecount))
continue;
if (!dqinit_needed(inode, type))
Expand All @@ -869,6 +874,12 @@ static void add_dquot_ref(struct super_block *sb, int type)
}
spin_unlock(&inode_lock);
iput(old_inode);

if (reserved) {
printk(KERN_WARNING "VFS (%s): Writes happened before quota"
" was turned on thus quota information is probably "
"inconsistent. Please run quotacheck(8).\n", sb->s_id);
}
}

/*
Expand Down Expand Up @@ -982,18 +993,25 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
/*
* Claim reserved quota space
*/
static void dquot_claim_reserved_space(struct dquot *dquot,
qsize_t number)
static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number)
{
WARN_ON(dquot->dq_dqb.dqb_rsvspace < number);
if (dquot->dq_dqb.dqb_rsvspace < number) {
WARN_ON_ONCE(1);
number = dquot->dq_dqb.dqb_rsvspace;
}
dquot->dq_dqb.dqb_curspace += number;
dquot->dq_dqb.dqb_rsvspace -= number;
}

static inline
void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)
{
dquot->dq_dqb.dqb_rsvspace -= number;
if (dquot->dq_dqb.dqb_rsvspace >= number)
dquot->dq_dqb.dqb_rsvspace -= number;
else {
WARN_ON_ONCE(1);
dquot->dq_dqb.dqb_rsvspace = 0;
}
}

static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
Expand Down Expand Up @@ -1246,6 +1264,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
return QUOTA_NL_BHARDBELOW;
return QUOTA_NL_NOWARN;
}

/*
* Initialize quota pointers in inode
* We do things in a bit complicated way but by that we avoid calling
Expand All @@ -1257,6 +1276,7 @@ int dquot_initialize(struct inode *inode, int type)
int cnt, ret = 0;
struct dquot *got[MAXQUOTAS] = { NULL, NULL };
struct super_block *sb = inode->i_sb;
qsize_t rsv;

/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
Expand Down Expand Up @@ -1290,6 +1310,13 @@ int dquot_initialize(struct inode *inode, int type)
if (!inode->i_dquot[cnt]) {
inode->i_dquot[cnt] = got[cnt];
got[cnt] = NULL;
/*
* Make quota reservation system happy if someone
* did a write before quota was turned on
*/
rsv = inode_get_rsv_space(inode);
if (unlikely(rsv))
dquot_resv_space(inode->i_dquot[cnt], rsv);
}
}
out_err:
Expand Down

0 comments on commit 0a5a9c7

Please sign in to comment.