aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dquot.c
diff options
context:
space:
mode:
authorMingming Cao <cmm@us.ibm.com>2009-01-13 10:43:09 -0500
committerJan Kara <jack@suse.cz>2009-03-25 21:15:50 -0400
commitf18df228997fb716990590d248663981a15f17d4 (patch)
treef5fc935b09cddde325235c265fd3a553ee40af51 /fs/dquot.c
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
quota: Add quota reservation support
Delayed allocation defers the block allocation at the dirty pages flush-out time, doing quota charge/check at that time is too late. But we can't charge the quota blocks until blocks are really allocated, otherwise users could get overcharged after reboot from system crash. This patch adds quota reservation for delayed allocation. Quota blocks are reserved in memory, inode and quota won't gets dirtied until later block allocation time. Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/dquot.c')
-rw-r--r--fs/dquot.c117
1 files changed, 86 insertions, 31 deletions
diff --git a/fs/dquot.c b/fs/dquot.c
index bca3cac4bee7..9b1c4d3c9d83 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -899,6 +899,11 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
899 dquot->dq_dqb.dqb_curspace += number; 899 dquot->dq_dqb.dqb_curspace += number;
900} 900}
901 901
902static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
903{
904 dquot->dq_dqb.dqb_rsvspace += number;
905}
906
902static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) 907static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
903{ 908{
904 if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || 909 if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
@@ -1068,7 +1073,11 @@ err_out:
1068 kfree_skb(skb); 1073 kfree_skb(skb);
1069} 1074}
1070#endif 1075#endif
1071 1076/*
1077 * Write warnings to the console and send warning messages over netlink.
1078 *
1079 * Note that this function can sleep.
1080 */
1072static inline void flush_warnings(struct dquot * const *dquots, char *warntype) 1081static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
1073{ 1082{
1074 int i; 1083 int i;
@@ -1129,13 +1138,18 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
1129/* needs dq_data_lock */ 1138/* needs dq_data_lock */
1130static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) 1139static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
1131{ 1140{
1141 qsize_t tspace;
1142
1132 *warntype = QUOTA_NL_NOWARN; 1143 *warntype = QUOTA_NL_NOWARN;
1133 if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || 1144 if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
1134 test_bit(DQ_FAKE_B, &dquot->dq_flags)) 1145 test_bit(DQ_FAKE_B, &dquot->dq_flags))
1135 return QUOTA_OK; 1146 return QUOTA_OK;
1136 1147
1148 tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
1149 + space;
1150
1137 if (dquot->dq_dqb.dqb_bhardlimit && 1151 if (dquot->dq_dqb.dqb_bhardlimit &&
1138 dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit && 1152 tspace > dquot->dq_dqb.dqb_bhardlimit &&
1139 !ignore_hardlimit(dquot)) { 1153 !ignore_hardlimit(dquot)) {
1140 if (!prealloc) 1154 if (!prealloc)
1141 *warntype = QUOTA_NL_BHARDWARN; 1155 *warntype = QUOTA_NL_BHARDWARN;
@@ -1143,7 +1157,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
1143 } 1157 }
1144 1158
1145 if (dquot->dq_dqb.dqb_bsoftlimit && 1159 if (dquot->dq_dqb.dqb_bsoftlimit &&
1146 dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && 1160 tspace > dquot->dq_dqb.dqb_bsoftlimit &&
1147 dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime && 1161 dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
1148 !ignore_hardlimit(dquot)) { 1162 !ignore_hardlimit(dquot)) {
1149 if (!prealloc) 1163 if (!prealloc)
@@ -1152,7 +1166,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
1152 } 1166 }
1153 1167
1154 if (dquot->dq_dqb.dqb_bsoftlimit && 1168 if (dquot->dq_dqb.dqb_bsoftlimit &&
1155 dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && 1169 tspace > dquot->dq_dqb.dqb_bsoftlimit &&
1156 dquot->dq_dqb.dqb_btime == 0) { 1170 dquot->dq_dqb.dqb_btime == 0) {
1157 if (!prealloc) { 1171 if (!prealloc) {
1158 *warntype = QUOTA_NL_BSOFTWARN; 1172 *warntype = QUOTA_NL_BSOFTWARN;
@@ -1306,51 +1320,92 @@ void vfs_dq_drop(struct inode *inode)
1306/* 1320/*
1307 * This operation can block, but only after everything is updated 1321 * This operation can block, but only after everything is updated
1308 */ 1322 */
1309int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) 1323int __dquot_alloc_space(struct inode *inode, qsize_t number,
1324 int warn, int reserve)
1310{ 1325{
1311 int cnt, ret = NO_QUOTA; 1326 int cnt, ret = QUOTA_OK;
1312 char warntype[MAXQUOTAS]; 1327 char warntype[MAXQUOTAS];
1313 1328
1314 /* First test before acquiring mutex - solves deadlocks when we
1315 * re-enter the quota code and are already holding the mutex */
1316 if (IS_NOQUOTA(inode)) {
1317out_add:
1318 inode_add_bytes(inode, number);
1319 return QUOTA_OK;
1320 }
1321 for (cnt = 0; cnt < MAXQUOTAS; cnt++) 1329 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1322 warntype[cnt] = QUOTA_NL_NOWARN; 1330 warntype[cnt] = QUOTA_NL_NOWARN;
1323 1331
1324 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1325 if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
1326 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1327 goto out_add;
1328 }
1329 spin_lock(&dq_data_lock); 1332 spin_lock(&dq_data_lock);
1330 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 1333 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1331 if (inode->i_dquot[cnt] == NODQUOT) 1334 if (inode->i_dquot[cnt] == NODQUOT)
1332 continue; 1335 continue;
1333 if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA) 1336 if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
1334 goto warn_put_all; 1337 == NO_QUOTA) {
1338 ret = NO_QUOTA;
1339 goto out_unlock;
1340 }
1335 } 1341 }
1336 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 1342 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1337 if (inode->i_dquot[cnt] == NODQUOT) 1343 if (inode->i_dquot[cnt] == NODQUOT)
1338 continue; 1344 continue;
1339 dquot_incr_space(inode->i_dquot[cnt], number); 1345 if (reserve)
1346 dquot_resv_space(inode->i_dquot[cnt], number);
1347 else
1348 dquot_incr_space(inode->i_dquot[cnt], number);
1340 } 1349 }
1341 inode_add_bytes(inode, number); 1350 if (!reserve)
1342 ret = QUOTA_OK; 1351 inode_add_bytes(inode, number);
1343warn_put_all: 1352out_unlock:
1344 spin_unlock(&dq_data_lock); 1353 spin_unlock(&dq_data_lock);
1345 if (ret == QUOTA_OK)
1346 /* Dirtify all the dquots - this can block when journalling */
1347 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1348 if (inode->i_dquot[cnt])
1349 mark_dquot_dirty(inode->i_dquot[cnt]);
1350 flush_warnings(inode->i_dquot, warntype); 1354 flush_warnings(inode->i_dquot, warntype);
1355 return ret;
1356}
1357
1358int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
1359{
1360 int cnt, ret = QUOTA_OK;
1361
1362 /*
1363 * First test before acquiring mutex - solves deadlocks when we
1364 * re-enter the quota code and are already holding the mutex
1365 */
1366 if (IS_NOQUOTA(inode)) {
1367 inode_add_bytes(inode, number);
1368 goto out;
1369 }
1370
1371 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1372 if (IS_NOQUOTA(inode)) {
1373 inode_add_bytes(inode, number);
1374 goto out_unlock;
1375 }
1376
1377 ret = __dquot_alloc_space(inode, number, warn, 0);
1378 if (ret == NO_QUOTA)
1379 goto out_unlock;
1380
1381 /* Dirtify all the dquots - this can block when journalling */
1382 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1383 if (inode->i_dquot[cnt])
1384 mark_dquot_dirty(inode->i_dquot[cnt]);
1385out_unlock:
1351 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 1386 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1387out:
1388 return ret;
1389}
1390
1391int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
1392{
1393 int ret = QUOTA_OK;
1394
1395 if (IS_NOQUOTA(inode))
1396 goto out;
1397
1398 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1399 if (IS_NOQUOTA(inode))
1400 goto out_unlock;
1401
1402 ret = __dquot_alloc_space(inode, number, warn, 1);
1403out_unlock:
1404 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1405out:
1352 return ret; 1406 return ret;
1353} 1407}
1408EXPORT_SYMBOL(dquot_reserve_space);
1354 1409
1355/* 1410/*
1356 * This operation can block, but only after everything is updated 1411 * This operation can block, but only after everything is updated
@@ -2057,7 +2112,7 @@ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
2057 spin_lock(&dq_data_lock); 2112 spin_lock(&dq_data_lock);
2058 di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit); 2113 di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
2059 di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit); 2114 di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
2060 di->dqb_curspace = dm->dqb_curspace; 2115 di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
2061 di->dqb_ihardlimit = dm->dqb_ihardlimit; 2116 di->dqb_ihardlimit = dm->dqb_ihardlimit;
2062 di->dqb_isoftlimit = dm->dqb_isoftlimit; 2117 di->dqb_isoftlimit = dm->dqb_isoftlimit;
2063 di->dqb_curinodes = dm->dqb_curinodes; 2118 di->dqb_curinodes = dm->dqb_curinodes;
@@ -2097,7 +2152,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
2097 2152
2098 spin_lock(&dq_data_lock); 2153 spin_lock(&dq_data_lock);
2099 if (di->dqb_valid & QIF_SPACE) { 2154 if (di->dqb_valid & QIF_SPACE) {
2100 dm->dqb_curspace = di->dqb_curspace; 2155 dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
2101 check_blim = 1; 2156 check_blim = 1;
2102 __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); 2157 __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
2103 } 2158 }