aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/dquot.c117
-rw-r--r--include/linux/quota.h3
-rw-r--r--include/linux/quotaops.h21
3 files changed, 110 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 }
diff --git a/include/linux/quota.h b/include/linux/quota.h
index d72d5d84fde5..54b837fa64f2 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -198,6 +198,7 @@ struct mem_dqblk {
198 qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ 198 qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
199 qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */ 199 qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
200 qsize_t dqb_curspace; /* current used space */ 200 qsize_t dqb_curspace; /* current used space */
201 qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
201 qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */ 202 qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
202 qsize_t dqb_isoftlimit; /* preferred inode limit */ 203 qsize_t dqb_isoftlimit; /* preferred inode limit */
203 qsize_t dqb_curinodes; /* current # allocated inodes */ 204 qsize_t dqb_curinodes; /* current # allocated inodes */
@@ -308,6 +309,8 @@ struct dquot_operations {
308 int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ 309 int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
309 int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ 310 int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
310 int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */ 311 int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
312 /* reserve quota for delayed block allocation */
313 int (*reserve_space) (struct inode *, qsize_t, int);
311}; 314};
312 315
313/* Operations handling requests from userspace */ 316/* Operations handling requests from userspace */
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 0b35b3a1be05..3e3a0d2874d9 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -183,6 +183,16 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr)
183 return ret; 183 return ret;
184} 184}
185 185
186static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
187{
188 if (sb_any_quota_active(inode->i_sb)) {
189 /* Used space is updated in alloc_space() */
190 if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
191 return 1;
192 }
193 return 0;
194}
195
186static inline int vfs_dq_alloc_inode(struct inode *inode) 196static inline int vfs_dq_alloc_inode(struct inode *inode)
187{ 197{
188 if (sb_any_quota_active(inode->i_sb)) { 198 if (sb_any_quota_active(inode->i_sb)) {
@@ -339,6 +349,11 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr)
339 return 0; 349 return 0;
340} 350}
341 351
352static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
353{
354 return 0;
355}
356
342static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) 357static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
343{ 358{
344 inode_sub_bytes(inode, nr); 359 inode_sub_bytes(inode, nr);
@@ -376,6 +391,12 @@ static inline int vfs_dq_alloc_block(struct inode *inode, qsize_t nr)
376 nr << inode->i_sb->s_blocksize_bits); 391 nr << inode->i_sb->s_blocksize_bits);
377} 392}
378 393
394static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
395{
396 return vfs_dq_reserve_space(inode,
397 nr << inode->i_blkbits);
398}
399
379static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr) 400static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
380{ 401{
381 vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits); 402 vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);