aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2010-02-09 12:20:39 -0500
committerJan Kara <jack@suse.cz>2010-03-04 18:20:21 -0500
commit0a5a9c725512461d19397490f3adf29931dca1f2 (patch)
tree8df303b6fe335d825cedbfa8cde5bd76c7f53742
parentc469070aea5a0ada45a836937c776fd3083dae2b (diff)
quota: Fix warning when a delayed write happens before quota is enabled
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>
-rw-r--r--fs/quota/dquot.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index f11255b18b58..6c849de5dc8f 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -229,6 +229,8 @@ static struct hlist_head *dquot_hash;
229struct dqstats dqstats; 229struct dqstats dqstats;
230EXPORT_SYMBOL(dqstats); 230EXPORT_SYMBOL(dqstats);
231 231
232static qsize_t inode_get_rsv_space(struct inode *inode);
233
232static inline unsigned int 234static inline unsigned int
233hashfn(const struct super_block *sb, unsigned int id, int type) 235hashfn(const struct super_block *sb, unsigned int id, int type)
234{ 236{
@@ -844,11 +846,14 @@ static int dqinit_needed(struct inode *inode, int type)
844static void add_dquot_ref(struct super_block *sb, int type) 846static void add_dquot_ref(struct super_block *sb, int type)
845{ 847{
846 struct inode *inode, *old_inode = NULL; 848 struct inode *inode, *old_inode = NULL;
849 int reserved = 0;
847 850
848 spin_lock(&inode_lock); 851 spin_lock(&inode_lock);
849 list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { 852 list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
850 if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) 853 if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
851 continue; 854 continue;
855 if (unlikely(inode_get_rsv_space(inode) > 0))
856 reserved = 1;
852 if (!atomic_read(&inode->i_writecount)) 857 if (!atomic_read(&inode->i_writecount))
853 continue; 858 continue;
854 if (!dqinit_needed(inode, type)) 859 if (!dqinit_needed(inode, type))
@@ -869,6 +874,12 @@ static void add_dquot_ref(struct super_block *sb, int type)
869 } 874 }
870 spin_unlock(&inode_lock); 875 spin_unlock(&inode_lock);
871 iput(old_inode); 876 iput(old_inode);
877
878 if (reserved) {
879 printk(KERN_WARNING "VFS (%s): Writes happened before quota"
880 " was turned on thus quota information is probably "
881 "inconsistent. Please run quotacheck(8).\n", sb->s_id);
882 }
872} 883}
873 884
874/* 885/*
@@ -982,10 +993,12 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
982/* 993/*
983 * Claim reserved quota space 994 * Claim reserved quota space
984 */ 995 */
985static void dquot_claim_reserved_space(struct dquot *dquot, 996static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number)
986 qsize_t number)
987{ 997{
988 WARN_ON(dquot->dq_dqb.dqb_rsvspace < number); 998 if (dquot->dq_dqb.dqb_rsvspace < number) {
999 WARN_ON_ONCE(1);
1000 number = dquot->dq_dqb.dqb_rsvspace;
1001 }
989 dquot->dq_dqb.dqb_curspace += number; 1002 dquot->dq_dqb.dqb_curspace += number;
990 dquot->dq_dqb.dqb_rsvspace -= number; 1003 dquot->dq_dqb.dqb_rsvspace -= number;
991} 1004}
@@ -993,7 +1006,12 @@ static void dquot_claim_reserved_space(struct dquot *dquot,
993static inline 1006static inline
994void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) 1007void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)
995{ 1008{
996 dquot->dq_dqb.dqb_rsvspace -= number; 1009 if (dquot->dq_dqb.dqb_rsvspace >= number)
1010 dquot->dq_dqb.dqb_rsvspace -= number;
1011 else {
1012 WARN_ON_ONCE(1);
1013 dquot->dq_dqb.dqb_rsvspace = 0;
1014 }
997} 1015}
998 1016
999static void dquot_decr_inodes(struct dquot *dquot, qsize_t number) 1017static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
@@ -1246,6 +1264,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
1246 return QUOTA_NL_BHARDBELOW; 1264 return QUOTA_NL_BHARDBELOW;
1247 return QUOTA_NL_NOWARN; 1265 return QUOTA_NL_NOWARN;
1248} 1266}
1267
1249/* 1268/*
1250 * Initialize quota pointers in inode 1269 * Initialize quota pointers in inode
1251 * We do things in a bit complicated way but by that we avoid calling 1270 * We do things in a bit complicated way but by that we avoid calling
@@ -1257,6 +1276,7 @@ int dquot_initialize(struct inode *inode, int type)
1257 int cnt, ret = 0; 1276 int cnt, ret = 0;
1258 struct dquot *got[MAXQUOTAS] = { NULL, NULL }; 1277 struct dquot *got[MAXQUOTAS] = { NULL, NULL };
1259 struct super_block *sb = inode->i_sb; 1278 struct super_block *sb = inode->i_sb;
1279 qsize_t rsv;
1260 1280
1261 /* First test before acquiring mutex - solves deadlocks when we 1281 /* First test before acquiring mutex - solves deadlocks when we
1262 * re-enter the quota code and are already holding the mutex */ 1282 * re-enter the quota code and are already holding the mutex */
@@ -1290,6 +1310,13 @@ int dquot_initialize(struct inode *inode, int type)
1290 if (!inode->i_dquot[cnt]) { 1310 if (!inode->i_dquot[cnt]) {
1291 inode->i_dquot[cnt] = got[cnt]; 1311 inode->i_dquot[cnt] = got[cnt];
1292 got[cnt] = NULL; 1312 got[cnt] = NULL;
1313 /*
1314 * Make quota reservation system happy if someone
1315 * did a write before quota was turned on
1316 */
1317 rsv = inode_get_rsv_space(inode);
1318 if (unlikely(rsv))
1319 dquot_resv_space(inode->i_dquot[cnt], rsv);
1293 } 1320 }
1294 } 1321 }
1295out_err: 1322out_err: