Re: [PATCH 11/11] quota: relax dq_data_lock dq_lock locking consistency

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue 05-10-10 22:20:27, Dmitry Monakhov wrote:
> In fact 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.
  OK, but comments like "It is ok to read dqi_bgrace without lock here"
do not explain us why it is ok. Instead of commenting at each place where
we read those values, I'd add more detailed comment before declaration of
mem_dqinfo that dqi_bgrace and dqi_igrace can be read without the lock and
that it's safe because the reads are atomic.

								Honza
> 
> Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxx>
> ---
>  fs/quota/dquot.c |   28 ++++++++--------------------
>  1 files changed, 8 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index fc3b63a..0c9cf67 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -1254,7 +1254,7 @@ static int ignore_hardlimit(struct dquot *dquot)
>  		!(info->dqi_flags & V1_DQF_RSQUASH));
>  }
>  
> -/* needs  dq_data_lock,  ->dq_lock */
> +/* needs  ->dq_lock */
>  static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
>  {
>  	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
> @@ -1284,6 +1284,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
>  	    newinodes > dquot->dq_dqb.dqb_isoftlimit &&
>  	    dquot->dq_dqb.dqb_itime == 0) {
>  		*warntype = QUOTA_NL_ISOFTWARN;
> +		/* It is ok to read dqi_bgrace without lock here */
>  		dquot->dq_dqb.dqb_itime = get_seconds() +
>  		    dq_opt(dquot)->info[dquot->dq_type].dqi_igrace;
>  	}
> @@ -1291,7 +1292,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
>  	return 0;
>  }
>  
> -/* needs  dq_data_lock, ->dq_lock */
> +/* needs  ->dq_lock */
>  static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
>  {
>  	qsize_t tspace;
> @@ -1328,6 +1329,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
>  	    dquot->dq_dqb.dqb_btime == 0) {
>  		if (!prealloc) {
>  			*warntype = QUOTA_NL_BSOFTWARN;
> +			/* It is ok to read dqi_bgrace without lock here */
>  			dquot->dq_dqb.dqb_btime = get_seconds() +
>  			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
>  		}
> @@ -1596,7 +1598,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(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, dquot);
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
>  		if (!dquot[cnt])
> @@ -1604,7 +1605,6 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
>  		ret = check_bdq(dquot[cnt], number, !warn, warntype+cnt);
>  		if (ret && !nofail) {
>  			dquot_unlock_all(dquot);
> -			spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  			goto out_flush_warn;
>  		}
>  	}
> @@ -1618,7 +1618,6 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
>  	}
>  	inode_incr_space(inode, number, reserve);
>  	dquot_unlock_all(dquot);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  
>  	if (reserve)
>  		goto out_flush_warn;
> @@ -1647,7 +1646,6 @@ int dquot_alloc_inode(const struct inode *inode)
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
>  		warntype[cnt] = QUOTA_NL_NOWARN;
>  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> -	spin_lock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, dquot);
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
>  		if (!dquot[cnt])
> @@ -1665,7 +1663,6 @@ int dquot_alloc_inode(const struct inode *inode)
>  
>  warn_put_all:
>  	dquot_unlock_all(dquot);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	if (ret == 0)
>  		mark_all_dquot_dirty(dquot);
>  	flush_warnings(dquot, warntype);
> @@ -1688,7 +1685,6 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
>  	}
>  
>  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> -	spin_lock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, dquot);
>  	/* Claim reserved quotas to allocated quotas */
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> @@ -1698,7 +1694,6 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
>  	/* Update inode bytes */
>  	inode_claim_rsv_space(inode, number);
>  	dquot_unlock_all(dquot);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	mark_all_dquot_dirty(dquot);
>  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
>  	return 0;
> @@ -1723,7 +1718,6 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
>  	}
>  
>  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> -	spin_lock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, dquot);
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
>  		if (!dquot[cnt])
> @@ -1736,7 +1730,6 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
>  	}
>  	inode_decr_space(inode, number, reserve);
>  	dquot_unlock_all(dquot);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  
>  	if (reserve)
>  		goto out_unlock;
> @@ -1762,7 +1755,6 @@ void dquot_free_inode(const struct inode *inode)
>  		return;
>  
>  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> -	spin_lock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, dquot);
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
>  		if (!dquot[cnt])
> @@ -1771,7 +1763,6 @@ void dquot_free_inode(const struct inode *inode)
>  		dquot_decr_inodes(dquot[cnt], 1);
>  	}
>  	dquot_unlock_all(dquot);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	mark_all_dquot_dirty(dquot);
>  	flush_warnings(dquot, warntype);
>  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> @@ -1809,7 +1800,6 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
>  		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
>  		return 0;
>  	}
> -	spin_lock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	inode_dquot_lock(inode, transfer_from);
>  	cur_space = inode_get_bytes(inode);
>  	rsv_space = inode_get_rsv_space(inode);
> @@ -1858,7 +1848,6 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
>  	}
>  	dquot_unlock_all(transfer_to);
>  	dquot_unlock_all(transfer_from);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
>  
>  	mark_all_dquot_dirty(transfer_from);
> @@ -1874,7 +1863,6 @@ warn:
>  over_quota:
>  	dquot_unlock_all(transfer_to);
>  	dquot_unlock_all(transfer_from);
> -	spin_unlock(&sb_dqopt(inode->i_sb)->dq_data_lock);
>  	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
>  	goto warn;
>  }
> @@ -2468,7 +2456,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(&dq_opt(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;
> @@ -2518,7 +2505,8 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  			dm->dqb_btime = 0;
>  			clear_bit(DQ_BLKS_B, &dquot->dq_flags);
>  		} else if (!(di->d_fieldmask & FS_DQ_BTIMER))
> -			/* Set grace only if user hasn't provided his own... */
> +			/* Set grace only if user hasn't provided his own...
> +			   Read dqi_bgrace without lock */
>  			dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
>  	}
>  	if (check_ilim) {
> @@ -2527,7 +2515,8 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  			dm->dqb_itime = 0;
>  			clear_bit(DQ_INODES_B, &dquot->dq_flags);
>  		} else if (!(di->d_fieldmask & FS_DQ_ITIMER))
> -			/* Set grace only if user hasn't provided his own... */
> +			/* Set grace only if user hasn't provided his own...
> +			   Read dqi_bgrace without lock */
>  			dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
>  	}
>  	if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit ||
> @@ -2536,7 +2525,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(&dq_opt(dquot)->dq_data_lock);
>  	mark_dquot_dirty(dquot);
>  
>  	return 0;
> -- 
> 1.6.6.1
> 
-- 
Jan Kara <jack@xxxxxxx>
SUSE Labs, CR
--
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


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux