diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/quota/dquot.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 7b980954993b..6e722c11ce13 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -225,6 +225,8 @@ static struct hlist_head *dquot_hash; | |||
225 | struct dqstats dqstats; | 225 | struct dqstats dqstats; |
226 | EXPORT_SYMBOL(dqstats); | 226 | EXPORT_SYMBOL(dqstats); |
227 | 227 | ||
228 | static qsize_t inode_get_rsv_space(struct inode *inode); | ||
229 | |||
228 | static inline unsigned int | 230 | static inline unsigned int |
229 | hashfn(const struct super_block *sb, unsigned int id, int type) | 231 | hashfn(const struct super_block *sb, unsigned int id, int type) |
230 | { | 232 | { |
@@ -840,11 +842,14 @@ static int dqinit_needed(struct inode *inode, int type) | |||
840 | static void add_dquot_ref(struct super_block *sb, int type) | 842 | static void add_dquot_ref(struct super_block *sb, int type) |
841 | { | 843 | { |
842 | struct inode *inode, *old_inode = NULL; | 844 | struct inode *inode, *old_inode = NULL; |
845 | int reserved = 0; | ||
843 | 846 | ||
844 | spin_lock(&inode_lock); | 847 | spin_lock(&inode_lock); |
845 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 848 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
846 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 849 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) |
847 | continue; | 850 | continue; |
851 | if (unlikely(inode_get_rsv_space(inode) > 0)) | ||
852 | reserved = 1; | ||
848 | if (!atomic_read(&inode->i_writecount)) | 853 | if (!atomic_read(&inode->i_writecount)) |
849 | continue; | 854 | continue; |
850 | if (!dqinit_needed(inode, type)) | 855 | if (!dqinit_needed(inode, type)) |
@@ -865,6 +870,12 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
865 | } | 870 | } |
866 | spin_unlock(&inode_lock); | 871 | spin_unlock(&inode_lock); |
867 | iput(old_inode); | 872 | iput(old_inode); |
873 | |||
874 | if (reserved) { | ||
875 | printk(KERN_WARNING "VFS (%s): Writes happened before quota" | ||
876 | " was turned on thus quota information is probably " | ||
877 | "inconsistent. Please run quotacheck(8).\n", sb->s_id); | ||
878 | } | ||
868 | } | 879 | } |
869 | 880 | ||
870 | /* | 881 | /* |
@@ -978,10 +989,12 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number) | |||
978 | /* | 989 | /* |
979 | * Claim reserved quota space | 990 | * Claim reserved quota space |
980 | */ | 991 | */ |
981 | static void dquot_claim_reserved_space(struct dquot *dquot, | 992 | static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number) |
982 | qsize_t number) | ||
983 | { | 993 | { |
984 | WARN_ON(dquot->dq_dqb.dqb_rsvspace < number); | 994 | if (dquot->dq_dqb.dqb_rsvspace < number) { |
995 | WARN_ON_ONCE(1); | ||
996 | number = dquot->dq_dqb.dqb_rsvspace; | ||
997 | } | ||
985 | dquot->dq_dqb.dqb_curspace += number; | 998 | dquot->dq_dqb.dqb_curspace += number; |
986 | dquot->dq_dqb.dqb_rsvspace -= number; | 999 | dquot->dq_dqb.dqb_rsvspace -= number; |
987 | } | 1000 | } |
@@ -989,7 +1002,12 @@ static void dquot_claim_reserved_space(struct dquot *dquot, | |||
989 | static inline | 1002 | static inline |
990 | void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) | 1003 | void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) |
991 | { | 1004 | { |
992 | dquot->dq_dqb.dqb_rsvspace -= number; | 1005 | if (dquot->dq_dqb.dqb_rsvspace >= number) |
1006 | dquot->dq_dqb.dqb_rsvspace -= number; | ||
1007 | else { | ||
1008 | WARN_ON_ONCE(1); | ||
1009 | dquot->dq_dqb.dqb_rsvspace = 0; | ||
1010 | } | ||
993 | } | 1011 | } |
994 | 1012 | ||
995 | static void dquot_decr_inodes(struct dquot *dquot, qsize_t number) | 1013 | static void dquot_decr_inodes(struct dquot *dquot, qsize_t number) |
@@ -1242,6 +1260,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space) | |||
1242 | return QUOTA_NL_BHARDBELOW; | 1260 | return QUOTA_NL_BHARDBELOW; |
1243 | return QUOTA_NL_NOWARN; | 1261 | return QUOTA_NL_NOWARN; |
1244 | } | 1262 | } |
1263 | |||
1245 | /* | 1264 | /* |
1246 | * Initialize quota pointers in inode | 1265 | * Initialize quota pointers in inode |
1247 | * We do things in a bit complicated way but by that we avoid calling | 1266 | * We do things in a bit complicated way but by that we avoid calling |
@@ -1253,6 +1272,7 @@ int dquot_initialize(struct inode *inode, int type) | |||
1253 | int cnt, ret = 0; | 1272 | int cnt, ret = 0; |
1254 | struct dquot *got[MAXQUOTAS] = { NULL, NULL }; | 1273 | struct dquot *got[MAXQUOTAS] = { NULL, NULL }; |
1255 | struct super_block *sb = inode->i_sb; | 1274 | struct super_block *sb = inode->i_sb; |
1275 | qsize_t rsv; | ||
1256 | 1276 | ||
1257 | /* First test before acquiring mutex - solves deadlocks when we | 1277 | /* First test before acquiring mutex - solves deadlocks when we |
1258 | * re-enter the quota code and are already holding the mutex */ | 1278 | * re-enter the quota code and are already holding the mutex */ |
@@ -1287,6 +1307,13 @@ int dquot_initialize(struct inode *inode, int type) | |||
1287 | if (!inode->i_dquot[cnt]) { | 1307 | if (!inode->i_dquot[cnt]) { |
1288 | inode->i_dquot[cnt] = got[cnt]; | 1308 | inode->i_dquot[cnt] = got[cnt]; |
1289 | got[cnt] = NULL; | 1309 | got[cnt] = NULL; |
1310 | /* | ||
1311 | * Make quota reservation system happy if someone | ||
1312 | * did a write before quota was turned on | ||
1313 | */ | ||
1314 | rsv = inode_get_rsv_space(inode); | ||
1315 | if (unlikely(rsv)) | ||
1316 | dquot_resv_space(inode->i_dquot[cnt], rsv); | ||
1290 | } | 1317 | } |
1291 | } | 1318 | } |
1292 | out_err: | 1319 | out_err: |