diff options
author | Jan Kara <jack@suse.cz> | 2010-05-13 13:58:50 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2010-05-21 13:30:45 -0400 |
commit | bc8e5f07392f05c47c8bdeff4f7098db440d065c (patch) | |
tree | 5ab56dabd75912267764849a594ec2f271fd4352 /fs/quota/dquot.c | |
parent | 12755627bdcddcdb30a1bfb9a09395a52b1d6838 (diff) |
quota: Refactor dquot_transfer code so that OCFS2 can pass in its references
Currently, __dquot_transfer() acquires its own references of dquot structures
that will be put into inode. But for OCFS2, this creates a lock inversion
between dq_lock (waited on in dqget) and transaction start (started in
ocfs2_setattr). Currently, deadlock is impossible because dq_lock is acquired
only during dquot_acquire and dquot_release and we already hold a reference to
dquot structures in ocfs2_setattr so neither of these functions can be called
while we call dquot_transfer. But this is rather subtle and it is hard to teach
lockdep about it. So provide __dquot_transfer function that can be passed dquot
references directly. OCFS2 can then pass acquired dquot references directly to
__dquot_transfer with proper locking.
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/quota/dquot.c')
-rw-r--r-- | fs/quota/dquot.c | 61 |
1 files changed, 26 insertions, 35 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 1056a21f0300..655a4c52b8c3 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -1703,16 +1703,19 @@ EXPORT_SYMBOL(dquot_free_inode); | |||
1703 | 1703 | ||
1704 | /* | 1704 | /* |
1705 | * Transfer the number of inode and blocks from one diskquota to an other. | 1705 | * Transfer the number of inode and blocks from one diskquota to an other. |
1706 | * On success, dquot references in transfer_to are consumed and references | ||
1707 | * to original dquots that need to be released are placed there. On failure, | ||
1708 | * references are kept untouched. | ||
1706 | * | 1709 | * |
1707 | * This operation can block, but only after everything is updated | 1710 | * This operation can block, but only after everything is updated |
1708 | * A transaction must be started when entering this function. | 1711 | * A transaction must be started when entering this function. |
1712 | * | ||
1709 | */ | 1713 | */ |
1710 | static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask) | 1714 | int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) |
1711 | { | 1715 | { |
1712 | qsize_t space, cur_space; | 1716 | qsize_t space, cur_space; |
1713 | qsize_t rsv_space = 0; | 1717 | qsize_t rsv_space = 0; |
1714 | struct dquot *transfer_from[MAXQUOTAS]; | 1718 | struct dquot *transfer_from[MAXQUOTAS] = {}; |
1715 | struct dquot *transfer_to[MAXQUOTAS]; | ||
1716 | int cnt, ret = 0; | 1719 | int cnt, ret = 0; |
1717 | char warntype_to[MAXQUOTAS]; | 1720 | char warntype_to[MAXQUOTAS]; |
1718 | char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS]; | 1721 | char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS]; |
@@ -1722,19 +1725,12 @@ static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask | |||
1722 | if (IS_NOQUOTA(inode)) | 1725 | if (IS_NOQUOTA(inode)) |
1723 | return 0; | 1726 | return 0; |
1724 | /* Initialize the arrays */ | 1727 | /* Initialize the arrays */ |
1725 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1728 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) |
1726 | transfer_from[cnt] = NULL; | ||
1727 | transfer_to[cnt] = NULL; | ||
1728 | warntype_to[cnt] = QUOTA_NL_NOWARN; | 1729 | warntype_to[cnt] = QUOTA_NL_NOWARN; |
1729 | } | ||
1730 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
1731 | if (mask & (1 << cnt)) | ||
1732 | transfer_to[cnt] = dqget(inode->i_sb, chid[cnt], cnt); | ||
1733 | } | ||
1734 | down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1730 | down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); |
1735 | if (IS_NOQUOTA(inode)) { /* File without quota accounting? */ | 1731 | if (IS_NOQUOTA(inode)) { /* File without quota accounting? */ |
1736 | up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1732 | up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); |
1737 | goto put_all; | 1733 | return 0; |
1738 | } | 1734 | } |
1739 | spin_lock(&dq_data_lock); | 1735 | spin_lock(&dq_data_lock); |
1740 | cur_space = inode_get_bytes(inode); | 1736 | cur_space = inode_get_bytes(inode); |
@@ -1786,46 +1782,41 @@ static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask | |||
1786 | 1782 | ||
1787 | mark_all_dquot_dirty(transfer_from); | 1783 | mark_all_dquot_dirty(transfer_from); |
1788 | mark_all_dquot_dirty(transfer_to); | 1784 | mark_all_dquot_dirty(transfer_to); |
1789 | /* The reference we got is transferred to the inode */ | 1785 | /* Pass back references to put */ |
1790 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | 1786 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) |
1791 | transfer_to[cnt] = NULL; | 1787 | transfer_to[cnt] = transfer_from[cnt]; |
1792 | warn_put_all: | 1788 | warn: |
1793 | flush_warnings(transfer_to, warntype_to); | 1789 | flush_warnings(transfer_to, warntype_to); |
1794 | flush_warnings(transfer_from, warntype_from_inodes); | 1790 | flush_warnings(transfer_from, warntype_from_inodes); |
1795 | flush_warnings(transfer_from, warntype_from_space); | 1791 | flush_warnings(transfer_from, warntype_from_space); |
1796 | put_all: | ||
1797 | dqput_all(transfer_from); | ||
1798 | dqput_all(transfer_to); | ||
1799 | return ret; | 1792 | return ret; |
1800 | over_quota: | 1793 | over_quota: |
1801 | spin_unlock(&dq_data_lock); | 1794 | spin_unlock(&dq_data_lock); |
1802 | up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1795 | up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); |
1803 | /* Clear dquot pointers we don't want to dqput() */ | 1796 | goto warn; |
1804 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | ||
1805 | transfer_from[cnt] = NULL; | ||
1806 | goto warn_put_all; | ||
1807 | } | 1797 | } |
1798 | EXPORT_SYMBOL(__dquot_transfer); | ||
1808 | 1799 | ||
1809 | /* Wrapper for transferring ownership of an inode for uid/gid only | 1800 | /* Wrapper for transferring ownership of an inode for uid/gid only |
1810 | * Called from FSXXX_setattr() | 1801 | * Called from FSXXX_setattr() |
1811 | */ | 1802 | */ |
1812 | int dquot_transfer(struct inode *inode, struct iattr *iattr) | 1803 | int dquot_transfer(struct inode *inode, struct iattr *iattr) |
1813 | { | 1804 | { |
1814 | qid_t chid[MAXQUOTAS]; | 1805 | struct dquot *transfer_to[MAXQUOTAS] = {}; |
1815 | unsigned long mask = 0; | 1806 | struct super_block *sb = inode->i_sb; |
1807 | int ret; | ||
1816 | 1808 | ||
1817 | if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) { | 1809 | if (!sb_any_quota_active(sb) || IS_NOQUOTA(inode)) |
1818 | mask |= 1 << USRQUOTA; | 1810 | return 0; |
1819 | chid[USRQUOTA] = iattr->ia_uid; | ||
1820 | } | ||
1821 | if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) { | ||
1822 | mask |= 1 << GRPQUOTA; | ||
1823 | chid[GRPQUOTA] = iattr->ia_gid; | ||
1824 | } | ||
1825 | if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) | ||
1826 | return __dquot_transfer(inode, chid, mask); | ||
1827 | 1811 | ||
1828 | return 0; | 1812 | if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) |
1813 | transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA); | ||
1814 | if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) | ||
1815 | transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_uid, GRPQUOTA); | ||
1816 | |||
1817 | ret = __dquot_transfer(inode, transfer_to); | ||
1818 | dqput_all(transfer_to); | ||
1819 | return ret; | ||
1829 | } | 1820 | } |
1830 | EXPORT_SYMBOL(dquot_transfer); | 1821 | EXPORT_SYMBOL(dquot_transfer); |
1831 | 1822 | ||