aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2010-05-13 13:58:50 -0400
committerJan Kara <jack@suse.cz>2010-05-21 13:30:45 -0400
commitbc8e5f07392f05c47c8bdeff4f7098db440d065c (patch)
tree5ab56dabd75912267764849a594ec2f271fd4352 /fs
parent12755627bdcddcdb30a1bfb9a09395a52b1d6838 (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')
-rw-r--r--fs/quota/dquot.c61
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 */
1710static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask) 1714int __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];
1792warn_put_all: 1788warn:
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);
1796put_all:
1797 dqput_all(transfer_from);
1798 dqput_all(transfer_to);
1799 return ret; 1792 return ret;
1800over_quota: 1793over_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}
1798EXPORT_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 */
1812int dquot_transfer(struct inode *inode, struct iattr *iattr) 1803int 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}
1830EXPORT_SYMBOL(dquot_transfer); 1821EXPORT_SYMBOL(dquot_transfer);
1831 1822