diff options
author | Mingming Cao <cmm@us.ibm.com> | 2009-01-13 10:43:14 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2009-03-25 21:18:24 -0400 |
commit | 740d9dcd949a986c88886a591054a0cdb89ef669 (patch) | |
tree | 3a422d30c838c80d35b8d52a05a4c55d3c806e4e | |
parent | f18df228997fb716990590d248663981a15f17d4 (diff) |
quota: Add quota reservation claim and released operations
Reserved quota will be claimed at the block allocation time. Over-booked
quota could be returned back with the release callback function.
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r-- | fs/dquot.c | 110 | ||||
-rw-r--r-- | include/linux/quota.h | 6 | ||||
-rw-r--r-- | include/linux/quotaops.h | 53 |
3 files changed, 165 insertions, 4 deletions
diff --git a/fs/dquot.c b/fs/dquot.c index 9b1c4d3c9d83..2916f91ca40c 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -904,6 +904,23 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number) | |||
904 | dquot->dq_dqb.dqb_rsvspace += number; | 904 | dquot->dq_dqb.dqb_rsvspace += number; |
905 | } | 905 | } |
906 | 906 | ||
907 | /* | ||
908 | * Claim reserved quota space | ||
909 | */ | ||
910 | static void dquot_claim_reserved_space(struct dquot *dquot, | ||
911 | qsize_t number) | ||
912 | { | ||
913 | WARN_ON(dquot->dq_dqb.dqb_rsvspace < number); | ||
914 | dquot->dq_dqb.dqb_curspace += number; | ||
915 | dquot->dq_dqb.dqb_rsvspace -= number; | ||
916 | } | ||
917 | |||
918 | static inline | ||
919 | void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) | ||
920 | { | ||
921 | dquot->dq_dqb.dqb_rsvspace -= number; | ||
922 | } | ||
923 | |||
907 | static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) | 924 | static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) |
908 | { | 925 | { |
909 | if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || | 926 | if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || |
@@ -1452,6 +1469,72 @@ warn_put_all: | |||
1452 | return ret; | 1469 | return ret; |
1453 | } | 1470 | } |
1454 | 1471 | ||
1472 | int dquot_claim_space(struct inode *inode, qsize_t number) | ||
1473 | { | ||
1474 | int cnt; | ||
1475 | int ret = QUOTA_OK; | ||
1476 | |||
1477 | if (IS_NOQUOTA(inode)) { | ||
1478 | inode_add_bytes(inode, number); | ||
1479 | goto out; | ||
1480 | } | ||
1481 | |||
1482 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | ||
1483 | if (IS_NOQUOTA(inode)) { | ||
1484 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | ||
1485 | inode_add_bytes(inode, number); | ||
1486 | goto out; | ||
1487 | } | ||
1488 | |||
1489 | spin_lock(&dq_data_lock); | ||
1490 | /* Claim reserved quotas to allocated quotas */ | ||
1491 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
1492 | if (inode->i_dquot[cnt] != NODQUOT) | ||
1493 | dquot_claim_reserved_space(inode->i_dquot[cnt], | ||
1494 | number); | ||
1495 | } | ||
1496 | /* Update inode bytes */ | ||
1497 | inode_add_bytes(inode, number); | ||
1498 | spin_unlock(&dq_data_lock); | ||
1499 | /* Dirtify all the dquots - this can block when journalling */ | ||
1500 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | ||
1501 | if (inode->i_dquot[cnt]) | ||
1502 | mark_dquot_dirty(inode->i_dquot[cnt]); | ||
1503 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | ||
1504 | out: | ||
1505 | return ret; | ||
1506 | } | ||
1507 | EXPORT_SYMBOL(dquot_claim_space); | ||
1508 | |||
1509 | /* | ||
1510 | * Release reserved quota space | ||
1511 | */ | ||
1512 | void dquot_release_reserved_space(struct inode *inode, qsize_t number) | ||
1513 | { | ||
1514 | int cnt; | ||
1515 | |||
1516 | if (IS_NOQUOTA(inode)) | ||
1517 | goto out; | ||
1518 | |||
1519 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | ||
1520 | if (IS_NOQUOTA(inode)) | ||
1521 | goto out_unlock; | ||
1522 | |||
1523 | spin_lock(&dq_data_lock); | ||
1524 | /* Release reserved dquots */ | ||
1525 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
1526 | if (inode->i_dquot[cnt] != NODQUOT) | ||
1527 | dquot_free_reserved_space(inode->i_dquot[cnt], number); | ||
1528 | } | ||
1529 | spin_unlock(&dq_data_lock); | ||
1530 | |||
1531 | out_unlock: | ||
1532 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | ||
1533 | out: | ||
1534 | return; | ||
1535 | } | ||
1536 | EXPORT_SYMBOL(dquot_release_reserved_space); | ||
1537 | |||
1455 | /* | 1538 | /* |
1456 | * This operation can block, but only after everything is updated | 1539 | * This operation can block, but only after everything is updated |
1457 | */ | 1540 | */ |
@@ -1529,6 +1612,19 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) | |||
1529 | } | 1612 | } |
1530 | 1613 | ||
1531 | /* | 1614 | /* |
1615 | * call back function, get reserved quota space from underlying fs | ||
1616 | */ | ||
1617 | qsize_t dquot_get_reserved_space(struct inode *inode) | ||
1618 | { | ||
1619 | qsize_t reserved_space = 0; | ||
1620 | |||
1621 | if (sb_any_quota_active(inode->i_sb) && | ||
1622 | inode->i_sb->dq_op->get_reserved_space) | ||
1623 | reserved_space = inode->i_sb->dq_op->get_reserved_space(inode); | ||
1624 | return reserved_space; | ||
1625 | } | ||
1626 | |||
1627 | /* | ||
1532 | * Transfer the number of inode and blocks from one diskquota to an other. | 1628 | * Transfer the number of inode and blocks from one diskquota to an other. |
1533 | * | 1629 | * |
1534 | * This operation can block, but only after everything is updated | 1630 | * This operation can block, but only after everything is updated |
@@ -1536,7 +1632,8 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) | |||
1536 | */ | 1632 | */ |
1537 | int dquot_transfer(struct inode *inode, struct iattr *iattr) | 1633 | int dquot_transfer(struct inode *inode, struct iattr *iattr) |
1538 | { | 1634 | { |
1539 | qsize_t space; | 1635 | qsize_t space, cur_space; |
1636 | qsize_t rsv_space = 0; | ||
1540 | struct dquot *transfer_from[MAXQUOTAS]; | 1637 | struct dquot *transfer_from[MAXQUOTAS]; |
1541 | struct dquot *transfer_to[MAXQUOTAS]; | 1638 | struct dquot *transfer_to[MAXQUOTAS]; |
1542 | int cnt, ret = QUOTA_OK; | 1639 | int cnt, ret = QUOTA_OK; |
@@ -1575,7 +1672,9 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
1575 | goto put_all; | 1672 | goto put_all; |
1576 | } | 1673 | } |
1577 | spin_lock(&dq_data_lock); | 1674 | spin_lock(&dq_data_lock); |
1578 | space = inode_get_bytes(inode); | 1675 | cur_space = inode_get_bytes(inode); |
1676 | rsv_space = dquot_get_reserved_space(inode); | ||
1677 | space = cur_space + rsv_space; | ||
1579 | /* Build the transfer_from list and check the limits */ | 1678 | /* Build the transfer_from list and check the limits */ |
1580 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1679 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
1581 | if (transfer_to[cnt] == NODQUOT) | 1680 | if (transfer_to[cnt] == NODQUOT) |
@@ -1604,11 +1703,14 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
1604 | warntype_from_space[cnt] = | 1703 | warntype_from_space[cnt] = |
1605 | info_bdq_free(transfer_from[cnt], space); | 1704 | info_bdq_free(transfer_from[cnt], space); |
1606 | dquot_decr_inodes(transfer_from[cnt], 1); | 1705 | dquot_decr_inodes(transfer_from[cnt], 1); |
1607 | dquot_decr_space(transfer_from[cnt], space); | 1706 | dquot_decr_space(transfer_from[cnt], cur_space); |
1707 | dquot_free_reserved_space(transfer_from[cnt], | ||
1708 | rsv_space); | ||
1608 | } | 1709 | } |
1609 | 1710 | ||
1610 | dquot_incr_inodes(transfer_to[cnt], 1); | 1711 | dquot_incr_inodes(transfer_to[cnt], 1); |
1611 | dquot_incr_space(transfer_to[cnt], space); | 1712 | dquot_incr_space(transfer_to[cnt], cur_space); |
1713 | dquot_resv_space(transfer_to[cnt], rsv_space); | ||
1612 | 1714 | ||
1613 | inode->i_dquot[cnt] = transfer_to[cnt]; | 1715 | inode->i_dquot[cnt] = transfer_to[cnt]; |
1614 | } | 1716 | } |
diff --git a/include/linux/quota.h b/include/linux/quota.h index 54b837fa64f2..a510d91561f4 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
@@ -311,6 +311,12 @@ struct dquot_operations { | |||
311 | 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 */ | 312 | /* reserve quota for delayed block allocation */ |
313 | int (*reserve_space) (struct inode *, qsize_t, int); | 313 | int (*reserve_space) (struct inode *, qsize_t, int); |
314 | /* claim reserved quota for delayed alloc */ | ||
315 | int (*claim_space) (struct inode *, qsize_t); | ||
316 | /* release rsved quota for delayed alloc */ | ||
317 | void (*release_rsv) (struct inode *, qsize_t); | ||
318 | /* get reserved quota for delayed alloc */ | ||
319 | qsize_t (*get_reserved_space) (struct inode *); | ||
314 | }; | 320 | }; |
315 | 321 | ||
316 | /* Operations handling requests from userspace */ | 322 | /* Operations handling requests from userspace */ |
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 3e3a0d2874d9..7369d04e0a86 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
@@ -35,6 +35,11 @@ void dquot_destroy(struct dquot *dquot); | |||
35 | int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); | 35 | int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); |
36 | int dquot_alloc_inode(const struct inode *inode, qsize_t number); | 36 | int dquot_alloc_inode(const struct inode *inode, qsize_t number); |
37 | 37 | ||
38 | int dquot_reserve_space(struct inode *inode, qsize_t number, int prealloc); | ||
39 | int dquot_claim_space(struct inode *inode, qsize_t number); | ||
40 | void dquot_release_reserved_space(struct inode *inode, qsize_t number); | ||
41 | qsize_t dquot_get_reserved_space(struct inode *inode); | ||
42 | |||
38 | int dquot_free_space(struct inode *inode, qsize_t number); | 43 | int dquot_free_space(struct inode *inode, qsize_t number); |
39 | int dquot_free_inode(const struct inode *inode, qsize_t number); | 44 | int dquot_free_inode(const struct inode *inode, qsize_t number); |
40 | 45 | ||
@@ -203,6 +208,31 @@ static inline int vfs_dq_alloc_inode(struct inode *inode) | |||
203 | return 0; | 208 | return 0; |
204 | } | 209 | } |
205 | 210 | ||
211 | /* | ||
212 | * Convert in-memory reserved quotas to real consumed quotas | ||
213 | */ | ||
214 | static inline int vfs_dq_claim_space(struct inode *inode, qsize_t nr) | ||
215 | { | ||
216 | if (sb_any_quota_active(inode->i_sb)) { | ||
217 | if (inode->i_sb->dq_op->claim_space(inode, nr) == NO_QUOTA) | ||
218 | return 1; | ||
219 | } else | ||
220 | inode_add_bytes(inode, nr); | ||
221 | |||
222 | mark_inode_dirty(inode); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * Release reserved (in-memory) quotas | ||
228 | */ | ||
229 | static inline | ||
230 | void vfs_dq_release_reservation_space(struct inode *inode, qsize_t nr) | ||
231 | { | ||
232 | if (sb_any_quota_active(inode->i_sb)) | ||
233 | inode->i_sb->dq_op->release_rsv(inode, nr); | ||
234 | } | ||
235 | |||
206 | static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) | 236 | static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) |
207 | { | 237 | { |
208 | if (sb_any_quota_active(inode->i_sb)) | 238 | if (sb_any_quota_active(inode->i_sb)) |
@@ -354,6 +384,17 @@ static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr) | |||
354 | return 0; | 384 | return 0; |
355 | } | 385 | } |
356 | 386 | ||
387 | static inline int vfs_dq_claim_space(struct inode *inode, qsize_t nr) | ||
388 | { | ||
389 | return vfs_dq_alloc_space(inode, nr); | ||
390 | } | ||
391 | |||
392 | static inline | ||
393 | int vfs_dq_release_reservation_space(struct inode *inode, qsize_t nr) | ||
394 | { | ||
395 | return 0; | ||
396 | } | ||
397 | |||
357 | static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) | 398 | static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) |
358 | { | 399 | { |
359 | inode_sub_bytes(inode, nr); | 400 | inode_sub_bytes(inode, nr); |
@@ -397,6 +438,18 @@ static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr) | |||
397 | nr << inode->i_blkbits); | 438 | nr << inode->i_blkbits); |
398 | } | 439 | } |
399 | 440 | ||
441 | static inline int vfs_dq_claim_block(struct inode *inode, qsize_t nr) | ||
442 | { | ||
443 | return vfs_dq_claim_space(inode, | ||
444 | nr << inode->i_blkbits); | ||
445 | } | ||
446 | |||
447 | static inline | ||
448 | void vfs_dq_release_reservation_block(struct inode *inode, qsize_t nr) | ||
449 | { | ||
450 | vfs_dq_release_reservation_space(inode, nr << inode->i_blkbits); | ||
451 | } | ||
452 | |||
400 | static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr) | 453 | static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr) |
401 | { | 454 | { |
402 | vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits); | 455 | vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits); |