mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	quota: Propagate error from ->acquire_dquot()
Currently when some error happened in ->acquire_dquot(), dqget() just returned NULL. That was indistinguishable from a case when e.g. someone run quotaoff and so was generally silently ignored. However ->acquire_dquot() can fail because of ENOSPC or EIO in which case user should better know. So propagate error up from ->acquire_dquot properly. Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
		
							parent
							
								
									d725e66c06
								
							
						
					
					
						commit
						6184fc0b8d
					
				
					 4 changed files with 72 additions and 33 deletions
				
			
		| 
						 | 
					@ -1209,8 +1209,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 | 
							    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 | 
				
			||||||
		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
 | 
							    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
 | 
				
			||||||
			transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
 | 
								transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
 | 
				
			||||||
			if (!transfer_to[USRQUOTA]) {
 | 
								if (IS_ERR(transfer_to[USRQUOTA])) {
 | 
				
			||||||
				status = -ESRCH;
 | 
									status = PTR_ERR(transfer_to[USRQUOTA]);
 | 
				
			||||||
				goto bail_unlock;
 | 
									goto bail_unlock;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1218,8 +1218,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 | 
							    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 | 
				
			||||||
		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
 | 
							    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
 | 
				
			||||||
			transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
 | 
								transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
 | 
				
			||||||
			if (!transfer_to[GRPQUOTA]) {
 | 
								if (IS_ERR(transfer_to[GRPQUOTA])) {
 | 
				
			||||||
				status = -ESRCH;
 | 
									status = PTR_ERR(transfer_to[GRPQUOTA]);
 | 
				
			||||||
				goto bail_unlock;
 | 
									goto bail_unlock;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -499,8 +499,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 | 
				
			||||||
			dquot = dqget(sb,
 | 
								dquot = dqget(sb,
 | 
				
			||||||
				      make_kqid(&init_user_ns, type,
 | 
									      make_kqid(&init_user_ns, type,
 | 
				
			||||||
						le64_to_cpu(dqblk->dqb_id)));
 | 
											le64_to_cpu(dqblk->dqb_id)));
 | 
				
			||||||
			if (!dquot) {
 | 
								if (IS_ERR(dquot)) {
 | 
				
			||||||
				status = -EIO;
 | 
									status = PTR_ERR(dquot);
 | 
				
			||||||
				mlog(ML_ERROR, "Failed to get quota structure "
 | 
									mlog(ML_ERROR, "Failed to get quota structure "
 | 
				
			||||||
				     "for id %u, type %d. Cannot finish quota "
 | 
									     "for id %u, type %d. Cannot finish quota "
 | 
				
			||||||
				     "file recovery.\n",
 | 
									     "file recovery.\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,7 +247,7 @@ struct dqstats dqstats;
 | 
				
			||||||
EXPORT_SYMBOL(dqstats);
 | 
					EXPORT_SYMBOL(dqstats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static qsize_t inode_get_rsv_space(struct inode *inode);
 | 
					static qsize_t inode_get_rsv_space(struct inode *inode);
 | 
				
			||||||
static void __dquot_initialize(struct inode *inode, int type);
 | 
					static int __dquot_initialize(struct inode *inode, int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline unsigned int
 | 
					static inline unsigned int
 | 
				
			||||||
hashfn(const struct super_block *sb, struct kqid qid)
 | 
					hashfn(const struct super_block *sb, struct kqid qid)
 | 
				
			||||||
| 
						 | 
					@ -832,16 +832,17 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 | 
				
			||||||
struct dquot *dqget(struct super_block *sb, struct kqid qid)
 | 
					struct dquot *dqget(struct super_block *sb, struct kqid qid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashent = hashfn(sb, qid);
 | 
						unsigned int hashent = hashfn(sb, qid);
 | 
				
			||||||
	struct dquot *dquot = NULL, *empty = NULL;
 | 
						struct dquot *dquot, *empty = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!sb_has_quota_active(sb, qid.type))
 | 
					        if (!sb_has_quota_active(sb, qid.type))
 | 
				
			||||||
		return NULL;
 | 
							return ERR_PTR(-ESRCH);
 | 
				
			||||||
we_slept:
 | 
					we_slept:
 | 
				
			||||||
	spin_lock(&dq_list_lock);
 | 
						spin_lock(&dq_list_lock);
 | 
				
			||||||
	spin_lock(&dq_state_lock);
 | 
						spin_lock(&dq_state_lock);
 | 
				
			||||||
	if (!sb_has_quota_active(sb, qid.type)) {
 | 
						if (!sb_has_quota_active(sb, qid.type)) {
 | 
				
			||||||
		spin_unlock(&dq_state_lock);
 | 
							spin_unlock(&dq_state_lock);
 | 
				
			||||||
		spin_unlock(&dq_list_lock);
 | 
							spin_unlock(&dq_list_lock);
 | 
				
			||||||
 | 
							dquot = ERR_PTR(-ESRCH);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock(&dq_state_lock);
 | 
						spin_unlock(&dq_state_lock);
 | 
				
			||||||
| 
						 | 
					@ -876,11 +877,15 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
 | 
				
			||||||
	 * already finished or it will be canceled due to dq_count > 1 test */
 | 
						 * already finished or it will be canceled due to dq_count > 1 test */
 | 
				
			||||||
	wait_on_dquot(dquot);
 | 
						wait_on_dquot(dquot);
 | 
				
			||||||
	/* Read the dquot / allocate space in quota file */
 | 
						/* Read the dquot / allocate space in quota file */
 | 
				
			||||||
	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) &&
 | 
						if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
 | 
				
			||||||
	    sb->dq_op->acquire_dquot(dquot) < 0) {
 | 
							int err;
 | 
				
			||||||
		dqput(dquot);
 | 
					
 | 
				
			||||||
		dquot = NULL;
 | 
							err = sb->dq_op->acquire_dquot(dquot);
 | 
				
			||||||
		goto out;
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								dqput(dquot);
 | 
				
			||||||
 | 
								dquot = ERR_PTR(err);
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifdef CONFIG_QUOTA_DEBUG
 | 
					#ifdef CONFIG_QUOTA_DEBUG
 | 
				
			||||||
	BUG_ON(!dquot->dq_sb);	/* Has somebody invalidated entry under us? */
 | 
						BUG_ON(!dquot->dq_sb);	/* Has somebody invalidated entry under us? */
 | 
				
			||||||
| 
						 | 
					@ -1390,15 +1395,16 @@ static int dquot_active(const struct inode *inode)
 | 
				
			||||||
 * It is better to call this function outside of any transaction as it
 | 
					 * It is better to call this function outside of any transaction as it
 | 
				
			||||||
 * might need a lot of space in journal for dquot structure allocation.
 | 
					 * might need a lot of space in journal for dquot structure allocation.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void __dquot_initialize(struct inode *inode, int type)
 | 
					static int __dquot_initialize(struct inode *inode, int type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int cnt, init_needed = 0;
 | 
						int cnt, init_needed = 0;
 | 
				
			||||||
	struct dquot **dquots, *got[MAXQUOTAS];
 | 
						struct dquot **dquots, *got[MAXQUOTAS];
 | 
				
			||||||
	struct super_block *sb = inode->i_sb;
 | 
						struct super_block *sb = inode->i_sb;
 | 
				
			||||||
	qsize_t rsv;
 | 
						qsize_t rsv;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dquot_active(inode))
 | 
						if (!dquot_active(inode))
 | 
				
			||||||
		return;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dquots = i_dquot(inode);
 | 
						dquots = i_dquot(inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1407,6 +1413,7 @@ static void __dquot_initialize(struct inode *inode, int type)
 | 
				
			||||||
		struct kqid qid;
 | 
							struct kqid qid;
 | 
				
			||||||
		kprojid_t projid;
 | 
							kprojid_t projid;
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
 | 
							struct dquot *dquot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		got[cnt] = NULL;
 | 
							got[cnt] = NULL;
 | 
				
			||||||
		if (type != -1 && cnt != type)
 | 
							if (type != -1 && cnt != type)
 | 
				
			||||||
| 
						 | 
					@ -1438,16 +1445,25 @@ static void __dquot_initialize(struct inode *inode, int type)
 | 
				
			||||||
			qid = make_kqid_projid(projid);
 | 
								qid = make_kqid_projid(projid);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		got[cnt] = dqget(sb, qid);
 | 
							dquot = dqget(sb, qid);
 | 
				
			||||||
 | 
							if (IS_ERR(dquot)) {
 | 
				
			||||||
 | 
								/* We raced with somebody turning quotas off... */
 | 
				
			||||||
 | 
								if (PTR_ERR(dquot) != -ESRCH) {
 | 
				
			||||||
 | 
									ret = PTR_ERR(dquot);
 | 
				
			||||||
 | 
									goto out_put;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dquot = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							got[cnt] = dquot;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* All required i_dquot has been initialized */
 | 
						/* All required i_dquot has been initialized */
 | 
				
			||||||
	if (!init_needed)
 | 
						if (!init_needed)
 | 
				
			||||||
		return;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&dq_data_lock);
 | 
						spin_lock(&dq_data_lock);
 | 
				
			||||||
	if (IS_NOQUOTA(inode))
 | 
						if (IS_NOQUOTA(inode))
 | 
				
			||||||
		goto out_err;
 | 
							goto out_lock;
 | 
				
			||||||
	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 | 
						for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 | 
				
			||||||
		if (type != -1 && cnt != type)
 | 
							if (type != -1 && cnt != type)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
| 
						 | 
					@ -1469,15 +1485,18 @@ static void __dquot_initialize(struct inode *inode, int type)
 | 
				
			||||||
				dquot_resv_space(dquots[cnt], rsv);
 | 
									dquot_resv_space(dquots[cnt], rsv);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out_err:
 | 
					out_lock:
 | 
				
			||||||
	spin_unlock(&dq_data_lock);
 | 
						spin_unlock(&dq_data_lock);
 | 
				
			||||||
 | 
					out_put:
 | 
				
			||||||
	/* Drop unused references */
 | 
						/* Drop unused references */
 | 
				
			||||||
	dqput_all(got);
 | 
						dqput_all(got);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dquot_initialize(struct inode *inode)
 | 
					int dquot_initialize(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__dquot_initialize(inode, -1);
 | 
						return __dquot_initialize(inode, -1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(dquot_initialize);
 | 
					EXPORT_SYMBOL(dquot_initialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1961,18 +1980,37 @@ EXPORT_SYMBOL(__dquot_transfer);
 | 
				
			||||||
int dquot_transfer(struct inode *inode, struct iattr *iattr)
 | 
					int dquot_transfer(struct inode *inode, struct iattr *iattr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dquot *transfer_to[MAXQUOTAS] = {};
 | 
						struct dquot *transfer_to[MAXQUOTAS] = {};
 | 
				
			||||||
 | 
						struct dquot *dquot;
 | 
				
			||||||
	struct super_block *sb = inode->i_sb;
 | 
						struct super_block *sb = inode->i_sb;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dquot_active(inode))
 | 
						if (!dquot_active(inode))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
 | 
						if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){
 | 
				
			||||||
		transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
 | 
							dquot = dqget(sb, make_kqid_uid(iattr->ia_uid));
 | 
				
			||||||
	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
 | 
							if (IS_ERR(dquot)) {
 | 
				
			||||||
		transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
 | 
								if (PTR_ERR(dquot) != -ESRCH) {
 | 
				
			||||||
 | 
									ret = PTR_ERR(dquot);
 | 
				
			||||||
 | 
									goto out_put;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dquot = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							transfer_to[USRQUOTA] = dquot;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){
 | 
				
			||||||
 | 
							dquot = dqget(sb, make_kqid_gid(iattr->ia_gid));
 | 
				
			||||||
 | 
							if (IS_ERR(dquot)) {
 | 
				
			||||||
 | 
								if (PTR_ERR(dquot) != -ESRCH) {
 | 
				
			||||||
 | 
									ret = PTR_ERR(dquot);
 | 
				
			||||||
 | 
									goto out_put;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dquot = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							transfer_to[GRPQUOTA] = dquot;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	ret = __dquot_transfer(inode, transfer_to);
 | 
						ret = __dquot_transfer(inode, transfer_to);
 | 
				
			||||||
 | 
					out_put:
 | 
				
			||||||
	dqput_all(transfer_to);
 | 
						dqput_all(transfer_to);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2518,8 +2556,8 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
 | 
				
			||||||
	struct dquot *dquot;
 | 
						struct dquot *dquot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dquot = dqget(sb, qid);
 | 
						dquot = dqget(sb, qid);
 | 
				
			||||||
	if (!dquot)
 | 
						if (IS_ERR(dquot))
 | 
				
			||||||
		return -ESRCH;
 | 
							return PTR_ERR(dquot);
 | 
				
			||||||
	do_get_dqblk(dquot, di);
 | 
						do_get_dqblk(dquot, di);
 | 
				
			||||||
	dqput(dquot);
 | 
						dqput(dquot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2631,8 +2669,8 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dquot = dqget(sb, qid);
 | 
						dquot = dqget(sb, qid);
 | 
				
			||||||
	if (!dquot) {
 | 
						if (IS_ERR(dquot)) {
 | 
				
			||||||
		rc = -ESRCH;
 | 
							rc = PTR_ERR(dquot);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc = do_set_dqblk(dquot, di);
 | 
						rc = do_set_dqblk(dquot, di);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ void inode_claim_rsv_space(struct inode *inode, qsize_t number);
 | 
				
			||||||
void inode_sub_rsv_space(struct inode *inode, qsize_t number);
 | 
					void inode_sub_rsv_space(struct inode *inode, qsize_t number);
 | 
				
			||||||
void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);
 | 
					void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dquot_initialize(struct inode *inode);
 | 
					int dquot_initialize(struct inode *inode);
 | 
				
			||||||
void dquot_drop(struct inode *inode);
 | 
					void dquot_drop(struct inode *inode);
 | 
				
			||||||
struct dquot *dqget(struct super_block *sb, struct kqid qid);
 | 
					struct dquot *dqget(struct super_block *sb, struct kqid qid);
 | 
				
			||||||
static inline struct dquot *dqgrab(struct dquot *dquot)
 | 
					static inline struct dquot *dqgrab(struct dquot *dquot)
 | 
				
			||||||
| 
						 | 
					@ -200,8 +200,9 @@ static inline int sb_has_quota_active(struct super_block *sb, int type)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void dquot_initialize(struct inode *inode)
 | 
					static inline int dquot_initialize(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void dquot_drop(struct inode *inode)
 | 
					static inline void dquot_drop(struct inode *inode)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue