Consistency between mem_info and dq_dqb is weak because we just copy data from dqi_{bi}grace to dqb_{bi}time. So we protect dqb_{bi}time from races with quota_ctl call. Nothing actually happens if we relax this consistency requirement. Since dqi_{bi}grace is (int) it is possible read it atomically without lock. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- fs/quota/dquot.c | 16 ---------------- include/linux/quota.h | 2 ++ 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 794c486..33dc32e 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1668,7 +1668,6 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = QUOTA_NL_NOWARN; - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); lock_inode_dquots(inode->i_dquot); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (!inode->i_dquot[cnt]) @@ -1677,7 +1676,6 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) warntype + cnt); if (ret && !nofail) { unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); goto out_flush_warn; } } @@ -1691,7 +1689,6 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) } inode_incr_space(inode, number, reserve); unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); if (reserve) goto out_flush_warn; @@ -1726,7 +1723,6 @@ int dquot_alloc_inode(const struct inode *inode) for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = QUOTA_NL_NOWARN; down_read(&dqopts(inode->i_sb)->dqptr_sem); - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); lock_inode_dquots(inode->i_dquot); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (!inode->i_dquot[cnt]) @@ -1744,7 +1740,6 @@ int dquot_alloc_inode(const struct inode *inode) warn_put_all: unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); if (ret == 0) mark_all_dquot_dirty(inode->i_dquot); flush_warnings(inode->i_dquot, warntype); @@ -1770,7 +1765,6 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) idx = srcu_read_lock(&dqopts(inode->i_sb)->dq_srcu); rcu_read_unlock(); down_read(&dqopts(inode->i_sb)->dqptr_sem); - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); lock_inode_dquots(inode->i_dquot); /* Claim reserved quotas to allocated quotas */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1781,7 +1775,6 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) /* Update inode bytes */ inode_claim_rsv_space(inode, number); unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); mark_all_dquot_dirty(inode->i_dquot); up_read(&dqopts(inode->i_sb)->dqptr_sem); srcu_read_unlock(&dqopts(inode->i_sb)->dq_srcu, idx); @@ -1810,7 +1803,6 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) idx = srcu_read_lock(&dqopts(inode->i_sb)->dq_srcu); rcu_read_unlock(); down_read(&dqopts(inode->i_sb)->dqptr_sem); - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); lock_inode_dquots(inode->i_dquot); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (!inode->i_dquot[cnt]) @@ -1823,7 +1815,6 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) } inode_decr_space(inode, number, reserve); unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); if (reserve) goto out_unlock; @@ -1853,7 +1844,6 @@ void dquot_free_inode(const struct inode *inode) idx = srcu_read_lock(&dqopts(inode->i_sb)->dq_srcu); rcu_read_unlock(); down_read(&dqopts(inode->i_sb)->dqptr_sem); - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); lock_inode_dquots(inode->i_dquot); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (!inode->i_dquot[cnt]) @@ -1862,7 +1852,6 @@ void dquot_free_inode(const struct inode *inode) dquot_decr_inodes(inode->i_dquot[cnt], 1); } unlock_inode_dquots(inode->i_dquot); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); mark_all_dquot_dirty(inode->i_dquot); flush_warnings(inode->i_dquot, warntype); up_read(&dqopts(inode->i_sb)->dqptr_sem); @@ -1909,7 +1898,6 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) srcu_read_unlock(&dqopts(inode->i_sb)->dq_srcu, idx); return 0; } - spin_lock(&dqopts(inode->i_sb)->dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* * Skip changes for same uid or gid or for turned off quota-type. @@ -1968,7 +1956,6 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) } unlock_inode_dquots(transfer_to); unlock_inode_dquots(transfer_from); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); up_write(&dqopts(inode->i_sb)->dqptr_sem); srcu_read_unlock(&dqopts(inode->i_sb)->dq_srcu, idx); mark_all_dquot_dirty(transfer_from); @@ -1984,7 +1971,6 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) over_quota: unlock_inode_dquots(transfer_to); unlock_inode_dquots(transfer_from); - spin_unlock(&dqopts(inode->i_sb)->dq_data_lock); up_write(&dqopts(inode->i_sb)->dqptr_sem); srcu_read_unlock(&dqopts(inode->i_sb)->dq_srcu, idx); flush_warnings(transfer_to, warntype_to); @@ -2596,7 +2582,6 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di) (di->d_ino_hardlimit > dqi->dqi_maxilimit))) return -ERANGE; - spin_lock(&sb_dqopts(dquot)->dq_data_lock); spin_lock(&dquot->dq_lock); if (di->d_fieldmask & FS_DQ_BCOUNT) { dm->dqb_curspace = di->d_bcount - dm->dqb_rsvspace; @@ -2664,7 +2649,6 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di) else set_bit(DQ_FAKE_B, &dquot->dq_flags); spin_unlock(&dquot->dq_lock); - spin_unlock(&sb_dqopts(dquot)->dq_data_lock); mark_dquot_dirty(dquot); return 0; diff --git a/include/linux/quota.h b/include/linux/quota.h index c88a352..949347a 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -221,6 +221,8 @@ struct mem_dqinfo { * quotas on after remount RW */ struct list_head dqi_dirty_list; /* List of dirty dquots */ unsigned long dqi_flags; + /* Readers are allowed to read following two variables without + ->dq_data_lock held */ unsigned int dqi_bgrace; unsigned int dqi_igrace; qsize_t dqi_maxblimit; -- 1.6.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html